diff --git a/capabilities/testdrive-jsui/IMPLEMENTATION_NOTES.md b/capabilities/testdrive-jsui/IMPLEMENTATION_NOTES.md
deleted file mode 100644
index 20ee9765..00000000
--- a/capabilities/testdrive-jsui/IMPLEMENTATION_NOTES.md
+++ /dev/null
@@ -1,146 +0,0 @@
-# TestDrive-JSUI Implementation Notes
-
-## Enhanced ControlBase Architecture
-
-### Overview
-The ControlBase class has been significantly enhanced to provide advanced panel behavior patterns based on the reference implementation in `relicts/DebugControlContent.html`. This creates a modern, interactive foundation for all UI control panels.
-
-### Key Features Implemented
-
-#### 1. Icon-Only Collapsed State
-- **Behavior**: Controls start as compact 40px icon buttons
-- **Styling**: Clean design with subtle shadows and hover effects
-- **Positioning**: Compass-based positioning (N, NE, E, SE, S, SW, W, NW)
-- **Implementation**: `control-toggle` button with icon display
-
-#### 2. Expand/Drag Functionality
-- **Behavior**: Click icon expands to full panel; drag header to reposition when expanded
-- **Event Handling**: Proper event delegation prevents conflicts
-- **Position Tracking**: Maintains drag offset for smooth movement
-- **Implementation**: `startDrag()`, `handleDrag()`, `stopDrag()` methods
-
-#### 3. Bottom-Left Corner Resize
-- **Behavior**: Resize handle (↙) appears in bottom-left when expanded
-- **Constraints**: Minimum 200px width, 150px height
-- **Direction**: Bottom-left resize (expand down and left)
-- **Implementation**: `addResizeHandle()`, resize event handlers
-
-#### 4. Collapse with Position Restoration
-- **Behavior**: Close button (✕) returns to original compass position
-- **State Management**: Clears drag positioning, restores transform/positioning
-- **Cleanup**: Removes resize handles and event listeners
-- **Implementation**: `collapse()` method with `originalPosition` restoration
-
-#### 5. Header Toggle for Content Visibility
-- **Behavior**: Click title toggles content area visibility
-- **States**: Full expanded vs header-only modes
-- **Preservation**: Maintains expanded state while hiding content
-- **Implementation**: `toggleHeaderOnly()` method
-
-### Technical Architecture
-
-#### State Management
-```javascript
-this.isExpanded = false; // Icon vs expanded panel
-this.isHeaderOnly = false; // Header-only vs full content
-this.isDragging = false; // Drag operation active
-this.isResizing = false; // Resize operation active
-this.originalPosition = null; // Compass position storage
-```
-
-#### DOM Structure
-```html
-
testdrive-jsui
-cd testdrive-jsui
-
-# Install Python package in development mode
-pip install -e .
-
-# (Optional) Install JavaScript dependencies for testing
-npm install
-```
-
-### Integration with MarkiTect
-
-If using within the MarkiTect project:
-
-```bash
-# Navigate to the capability directory
-cd capabilities/testdrive-jsui
-
-# Quick setup (installs everything)
-make testdrive-jsui-quickstart
-
-# Or step by step:
-make testdrive-jsui-setup # Install all dependencies
-make testdrive-jsui-status # Check environment
-make testdrive-jsui-test-all # Run all tests
-```
-
-## 📦 **Standalone Usage**
-
-### As a Rendering Engine Plugin
-
-TestDrive-JSUI implements a plugin interface that allows it to be used independently:
-
-```python
-from pathlib import Path
-from testdrive_jsui import TestDriveJSUIEngine
-
-# Create engine instance
-engine = TestDriveJSUIEngine()
-
-# The engine declares its own location - no hardcoded paths!
-source_dir = engine.get_plugin_source_dir()
-print(f"Plugin located at: {source_dir}")
-
-# Get organized asset paths
-asset_paths = engine.get_asset_paths()
-# Returns: {'js': Path(...), 'css': Path(...), 'images': Path(...), 'templates': Path(...)}
-
-# Get required assets list
-assets = engine.get_required_assets()
-# Returns: {'js': [...], 'css': [...], 'images': [...], 'external': [...]}
-```
-
-### Rendering Documents
-
-Use the engine to render markdown content with an interactive JavaScript UI:
-
-```python
-from testdrive_jsui import TestDriveJSUIEngine
-from markitect.plugins.rendering import RenderingConfig
-from pathlib import Path
-
-# Create engine
-engine = TestDriveJSUIEngine()
-
-# Configure for development (serves from source)
-config = RenderingConfig(
- asset_base_url='.',
- development_mode=True,
- plugin_source_dirs={'testdrive-jsui': engine.get_plugin_source_dir()}
-)
-
-# Render markdown content
-markdown_content = """
-# My Document
-
-This is a test of the **TestDrive-JSUI** rendering engine.
-
-## Features
-- Interactive editing
-- Section management
-- Debug controls
-"""
-
-html = engine.render_document(markdown_content, 'edit', config)
-
-# Save to file
-Path('output.html').write_text(html)
-print("✅ Rendered to output.html")
-```
-
-### Production Deployment
-
-For production, deploy assets to a static directory:
-
-```python
-from testdrive_jsui import TestDriveJSUIEngine
-from markitect.plugins.rendering import RenderingConfig
-from pathlib import Path
-
-engine = TestDriveJSUIEngine()
-
-# Configure for production
-config = RenderingConfig(
- asset_base_url='/_static',
- development_mode=False,
- output_directory=Path('./dist')
-)
-
-# Assets will be copied to: dist/_static/plugins/testdrive-jsui/
-html = engine.render_document(content, 'view', config)
-```
-
-### Plugin Independence
-
-TestDrive-JSUI is designed to be fully independent:
-
-- ✅ **Self-contained**: All assets in one directory
-- ✅ **Self-declaring**: Plugin declares its own location
-- ✅ **No hardcoded paths**: Works regardless of installation location
-- ✅ **Clean interface**: Pure JSON configuration boundary
-- ✅ **No JavaScript in Python**: All JS in separate files
-- ✅ **Reusable**: Can be used in any Python project
-
-### Supported Modes
-
-```python
-# Check supported rendering modes
-modes = engine.get_supported_modes()
-# Returns: ['edit', 'view']
-
-# Validate a mode
-if engine.validate_mode('edit'):
- html = engine.render_document(content, 'edit', config)
-```
-
-## 🧪 **Testing**
-
-### JavaScript Tests
-
-```bash
-# Run JavaScript tests only
-make testdrive-jsui-test-js
-
-# Run with coverage
-npm run test:coverage
-
-# Watch mode for development
-make testdrive-jsui-watch
-```
-
-### Python Integration Tests
-
-```bash
-# Run Python tests only
-make testdrive-jsui-test-python
-
-# Run integration tests
-make testdrive-jsui-test-integration
-
-# Run all tests
-make testdrive-jsui-test-all
-```
-
-### Main Project Integration
-
-From the main MarkiTect project:
-
-```bash
-# Run capability tests
-make testdrive-jsui-test-all
-
-# Include in main test suite
-make test-all # (when integrated)
-```
-
-## 📋 **Available Commands**
-
-| Command | Description |
-|---------|-------------|
-| `make testdrive-jsui-help` | Show all available commands |
-| `make testdrive-jsui-status` | Check environment status |
-| `make testdrive-jsui-setup` | Install all dependencies |
-| `make testdrive-jsui-test-all` | Run all tests |
-| `make testdrive-jsui-watch` | Development watch mode |
-| `make testdrive-jsui-clean` | Clean build artifacts |
-
-## 🔧 **Development**
-
-### Adding JavaScript Tests
-
-1. Create test files in `js/tests/`:
- ```javascript
- // js/tests/test-my-component.js
- describe('MyComponent', () => {
- test('should do something', () => {
- // Your test here
- });
- });
- ```
-
-2. Run tests:
- ```bash
- make testdrive-jsui-test-js
- ```
-
-### Adding Python Integration Tests
-
-1. Create test files in `tests/`:
- ```python
- # tests/test_my_integration.py
- import pytest
- from testdrive_jsui.testing import JavaScriptTestRunner
-
- @pytest.mark.javascript
- def test_my_js_component():
- runner = JavaScriptTestRunner()
- result = runner.run_specific_test('test-my-component.js')
- assert result.success
- ```
-
-2. Run tests:
- ```bash
- make testdrive-jsui-test-integration
- ```
-
-### Code Quality
-
-```bash
-# Lint JavaScript
-make testdrive-jsui-lint-js
-
-# Lint Python
-make testdrive-jsui-lint-python
-
-# Format Python code
-make testdrive-jsui-format-python
-```
-
-## 🔗 **Integration with Main Project**
-
-### Python Test Suite Integration
-
-The capability provides pytest integration to run JavaScript tests from Python:
-
-```python
-# In main project tests
-from testdrive_jsui.testing import JavaScriptTestRunner
-
-def test_javascript_ui_components():
- runner = JavaScriptTestRunner()
- result = runner.run_js_tests()
- assert result.success
- assert result.tests_passed > 0
-```
-
-### Capability System Integration
-
-The capability integrates with MarkiTect's capability discovery system:
-
-```bash
-# From main project
-make capabilities-list # Shows testdrive-jsui
-make testdrive-jsui-test-all # Direct delegation
-make capabilities-test # Includes JS tests
-```
-
-## 📊 **Testing Framework Features**
-
-### JavaScript Test Runner
-
-- **Jest integration** with JSDOM environment
-- **Coverage reporting** with detailed metrics
-- **Test isolation** with proper setup/teardown
-- **Mock support** for DOM APIs and browser features
-- **Async testing** support for modern JavaScript
-
-### Python-JavaScript Bridge
-
-- **Subprocess execution** of JavaScript tests
-- **Result parsing** with structured output
-- **Error handling** with detailed failure information
-- **Test discovery** for pytest integration
-- **Coverage integration** between Python and JavaScript
-
-### Safety Mechanisms
-
-- **Copy-first migration** (never move, always copy)
-- **Dual-track testing** during migration
-- **Gradual integration** with rollback options
-- **Test verification** at each step
-- **Environment validation** before execution
-
-## 🔄 **Migration Strategy**
-
-When migrating JavaScript UI code to this capability:
-
-1. **Copy** (don't move) JavaScript files to `js/` directory
-2. **Verify** tests work in new location
-3. **Create** Python integration tests
-4. **Run** dual-track testing to compare results
-5. **Gradually** switch to capability-based testing
-6. **Remove** original files only after full verification
-
-## 📚 **Examples**
-
-### Running Specific Tests
-
-```bash
-# Run a specific JavaScript test
-npm test -- --testNamePattern="SectionManager"
-
-# Run specific Python integration test
-pytest tests/test_section_manager_integration.py -v
-
-# Run tests with coverage
-npm run test:coverage
-```
-
-### Environment Information
-
-```bash
-# Get detailed environment info
-make testdrive-jsui-info
-
-# Check what tests are available
-make testdrive-jsui-status
-```
-
-### Development Workflow
-
-```bash
-# Start development session
-make testdrive-jsui-watch # Terminal 1: Watch JS tests
-make testdrive-jsui-test-python # Terminal 2: Run Python tests
-
-# Before committing
-make testdrive-jsui-lint-js # Lint JavaScript
-make testdrive-jsui-format-python # Format Python
-make testdrive-jsui-test-all # Run all tests
-```
-
-## 🎯 **Future Enhancements**
-
-- **Visual regression testing** with screenshot comparison
-- **Performance benchmarking** for JavaScript components
-- **Browser automation** with Selenium/Playwright
-- **Component documentation** auto-generation
-- **Real browser testing** in CI/CD pipelines
-
-## 📋 **Troubleshooting**
-
-### Common Issues
-
-**Node.js not found:**
-```bash
-# Install Node.js first
-curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
-sudo apt-get install -y nodejs
-```
-
-**Tests failing:**
-```bash
-# Check environment
-make testdrive-jsui-status
-
-# Reinstall dependencies
-make testdrive-jsui-clean
-make testdrive-jsui-setup
-```
-
-**Integration issues:**
-```bash
-# Verify Python package is installed
-pip list | grep testdrive-jsui
-
-# Check JavaScript dependencies
-npm list
-```
-
-## 📄 **License**
-
-MIT License - See main MarkiTect project for details.
-
----
-
-*Generated: 2025-11-09*
-*Status: Phase 1 Implementation*
-*Next: Copy JavaScript files and create integration tests*
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/components/debug-panel.js b/capabilities/testdrive-jsui/js/components/debug-panel.js
deleted file mode 100644
index d22706a0..00000000
--- a/capabilities/testdrive-jsui/js/components/debug-panel.js
+++ /dev/null
@@ -1,191 +0,0 @@
-/**
- * DebugPanel Component
- *
- * Extracted from monolithic editor.js as part of architecture refactoring.
- * Handles debug message display and management for client-side debugging.
- *
- * Dependencies:
- * - None (standalone component)
- */
-
-/**
- * DebugPanel - Manages debug message display and interaction
- */
-class DebugPanel {
- constructor() {
- this.messages = [];
- this.isActive = false;
- this.maxMessages = 1000; // Keep last 1000 messages
- }
-
- /**
- * Add a debug message
- */
- addMessage(message, category = 'INFO') {
- const messageObj = {
- message,
- category,
- timestamp: new Date().toLocaleTimeString()
- };
-
- this.messages.push(messageObj);
-
- // Keep only last maxMessages
- if (this.messages.length > this.maxMessages) {
- this.messages = this.messages.slice(-this.maxMessages);
- }
-
- // Auto-update if panel is visible
- if (this.isActive) {
- this.update();
- }
- }
-
- /**
- * Toggle the debug panel on/off
- */
- toggle() {
- const debugContainer = document.getElementById('debug-messages-container');
- const debugButton = document.getElementById('toggle-debug');
-
- if (!debugContainer || !debugButton) {
- console.warn('DebugPanel: Required DOM elements not found');
- return;
- }
-
- if (this.isActive) {
- this.hide();
- } else {
- this.show();
- }
- }
-
- /**
- * Show the debug panel
- */
- show() {
- const debugContainer = document.getElementById('debug-messages-container');
- const debugButton = document.getElementById('toggle-debug');
-
- if (!debugContainer || !debugButton) {
- console.warn('DebugPanel: Required DOM elements not found');
- return;
- }
-
- debugContainer.style.display = 'block';
- debugButton.textContent = '🔍 Debug (ON)';
- debugButton.style.background = '#28a745';
- this.isActive = true;
- this.update();
- }
-
- /**
- * Hide the debug panel
- */
- hide() {
- const debugContainer = document.getElementById('debug-messages-container');
- const debugButton = document.getElementById('toggle-debug');
-
- if (!debugContainer || !debugButton) {
- console.warn('DebugPanel: Required DOM elements not found');
- return;
- }
-
- debugContainer.style.display = 'none';
- debugButton.textContent = '🔍 Debug';
- debugButton.style.background = '#6c757d';
- this.isActive = false;
- }
-
- /**
- * Update the debug panel with current messages
- */
- update() {
- const debugContainer = document.getElementById('debug-messages-container');
- if (!debugContainer || !this.isActive) {
- return;
- }
-
- if (this.messages.length === 0) {
- debugContainer.innerHTML = 'No debug messages yet. Click sections to generate debug output.
';
- return;
- }
-
- // Show the last 50 messages in reverse order (newest first)
- const recentMessages = this.messages.slice(-50).reverse();
-
- const messagesHtml = recentMessages.map(msg => {
- const categoryColor = {
- 'INFO': '#17a2b8',
- 'WARNING': '#ffc107',
- 'ERROR': '#dc3545',
- 'SUCCESS': '#28a745',
- 'DEBUG': '#6f42c1'
- }[msg.category] || '#6c757d';
-
- return `
-
- [${msg.timestamp}]
- ${msg.category}:
- ${msg.message}
-
- `;
- }).join('');
-
- debugContainer.innerHTML = `
-
- Debug Messages (${this.messages.length} total, showing last ${recentMessages.length})
-
-
-
- ${messagesHtml}
-
- `;
-
- // Add event listener for clear button
- const clearBtn = debugContainer.querySelector('#debug-clear-btn');
- if (clearBtn) {
- clearBtn.addEventListener('click', () => {
- this.clear();
- });
- }
-
- // Auto-scroll to bottom to show newest messages
- const scrollContainer = debugContainer.querySelector('div[style*="overflow-y"]');
- if (scrollContainer) {
- scrollContainer.scrollTop = scrollContainer.scrollHeight;
- }
- }
-
- /**
- * Clear all debug messages
- */
- clear() {
- this.messages = [];
- this.update();
- }
-
- /**
- * Get the number of messages
- */
- getMessageCount() {
- return this.messages.length;
- }
-
- /**
- * Get recent messages
- */
- getRecentMessages(count = 10) {
- return this.messages.slice(-count);
- }
-}
-
-// Export for use in tests and other modules
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = { DebugPanel };
-}
-
-// Export for browser use
-if (typeof window !== 'undefined') {
- window.DebugPanel = DebugPanel;
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/components/dom-renderer.js b/capabilities/testdrive-jsui/js/components/dom-renderer.js
deleted file mode 100644
index 20748483..00000000
--- a/capabilities/testdrive-jsui/js/components/dom-renderer.js
+++ /dev/null
@@ -1,1128 +0,0 @@
-/**
- * DOMRenderer Component
- *
- * Extracted from monolithic editor.js as part of architecture refactoring.
- * Handles all DOM interactions and UI rendering for section editing.
- *
- * Dependencies:
- * - FloatingMenu component (to be extracted)
- * - debug function (imported from utils)
- */
-
-// Import dependencies (placeholders for now)
-function debug(message, category = 'INFO') {
- console.log(`DEBUG ${category}: ${message}`);
-}
-
-/**
- * Simple FloatingMenu implementation (will be extracted to separate component later)
- */
-class FloatingMenu {
- constructor(sectionId, type, renderer) {
- this.sectionId = sectionId;
- this.type = type;
- this.renderer = renderer;
- this.element = null;
- this.isVisible = false;
- }
-
- show(contentElement, controlsElement) {
- if (this.isVisible) this.hide();
-
- const targetElement = this.renderer.findSectionElement(this.sectionId);
- if (!targetElement) return null;
-
- // Get content dimensions and position
- const rect = targetElement.getBoundingClientRect();
- const viewport = {
- width: window.innerWidth,
- height: window.innerHeight
- };
-
- // Calculate content width and responsive extension
- const contentWidth = rect.width;
- const buttonAreaWidth = 120; // Space needed for buttons
- const minMenuWidth = Math.max(300, contentWidth); // At least content width or 300px
- const preferredMenuWidth = contentWidth + buttonAreaWidth;
-
- // Check if we have space to extend to the right
- const spaceOnRight = viewport.width - rect.right;
- const canExtendRight = spaceOnRight >= buttonAreaWidth + 20; // 20px margin
-
- // Determine final menu width
- let menuWidth;
- if (canExtendRight && viewport.width >= 800) { // Only on wide screens
- menuWidth = Math.min(preferredMenuWidth, viewport.width - rect.left - 20);
- } else {
- menuWidth = Math.min(minMenuWidth, viewport.width - 40); // 20px margins
- }
-
- // Create floating menu element
- this.element = document.createElement('div');
- this.element.className = 'ui-edit-floating-menu';
- this.element.style.cssText = `
- position: fixed;
- z-index: 10000;
- background: white;
- border: 1px solid #ddd;
- border-radius: 8px;
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
- padding: 0;
- width: ${menuWidth}px;
- box-sizing: border-box;
- `;
-
- // Add headline
- const headline = document.createElement('div');
- headline.className = 'ui-edit-headline';
- headline.textContent = `Editing ${this.type === 'image' ? 'Image' : 'Section'}`;
- headline.style.cssText = `
- background: #f8f9fa;
- border-bottom: 1px solid #ddd;
- padding: 8px 16px;
- font-weight: 600;
- font-size: 12px;
- color: #495057;
- border-radius: 8px 8px 0 0;
- text-transform: uppercase;
- letter-spacing: 0.5px;
- `;
-
- // Create content wrapper with padding
- const contentWrapper = document.createElement('div');
- contentWrapper.style.cssText = `
- padding: 16px;
- `;
-
- this.element.appendChild(headline);
-
- // Position directly over content (overlay positioning)
- let left = rect.left;
- let top = rect.top;
-
- // Ensure menu doesn't go off-screen horizontally
- if (left + menuWidth > viewport.width) {
- left = viewport.width - menuWidth - 20;
- }
- if (left < 10) {
- left = 10;
- }
-
- // For vertical positioning, prefer staying on top of content
- // Only move if absolutely necessary
- const menuHeight = this.type === 'image' ? 350 : 200; // Better height estimates
- const wouldGoOffBottom = top + menuHeight > viewport.height;
- const wouldGoOffTop = top < 10;
-
- if (wouldGoOffBottom && !wouldGoOffTop) {
- // Try to fit by moving up, but keep some overlay if possible
- const maxTop = viewport.height - menuHeight - 10;
- top = Math.max(rect.top - 50, maxTop); // Prefer staying near original position
- } else if (wouldGoOffTop) {
- top = 10; // Minimum distance from top
- }
- // Otherwise, keep the original overlay position
-
- this.element.style.left = `${left}px`;
- this.element.style.top = `${top}px`;
-
- // Add content to wrapper
- if (contentElement) {
- contentWrapper.appendChild(contentElement);
- }
- if (controlsElement) {
- contentWrapper.appendChild(controlsElement);
- }
-
- this.element.appendChild(contentWrapper);
-
- // Add close button to headline
- const closeButton = document.createElement('button');
- closeButton.textContent = '×';
- closeButton.style.cssText = `
- position: absolute;
- top: 4px;
- right: 8px;
- background: none;
- border: none;
- font-size: 18px;
- cursor: pointer;
- color: #666;
- width: 24px;
- height: 24px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 4px;
- transition: background-color 0.2s ease;
- `;
- closeButton.addEventListener('mouseover', () => {
- closeButton.style.backgroundColor = '#e9ecef';
- });
- closeButton.addEventListener('mouseout', () => {
- closeButton.style.backgroundColor = 'transparent';
- });
- closeButton.addEventListener('click', (event) => {
- event.stopPropagation();
- this.hide();
- });
- this.element.appendChild(closeButton);
-
- document.body.appendChild(this.element);
- this.isVisible = true;
-
- return this.element;
- }
-
- hide() {
- if (this.element && this.element.parentNode) {
- this.element.parentNode.removeChild(this.element);
- }
- this.element = null;
- this.isVisible = false;
-
- // Stop editing state in the section manager
- const section = this.renderer.sectionManager.sections.get(this.sectionId);
- if (section && section.isEditing()) {
- section.stopEditing();
- }
-
- // Remove from editing sections
- this.renderer.editingSections.delete(this.sectionId);
- }
-}
-
-/**
- * DOMRenderer - Handles DOM interactions and section rendering
- */
-class DOMRenderer {
- constructor(sectionManager, container) {
- this.sectionManager = sectionManager;
- this.container = container;
- this.editingSections = new Set();
- this.currentFloatingMenu = null;
- this.eventListenersAttached = false;
- this.lastClickTime = 0;
- this.clickDebounceMs = 300; // Prevent rapid clicks
-
- // Enhanced Event System - Track event types
- this.eventHistory = [];
- this.eventStats = {
- 'section-click': 0,
- 'section-hover-enter': 0,
- 'section-hover-leave': 0,
- 'keyboard-shortcut': 0,
- 'section-drag-start': 0,
- 'section-drag-over': 0,
- 'section-drop': 0,
- 'section-focus-in': 0,
- 'section-focus-out': 0,
- 'section-context-menu': 0
- };
-
- // Bind event handlers
- this.handleSectionClick = this.handleSectionClick.bind(this);
- this.handleKeydown = this.handleKeydown.bind(this);
-
- this.setupEventListeners();
- }
-
- setupEventListeners() {
- this.sectionManager.on('sections-created', (data) => {
- this.renderAllSections(data.sections);
- });
- this.sectionManager.on('edit-started', (data) => {
- debug('EVENT: edit-started event received for: ' + data.sectionId, 'EVENT');
- this.showEditor(data.sectionId, data.content);
- });
- }
-
- /**
- * Render all sections to the DOM
- */
- renderAllSections(sections) {
- debug('21: renderAllSections called with ' + sections.length + ' sections', 'RENDER');
-
- // Clear container
- this.container.innerHTML = '';
- debug('22: Container cleared', 'RENDER');
-
- const contentArea = this.container.querySelector('#markdown-content') || this.container;
-
- // Render each section
- sections.forEach((section, index) => {
- debug('23: Creating element for section ' + (index + 1) + ': ' + section.id, 'RENDER');
- const element = this.renderSection(section);
- if (element) {
- contentArea.appendChild(element);
- }
- });
-
- debug('24: All section elements added to container', 'RENDER');
-
- // Attach event listeners only once
- if (!this.eventListenersAttached) {
- this.container.addEventListener('click', this.handleSectionClick);
- this.eventListenersAttached = true;
- debug('25: Enhanced event listeners attached for the first time', 'RENDER');
- } else {
- debug('25: Event listeners already attached, skipping', 'RENDER');
- }
-
- debug('25: Container content length: ' + this.container.innerHTML.length, 'RENDER');
- }
-
- /**
- * Render a single section to DOM element
- */
- renderSection(section) {
- const element = document.createElement('div');
- element.className = 'ui-edit-section';
- element.setAttribute('data-section-id', section.id);
-
- // Add section content
- // Render all sections using markdown rendering (images need HTML conversion too)
- const content = this.simpleMarkdownRender(section.currentMarkdown);
- element.innerHTML = content;
-
- // Add styling
- element.style.cssText = `
- margin: 16px 0;
- padding: 12px;
- border: 1px solid transparent;
- border-radius: 4px;
- cursor: pointer;
- transition: all 0.2s ease;
- `;
-
- element.addEventListener('mouseenter', () => {
- element.style.backgroundColor = 'rgba(0, 122, 204, 0.05)';
- element.style.borderColor = 'rgba(0, 122, 204, 0.2)';
- });
-
- element.addEventListener('mouseleave', () => {
- if (!section.isEditing()) {
- element.style.backgroundColor = 'transparent';
- element.style.borderColor = 'transparent';
- }
- });
-
- debug('SECTION: Section element setup complete for ' + section.id, 'SECTION');
- return element;
- }
-
- /**
- * Simple markdown rendering (placeholder)
- */
- simpleMarkdownRender(markdown) {
- return markdown
- .replace(/^# (.*$)/gim, '$1
')
- .replace(/^## (.*$)/gim, '$1
')
- .replace(/^### (.*$)/gim, '$1
')
- .replace(/!\[(.*?)\]\((.*?)\)/gim, '
')
- .replace(/\[([^\]]+)\]\(([^)]+)\)/gim, '$1')
- .replace(/\*\*(.*?)\*\*/gim, '$1')
- .replace(/\*(.*?)\*/gim, '$1')
- .replace(/\n/gim, '
');
- }
-
- /**
- * Find DOM element for a section
- */
- findSectionElement(sectionId) {
- return this.container.querySelector(`[data-section-id="${sectionId}"]`);
- }
-
- /**
- * Handle section click events
- */
- handleSectionClick(event) {
- debug('handleSectionClick: Click detected on target: ' + event.target.tagName + ' ' + (event.target.className || ''), 'CLICK');
-
- // Debounce rapid clicks
- const now = Date.now();
- if (now - this.lastClickTime < this.clickDebounceMs) {
- debug('handleSectionClick: Click debounced (too rapid)', 'CLICK');
- return;
- }
- this.lastClickTime = now;
-
- // Don't handle clicks on form elements, buttons, or links
- if (event.target.closest('textarea, button, input, a')) {
- debug('handleSectionClick: Ignoring click on form element', 'CLICK');
- return;
- }
-
- const sectionElement = event.target.closest('.ui-edit-section');
- debug('handleSectionClick: Found section element: ' + (sectionElement ? sectionElement.getAttribute('data-section-id') : 'null'), 'CLICK');
- if (!sectionElement) return;
-
- const sectionId = sectionElement.getAttribute('data-section-id');
- debug('handleSectionClick: Section ID: ' + sectionId, 'CLICK');
- if (!sectionId) return;
-
- // Track the click event
- this.trackEvent('section-click', {
- sectionId,
- event,
- timestamp: Date.now()
- });
-
- // Check if this section is already being edited
- const section = this.sectionManager.sections.get(sectionId);
- debug('handleSectionClick: Found section object: ' + (section ? 'YES' : 'NO'), 'CLICK');
-
- if (section && section.isEditing()) {
- debug('handleSectionClick: Section already being edited, checking if dialog is visible: ' + sectionId, 'CLICK');
- // If section is editing but no dialog is visible, allow re-opening
- const existingDialog = document.querySelector('.ui-edit-floating-menu');
- if (existingDialog) {
- debug('handleSectionClick: Dialog already visible, ignoring click', 'CLICK');
- return;
- } else {
- debug('handleSectionClick: Section editing but no dialog visible, proceeding to show editor', 'CLICK');
- }
- }
-
- debug('handleSectionClick: About to start editing for section: ' + sectionId, 'CLICK');
-
- try {
- debug('handleSectionClick: Calling sectionManager.startEditing', 'CLICK');
- this.sectionManager.startEditing(sectionId);
- debug('handleSectionClick: Successfully called startEditing', 'CLICK');
- } catch (error) {
- debug('handleSectionClick: ERROR in startEditing: ' + error.message, 'ERROR');
- console.error('Failed to start editing:', error);
- }
- }
-
- /**
- * Show editor for a section
- */
- showEditor(sectionId, content) {
- debug('showEditor: called for section: ' + sectionId, 'EDITOR');
-
- const element = this.findSectionElement(sectionId);
- debug('showEditor: Found element: ' + (element ? 'YES' : 'NO'), 'EDITOR');
- if (!element) return;
-
- debug('showEditor: About to hide current editor', 'EDITOR');
- this.hideCurrentEditor();
- debug('showEditor: Hidden current editor', 'EDITOR');
-
- const section = this.sectionManager.sections.get(sectionId);
- const isImageSection = section && section.isImage();
-
- if (isImageSection) {
- this.showImageEditor(sectionId, section);
- return;
- }
-
- // Create content area for text editing
- const editorContent = document.createElement('div');
- editorContent.className = 'ui-edit-editor-content';
-
- // Check if we have space for side-by-side layout
- const targetElement = this.findSectionElement(sectionId);
- const rect = targetElement ? targetElement.getBoundingClientRect() : null;
- const viewport = { width: window.innerWidth, height: window.innerHeight };
- const hasWideLayout = rect && viewport.width >= 800 && (viewport.width - rect.right) >= 120;
-
- if (hasWideLayout) {
- // Side-by-side layout: textarea on left, controls on right
- editorContent.style.cssText = `
- display: flex;
- gap: 16px;
- flex: 1;
- min-width: 0;
- align-items: flex-start;
- `;
- } else {
- // Stacked layout: textarea above, controls below
- editorContent.style.cssText = `
- display: flex;
- flex-direction: column;
- gap: 12px;
- flex: 1;
- min-width: 0;
- `;
- }
-
- // Create textarea container
- const textareaContainer = document.createElement('div');
- textareaContainer.style.cssText = hasWideLayout ? 'flex: 1; min-width: 0;' : 'width: 100%;';
-
- // Create textarea
- const textarea = document.createElement('textarea');
- textarea.value = content || section.currentMarkdown;
- textarea.style.cssText = `
- width: 100%;
- min-height: 120px;
- padding: 12px;
- border: 1px solid #ddd;
- border-radius: 4px;
- font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
- font-size: 14px;
- line-height: 1.5;
- resize: vertical;
- box-sizing: border-box;
- `;
-
- // Create controls
- const controls = document.createElement('div');
- if (hasWideLayout) {
- controls.style.cssText = `
- display: flex;
- flex-direction: column;
- gap: 8px;
- min-width: 100px;
- flex-shrink: 0;
- `;
- } else {
- controls.style.cssText = `
- display: flex;
- gap: 8px;
- justify-content: flex-end;
- flex-wrap: wrap;
- `;
- }
-
- const acceptButton = document.createElement('button');
- acceptButton.textContent = hasWideLayout ? '✓' : 'Accept';
- acceptButton.style.cssText = `
- background: #28a745;
- color: white;
- border: none;
- padding: ${hasWideLayout ? '8px 12px' : '8px 16px'};
- border-radius: 4px;
- cursor: pointer;
- ${hasWideLayout ? 'width: 100%;' : ''}
- font-size: ${hasWideLayout ? '14px' : '13px'};
- `;
-
- const cancelButton = document.createElement('button');
- cancelButton.textContent = hasWideLayout ? '✗' : 'Cancel';
- cancelButton.style.cssText = `
- background: #dc3545;
- color: white;
- border: none;
- padding: ${hasWideLayout ? '8px 12px' : '8px 16px'};
- border-radius: 4px;
- cursor: pointer;
- ${hasWideLayout ? 'width: 100%;' : ''}
- font-size: ${hasWideLayout ? '14px' : '13px'};
- `;
-
- const resetButton = document.createElement('button');
- resetButton.textContent = hasWideLayout ? '↺' : '↺ Reset';
- resetButton.style.cssText = `
- background: #fd7e14;
- color: white;
- border: none;
- padding: ${hasWideLayout ? '8px 12px' : '8px 16px'};
- border-radius: 4px;
- cursor: pointer;
- ${hasWideLayout ? 'width: 100%;' : ''}
- font-size: ${hasWideLayout ? '14px' : '13px'};
- `;
-
- controls.appendChild(acceptButton);
- controls.appendChild(cancelButton);
- controls.appendChild(resetButton);
-
- // Assemble the layout
- textareaContainer.appendChild(textarea);
-
- if (hasWideLayout) {
- editorContent.appendChild(textareaContainer);
- editorContent.appendChild(controls);
- } else {
- editorContent.appendChild(textareaContainer);
- editorContent.appendChild(controls);
- }
-
- // Create floating menu
- const floatingMenu = new FloatingMenu(sectionId, 'text', this);
- this.currentFloatingMenu = floatingMenu;
- this.editingSections.add(sectionId);
-
- floatingMenu.show(editorContent);
-
- // Add event listeners
- acceptButton.addEventListener('click', () => {
- this.sectionManager.updateContent(sectionId, textarea.value);
- this.sectionManager.acceptChanges(sectionId);
- floatingMenu.hide();
- this.currentFloatingMenu = null; // Clear reference
- });
-
- cancelButton.addEventListener('click', () => {
- this.sectionManager.cancelChanges(sectionId);
- floatingMenu.hide();
- this.currentFloatingMenu = null; // Clear reference
- });
-
- resetButton.addEventListener('click', () => {
- // Reset textarea to original content and apply the change
- const section = this.sectionManager.sections.get(sectionId);
- if (section) {
- textarea.value = section.originalMarkdown;
- // Actually update the section content to original and accept the changes
- this.sectionManager.updateContent(sectionId, section.originalMarkdown);
- this.sectionManager.acceptChanges(sectionId);
- // Close the editor
- floatingMenu.hide();
- this.currentFloatingMenu = null;
- }
- });
-
- // Auto-focus textarea
- setTimeout(() => textarea.focus(), 100);
- }
-
- /**
- * Show advanced image editor with drag & drop, file upload, and preview
- */
- showImageEditor(sectionId, section) {
- debug('showImageEditor: called for image section: ' + sectionId, 'EDITOR');
-
- // Track staging state for this editor
- const stagingState = {
- originalMarkdown: section.originalMarkdown,
- currentAltText: '',
- currentImageSrc: '',
- stagedImageSrc: null,
- stagedAltText: null,
- hasChanges: false
- };
-
- // Parse markdown to extract image info
- const imageMatch = section.currentMarkdown.match(/!\[(.*?)\]\((.*?)\)/);
- if (imageMatch) {
- const [, altText, imageSrc] = imageMatch;
- stagingState.currentAltText = altText;
- stagingState.currentImageSrc = imageSrc;
- }
-
- // Check if we have space for side-by-side layout
- const targetElement = this.findSectionElement(sectionId);
- const rect = targetElement ? targetElement.getBoundingClientRect() : null;
- const viewport = { width: window.innerWidth, height: window.innerHeight };
- const hasWideLayout = rect && viewport.width >= 800 && (viewport.width - rect.right) >= 120;
-
- // Create image editor content area
- const editorContent = document.createElement('div');
- editorContent.className = 'ui-edit-image-content';
-
- if (hasWideLayout) {
- // Side-by-side layout: content on left, controls on right
- editorContent.style.cssText = `
- display: flex;
- gap: 16px;
- flex: 1;
- min-width: 0;
- align-items: flex-start;
- `;
- } else {
- // Stacked layout: content above, controls below
- editorContent.style.cssText = `
- display: flex;
- flex-direction: column;
- gap: 15px;
- flex: 1;
- min-width: 0;
- `;
- }
-
- // Create content container for image and alt text
- const contentContainer = document.createElement('div');
- contentContainer.style.cssText = hasWideLayout ? 'flex: 1; min-width: 0;' : 'width: 100%;';
- if (!hasWideLayout) {
- contentContainer.style.cssText += `
- display: flex;
- flex-direction: column;
- gap: 15px;
- `;
- } else {
- contentContainer.style.cssText += `
- display: flex;
- flex-direction: column;
- gap: 12px;
- `;
- }
-
- // Image preview with drop zone
- const imagePreview = document.createElement('div');
- imagePreview.className = 'ui-edit-image-preview';
- imagePreview.style.cssText = `
- width: 100%;
- height: 180px;
- text-align: center;
- background: white;
- padding: 12px;
- border-radius: 8px;
- border: 2px dashed #007bff;
- transition: all 0.3s ease;
- cursor: pointer;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- position: relative;
- box-sizing: border-box;
- overflow: hidden;
- `;
-
- // Function to update image preview
- const updateImagePreview = (imageSrc, altText) => {
- imagePreview.innerHTML = '';
-
- if (imageSrc) {
- const img = document.createElement('img');
- img.src = imageSrc;
- img.alt = altText || '';
- img.style.cssText = `
- max-width: 100%;
- max-height: 150px;
- border-radius: 4px;
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
- `;
- imagePreview.appendChild(img);
-
- // Add overlay for drop zone
- const overlay = document.createElement('div');
- overlay.className = 'drop-overlay';
- overlay.style.cssText = `
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(0, 123, 255, 0.1);
- border-radius: 6px;
- display: none;
- align-items: center;
- justify-content: center;
- color: #007bff;
- font-weight: bold;
- font-size: 16px;
- `;
- overlay.textContent = '📁 Drop new image here';
- imagePreview.appendChild(overlay);
- } else {
- // Show drop zone placeholder
- const placeholder = document.createElement('div');
- placeholder.style.cssText = `
- text-align: center;
- color: #6c757d;
- font-size: 14px;
- `;
- placeholder.innerHTML = `
- 📁
- Drop image here or click to select
- Supports JPG, PNG, GIF, WebP
- `;
- imagePreview.appendChild(placeholder);
- }
- };
-
- // Initialize preview
- updateImagePreview(stagingState.currentImageSrc, stagingState.currentAltText);
-
- // File input for image selection
- const fileInput = document.createElement('input');
- fileInput.type = 'file';
- fileInput.accept = 'image/*';
- fileInput.style.display = 'none';
-
- // Function to handle image file selection
- const handleImageFile = (file) => {
- if (file && file.type.startsWith('image/')) {
- const reader = new FileReader();
- reader.onload = (event) => {
- stagingState.stagedImageSrc = event.target.result;
- stagingState.hasChanges = true;
- updateImagePreview(stagingState.stagedImageSrc, altTextInput.value);
- updateChangeIndicator();
- };
- reader.readAsDataURL(file);
- }
- };
-
- // Drag and drop functionality
- imagePreview.addEventListener('dragover', (e) => {
- e.preventDefault();
- imagePreview.style.borderColor = '#28a745';
- imagePreview.style.backgroundColor = '#f8fff8';
- const overlay = imagePreview.querySelector('.drop-overlay');
- if (overlay) overlay.style.display = 'flex';
- });
-
- imagePreview.addEventListener('dragleave', (e) => {
- e.preventDefault();
- imagePreview.style.borderColor = '#007bff';
- imagePreview.style.backgroundColor = 'white';
- const overlay = imagePreview.querySelector('.drop-overlay');
- if (overlay) overlay.style.display = 'none';
- });
-
- imagePreview.addEventListener('drop', (e) => {
- e.preventDefault();
- imagePreview.style.borderColor = '#007bff';
- imagePreview.style.backgroundColor = 'white';
- const overlay = imagePreview.querySelector('.drop-overlay');
- if (overlay) overlay.style.display = 'none';
-
- const files = e.dataTransfer.files;
- if (files.length > 0) {
- handleImageFile(files[0]);
- }
- });
-
- // Click to select file
- imagePreview.addEventListener('click', () => {
- fileInput.click();
- });
-
- fileInput.addEventListener('change', (e) => {
- if (e.target.files.length > 0) {
- handleImageFile(e.target.files[0]);
- }
- });
-
- // Alt text editor
- const altTextContainer = document.createElement('div');
- altTextContainer.className = 'ui-edit-alt-text-container';
- altTextContainer.style.cssText = `
- display: flex;
- flex-direction: column;
- gap: 8px;
- `;
-
- const altTextLabel = document.createElement('label');
- altTextLabel.textContent = 'Alt Text Description:';
- altTextLabel.style.cssText = `
- font-size: 13px;
- font-weight: 600;
- color: #333;
- margin: 0;
- `;
-
- const altTextInput = document.createElement('input');
- altTextInput.type = 'text';
- altTextInput.value = stagingState.currentAltText;
- altTextInput.style.cssText = `
- width: 100%;
- padding: 10px 12px;
- border: 1px solid #ddd;
- border-radius: 6px;
- font-size: 14px;
- box-sizing: border-box;
- outline: none;
- transition: border-color 0.2s ease;
- `;
-
- altTextInput.addEventListener('focus', () => {
- altTextInput.style.borderColor = '#007bff';
- });
-
- altTextInput.addEventListener('blur', () => {
- altTextInput.style.borderColor = '#ddd';
- });
-
- // Track alt text changes
- altTextInput.addEventListener('input', () => {
- stagingState.stagedAltText = altTextInput.value;
- stagingState.hasChanges = altTextInput.value !== stagingState.currentAltText || stagingState.stagedImageSrc !== null;
- updateChangeIndicator();
- });
-
- altTextContainer.appendChild(altTextLabel);
- altTextContainer.appendChild(altTextInput);
-
- // Change indicator
- const changeIndicator = document.createElement('div');
- changeIndicator.className = 'change-indicator';
- changeIndicator.style.cssText = `
- padding: 8px 12px;
- background: #fff3cd;
- border: 1px solid #ffeaa7;
- border-radius: 6px;
- color: #856404;
- font-size: 12px;
- text-align: center;
- display: none;
- font-weight: 500;
- `;
- changeIndicator.textContent = '⚠️ You have unsaved changes';
-
- const updateChangeIndicator = () => {
- if (stagingState.hasChanges) {
- changeIndicator.style.display = 'block';
- } else {
- changeIndicator.style.display = 'none';
- }
- };
-
- // Assemble content container
- contentContainer.appendChild(imagePreview);
- contentContainer.appendChild(altTextContainer);
- contentContainer.appendChild(changeIndicator);
- contentContainer.appendChild(fileInput);
-
- // Create controls
- const controls = document.createElement('div');
- controls.className = 'ui-edit-controls';
- if (hasWideLayout) {
- controls.style.cssText = `
- display: flex;
- flex-direction: column;
- gap: 8px;
- min-width: 100px;
- flex-shrink: 0;
- `;
- } else {
- controls.style.cssText = `
- display: flex;
- flex-direction: column;
- gap: 8px;
- width: 100%;
- `;
- }
-
- const acceptBtn = document.createElement('button');
- acceptBtn.textContent = hasWideLayout ? '✓' : '✓ Accept';
- acceptBtn.style.cssText = `
- padding: ${hasWideLayout ? '8px 12px' : '8px 12px'};
- font-size: ${hasWideLayout ? '14px' : '12px'};
- border-radius: 6px;
- border: none;
- color: white;
- cursor: pointer;
- font-weight: 600;
- transition: all 0.2s ease;
- width: 100%;
- text-align: center;
- background: #28a745;
- `;
-
- const cancelBtn = document.createElement('button');
- cancelBtn.textContent = hasWideLayout ? '✗' : '✗ Cancel';
- cancelBtn.style.cssText = `
- padding: ${hasWideLayout ? '8px 12px' : '8px 12px'};
- font-size: ${hasWideLayout ? '14px' : '12px'};
- border-radius: 6px;
- border: none;
- color: white;
- cursor: pointer;
- font-weight: 600;
- transition: all 0.2s ease;
- width: 100%;
- text-align: center;
- background: #dc3545;
- `;
-
- const resetBtn = document.createElement('button');
- resetBtn.textContent = hasWideLayout ? '↺' : '↺ Reset';
- resetBtn.style.cssText = `
- padding: ${hasWideLayout ? '8px 12px' : '8px 12px'};
- font-size: ${hasWideLayout ? '14px' : '12px'};
- border-radius: 6px;
- border: none;
- color: white;
- cursor: pointer;
- font-weight: 600;
- transition: all 0.2s ease;
- width: 100%;
- text-align: center;
- background: #fd7e14;
- `;
-
- controls.appendChild(acceptBtn);
- controls.appendChild(cancelBtn);
- controls.appendChild(resetBtn);
-
-
- // Event handlers
- acceptBtn.addEventListener('click', () => {
- // Apply staged changes only when accept is clicked
- if (stagingState.hasChanges) {
- let newMarkdown = stagingState.originalMarkdown;
-
- // Apply image source change if staged
- if (stagingState.stagedImageSrc !== null) {
- const currentImageMatch = newMarkdown.match(/!\[(.*?)\]\((.*?)\)/);
- if (currentImageMatch) {
- newMarkdown = newMarkdown.replace(
- /!\[(.*?)\]\((.*?)\)/,
- `![${currentImageMatch[1]}](${stagingState.stagedImageSrc})`
- );
- }
- }
-
- // Apply alt text change if staged
- if (stagingState.stagedAltText !== null) {
- newMarkdown = newMarkdown.replace(
- /!\[(.*?)\]/,
- `![${stagingState.stagedAltText}]`
- );
- }
-
- // Update section with final changes
- this.sectionManager.updateContent(sectionId, newMarkdown);
- }
-
- // Accept changes and hide editor
- this.sectionManager.acceptChanges(sectionId);
- this.currentFloatingMenu.hide();
- this.currentFloatingMenu = null;
- });
-
- cancelBtn.addEventListener('click', () => {
- // Discard all staged changes and hide editor
- this.sectionManager.cancelChanges(sectionId);
- this.currentFloatingMenu.hide();
- this.currentFloatingMenu = null;
- });
-
- resetBtn.addEventListener('click', (event) => {
- event.preventDefault();
- event.stopPropagation();
-
- // Reset to original content
- const originalImageMatch = stagingState.originalMarkdown.match(/!\[(.*?)\]\((.*?)\)/);
-
- if (originalImageMatch) {
- const [, originalAltText, originalImageSrc] = originalImageMatch;
-
- // Update staging state to original values
- stagingState.currentAltText = originalAltText;
- stagingState.currentImageSrc = originalImageSrc;
-
- // Clear any staged changes
- stagingState.stagedImageSrc = null;
- stagingState.stagedAltText = null;
- stagingState.hasChanges = false;
-
- // Reset alt text input to original
- altTextInput.value = originalAltText;
-
- // Trigger input event to ensure UI consistency
- const inputEvent = new Event('input', { bubbles: true, cancelable: true });
- altTextInput.dispatchEvent(inputEvent);
-
- // Reset preview to original image
- updateImagePreview(originalImageSrc, originalAltText);
-
- // Update change indicator
- updateChangeIndicator();
-
- // Actually update the section content to original and accept the changes
- this.sectionManager.updateContent(sectionId, stagingState.originalMarkdown);
- this.sectionManager.acceptChanges(sectionId);
-
- // Close the editor
- this.currentFloatingMenu.hide();
- this.currentFloatingMenu = null;
- }
- });
-
- // Assemble the final layout
- if (hasWideLayout) {
- editorContent.appendChild(contentContainer);
- editorContent.appendChild(controls);
- } else {
- editorContent.appendChild(contentContainer);
- editorContent.appendChild(controls);
- }
-
- // Create floating menu
- const floatingMenu = new FloatingMenu(sectionId, 'image', this);
- this.currentFloatingMenu = floatingMenu;
- this.editingSections.add(sectionId);
-
- floatingMenu.show(editorContent);
- }
-
- /**
- * Hide current editor
- */
- hideCurrentEditor() {
- debug('EDITOR: hideCurrentEditor called', 'EDITOR');
-
- if (this.currentFloatingMenu) {
- this.currentFloatingMenu.hide();
- this.currentFloatingMenu = null;
- }
-
- debug('EDITOR: hideCurrentEditor completed', 'EDITOR');
- }
-
- /**
- * Track event for analytics
- */
- trackEvent(eventType, data) {
- const eventRecord = {
- type: eventType,
- data: data,
- timestamp: new Date().toISOString()
- };
-
- this.eventHistory.push(eventRecord);
- if (this.eventStats.hasOwnProperty(eventType)) {
- this.eventStats[eventType]++;
- }
-
- // Keep only last 100 events
- if (this.eventHistory.length > 100) {
- this.eventHistory = this.eventHistory.slice(-100);
- }
- }
-
- /**
- * Get event statistics
- */
- getEventStats() {
- const totalEvents = Object.values(this.eventStats).reduce((sum, count) => sum + count, 0);
-
- return {
- stats: { ...this.eventStats },
- totalEvents,
- recentEvents: this.eventHistory.slice(-10)
- };
- }
-
- /**
- * Handle keyboard shortcuts
- */
- handleKeydown(event) {
- // Basic keyboard shortcut handling
- if (event.ctrlKey || event.metaKey) {
- if (event.key === 'Enter') {
- // Accept changes
- const activeSection = Array.from(this.editingSections)[0];
- if (activeSection) {
- this.trackEvent('keyboard-shortcut', { shortcut: 'ctrl+enter', action: 'accept' });
- }
- } else if (event.key === 'Escape') {
- // Cancel changes
- const activeSection = Array.from(this.editingSections)[0];
- if (activeSection) {
- this.trackEvent('keyboard-shortcut', { shortcut: 'escape', action: 'cancel' });
- this.hideCurrentEditor();
- }
- }
- }
- }
-}
-
-// Export for use in tests and other modules
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = { DOMRenderer, FloatingMenu };
-}
-
-// Export for browser use
-if (typeof window !== 'undefined') {
- window.DOMRenderer = DOMRenderer;
- window.FloatingMenu = FloatingMenu;
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/config-loader.js b/capabilities/testdrive-jsui/js/config-loader.js
deleted file mode 100644
index 70964a7c..00000000
--- a/capabilities/testdrive-jsui/js/config-loader.js
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * Configuration Loader - Clean interface between Python and JavaScript
- *
- * This module provides the ONLY interface for Python-generated data.
- * All dynamic data from Python must be passed through this JSON configuration.
- */
-
-class MarkitectConfig {
- constructor() {
- this.config = null;
- this.loaded = false;
-
- // Simple immediate loading - if script is loaded, DOM is ready
- this.loadConfig();
- }
-
- loadConfig() {
- try {
- const configElement = document.getElementById('markitect-config');
- if (!configElement) {
- throw new Error('Markitect configuration not found - missing markitect-config script element');
- }
-
- this.config = JSON.parse(configElement.textContent);
- this.loaded = true;
- console.log('✅ Markitect configuration loaded successfully');
-
- // Validate required fields
- this.validateConfig();
-
- } catch (error) {
- console.error('❌ Failed to load Markitect configuration:', error);
- this.config = this.getDefaultConfig();
- }
- }
-
- validateConfig() {
- const required = ['markdownContent', 'mode'];
- const missing = required.filter(key => !(key in this.config));
-
- if (missing.length > 0) {
- console.warn('⚠️ Missing required config fields:', missing);
- }
- }
-
- getDefaultConfig() {
- return {
- markdownContent: '# Default Content\n\nConfiguration failed to load.',
- markdownContentWithDogtag: '# Default Content\n\nConfiguration failed to load.',
- dogtagContent: '',
- mode: 'edit',
- theme: 'github',
- keyboardShortcuts: true,
- autosave: false,
- sections: true,
- originalFilename: 'document',
- version: 'Markitect v0.8.1',
- repoName: 'Markitect',
- base64References: {}
- };
- }
-
- // Getter methods for clean access
- get markdownContent() {
- return this.config.markdownContent || '';
- }
-
- get markdownContentWithDogtag() {
- return this.config.markdownContentWithDogtag || this.markdownContent;
- }
-
- get dogtagContent() {
- return this.config.dogtagContent || '';
- }
-
- get mode() {
- return this.config.mode || 'edit';
- }
-
- get isEditMode() {
- return this.mode === 'edit';
- }
-
- get isInsertMode() {
- return this.mode === 'insert';
- }
-
- get theme() {
- return this.config.theme || 'github';
- }
-
- get originalFilename() {
- return this.config.originalFilename || 'document';
- }
-
- get version() {
- return this.config.version || 'Markitect v0.8.1';
- }
-
- get repoName() {
- return this.config.repoName || 'Markitect';
- }
-
- get keyboardShortcuts() {
- return this.config.keyboardShortcuts !== false;
- }
-
- get base64References() {
- return this.config.base64References || {};
- }
-
- get restrictedHeadingLevels() {
- return this.config.restrictedHeadingLevels || [1, 2, 3];
- }
-
- // Check if config is ready for access
- isReady() {
- return this.loaded && this.config !== null;
- }
-
- // Wait for config to be ready
- waitForReady(callback, maxWait = 5000) {
- const startTime = Date.now();
- const checkReady = () => {
- if (this.isReady()) {
- callback();
- } else if (Date.now() - startTime < maxWait) {
- setTimeout(checkReady, 50);
- } else {
- console.error('❌ Configuration loading timeout after', maxWait, 'ms');
- callback(); // Call anyway with default config
- }
- };
- checkReady();
- }
-
- // Get full editor configuration object
- getEditorConfig() {
- if (!this.isReady()) {
- console.warn('⚠️ Configuration not ready, using defaults');
- return this.getDefaultConfig();
- }
-
- return {
- mode: this.mode,
- theme: this.theme,
- keyboardShortcuts: this.keyboardShortcuts,
- autosave: this.config.autosave || false,
- sections: this.config.sections !== false,
- originalFilename: this.originalFilename,
- version: this.version,
- repoName: this.repoName,
- restrictedHeadingLevels: this.restrictedHeadingLevels
- };
- }
-}
-
-// Global configuration instance
-window.markitectConfig = new MarkitectConfig();
-
-// Legacy compatibility - expose common config values globally
-window.editorConfig = window.markitectConfig.getEditorConfig();
-window.markitectBase64References = window.markitectConfig.base64References;
-
-// Export for module use
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = MarkitectConfig;
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/controls/contents-control.js b/capabilities/testdrive-jsui/js/controls/contents-control.js
deleted file mode 100644
index 680dbc33..00000000
--- a/capabilities/testdrive-jsui/js/controls/contents-control.js
+++ /dev/null
@@ -1,287 +0,0 @@
-/**
- * ContentsControl - Table of Contents Display Control
- *
- * Provides an interactive table of contents for document navigation.
- * Extracts headings from the document and displays them in a hierarchical
- * structure with clickable links for quick navigation.
- *
- * Features:
- * - Automatic heading extraction from document
- * - Hierarchical display with proper indentation
- * - Clickable navigation links with smooth scrolling
- * - Real-time updates when document structure changes
- * - Search functionality within the table of contents
- *
- * Dependencies:
- * - ControlBase (base control functionality)
- */
-
-/**
- * ContentsControl - Interactive table of contents control
- *
- * Built on the base class architecture for consistency with other panels.
- * Only implements content-specific functionality while inheriting all
- * common panel behavior from ControlBase.
- */
-class ContentsControl extends ControlBase {
- constructor() {
- super();
-
- // Configure for contents functionality
- this.config = {
- icon: '📋',
- title: 'Contents',
- className: 'contents-control',
- defaultContent: 'Loading table of contents...',
- ariaLabel: 'Table of Contents Control',
- position: 'w' // West positioning
- };
-
- // Contents-specific state
- this.headings = [];
- this.lastScanTime = null;
- this.updateInterval = null;
- this.searchQuery = '';
- }
-
- /**
- * Generate contents control content (called by base class buildContent)
- */
- generateContent() {
- // Extract headings first
- this.extractHeadings();
-
- return this.safeOperation(() => {
- if (this.headings.length === 0) {
- return `
-
-
No headings found in document
-
-
- `;
- }
-
- const searchHTML = `
-
-
-
- `;
-
- const filteredHeadings = this.filterHeadings(this.headings, this.searchQuery);
- const contentsHTML = filteredHeadings.map(heading => {
- const indentLevel = Math.max(0, heading.level - 1);
- const indentPx = indentLevel * 15;
-
- return `
-
- `;
- }).join('');
-
- const statusHTML = `
-
- Found ${filteredHeadings.length} heading${filteredHeadings.length !== 1 ? 's' : ''}
-
- `;
-
- const refreshButtonHTML = `
-
-
-
- `;
-
- return `
- ${searchHTML}
- ${statusHTML}
- ${contentsHTML}
- ${refreshButtonHTML}
- `;
-
- }, 'Error generating contents', 'generateContent');
- }
-
- /**
- * Extract all headings from the document
- * Creates a hierarchical structure of the document's heading elements
- */
- extractHeadings() {
- return this.safeOperation(() => {
- const headingSelectors = 'h1, h2, h3, h4, h5, h6';
- const headingElements = document.querySelectorAll(headingSelectors);
- const extractedHeadings = [];
-
- headingElements.forEach((heading, index) => {
- const level = parseInt(heading.tagName.charAt(1));
- const text = heading.textContent.trim();
-
- // Generate or use existing ID for anchor links
- let id = heading.id;
- if (!id) {
- id = text.toLowerCase()
- .replace(/[^\w\s-]/g, '')
- .replace(/\s+/g, '-')
- .substring(0, 50);
-
- // Ensure uniqueness
- let counter = 1;
- let uniqueId = id;
- while (document.getElementById(uniqueId)) {
- uniqueId = `${id}-${counter}`;
- counter++;
- }
-
- heading.id = uniqueId;
- id = uniqueId;
- }
-
- extractedHeadings.push({
- id,
- text,
- level,
- element: heading,
- index
- });
- });
-
- this.headings = extractedHeadings;
- this.lastScanTime = Date.now();
- return extractedHeadings;
-
- }, [], 'extractHeadings');
- }
-
- /**
- * Filter headings based on search query
- */
- filterHeadings(headings, query) {
- if (!query || query.trim() === '') {
- return headings;
- }
-
- const normalizedQuery = query.toLowerCase().trim();
- return headings.filter(heading =>
- heading.text.toLowerCase().includes(normalizedQuery)
- );
- }
-
- /**
- * Navigate to a specific heading with smooth scrolling
- */
- navigateToHeading(headingId) {
- return this.safeOperation(() => {
- const targetElement = document.getElementById(headingId);
- if (targetElement) {
- targetElement.scrollIntoView({
- behavior: 'smooth',
- block: 'start'
- });
-
- // Highlight the target temporarily
- const originalStyle = targetElement.style.backgroundColor;
- targetElement.style.backgroundColor = '#fff3cd';
- targetElement.style.transition = 'background-color 0.3s ease';
-
- setTimeout(() => {
- targetElement.style.backgroundColor = originalStyle;
- setTimeout(() => {
- targetElement.style.transition = '';
- }, 300);
- }, 1500);
-
- return true;
- }
- return false;
- }, false, 'navigateToHeading');
- }
-
- /**
- * Handle search input
- */
- handleSearch(query) {
- this.searchQuery = query;
- this.buildContent(); // Rebuild content with new filter
- }
-
- /**
- * Refresh the contents by re-scanning the document
- */
- refreshContents() {
- return this.safeOperation(() => {
- this.extractHeadings();
- this.buildContent(); // Rebuild content with updated headings
-
- // Show success feedback
- const refreshBtn = this.element?.querySelector('button');
- if (refreshBtn && refreshBtn.textContent.includes('Refresh')) {
- const originalText = refreshBtn.innerHTML;
- refreshBtn.innerHTML = '✅ Updated';
- refreshBtn.style.background = '#28a745';
-
- setTimeout(() => {
- refreshBtn.innerHTML = originalText;
- refreshBtn.style.background = '#28a745';
- }, 1000);
- }
- }, null, 'refreshContents');
- }
-
- /**
- * Override buildContent to add control reference and auto-refresh
- */
- buildContent() {
- super.buildContent();
-
- // Store reference to this control for onclick handlers
- if (this.element) {
- this.element.contentsControl = this;
- }
-
- // Set up auto-refresh for dynamic content
- if (this.updateInterval) {
- clearInterval(this.updateInterval);
- }
-
- this.updateInterval = setInterval(() => {
- const currentHeadingCount = document.querySelectorAll('h1, h2, h3, h4, h5, h6').length;
- if (currentHeadingCount !== this.headings.length) {
- this.refreshContents();
- }
- }, 5000); // Check every 5 seconds
- }
-
- /**
- * Clean up resources when control is destroyed
- */
- destroy() {
- if (this.updateInterval) {
- clearInterval(this.updateInterval);
- this.updateInterval = null;
- }
- super.destroy();
- }
-}
-
-// Export for module systems or attach to global for direct usage
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = ContentsControl;
-} else {
- window.ContentsControl = ContentsControl;
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/controls/control-base.js b/capabilities/testdrive-jsui/js/controls/control-base.js
deleted file mode 100644
index f37d52ca..00000000
--- a/capabilities/testdrive-jsui/js/controls/control-base.js
+++ /dev/null
@@ -1,852 +0,0 @@
-/**
- * Base Control Class for TestDrive-JSUI Controls
- *
- * Provides common functionality for positioning, drag, resize, expand/collapse operations.
- * This is the foundation class that all UI controls inherit from to ensure consistent
- * behavior across the TestDrive-JSUI component system.
- *
- * Key Features:
- * - Drag and drop positioning with compass-based anchoring
- * - Resize handles with hover-based visibility
- * - Expand/collapse state management
- * - Safe operation wrappers with error handling
- * - Development mode with strict error checking
- * - Accessibility support with proper ARIA labels
- *
- * Dependencies:
- * - None (standalone base class)
- *
- * Usage:
- * Controls inherit from this base by using Object.create(Control) and
- * implementing their specific buildContent() methods.
- */
-
-// Development mode detection for enhanced error reporting
-const MARKITECT_STRICT_MODE = (
- window.location.hostname === 'localhost' ||
- window.location.hostname === '127.0.0.1' ||
- window.location.search.includes('strict=true') ||
- window.markitectStrictMode === true
-);
-
-/**
- * ControlBase - Foundation class for all TestDrive-JSUI controls
- *
- * Provides the base functionality that all controls inherit:
- * - DOM element management
- * - Positioning and drag behavior
- * - Resize handle management
- * - State persistence
- * - Error handling with strict mode support
- */
-class ControlBase {
- constructor() {
- // Default configuration that controls can override
- this.config = {
- icon: '🔧',
- title: 'Control',
- className: 'base-control',
- defaultContent: 'Control content',
- ariaLabel: 'Base Control',
- position: 'w', // Compass position: west (middle-left)
- footer: null // Custom footer text
- };
-
- // Internal state
- this.element = null;
- this.isExpanded = false;
- this.isHeaderOnly = false; // New state for header-only visibility
- this.isDragging = false;
- this.isResizing = false;
- this.position = { x: 0, y: 0 };
- this.size = {
- width: 300,
- height: Math.floor(window.innerHeight / 3)
- };
- this.originalPosition = null; // Store original position for collapse
-
- // Event handlers storage
- this.eventHandlers = new Map();
- }
-
- /**
- * Safe operation wrapper with error handling
- * Provides consistent error handling across all control operations
- */
- safeOperation(operation, fallback = null, context = 'Unknown') {
- try {
- return operation();
- } catch (error) {
- console.error(`Control operation failed in ${context}:`, error);
-
- if (MARKITECT_STRICT_MODE) {
- throw error; // Re-throw in strict mode for debugging
- }
-
- return fallback;
- }
- }
-
- /**
- * Create and initialize the control element
- * This method sets up the basic DOM structure that all controls use
- */
- createElement() {
- return this.safeOperation(() => {
- if (this.element) {
- this.destroy(); // Clean up existing element
- }
-
- const control = document.createElement('div');
- control.className = `control-panel ${this.config.className}`;
- control.setAttribute('role', 'dialog');
- control.setAttribute('aria-label', this.config.ariaLabel);
-
- control.innerHTML = `
-
-
-
-
- ${this.config.defaultContent}
-
-
- `;
-
- this.element = control;
- this.setupStyles();
- this.setupEventListeners();
- return control;
-
- }, null, 'createElement');
- }
-
- /**
- * Set up base styles for the control
- */
- setupStyles() {
- if (!this.element) return;
-
- // Position the element
- this.element.style.position = 'fixed';
- this.element.style.zIndex = '1000';
-
- // Store original position for collapse
- this.storeOriginalPosition();
-
- // Style the icon-only toggle button
- const toggleBtn = this.element.querySelector('.control-toggle');
- if (toggleBtn) {
- toggleBtn.style.cssText = `
- width: 40px;
- height: 40px;
- border: none;
- background: rgba(248, 249, 250, 0.95);
- border: 1px solid #dee2e6;
- border-radius: 8px;
- cursor: pointer;
- font-size: 16px;
- display: flex;
- align-items: center;
- justify-content: center;
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
- transition: all 0.2s ease;
- `;
- }
- }
-
- /**
- * Set up event listeners for control interaction
- * Handles dragging, resizing, and toggle functionality
- */
- setupEventListeners() {
- if (!this.element) return;
-
- // Icon toggle to expand
- const toggleBtn = this.element.querySelector('.control-toggle');
- if (toggleBtn) {
- this.addEventListener(toggleBtn, 'click', () => this.expand());
- }
-
- // Close button to collapse back to icon
- const closeBtn = this.element.querySelector('.control-close');
- if (closeBtn) {
- this.addEventListener(closeBtn, 'click', () => this.collapse());
- }
-
- // Header title click to toggle content visibility
- const title = this.element.querySelector('.control-title');
- if (title) {
- this.addEventListener(title, 'click', () => this.toggleHeaderOnly());
- }
-
- // Drag functionality on header when expanded
- const header = this.element.querySelector('.control-header');
- if (header) {
- this.addEventListener(header, 'mousedown', (e) => {
- if (this.isExpanded && e.target !== title && e.target !== closeBtn) {
- this.startDrag(e);
- }
- });
- }
- }
-
- /**
- * Add event listener with automatic cleanup tracking
- */
- addEventListener(element, event, handler) {
- const key = `${element.className}_${event}`;
-
- // Remove existing handler if it exists
- if (this.eventHandlers.has(key)) {
- const [oldElement, oldEvent, oldHandler] = this.eventHandlers.get(key);
- oldElement.removeEventListener(oldEvent, oldHandler);
- }
-
- // Add new handler
- element.addEventListener(event, handler);
- this.eventHandlers.set(key, [element, event, handler]);
- }
-
- /**
- * Store original position for collapse restoration
- */
- storeOriginalPosition() {
- if (!this.element) return;
-
- const positionStyles = this.getCompassPosition();
- this.originalPosition = {
- top: positionStyles.top,
- left: positionStyles.left,
- right: positionStyles.right,
- bottom: positionStyles.bottom,
- transform: positionStyles.transform
- };
-
- // Apply original position
- Object.assign(this.element.style, positionStyles);
- }
-
- /**
- * Get compass-based positioning styles
- */
- getCompassPosition() {
- const positions = {
- 'n': { top: '20px', left: '50%', transform: 'translateX(-50%)' },
- 'ne': { top: '20px', right: '20px' },
- 'e': { right: '20px', top: '50%', transform: 'translateY(-50%)' },
- 'se': { bottom: '20px', right: '20px' },
- 's': { bottom: '20px', left: '50%', transform: 'translateX(-50%)' },
- 'sw': { bottom: '20px', left: '20px' },
- 'w': { left: '20px', top: '50%', transform: 'translateY(-50%)' },
- 'nw': { top: '20px', left: '20px' }
- };
-
- return positions[this.config.position] || positions['w'];
- }
-
- /**
- * Expand the control from icon-only state
- */
- expand() {
- return this.safeOperation(() => {
- this.isExpanded = true;
- const panel = this.element?.querySelector('.control-panel-expanded');
- const toggleBtn = this.element?.querySelector('.control-toggle');
-
- if (panel && toggleBtn) {
- panel.style.display = 'block';
- toggleBtn.style.display = 'none';
-
- // Calculate default height as 1/3 of window height
- const defaultHeight = Math.floor(window.innerHeight / 3);
-
- // Style expanded panel
- panel.style.cssText = `
- position: relative;
- display: flex;
- flex-direction: column;
- background: rgba(248, 249, 250, 0.95);
- border: 1px solid #dee2e6;
- border-radius: 8px;
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
- backdrop-filter: blur(8px);
- min-width: 300px;
- min-height: 200px;
- max-height: calc(100vh - 40px);
- width: auto;
- height: ${defaultHeight}px;
- overflow: hidden;
- `;
-
- // Style header
- const header = this.element.querySelector('.control-header');
- if (header) {
- header.style.cssText = `
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 4px 12px;
- background: rgba(0,0,0,0.05);
- border-bottom: 1px solid #dee2e6;
- cursor: move;
- user-select: none;
- flex-shrink: 0;
- min-height: 24px;
- border-radius: 7px 7px 0 0;
- margin: -1px -1px 0 -1px;
- `;
- }
-
- // Style content area container
- const contentArea = this.element.querySelector('.control-content');
- if (contentArea) {
- contentArea.style.cssText = `
- flex: 1;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- min-height: 0;
- `;
- }
-
- // Style close button
- const closeBtn = this.element.querySelector('.control-close');
- if (closeBtn) {
- closeBtn.style.cssText = `
- background: none;
- border: none;
- font-size: 16px;
- cursor: pointer;
- padding: 0;
- width: 20px;
- height: 20px;
- display: flex;
- align-items: center;
- justify-content: center;
- `;
- }
-
- // Add resize handle
- this.addResizeHandle();
- this.buildContent();
- }
-
- return this.isExpanded;
- }, false, 'expand');
- }
-
- /**
- * Collapse back to icon-only state at original position
- */
- collapse() {
- return this.safeOperation(() => {
- this.isExpanded = false;
- this.isHeaderOnly = false;
- const panel = this.element?.querySelector('.control-panel-expanded');
- const toggleBtn = this.element?.querySelector('.control-toggle');
-
- if (panel && toggleBtn) {
- panel.style.display = 'none';
- toggleBtn.style.display = 'block';
-
- // Restore original position
- if (this.originalPosition) {
- // Clear any drag positioning
- this.element.style.left = this.originalPosition.left || '';
- this.element.style.right = this.originalPosition.right || '';
- this.element.style.top = this.originalPosition.top || '';
- this.element.style.bottom = this.originalPosition.bottom || '';
- this.element.style.transform = this.originalPosition.transform || '';
- }
-
- // Reset panel size to defaults
- panel.style.width = '';
- panel.style.height = '';
- panel.style.minWidth = '300px';
- panel.style.minHeight = '200px';
-
- // Reset internal size tracking
- this.size.width = 300;
- this.size.height = Math.floor(window.innerHeight / 3);
- this.storedWidth = null;
-
- // Remove resize handle
- this.removeResizeHandle();
- }
-
- return !this.isExpanded;
- }, false, 'collapse');
- }
-
- /**
- * Toggle header-only visibility (content show/hide)
- */
- toggleHeaderOnly() {
- return this.safeOperation(() => {
- if (!this.isExpanded) {
- // If collapsed, expand first
- this.expand();
- return;
- }
-
- const content = this.element?.querySelector('.control-content');
- const panel = this.element?.querySelector('.control-panel-expanded');
-
- if (content && panel) {
- this.isHeaderOnly = !this.isHeaderOnly;
- const resizeHandle = this.element?.querySelector('.control-resize-handle');
-
- if (this.isHeaderOnly) {
- // Store current width before collapsing
- const currentWidth = panel.offsetWidth;
- this.storedWidth = currentWidth;
-
- // Hide content and shrink panel height only
- content.style.display = 'none';
- panel.style.minHeight = 'auto';
- panel.style.height = 'auto';
-
- // Keep the same width and position
- panel.style.width = `${currentWidth}px`;
- panel.style.minWidth = `${currentWidth}px`;
-
- // Hide resize handle in header-only mode
- if (resizeHandle) {
- resizeHandle.style.display = 'none';
- }
- } else {
- // Show content and restore full panel size
- content.style.display = 'block';
- panel.style.minHeight = '200px';
-
- // Restore stored width or use default
- const widthToRestore = this.storedWidth || 300;
- panel.style.minWidth = `${widthToRestore}px`;
-
- // Restore height if it was auto
- if (!panel.style.height || panel.style.height === 'auto') {
- panel.style.height = '200px';
- }
- if (!panel.style.width || panel.style.width === `${widthToRestore}px`) {
- panel.style.width = `${widthToRestore}px`;
- }
-
- // Show resize handle when fully expanded
- if (resizeHandle) {
- resizeHandle.style.display = 'flex';
- }
- }
- }
-
- return this.isHeaderOnly;
- }, false, 'toggleHeaderOnly');
- }
-
- /**
- * Start drag operation
- */
- startDrag(event) {
- if (!this.isExpanded) return; // Only drag when expanded
-
- this.isDragging = true;
- const rect = this.element.getBoundingClientRect();
-
- // Calculate offset from mouse to element origin
- this.dragOffset = {
- x: event.clientX - rect.left,
- y: event.clientY - rect.top
- };
-
- // Store current computed position before clearing styles
- const computedStyle = window.getComputedStyle(this.element);
- const currentLeft = rect.left;
- const currentTop = rect.top;
-
- // Clear any positioning styles that interfere with dragging
- this.element.style.right = '';
- this.element.style.bottom = '';
- this.element.style.transform = '';
-
- // Set the element to its current visual position using left/top
- this.element.style.left = `${currentLeft}px`;
- this.element.style.top = `${currentTop}px`;
-
- // Update internal position tracking
- this.position.x = currentLeft;
- this.position.y = currentTop;
-
- // Add global mouse move and up handlers
- const handleMouseMove = (e) => this.handleDrag(e);
- const handleMouseUp = () => this.stopDrag();
-
- document.addEventListener('mousemove', handleMouseMove);
- document.addEventListener('mouseup', handleMouseUp);
-
- // Store handlers for cleanup (but don't use the tracked version to avoid conflicts)
- this._dragHandlers = { move: handleMouseMove, up: handleMouseUp };
-
- event.preventDefault();
- }
-
- /**
- * Handle drag movement
- */
- handleDrag(event) {
- if (!this.isDragging || !this.element) return;
-
- // Calculate new position based on mouse position and offset
- const newX = event.clientX - this.dragOffset.x;
- const newY = event.clientY - this.dragOffset.y;
-
- // Update element position
- this.element.style.left = `${newX}px`;
- this.element.style.top = `${newY}px`;
-
- this.position.x = newX;
- this.position.y = newY;
-
- event.preventDefault();
- }
-
- /**
- * Stop drag operation
- */
- stopDrag() {
- if (!this.isDragging) return;
-
- this.isDragging = false;
-
- // Clean up event handlers
- if (this._dragHandlers) {
- document.removeEventListener('mousemove', this._dragHandlers.move);
- document.removeEventListener('mouseup', this._dragHandlers.up);
- delete this._dragHandlers;
- }
- }
-
- /**
- * Add resize handle to expanded control
- */
- addResizeHandle() {
- // Remove existing resize handle if any
- this.removeResizeHandle();
-
- const resizeHandle = document.createElement('div');
- resizeHandle.className = 'control-resize-handle';
- resizeHandle.innerHTML = '●'; // Dot resize indicator
- resizeHandle.style.cssText = `
- position: absolute;
- bottom: 0px;
- right: 1px;
- width: 12px;
- height: 12px;
- cursor: se-resize;
- font-size: 10px;
- line-height: 1;
- user-select: none;
- color: #999;
- background: transparent;
- z-index: 10;
- `;
-
- // Add to the expanded panel
- const panel = this.element?.querySelector('.control-panel-expanded');
- if (panel) {
- panel.appendChild(resizeHandle);
-
- // Set up resize handlers
- this.addEventListener(resizeHandle, 'mousedown', (e) => this.startResize(e));
- this.addEventListener(resizeHandle, 'dblclick', (e) => this.autoResizeToContent(e));
- }
- }
-
- /**
- * Remove resize handle
- */
- removeResizeHandle() {
- const handle = this.element?.querySelector('.control-resize-handle');
- if (handle && handle.parentNode) {
- handle.parentNode.removeChild(handle);
- }
- }
-
- /**
- * Start resize operation
- */
- startResize(event) {
- event.stopPropagation(); // Prevent drag from starting
- if (!this.isExpanded) return;
-
- this.isResizing = true;
- const rect = this.element.getBoundingClientRect();
-
- // Store initial size and mouse position
- this.resizeStart = {
- width: rect.width,
- height: rect.height,
- mouseX: event.clientX,
- mouseY: event.clientY
- };
-
- // Add global mouse move and up handlers
- const handleMouseMove = (e) => this.handleResize(e);
- const handleMouseUp = () => this.stopResize();
-
- document.addEventListener('mousemove', handleMouseMove);
- document.addEventListener('mouseup', handleMouseUp);
-
- // Store handlers for cleanup
- this._resizeHandlers = { move: handleMouseMove, up: handleMouseUp };
-
- event.preventDefault();
- }
-
- /**
- * Handle resize movement (bottom-right corner resize)
- */
- handleResize(event) {
- if (!this.isResizing || !this.element) return;
-
- const panel = this.element.querySelector('.control-panel-expanded');
- if (!panel) return;
-
- // Calculate size change based on mouse movement (bottom-right corner)
- const deltaX = event.clientX - this.resizeStart.mouseX; // Right direction
- const deltaY = event.clientY - this.resizeStart.mouseY; // Down direction
-
- // Get minimum size (collapsed header size or default minimum)
- const headerHeight = this.element.querySelector('.control-header')?.offsetHeight || 40;
- const minWidth = 200;
- const minHeight = headerHeight + 20; // Header plus small padding
-
- // Calculate new dimensions with minimum constraints
- const newWidth = Math.max(minWidth, this.resizeStart.width + deltaX);
- const newHeight = Math.max(minHeight, this.resizeStart.height + deltaY);
-
- // Apply new size to the panel
- panel.style.width = `${newWidth}px`;
- panel.style.height = `${newHeight}px`;
-
- // Update stored size
- this.size.width = newWidth;
- this.size.height = newHeight;
-
- event.preventDefault();
- }
-
- /**
- * Stop resize operation
- */
- stopResize() {
- if (!this.isResizing) return;
-
- this.isResizing = false;
-
- // Clean up event handlers
- if (this._resizeHandlers) {
- document.removeEventListener('mousemove', this._resizeHandlers.move);
- document.removeEventListener('mouseup', this._resizeHandlers.up);
- delete this._resizeHandlers;
- }
- }
-
- /**
- * Auto-resize panel to fit content size with viewport repositioning
- */
- autoResizeToContent(event) {
- return this.safeOperation(() => {
- event.preventDefault();
- event.stopPropagation();
-
- if (!this.isExpanded) return;
-
- const panel = this.element?.querySelector('.control-panel-expanded');
- const contentBody = this.element?.querySelector('.control-content-body');
-
- if (!panel || !contentBody) return;
-
- // Get current panel position
- const rect = panel.getBoundingClientRect();
- const currentLeft = rect.left;
- const currentTop = rect.top;
-
- // Measure content size by temporarily allowing natural sizing
- const originalOverflow = contentBody.style.overflow;
- const originalMaxHeight = panel.style.maxHeight;
- const originalHeight = panel.style.height;
- const originalWidth = panel.style.width;
-
- // Temporarily remove constraints to measure natural size
- contentBody.style.overflow = 'visible';
- panel.style.maxHeight = 'none';
- panel.style.height = 'auto';
- panel.style.width = 'auto';
-
- // Force reflow and measure
- panel.offsetHeight; // Force reflow
- const contentRect = contentBody.getBoundingClientRect();
- const headerHeight = this.element.querySelector('.control-header')?.offsetHeight || 24;
-
- // Calculate ideal size with padding and margins
- const idealWidth = Math.max(300, Math.min(window.innerWidth - 40, contentRect.width + 40));
- const idealHeight = Math.max(200, Math.min(window.innerHeight - 40, contentRect.height + headerHeight + 40));
-
- // Restore original constraints
- contentBody.style.overflow = originalOverflow;
- panel.style.maxHeight = originalMaxHeight;
-
- // Calculate new position to keep panel in viewport
- let newLeft = currentLeft;
- let newTop = currentTop;
-
- // Adjust position if panel would go outside viewport
- if (currentLeft + idealWidth > window.innerWidth) {
- newLeft = window.innerWidth - idealWidth - 20;
- }
- if (newLeft < 20) {
- newLeft = 20;
- }
-
- if (currentTop + idealHeight > window.innerHeight) {
- newTop = window.innerHeight - idealHeight - 20;
- }
- if (newTop < 20) {
- newTop = 20;
- }
-
- // Apply new size and position
- panel.style.width = `${idealWidth}px`;
- panel.style.height = `${idealHeight}px`;
-
- // Update position if it changed
- if (newLeft !== currentLeft || newTop !== currentTop) {
- this.element.style.left = `${newLeft}px`;
- this.element.style.top = `${newTop}px`;
- this.position.x = newLeft;
- this.position.y = newTop;
- }
-
- // Update internal size tracking
- this.size.width = idealWidth;
- this.size.height = idealHeight;
-
- }, null, 'autoResizeToContent');
- }
-
- /**
- * Position the control based on compass position (used by show method)
- */
- positionControl() {
- if (!this.element) return;
-
- // Use the compass positioning from setupStyles
- this.storeOriginalPosition();
- }
-
- /**
- * Build the control content (to be overridden by subclasses)
- */
- /**
- * Build content with consistent styling - calls subclass generateContent()
- */
- buildContent() {
- const content = this.element?.querySelector('.control-content');
- if (content) {
- // Get content from subclass
- const innerContent = this.generateContent ? this.generateContent() : this.config.defaultContent;
-
- // Apply consistent container styling
- content.innerHTML = `
-
- `;
- }
- }
-
- /**
- * Generate content - subclasses should override this method
- * @returns {string} HTML content for the panel body
- */
- generateContent() {
- return this.config.defaultContent || `Panel content goes here...
`;
- }
-
- /**
- * Show the control
- */
- show() {
- return this.safeOperation(() => {
- if (!this.element) {
- this.createElement();
- }
-
- document.body.appendChild(this.element);
- this.positionControl();
- this.buildContent();
-
- return this.element;
- }, null, 'show');
- }
-
- /**
- * Hide the control
- */
- hide() {
- return this.safeOperation(() => {
- if (this.element && this.element.parentNode) {
- this.element.parentNode.removeChild(this.element);
- }
- }, null, 'hide');
- }
-
- /**
- * Destroy the control and clean up resources
- */
- destroy() {
- return this.safeOperation(() => {
- // Clean up event listeners
- for (const [element, event, handler] of this.eventHandlers.values()) {
- element.removeEventListener(event, handler);
- }
- this.eventHandlers.clear();
-
- // Remove element from DOM
- if (this.element && this.element.parentNode) {
- this.element.parentNode.removeChild(this.element);
- }
-
- this.element = null;
- }, null, 'destroy');
- }
-}
-
-// Export for module systems or attach to global for direct usage
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = ControlBase;
-} else {
- window.ControlBase = ControlBase;
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/controls/debug-control.js b/capabilities/testdrive-jsui/js/controls/debug-control.js
deleted file mode 100644
index 431659ee..00000000
--- a/capabilities/testdrive-jsui/js/controls/debug-control.js
+++ /dev/null
@@ -1,483 +0,0 @@
-/**
- * DebugControl - System Debug Information and Message Display Control
- *
- * Provides comprehensive debugging capabilities including system message display,
- * error tracking, performance monitoring, and development tools. Essential for
- * troubleshooting and development workflows within the TestDrive-JSUI environment.
- *
- * Features:
- * - Real-time debug message display with categorization
- * - Error tracking with stack trace information
- * - Performance metrics and timing measurements
- * - System information display (browser, viewport, etc.)
- * - Message filtering and search capabilities
- * - Export functionality for debug logs
- * - Integration with MarkitectDebugSystem
- *
- * Dependencies:
- * - ControlBase (base control functionality)
- * - MarkitectDebugSystem (optional, for enhanced debugging)
- */
-
-/**
- * DebugControl - Development and debugging information control
- *
- * This control serves as a central hub for all debugging activities,
- * providing developers with essential information for troubleshooting
- * and performance optimization.
- */
-class DebugControl extends ControlBase {
- constructor() {
- super();
-
- // Configure for debug functionality
- this.config = {
- icon: '🐛',
- title: 'Debug',
- className: 'debug-control',
- defaultContent: 'Debug information loading...',
- ariaLabel: 'Debug Information Control',
- position: 'w' // West positioning
- };
-
- // Debug control state
- this.messages = [];
- this.maxMessages = 100;
- this.messageFilter = 'all'; // 'all', 'error', 'warn', 'info', 'debug'
- this.autoScroll = true;
- this.isRecording = true;
- this.startTime = Date.now();
- this.performanceMarks = new Map();
-
- this.initializeDebugCapture();
- }
-
- /**
- * Initialize debug message capture
- */
- initializeDebugCapture() {
- return this.safeOperation(() => {
- // Capture console messages
- this.originalConsole = {
- log: console.log,
- error: console.error,
- warn: console.warn,
- info: console.info,
- debug: console.debug
- };
-
- // Override console methods to capture messages
- console.log = (...args) => {
- this.originalConsole.log(...args);
- this.addDebugMessage('LOG', args.join(' '), 'info');
- };
-
- console.error = (...args) => {
- this.originalConsole.error(...args);
- this.addDebugMessage('ERROR', args.join(' '), 'error');
- };
-
- console.warn = (...args) => {
- this.originalConsole.warn(...args);
- this.addDebugMessage('WARN', args.join(' '), 'warn');
- };
-
- console.info = (...args) => {
- this.originalConsole.info(...args);
- this.addDebugMessage('INFO', args.join(' '), 'info');
- };
-
- console.debug = (...args) => {
- this.originalConsole.debug(...args);
- this.addDebugMessage('DEBUG', args.join(' '), 'debug');
- };
-
- // Capture global errors
- window.addEventListener('error', (event) => {
- this.addDebugMessage('ERROR', `${event.message} at ${event.filename}:${event.lineno}`, 'error');
- });
-
- // Capture unhandled promise rejections
- window.addEventListener('unhandledrejection', (event) => {
- this.addDebugMessage('PROMISE_REJECT', `Unhandled promise rejection: ${event.reason}`, 'error');
- });
-
- }, null, 'initializeDebugCapture');
- }
-
- /**
- * Add a debug message to the log
- */
- addDebugMessage(category, message, level = 'info') {
- return this.safeOperation(() => {
- if (!this.isRecording) return;
-
- const debugMessage = {
- id: Date.now() + Math.random(),
- timestamp: Date.now(),
- category,
- message,
- level,
- displayTime: new Date().toLocaleTimeString(),
- relativeTime: Date.now() - this.startTime
- };
-
- this.messages.push(debugMessage);
-
- // Limit message history
- if (this.messages.length > this.maxMessages) {
- this.messages.shift();
- }
-
- // Update display if visible
- if (this.element && this.isExpanded) {
- this.updateMessageDisplay();
- }
-
- }, null, 'addDebugMessage');
- }
-
- /**
- * Get messages filtered by current filter setting
- */
- getFilteredMessages() {
- if (this.messageFilter === 'all') {
- return this.messages;
- }
- return this.messages.filter(msg => msg.level === this.messageFilter);
- }
-
- /**
- * Generate system information HTML
- */
- generateSystemInfoHTML() {
- return this.safeOperation(() => {
- const systemInfo = {
- userAgent: navigator.userAgent,
- viewport: `${window.innerWidth}x${window.innerHeight}`,
- screen: `${screen.width}x${screen.height}`,
- colorDepth: screen.colorDepth,
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
- language: navigator.language,
- cookieEnabled: navigator.cookieEnabled,
- onlineStatus: navigator.onLine ? 'Online' : 'Offline',
- protocol: window.location.protocol,
- memory: performance.memory ?
- `Used: ${Math.round(performance.memory.usedJSHeapSize / 1024 / 1024)}MB` :
- 'Not available'
- };
-
- // Get Markitect version from config or default
- const markitectVersion = window.markitectConfig?.version || 'Unknown';
-
- return `
-
-
-
Markitect: ${markitectVersion}
-
Viewport: ${systemInfo.viewport}
-
Screen: ${systemInfo.screen}
-
Memory: ${systemInfo.memory}
-
Language: ${systemInfo.language}
-
Status: ${systemInfo.onlineStatus}
-
Protocol: ${systemInfo.protocol}
-
-
- `;
-
- }, '', 'generateSystemInfoHTML');
- }
-
- /**
- * Generate performance metrics HTML
- */
- generatePerformanceHTML() {
- return this.safeOperation(() => {
- const timing = performance.timing;
- const navigation = performance.getEntriesByType('navigation')[0];
-
- const metrics = {
- pageLoad: timing.loadEventEnd - timing.navigationStart,
- domReady: timing.domContentLoadedEventEnd - timing.navigationStart,
- firstByte: timing.responseStart - timing.navigationStart,
- uptime: Date.now() - this.startTime,
- messagesCount: this.messages.length
- };
-
- return `
-
- `;
-
- }, '', 'generatePerformanceHTML');
- }
-
- /**
- * Generate debug messages HTML
- */
- generateMessagesHTML() {
- return this.safeOperation(() => {
- const filteredMessages = this.getFilteredMessages();
-
- if (filteredMessages.length === 0) {
- return `
-
- No ${this.messageFilter === 'all' ? '' : this.messageFilter + ' '}messages yet
-
- `;
- }
-
- const messagesHTML = filteredMessages.slice(-20).map(msg => {
- const levelColors = {
- error: '#dc3545',
- warn: '#ffc107',
- info: '#17a2b8',
- debug: '#6c757d'
- };
-
- const backgroundColor = levelColors[msg.level] || '#6c757d';
- const textColor = msg.level === 'warn' ? '#000' : '#fff';
-
- return `
-
-
-
- ${msg.category}
-
-
- ${msg.displayTime}
-
-
-
- ${msg.message}
-
-
- `;
- }).join('');
-
- return `
-
- ${messagesHTML}
-
- `;
-
- }, 'Error displaying messages
', 'generateMessagesHTML');
- }
-
- /**
- * Generate control buttons HTML
- */
- generateControlButtonsHTML() {
- return `
-
-
-
-
-
-
-
-
-
- `;
- }
-
- /**
- * Generate filter controls HTML
- */
- generateFilterControlsHTML() {
- const filters = ['all', 'error', 'warn', 'info', 'debug'];
-
- const filterButtons = filters.map(filter => {
- const isActive = this.messageFilter === filter;
- return `
-
- `;
- }).join('');
-
- return `
-
-
Filter:
- ${filterButtons}
-
- `;
- }
-
- /**
- * Update the message display
- */
- updateMessageDisplay() {
- return this.safeOperation(() => {
- const messagesContainer = this.element?.querySelector('.messages-container');
- if (messagesContainer) {
- const parent = messagesContainer.parentElement;
- parent.innerHTML = this.generateMessagesHTML();
-
- // Auto-scroll to bottom if enabled
- if (this.autoScroll) {
- const newContainer = parent.querySelector('.messages-container');
- if (newContainer) {
- newContainer.scrollTop = newContainer.scrollHeight;
- }
- }
- }
- }, null, 'updateMessageDisplay');
- }
-
- /**
- * Clear all debug messages
- */
- clearMessages() {
- this.messages = [];
- if (window.MarkitectDebugSystem) {
- window.MarkitectDebugSystem.clearMessages();
- }
- this.buildContent();
- }
-
- /**
- * Export debug messages to file
- */
- exportMessages() {
- return this.safeOperation(() => {
- const exportData = {
- timestamp: new Date().toISOString(),
- session: {
- startTime: new Date(this.startTime).toISOString(),
- duration: Date.now() - this.startTime,
- messageCount: this.messages.length
- },
- system: {
- userAgent: navigator.userAgent,
- viewport: `${window.innerWidth}x${window.innerHeight}`,
- url: window.location.href
- },
- messages: this.messages
- };
-
- const dataStr = JSON.stringify(exportData, null, 2);
- const dataBlob = new Blob([dataStr], { type: 'application/json' });
- const url = URL.createObjectURL(dataBlob);
-
- const link = document.createElement('a');
- link.href = url;
- link.download = `debug-log-${new Date().toISOString().split('T')[0]}.json`;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
-
- URL.revokeObjectURL(url);
- this.addDebugMessage('EXPORT', 'Debug log exported successfully', 'info');
-
- }, null, 'exportMessages');
- }
-
- /**
- * Toggle message recording
- */
- toggleRecording() {
- this.isRecording = !this.isRecording;
- this.buildContent();
- this.addDebugMessage('CONTROL', `Recording ${this.isRecording ? 'started' : 'paused'}`, 'info');
- }
-
- /**
- * Add a test message
- */
- addTestMessage() {
- const testMessages = [
- { category: 'TEST', message: 'This is a test info message', level: 'info' },
- { category: 'TEST', message: 'This is a test warning message', level: 'warn' },
- { category: 'TEST', message: 'This is a test error message', level: 'error' },
- { category: 'TEST', message: 'This is a test debug message', level: 'debug' }
- ];
-
- const randomMessage = testMessages[Math.floor(Math.random() * testMessages.length)];
- this.addDebugMessage(randomMessage.category, randomMessage.message, randomMessage.level);
- }
-
- /**
- * Set message filter
- */
- setMessageFilter(filter) {
- this.messageFilter = filter;
- this.buildContent();
- }
-
- /**
- * Generate debug control content (called by base class buildContent)
- */
- generateContent() {
- return this.safeOperation(() => {
- return `
- ${this.generateSystemInfoHTML()}
- ${this.generatePerformanceHTML()}
- ${this.generateFilterControlsHTML()}
- ${this.generateMessagesHTML()}
- ${this.generateControlButtonsHTML()}
-
-
- Recording: ${this.isRecording ? '🟢 Active' : '🔴 Paused'} |
- Filter: ${this.messageFilter.toUpperCase()} |
- Messages: ${this.getFilteredMessages().length}/${this.messages.length}
-
- `;
- }, 'Error generating debug content', 'generateContent');
- }
-
- /**
- * Override buildContent to add control reference
- */
- buildContent() {
- super.buildContent();
-
- // Store reference to this control for onclick handlers
- if (this.element) {
- this.element.debugControl = this;
- }
- }
-
- /**
- * Clean up resources when control is destroyed
- */
- destroy() {
- // Restore original console methods
- if (this.originalConsole) {
- console.log = this.originalConsole.log;
- console.error = this.originalConsole.error;
- console.warn = this.originalConsole.warn;
- console.info = this.originalConsole.info;
- console.debug = this.originalConsole.debug;
- }
-
- super.destroy();
- }
-}
-
-// Export for module systems or attach to global for direct usage
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = DebugControl;
-} else {
- window.DebugControl = DebugControl;
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/controls/edit-control.js b/capabilities/testdrive-jsui/js/controls/edit-control.js
deleted file mode 100644
index 1f36891f..00000000
--- a/capabilities/testdrive-jsui/js/controls/edit-control.js
+++ /dev/null
@@ -1,573 +0,0 @@
-/**
- * EditControl - Document Editing Tools and Actions Control
- *
- * Provides a comprehensive set of document editing tools including text formatting,
- * document actions (print, save, export), navigation helpers, and editing modes.
- * Designed to enhance the writing and editing experience within the TestDrive-JSUI
- * environment.
- *
- * Features:
- * - Document actions (print, save, export to various formats)
- * - Text formatting tools (bold, italic, headers)
- * - Navigation helpers (scroll to top/bottom, go to line)
- * - Word processing features (find/replace, word count)
- * - Accessibility tools (font size, contrast adjustment)
- * - Markdown formatting shortcuts
- *
- * Dependencies:
- * - ControlBase (base control functionality)
- */
-
-/**
- * EditControl - Comprehensive document editing control
- *
- * This control provides writers and editors with essential tools for document
- * creation and modification. It includes both basic text operations and
- * advanced features for content management and formatting.
- */
-class EditControl extends ControlBase {
- constructor() {
- super();
-
- // Configure for editing functionality
- this.config = {
- icon: '✏️',
- title: 'Edit',
- className: 'edit-control',
- defaultContent: 'Document editing tools loading...',
- ariaLabel: 'Document Edit Control',
- position: 'e' // East positioning
- };
-
- // Edit control state
- this.editingMode = 'view'; // 'view', 'edit', 'preview'
- this.fontSize = 16;
- this.lastSaveTime = null;
- this.unsavedChanges = false;
- this.shortcuts = new Map();
-
- this.initializeShortcuts();
- }
-
- /**
- * Initialize keyboard shortcuts for editing
- */
- initializeShortcuts() {
- this.shortcuts.set('Ctrl+S', () => this.saveDocument());
- this.shortcuts.set('Ctrl+P', () => this.printDocument());
- this.shortcuts.set('Ctrl+F', () => this.showFindDialog());
- this.shortcuts.set('Ctrl+B', () => this.toggleBold());
- this.shortcuts.set('Ctrl+I', () => this.toggleItalic());
- this.shortcuts.set('Escape', () => this.exitEditMode());
- }
-
- /**
- * Generate the main editing tools HTML
- */
- generateEditToolsHTML() {
- return this.safeOperation(() => {
- return `
-
-
-
Document Actions
-
-
-
-
-
-
-
-
-
-
-
-
-
Navigation
-
-
-
-
-
-
-
-
-
-
-
-
-
Text Tools
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Markdown Tools
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Mode: ${this.editingMode}
-
Font: ${this.fontSize}px
- ${this.lastSaveTime ? `
Saved: ${new Date(this.lastSaveTime).toLocaleTimeString()}
` : ''}
- ${this.unsavedChanges ? '
⚠️ Unsaved changes
' : ''}
-
-
- `;
-
- }, 'Error generating edit tools
', 'generateEditToolsHTML');
- }
-
- /**
- * Print the document
- */
- printDocument() {
- return this.safeOperation(() => {
- window.print();
-
- // Show feedback
- this.showActionFeedback('🖨️ Print dialog opened', '#28a745');
- }, null, 'printDocument');
- }
-
- /**
- * Save document (placeholder - would integrate with actual save system)
- */
- saveDocument() {
- return this.safeOperation(() => {
- // In a real implementation, this would save to a backend
- this.lastSaveTime = Date.now();
- this.unsavedChanges = false;
-
- // Update display
- this.buildContent();
-
- // Show feedback
- this.showActionFeedback('💾 Document saved', '#007bff');
- }, null, 'saveDocument');
- }
-
- /**
- * Export document to various formats
- */
- exportDocument() {
- return this.safeOperation(() => {
- const contentArea = document.querySelector('#markitect-content') || document.body;
- const htmlContent = contentArea.innerHTML;
- const textContent = contentArea.textContent;
-
- // Create export menu
- const exportMenu = document.createElement('div');
- exportMenu.style.cssText = `
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- background: white;
- border: 2px solid #007bff;
- border-radius: 8px;
- padding: 1rem;
- z-index: 10000;
- box-shadow: 0 4px 20px rgba(0,0,0,0.3);
- `;
-
- exportMenu.innerHTML = `
- Export Document
-
-
-
-
- `;
-
- // Add export functions
- exportMenu.exportAsHTML = () => {
- this.downloadFile(htmlContent, 'document.html', 'text/html');
- document.body.removeChild(exportMenu);
- };
-
- exportMenu.exportAsText = () => {
- this.downloadFile(textContent, 'document.txt', 'text/plain');
- document.body.removeChild(exportMenu);
- };
-
- exportMenu.exportAsMarkdown = () => {
- // Simple HTML to Markdown conversion (basic)
- let markdown = htmlContent
- .replace(/]*>(.*?)<\/h1>/gi, '# $1\n\n')
- .replace(/]*>(.*?)<\/h2>/gi, '## $1\n\n')
- .replace(/]*>(.*?)<\/h3>/gi, '### $1\n\n')
- .replace(/
]*>(.*?)<\/p>/gi, '$1\n\n')
- .replace(/]*>(.*?)<\/strong>/gi, '**$1**')
- .replace(/]*>(.*?)<\/em>/gi, '*$1*')
- .replace(/<[^>]*>/g, ''); // Remove remaining HTML tags
-
- this.downloadFile(markdown, 'document.md', 'text/markdown');
- document.body.removeChild(exportMenu);
- };
-
- document.body.appendChild(exportMenu);
-
- }, null, 'exportDocument');
- }
-
- /**
- * Download a file with given content
- */
- downloadFile(content, filename, mimeType) {
- const blob = new Blob([content], { type: mimeType });
- const url = URL.createObjectURL(blob);
- const link = document.createElement('a');
- link.href = url;
- link.download = filename;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- URL.revokeObjectURL(url);
- }
-
- /**
- * Reset all changes and restore document to original state
- */
- resetAll() {
- return this.safeOperation(() => {
- // Show confirmation dialog
- const confirmed = window.confirm(
- 'Reset all changes?\n\nThis will:\n' +
- '• Restore document to original state\n' +
- '• Clear all unsaved changes\n' +
- '• Reset font size and other settings\n\n' +
- 'This action cannot be undone.'
- );
-
- if (!confirmed) {
- this.showActionFeedback('🚫 Reset cancelled', '#6c757d');
- return;
- }
-
- // Reset edit control state
- this.fontSize = 16;
- this.editingMode = 'view';
- this.unsavedChanges = false;
- this.lastSaveTime = null;
-
- // Reset font size
- this.applyFontSize();
-
- // Clear any highlights
- document.querySelectorAll('.edit-highlight').forEach(el => {
- el.outerHTML = el.innerHTML;
- });
-
- // Try to reset sections if SectionManager is available
- if (window.sectionManager && typeof window.sectionManager.resetAllSections === 'function') {
- window.sectionManager.resetAllSections();
- }
-
- // Try to reset document controls if available
- if (window.documentControls && typeof window.documentControls.resetAllChanges === 'function') {
- window.documentControls.resetAllChanges();
- }
-
- // Clear any debug messages if debug control is available
- if (window.debugControl && typeof window.debugControl.clearMessages === 'function') {
- window.debugControl.clearMessages();
- }
-
- // Reload the page as ultimate fallback
- if (window.confirm('Reload page to complete reset?')) {
- window.location.reload();
- return;
- }
-
- // Update the control display
- this.buildContent();
-
- // Show feedback
- this.showActionFeedback('🔄 All changes reset', '#ffc107', '#212529');
-
- }, null, 'resetAll');
- }
-
- /**
- * Scroll to top of document
- */
- scrollToTop() {
- window.scrollTo({ top: 0, behavior: 'smooth' });
- this.showActionFeedback('⬆️ Scrolled to top', '#6c757d');
- }
-
- /**
- * Scroll to bottom of document
- */
- scrollToBottom() {
- window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
- this.showActionFeedback('⬇️ Scrolled to bottom', '#6c757d');
- }
-
- /**
- * Show go to line dialog
- */
- showGoToLine() {
- const lineNumber = prompt('Go to line number:');
- if (lineNumber && !isNaN(lineNumber)) {
- // Simple implementation - scroll to approximate position
- const totalHeight = document.body.scrollHeight;
- const approximatePosition = (parseInt(lineNumber) / 100) * totalHeight;
- window.scrollTo({ top: approximatePosition, behavior: 'smooth' });
- this.showActionFeedback(`🎯 Went to line ${lineNumber}`, '#6c757d');
- }
- }
-
- /**
- * Show find and replace dialog
- */
- showFindReplace() {
- const searchTerm = prompt('Find text:');
- if (searchTerm) {
- // Simple highlight implementation
- this.highlightText(searchTerm);
- this.showActionFeedback(`🔍 Highlighted "${searchTerm}"`, '#ffc107', '#000');
- }
- }
-
- /**
- * Highlight text in the document
- */
- highlightText(searchTerm) {
- return this.safeOperation(() => {
- // Remove previous highlights
- document.querySelectorAll('.edit-highlight').forEach(el => {
- el.outerHTML = el.innerHTML;
- });
-
- // Add new highlights
- const contentArea = document.querySelector('#markitect-content') || document.body;
- const walker = document.createTreeWalker(
- contentArea,
- NodeFilter.SHOW_TEXT,
- null,
- false
- );
-
- const textNodes = [];
- let node;
- while (node = walker.nextNode()) {
- textNodes.push(node);
- }
-
- textNodes.forEach(textNode => {
- const parent = textNode.parentNode;
- const text = textNode.textContent;
- if (text.toLowerCase().includes(searchTerm.toLowerCase())) {
- const regex = new RegExp(`(${searchTerm})`, 'gi');
- const highlightedHTML = text.replace(regex, '$1');
-
- const wrapper = document.createElement('div');
- wrapper.innerHTML = highlightedHTML;
- while (wrapper.firstChild) {
- parent.insertBefore(wrapper.firstChild, textNode);
- }
- parent.removeChild(textNode);
- }
- });
- }, null, 'highlightText');
- }
-
- /**
- * Increase font size
- */
- increaseFontSize() {
- this.fontSize = Math.min(this.fontSize + 2, 24);
- this.applyFontSize();
- this.buildContent();
- }
-
- /**
- * Decrease font size
- */
- decreaseFontSize() {
- this.fontSize = Math.max(this.fontSize - 2, 12);
- this.applyFontSize();
- this.buildContent();
- }
-
- /**
- * Apply font size to document
- */
- applyFontSize() {
- const contentArea = document.querySelector('#markitect-content') || document.body;
- contentArea.style.fontSize = `${this.fontSize}px`;
- }
-
- /**
- * Copy page link to clipboard
- */
- copyLink() {
- return this.safeOperation(() => {
- const url = window.location.href;
- if (navigator.clipboard) {
- navigator.clipboard.writeText(url).then(() => {
- this.showActionFeedback('📋 Link copied to clipboard', '#fd7e14');
- });
- } else {
- // Fallback for older browsers
- prompt('Copy this link:', url);
- this.showActionFeedback('📋 Link displayed for copying', '#fd7e14');
- }
- }, null, 'copyLink');
- }
-
- /**
- * Insert markdown formatting
- */
- insertMarkdown(prefix, suffix, placeholder) {
- // This would integrate with an actual text editor
- // For now, just show what would be inserted
- const text = `${prefix}${placeholder}${suffix}`;
- if (navigator.clipboard) {
- navigator.clipboard.writeText(text);
- this.showActionFeedback(`📋 Copied: ${text}`, '#495057');
- } else {
- prompt('Markdown to copy:', text);
- }
- }
-
- /**
- * Show action feedback message
- */
- showActionFeedback(message, backgroundColor, color = 'white') {
- const feedback = document.createElement('div');
- feedback.style.cssText = `
- position: fixed;
- top: 20px;
- right: 20px;
- background: ${backgroundColor};
- color: ${color};
- padding: 0.5rem 1rem;
- border-radius: 4px;
- z-index: 9999;
- font-size: 0.8rem;
- box-shadow: 0 2px 10px rgba(0,0,0,0.2);
- `;
- feedback.textContent = message;
- document.body.appendChild(feedback);
-
- setTimeout(() => {
- if (feedback.parentNode) {
- document.body.removeChild(feedback);
- }
- }, 3000);
- }
-
- /**
- * Build the control content
- * Override of base class method to provide edit-specific functionality
- */
- /**
- * Generate edit control content (called by base class buildContent)
- */
- generateContent() {
- return this.safeOperation(() => {
- return this.generateEditToolsHTML();
- }, 'Error generating edit content', 'generateContent');
- }
-
- /**
- * Override buildContent to add control reference
- */
- buildContent() {
- super.buildContent();
-
- // Store reference to this control for onclick handlers
- if (this.element) {
- this.element.editControl = this;
- }
- }
-
- /**
- * Exit edit mode
- */
- exitEditMode() {
- this.editingMode = 'view';
- this.buildContent();
- }
-}
-
-// Export for module systems or attach to global for direct usage
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = EditControl;
-} else {
- window.EditControl = EditControl;
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/controls/status-control.js b/capabilities/testdrive-jsui/js/controls/status-control.js
deleted file mode 100644
index 4f1ae60c..00000000
--- a/capabilities/testdrive-jsui/js/controls/status-control.js
+++ /dev/null
@@ -1,371 +0,0 @@
-/**
- * StatusControl - Document Statistics and Change Tracking Control
- *
- * Provides real-time document statistics including word count, character count,
- * reading time estimation, and change tracking. Monitors document modifications
- * and provides insights into document structure and content metrics.
- *
- * Features:
- * - Real-time word and character counting
- * - Reading time estimation based on content
- * - Document structure analysis (headings, paragraphs, lists)
- * - Change tracking with before/after comparisons
- * - Content complexity metrics
- * - Export functionality for statistics
- *
- * Dependencies:
- * - ControlBase (base control functionality)
- */
-
-/**
- * StatusControl - Document statistics and monitoring control
- *
- * This control continuously monitors the document for changes and provides
- * detailed statistics about content, structure, and reading metrics.
- * Useful for writers, editors, and content creators.
- */
-class StatusControl extends ControlBase {
- constructor() {
- super();
-
- // Configure for status functionality
- this.config = {
- icon: '📊',
- title: 'Status',
- className: 'status-control',
- defaultContent: 'Loading document statistics...',
- ariaLabel: 'Document Status Control',
- position: 'e' // East positioning
- };
-
- // Status tracking state
- this.stats = {
- characters: 0,
- charactersNoSpaces: 0,
- words: 0,
- sentences: 0,
- paragraphs: 0,
- headings: 0,
- lists: 0,
- images: 0,
- links: 0,
- readingTimeMinutes: 0
- };
-
- this.previousStats = { ...this.stats };
- this.lastUpdateTime = null;
- this.updateInterval = null;
- this.wordsPerMinute = 200; // Average reading speed
- }
-
- /**
- * Extract and count document content statistics
- */
- analyzeDocument() {
- return this.safeOperation(() => {
- const contentArea = document.querySelector('#markitect-content') || document.body;
- const textContent = contentArea.textContent || '';
-
- // Basic text statistics
- this.stats.characters = textContent.length;
- this.stats.charactersNoSpaces = textContent.replace(/\s/g, '').length;
-
- // Word counting (more accurate)
- const words = textContent.trim().split(/\s+/).filter(word => word.length > 0);
- this.stats.words = words.length;
-
- // Sentence counting (approximate)
- const sentences = textContent.split(/[.!?]+/).filter(s => s.trim().length > 0);
- this.stats.sentences = sentences.length;
-
- // Structural elements
- this.stats.paragraphs = contentArea.querySelectorAll('p').length;
- this.stats.headings = contentArea.querySelectorAll('h1, h2, h3, h4, h5, h6').length;
- this.stats.lists = contentArea.querySelectorAll('ul, ol').length;
- this.stats.images = contentArea.querySelectorAll('img').length;
- this.stats.links = contentArea.querySelectorAll('a').length;
-
- // Reading time calculation
- this.stats.readingTimeMinutes = Math.ceil(this.stats.words / this.wordsPerMinute);
-
- this.lastUpdateTime = Date.now();
- return this.stats;
-
- }, this.stats, 'analyzeDocument');
- }
-
- /**
- * Calculate changes since last analysis
- */
- calculateChanges() {
- return this.safeOperation(() => {
- const changes = {};
- for (const [key, currentValue] of Object.entries(this.stats)) {
- const previousValue = this.previousStats[key] || 0;
- const difference = currentValue - previousValue;
- changes[key] = {
- current: currentValue,
- previous: previousValue,
- change: difference,
- hasChanged: difference !== 0
- };
- }
- return changes;
- }, {}, 'calculateChanges');
- }
-
- /**
- * Format statistics for display
- */
- formatStatistics() {
- return this.safeOperation(() => {
- const changes = this.calculateChanges();
-
- const formatChange = (changeData) => {
- if (!changeData.hasChanged) return '';
- const sign = changeData.change > 0 ? '+' : '';
- const color = changeData.change > 0 ? '#28a745' : '#dc3545';
- return ` (${sign}${changeData.change})`;
- };
-
- const formatNumber = (num) => num.toLocaleString();
-
- return `
-
-
- Words:
- ${formatNumber(this.stats.words)}
- ${formatChange(changes.words)}
-
-
-
- Characters:
- ${formatNumber(this.stats.characters)}
- ${formatChange(changes.characters)}
-
-
-
- Reading Time:
- ${this.stats.readingTimeMinutes} min
- ${formatChange(changes.readingTimeMinutes)}
-
-
-
- Sentences:
- ${formatNumber(this.stats.sentences)}
- ${formatChange(changes.sentences)}
-
-
-
-
-
Document Structure
-
-
- Paragraphs:
- ${this.stats.paragraphs}${formatChange(changes.paragraphs)}
-
-
-
- Headings:
- ${this.stats.headings}${formatChange(changes.headings)}
-
-
-
- Lists:
- ${this.stats.lists}${formatChange(changes.lists)}
-
-
-
- Images:
- ${this.stats.images}${formatChange(changes.images)}
-
-
-
- Links:
- ${this.stats.links}${formatChange(changes.links)}
-
-
-
-
-
-
-
-
-
- ${this.lastUpdateTime ? `
-
- Updated: ${new Date(this.lastUpdateTime).toLocaleTimeString()}
-
- ` : ''}
- `;
-
- }, 'Error displaying statistics
', 'formatStatistics');
- }
-
- /**
- * Refresh statistics and update display
- */
- refreshStats() {
- return this.safeOperation(() => {
- // Save current stats as previous
- this.previousStats = { ...this.stats };
-
- // Analyze document
- this.analyzeDocument();
-
- // Update display
- this.buildContent();
-
- // Show success feedback
- const refreshBtn = this.element?.querySelector('button');
- if (refreshBtn) {
- const originalText = refreshBtn.innerHTML;
- refreshBtn.innerHTML = '✅ Updated';
-
- setTimeout(() => {
- refreshBtn.innerHTML = originalText;
- }, 1000);
- }
-
- }, null, 'refreshStats');
- }
-
- /**
- * Export statistics to various formats
- */
- exportStats() {
- return this.safeOperation(() => {
- const exportData = {
- timestamp: new Date().toISOString(),
- document: {
- title: document.title || 'Untitled Document',
- url: window.location.href
- },
- statistics: this.stats,
- metadata: {
- wordsPerMinute: this.wordsPerMinute,
- analysisDate: new Date(this.lastUpdateTime).toISOString()
- }
- };
-
- // Create downloadable JSON
- const dataStr = JSON.stringify(exportData, null, 2);
- const dataBlob = new Blob([dataStr], { type: 'application/json' });
- const url = URL.createObjectURL(dataBlob);
-
- // Create temporary download link
- const link = document.createElement('a');
- link.href = url;
- link.download = `document-stats-${new Date().toISOString().split('T')[0]}.json`;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
-
- // Clean up
- URL.revokeObjectURL(url);
-
- // Show feedback
- const exportBtn = this.element?.querySelector('button:last-child');
- if (exportBtn) {
- const originalText = exportBtn.innerHTML;
- exportBtn.innerHTML = '✅ Exported';
- exportBtn.style.background = '#28a745';
-
- setTimeout(() => {
- exportBtn.innerHTML = originalText;
- exportBtn.style.background = '#28a745';
- }, 2000);
- }
-
- }, null, 'exportStats');
- }
-
- /**
- * Get reading difficulty score (Flesch Reading Ease approximation)
- */
- calculateReadabilityScore() {
- return this.safeOperation(() => {
- if (this.stats.sentences === 0 || this.stats.words === 0) {
- return { score: 0, level: 'Unknown' };
- }
-
- const avgWordsPerSentence = this.stats.words / this.stats.sentences;
- const avgSyllablesPerWord = 1.5; // Simplified approximation
-
- // Flesch Reading Ease formula (simplified)
- const score = 206.835 - (1.015 * avgWordsPerSentence) - (84.6 * avgSyllablesPerWord);
-
- let level;
- if (score >= 90) level = 'Very Easy';
- else if (score >= 80) level = 'Easy';
- else if (score >= 70) level = 'Fairly Easy';
- else if (score >= 60) level = 'Standard';
- else if (score >= 50) level = 'Fairly Difficult';
- else if (score >= 30) level = 'Difficult';
- else level = 'Very Difficult';
-
- return { score: Math.round(score), level };
- }, { score: 0, level: 'Unknown' }, 'calculateReadabilityScore');
- }
-
- /**
- * Build the control content
- * Override of base class method to provide status-specific functionality
- */
- /**
- * Generate status control content (called by base class buildContent)
- */
- generateContent() {
- // Analyze document first
- this.analyzeDocument();
-
- return this.safeOperation(() => {
- return this.formatStatistics();
- }, 'Error generating status content', 'generateContent');
- }
-
- /**
- * Override buildContent to add control reference and auto-refresh
- */
- buildContent() {
- super.buildContent();
-
- // Store reference to this control for onclick handlers
- if (this.element) {
- this.element.statusControl = this;
- }
-
- // Set up auto-refresh for dynamic content
- if (this.updateInterval) {
- clearInterval(this.updateInterval);
- }
-
- this.updateInterval = setInterval(() => {
- this.refreshStats();
- }, 10000); // Update every 10 seconds
- }
-
- /**
- * Clean up resources when control is destroyed
- */
- destroy() {
- if (this.updateInterval) {
- clearInterval(this.updateInterval);
- this.updateInterval = null;
- }
- super.destroy();
- }
-}
-
-// Export for module systems or attach to global for direct usage
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = StatusControl;
-} else {
- window.StatusControl = StatusControl;
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/core/debug-system.js b/capabilities/testdrive-jsui/js/core/debug-system.js
deleted file mode 100644
index e9776da6..00000000
--- a/capabilities/testdrive-jsui/js/core/debug-system.js
+++ /dev/null
@@ -1,290 +0,0 @@
-/**
- * Independent Debug System for Markitect
- * Uses IndexedDB for persistence and provides selection-based filtering
- */
-class MarkitectDebugSystem {
- constructor() {
- this.db = null;
- this.messages = [];
- this.maxMessages = 1000;
- this.isEnabled = true;
- this.subscribers = [];
-
- // Selection and filtering system
- this.selectionCriteria = {
- includeDocumentEvents: true,
- includeSystemEvents: false,
- includeControlEvents: true,
- includeEditingEvents: true,
- includeNavigationEvents: false,
- includedHeadings: new Set(), // Track which document headings to monitor
- excludedSources: new Set(['ContentsControl', 'DocumentNavigator'])
- };
-
- this.init();
- }
-
- // Initialize IndexedDB for persistence
- async init() {
- return new Promise((resolve, reject) => {
- const request = indexedDB.open('MarkitectDebugDB', 1);
-
- request.onerror = () => reject(request.error);
- request.onsuccess = () => {
- this.db = request.result;
- this.loadMessages().then(resolve);
- };
-
- request.onupgradeneeded = (e) => {
- const db = e.target.result;
- if (!db.objectStoreNames.contains('messages')) {
- const store = db.createObjectStore('messages', { keyPath: 'id', autoIncrement: true });
- store.createIndex('timestamp', 'timestamp', { unique: false });
- store.createIndex('category', 'category', { unique: false });
- }
- };
- });
- }
-
- // Add a debug message with selection filtering
- async addMessage(message, category = 'INFO', source = 'System', context = {}) {
- // Check if this message should be included based on selection criteria
- if (!this.shouldIncludeMessage(message, category, source, context)) {
- return null;
- }
-
- const messageObj = {
- timestamp: new Date().toISOString(),
- message: String(message),
- category: category.toUpperCase(),
- source: String(source),
- context: context || {},
- id: null // Will be set by IndexedDB
- };
-
- // Store in IndexedDB if available
- if (this.db) {
- try {
- await this.saveMessage(messageObj);
- } catch (error) {
- console.warn('Failed to save debug message to IndexedDB:', error);
- }
- }
-
- // Store in memory
- this.messages.unshift(messageObj);
-
- // Limit memory storage
- if (this.messages.length > this.maxMessages) {
- this.messages = this.messages.slice(0, this.maxMessages);
- }
-
- // Notify subscribers
- this.notifySubscribers(messageObj);
-
- // Console output for development
- const consoleMethod = category.toLowerCase() === 'error' ? 'error' :
- category.toLowerCase() === 'warning' ? 'warn' : 'log';
- console[consoleMethod](`[${source}] ${message}`, context);
-
- return messageObj;
- }
-
- // Selection filtering logic
- shouldIncludeMessage(message, category, source, context) {
- if (!this.isEnabled) return false;
-
- const eventType = context.eventType || 'UNKNOWN';
- const criteria = this.selectionCriteria;
-
- // Check event type filters
- switch (eventType.toUpperCase()) {
- case 'DOCUMENT':
- if (!criteria.includeDocumentEvents) return false;
- break;
- case 'SYSTEM':
- if (!criteria.includeSystemEvents) return false;
- break;
- case 'CONTROL':
- if (!criteria.includeControlEvents) return false;
- break;
- case 'EDITING':
- if (!criteria.includeEditingEvents) return false;
- break;
- case 'NAVIGATION':
- if (!criteria.includeNavigationEvents) return false;
- break;
- }
-
- // Check excluded sources
- if (criteria.excludedSources.has(source)) {
- return false;
- }
-
- // Check heading-specific filtering
- if (context.sectionId && criteria.includedHeadings.size > 0) {
- const sectionElement = document.getElementById(context.sectionId);
- if (sectionElement) {
- const heading = sectionElement.querySelector('h1, h2, h3, h4, h5, h6');
- if (heading && !criteria.includedHeadings.has(heading.textContent.trim())) {
- return false;
- }
- }
- }
-
- return true;
- }
-
- // Save message to IndexedDB
- async saveMessage(messageObj) {
- return new Promise((resolve, reject) => {
- const transaction = this.db.transaction(['messages'], 'readwrite');
- const store = transaction.objectStore('messages');
- const request = store.add(messageObj);
-
- request.onsuccess = () => resolve(request.result);
- request.onerror = () => reject(request.error);
- });
- }
-
- // Load messages from IndexedDB
- async loadMessages() {
- if (!this.db) return [];
-
- return new Promise((resolve, reject) => {
- const transaction = this.db.transaction(['messages'], 'readonly');
- const store = transaction.objectStore('messages');
- const request = store.getAll();
-
- request.onsuccess = () => {
- this.messages = request.result.reverse(); // Most recent first
- resolve(this.messages);
- };
- request.onerror = () => reject(request.error);
- });
- }
-
- // Clear all messages
- async clearMessages() {
- this.messages = [];
-
- if (this.db) {
- return new Promise((resolve, reject) => {
- const transaction = this.db.transaction(['messages'], 'readwrite');
- const store = transaction.objectStore('messages');
- const request = store.clear();
-
- request.onsuccess = () => resolve();
- request.onerror = () => reject(request.error);
- });
- }
- }
-
- // Get filtered messages
- getMessages(filter = {}) {
- let filteredMessages = [...this.messages];
-
- if (filter.category) {
- filteredMessages = filteredMessages.filter(msg =>
- msg.category.toLowerCase() === filter.category.toLowerCase()
- );
- }
-
- if (filter.source) {
- filteredMessages = filteredMessages.filter(msg =>
- msg.source.toLowerCase().includes(filter.source.toLowerCase())
- );
- }
-
- if (filter.since) {
- const sinceDate = new Date(filter.since);
- filteredMessages = filteredMessages.filter(msg =>
- new Date(msg.timestamp) >= sinceDate
- );
- }
-
- if (filter.limit) {
- filteredMessages = filteredMessages.slice(0, filter.limit);
- }
-
- return filteredMessages;
- }
-
- // Update selection criteria
- updateSelectionCriteria(updates) {
- Object.assign(this.selectionCriteria, updates);
- this.notifySubscribers({ type: 'criteria-updated', criteria: this.selectionCriteria });
- }
-
- // Add heading to monitoring
- addHeadingToMonitoring(headingText) {
- this.selectionCriteria.includedHeadings.add(headingText);
- }
-
- // Remove heading from monitoring
- removeHeadingFromMonitoring(headingText) {
- this.selectionCriteria.includedHeadings.delete(headingText);
- }
-
- // Scan document for available headings
- scanDocumentHeadings() {
- const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
- return Array.from(headings)
- .map(h => h.textContent.trim())
- .filter(text => text.length > 0 && !text.toLowerCase().includes('control'));
- }
-
- // Subscribe to debug messages
- subscribe(callback) {
- this.subscribers.push(callback);
- return () => {
- const index = this.subscribers.indexOf(callback);
- if (index > -1) {
- this.subscribers.splice(index, 1);
- }
- };
- }
-
- // Notify all subscribers
- notifySubscribers(message) {
- this.subscribers.forEach(callback => {
- try {
- callback(message);
- } catch (error) {
- console.error('Debug subscriber error:', error);
- }
- });
- }
-
- // Toggle debug system
- setEnabled(enabled) {
- this.isEnabled = enabled;
- this.addMessage(
- `Debug system ${enabled ? 'enabled' : 'disabled'}`,
- 'INFO',
- 'DebugSystem',
- { eventType: 'SYSTEM' }
- );
- }
-
- // Get statistics
- getStats() {
- const stats = {
- total: this.messages.length,
- byCategory: {},
- bySource: {},
- enabled: this.isEnabled,
- criteria: { ...this.selectionCriteria }
- };
-
- this.messages.forEach(msg => {
- stats.byCategory[msg.category] = (stats.byCategory[msg.category] || 0) + 1;
- stats.bySource[msg.source] = (stats.bySource[msg.source] || 0) + 1;
- });
-
- return stats;
- }
-}
-
-// Initialize and expose globally
-window.MarkitectDebugSystem = new MarkitectDebugSystem();
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/core/section-manager.js b/capabilities/testdrive-jsui/js/core/section-manager.js
deleted file mode 100644
index b1dc6fd0..00000000
--- a/capabilities/testdrive-jsui/js/core/section-manager.js
+++ /dev/null
@@ -1,544 +0,0 @@
-/**
- * SectionManager Component
- *
- * Extracted from monolithic editor.js as part of architecture refactoring.
- * Manages the collection of sections and their state transitions.
- *
- * Dependencies:
- * - EditState enum (imported)
- * - SectionType enum (imported)
- * - Section class (imported)
- * - debug function (imported)
- */
-
-// Import dependencies - these will be separate modules
-const EditState = Object.freeze({
- ORIGINAL: 'original',
- EDITING: 'editing',
- MODIFIED: 'modified',
- SAVED: 'saved'
-});
-
-const SectionType = Object.freeze({
- HEADING: 'heading',
- PARAGRAPH: 'paragraph',
- LIST: 'list',
- CODE: 'code',
- QUOTE: 'quote',
- TABLE: 'table',
- HR: 'hr',
- IMAGE: 'image'
-});
-
-// Debug function (will be extracted to utils)
-function debug(message, category = 'INFO') {
- // Simple console debug for now - will be enhanced later
- console.log(`DEBUG ${category}: ${message}`);
-}
-
-/**
- * Section Class - manages individual section state and content
- */
-class Section {
- constructor(id, markdown, type) {
- this.id = id;
- this.originalMarkdown = markdown;
- this.currentMarkdown = markdown;
- this.editingMarkdown = markdown;
- this.pendingMarkdown = null;
- this.type = type;
- this.state = EditState.ORIGINAL;
- this.domElement = null;
- this.lastSaved = null;
- this.created = new Date();
- }
-
- static generateId(markdown, position, strategy = 'hash', parentId = null) {
- return this.generateIdWithStrategy(markdown, position, strategy, parentId);
- }
-
- static generateIdWithStrategy(markdown, position, strategy = 'hash', parentId = null) {
- const sanitizedContent = this.sanitizeContentForId(markdown);
- const normalizedContent = this.normalizeContentForHashing(sanitizedContent);
- const sectionType = this.detectType(markdown);
-
- switch (strategy) {
- case 'timestamp':
- return this.generateTimestampId(normalizedContent, position, sectionType);
- case 'sequential':
- return this.generateSequentialId(normalizedContent, position, sectionType);
- case 'hierarchical':
- return this.generateHierarchicalId(normalizedContent, position, parentId);
- case 'hash':
- default:
- return this.generateAdvancedId(normalizedContent, position, sectionType);
- }
- }
-
- static generateAdvancedId(content, position, sectionType) {
- const contentHash = this.generateCryptoHash(content);
- const safeType = sectionType || 'paragraph';
- const typePrefix = safeType.substring(0, 3);
- const positionHex = position.toString(16).padStart(2, '0');
-
- return `section-${typePrefix}-${contentHash}-${positionHex}`;
- }
-
- static generateCryptoHash(content) {
- let hash = 0;
- if (content.length === 0) return '00000000';
-
- for (let i = 0; i < content.length; i++) {
- const char = content.charCodeAt(i);
- hash = ((hash << 5) - hash) + char;
- hash = hash & hash;
- }
-
- const hexHash = Math.abs(hash).toString(16).padStart(8, '0');
- return hexHash.substring(0, 8);
- }
-
- static normalizeContentForHashing(content) {
- if (!content || typeof content !== 'string') {
- return '';
- }
-
- return content
- .trim()
- .replace(/\s+/g, ' ')
- .replace(/\r\n/g, '\n')
- .toLowerCase();
- }
-
- static sanitizeContentForId(content) {
- if (!content || typeof content !== 'string') {
- return '';
- }
-
- return content
- .replace(/<[^>]*>/g, '')
- .replace(/javascript:/gi, '')
- .replace(/[^\w\s\-_.#]/g, '')
- .trim();
- }
-
- static generateTimestampId(content, position = 0, sectionType = 'paragraph') {
- const timestamp = Date.now().toString(36);
- const contentSnippet = this.generateCryptoHash(content || '').substring(0, 4);
- const safeType = sectionType || 'paragraph';
- const typePrefix = safeType.substring(0, 3);
-
- return `section-${typePrefix}-${contentSnippet}-${timestamp}`;
- }
-
- static generateSequentialId(content, position, sectionType = 'paragraph') {
- const safeType = sectionType || 'paragraph';
- const typePrefix = safeType.substring(0, 3);
- const seqNumber = (position || 0).toString().padStart(3, '0');
- const contentHash = this.generateCryptoHash(content || '').substring(0, 4);
-
- return `section-${typePrefix}-seq${seqNumber}-${contentHash}`;
- }
-
- static generateHierarchicalId(content, position, parentId = null) {
- const contentHash = this.generateCryptoHash(content || '').substring(0, 6);
-
- if (parentId) {
- const childIndex = (position || 0).toString().padStart(2, '0');
- return `${parentId}-child-${childIndex}-${contentHash}`;
- } else {
- return `section-root-${position || 0}-${contentHash}`;
- }
- }
-
- static detectType(markdown) {
- if (!markdown || typeof markdown !== 'string') {
- return SectionType.PARAGRAPH;
- }
-
- const content = markdown.replace(/^\n+|\n+$/g, '');
- if (!content) {
- return SectionType.PARAGRAPH;
- }
-
- const trimmed = content.trim();
-
- // Detection order matters - most specific first
- if (this.isHeading(trimmed)) {
- return SectionType.HEADING;
- }
-
- if (this.isImage(trimmed)) {
- return SectionType.IMAGE;
- }
-
- if (this.isCodeBlock(trimmed)) {
- return SectionType.CODE;
- }
-
- return SectionType.PARAGRAPH;
- }
-
- static isHeading(trimmed) {
- const headingPattern = /^#{1,6}\s+.+/;
- return headingPattern.test(trimmed);
- }
-
- static isImage(trimmed) {
- const imagePattern = /!\[.*?\]\([^)]+\)/;
- return imagePattern.test(trimmed);
- }
-
- static isCodeBlock(trimmed) {
- if (trimmed.startsWith('```') || trimmed.startsWith('~~~')) {
- return true;
- }
- if (trimmed.includes('```') || trimmed.includes('~~~')) {
- const codeBlockPattern = /```[\s\S]*?```|~~~[\s\S]*?~~~/;
- if (codeBlockPattern.test(trimmed)) {
- return true;
- }
- }
- return false;
- }
-
- startEdit() {
- if (this.state === EditState.EDITING) {
- throw new Error(`Section ${this.id} is already being edited`);
- }
- this.editingMarkdown = this.pendingMarkdown || this.currentMarkdown;
- this.state = EditState.EDITING;
- return this.editingMarkdown;
- }
-
- updateContent(markdown) {
- if (this.state !== EditState.EDITING) {
- throw new Error(`Section ${this.id} is not in editing state`);
- }
- this.editingMarkdown = markdown;
- }
-
- acceptChanges() {
- if (this.state !== EditState.EDITING) {
- throw new Error(`Section ${this.id} is not in editing state`);
- }
- this.currentMarkdown = this.editingMarkdown;
- this.editingMarkdown = null;
- this.pendingMarkdown = null;
- this.state = EditState.SAVED;
- this.lastSaved = new Date();
- return this.currentMarkdown;
- }
-
- cancelChanges() {
- if (this.state !== EditState.EDITING) {
- throw new Error(`Section ${this.id} is not in editing state`);
- }
- this.editingMarkdown = null;
- if (this.pendingMarkdown !== null) {
- this.state = EditState.MODIFIED;
- return this.pendingMarkdown;
- } else if (this.lastSaved !== null) {
- this.state = EditState.SAVED;
- return this.currentMarkdown;
- } else {
- this.state = this.hasChanges() ? EditState.MODIFIED : EditState.ORIGINAL;
- return this.currentMarkdown;
- }
- }
-
- stopEditing() {
- if (this.state !== EditState.EDITING) {
- return this.state;
- }
-
- if (this.editingMarkdown && this.editingMarkdown !== this.currentMarkdown) {
- this.pendingMarkdown = this.editingMarkdown;
- this.state = EditState.MODIFIED;
- } else {
- this.pendingMarkdown = null;
- if (this.lastSaved !== null) {
- this.state = EditState.SAVED;
- } else {
- this.state = this.hasChanges() ? EditState.MODIFIED : EditState.ORIGINAL;
- }
- }
-
- this.editingMarkdown = null;
- return this.state;
- }
-
- resetToOriginal() {
- this.currentMarkdown = this.originalMarkdown;
- this.editingMarkdown = this.originalMarkdown;
- this.pendingMarkdown = null;
- this.state = EditState.ORIGINAL;
- return this.originalMarkdown;
- }
-
- isEditing() {
- return this.state === EditState.EDITING;
- }
-
- hasChanges() {
- return this.currentMarkdown !== this.originalMarkdown;
- }
-
- getStatus() {
- return {
- id: this.id,
- state: this.state,
- hasChanges: this.hasChanges(),
- isEditing: this.isEditing(),
- contentLength: this.currentMarkdown.length,
- lastSaved: this.lastSaved,
- type: this.type,
- originalLength: this.originalMarkdown.length,
- currentLength: this.currentMarkdown.length
- };
- }
-
- isImage() {
- return this.type === SectionType.IMAGE;
- }
-
- redetectType(content = null) {
- const markdown = content || this.currentMarkdown;
- const oldType = this.type;
- this.type = Section.detectType(markdown);
-
- if (oldType !== this.type) {
- debug(`Section ${this.id} type changed from ${oldType} to ${this.type}`, 'TYPE_DETECTION');
- }
-
- return this.type;
- }
-}
-
-/**
- * SectionManager - Manages the collection of sections
- */
-class SectionManager {
- constructor() {
- this.sections = new Map();
- this.listeners = new Map();
- this.statusInterval = null;
- this.lastStatusUpdate = new Date().toISOString();
- }
-
- on(event, callback) {
- if (!this.listeners.has(event)) {
- this.listeners.set(event, []);
- }
- this.listeners.get(event).push(callback);
- }
-
- emit(event, data) {
- if (this.listeners.has(event)) {
- this.listeners.get(event).forEach(callback => callback(data));
- }
- }
-
- createSectionsFromMarkdown(markdownContent) {
- // Split content into blocks separated by double newlines
- const blocks = markdownContent.split(/\n\s*\n/);
- const sections = [];
- let position = 0;
-
- for (const block of blocks) {
- const trimmedBlock = block.trim();
- if (!trimmedBlock) continue;
-
- // Check if this block should be split further
- const lines = trimmedBlock.split('\n');
- let currentSection = '';
-
- for (let i = 0; i < lines.length; i++) {
- const line = lines[i];
- const isHeading = /^#{1,6}\s/.test(line.trim());
- const isImage = /^\s*!\[.*?\]\(.*?\)\s*$/.test(line);
-
- // Each heading or image starts a new section
- if ((isHeading || isImage) && currentSection.trim()) {
- // Save the previous section
- const sectionId = Section.generateId(currentSection, position);
- const sectionType = Section.detectType(currentSection);
- const section = new Section(sectionId, currentSection.trim(), sectionType);
- sections.push(section);
- this.sections.set(sectionId, section);
- position++;
- currentSection = line;
- } else {
- if (currentSection) currentSection += '\n';
- currentSection += line;
- }
- }
-
- // Save the final section from this block
- if (currentSection.trim()) {
- const sectionId = Section.generateId(currentSection, position);
- const sectionType = Section.detectType(currentSection);
- const section = new Section(sectionId, currentSection.trim(), sectionType);
- sections.push(section);
- this.sections.set(sectionId, section);
- position++;
- }
- }
-
- this.emit('sections-created', { sections, count: sections.length });
- return sections;
- }
-
- startEditing(sectionId) {
- debug('MANAGER: startEditing called for: ' + sectionId, 'MANAGER');
-
- const section = this.sections.get(sectionId);
- if (!section) {
- throw new Error(`Section ${sectionId} not found`);
- }
-
- if (section.isEditing()) {
- debug('MANAGER: Section already in editing state: ' + sectionId, 'MANAGER');
- return section.editingMarkdown;
- }
-
- debug('MANAGER: Starting edit for section: ' + sectionId, 'MANAGER');
- const content = section.startEdit();
-
- debug('MANAGER: About to emit edit-started event for: ' + sectionId, 'MANAGER');
- this.emit('edit-started', { sectionId, content, section: section.getStatus() });
- debug('MANAGER: Emitted edit-started event for: ' + sectionId, 'MANAGER');
-
- return content;
- }
-
- updateContent(sectionId, markdown) {
- const section = this.sections.get(sectionId);
- if (!section) {
- throw new Error(`Section ${sectionId} not found`);
- }
-
- const oldType = section.type;
- section.updateContent(markdown);
- const newType = section.redetectType(markdown);
-
- const eventData = {
- sectionId,
- markdown,
- section: section.getStatus(),
- typeChanged: oldType !== newType,
- oldType,
- newType
- };
-
- this.emit('content-updated', eventData);
-
- if (oldType !== newType) {
- this.emit('section-type-changed', {
- sectionId,
- oldType,
- newType,
- section: section.getStatus()
- });
- }
- }
-
- acceptChanges(sectionId) {
- const section = this.sections.get(sectionId);
- if (!section) {
- throw new Error(`Section ${sectionId} not found`);
- }
-
- const content = section.acceptChanges();
- this.emit('changes-accepted', { sectionId, content, section: section.getStatus() });
- return content;
- }
-
- cancelChanges(sectionId) {
- const section = this.sections.get(sectionId);
- if (!section) {
- throw new Error(`Section ${sectionId} not found`);
- }
-
- const content = section.cancelChanges();
- this.emit('changes-cancelled', { sectionId, content, section: section.getStatus() });
- return content;
- }
-
- resetSection(sectionId) {
- const section = this.sections.get(sectionId);
- if (!section) {
- throw new Error(`Section ${sectionId} not found`);
- }
-
- const content = section.resetToOriginal();
- this.emit('section-reset', { sectionId, content, section: section.getStatus() });
- return content;
- }
-
- getDocumentMarkdown() {
- const sortedSections = Array.from(this.sections.values())
- .sort((a, b) => a.created - b.created);
-
- return sortedSections.map(section => section.currentMarkdown).join('\n\n');
- }
-
- getAllSections() {
- return Array.from(this.sections.values());
- }
-
- getDocumentStatus() {
- const sections = Array.from(this.sections.values());
- const editingSections = sections.filter(section => section.isEditing).length;
-
- return {
- totalSections: sections.length,
- editingSections: editingSections
- };
- }
-
- extractHeadings(content) {
- if (!content) return [];
- const lines = content.split('\n');
- return lines.filter(line => /^#{1,6}\s/.test(line.trim()));
- }
-
- handleSectionSplit(sectionId, newContent) {
- const section = this.sections.get(sectionId);
- if (!section) {
- throw new Error(`Section ${sectionId} not found`);
- }
-
- // Remove the original section
- this.sections.delete(sectionId);
-
- // Create new sections from the content
- const newSections = this.createSectionsFromMarkdown(newContent);
-
- // Emit section-split event
- this.emit('section-split', {
- originalSectionId: sectionId,
- newSections: newSections,
- count: newSections.length
- });
-
- return newSections;
- }
-
- createSectionsFromContent(content) {
- return this.createSectionsFromMarkdown(content);
- }
-}
-
-// Export for use in tests and other modules
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = { SectionManager, Section, EditState, SectionType };
-}
-
-// Export for browser use
-if (typeof window !== 'undefined') {
- window.SectionManager = SectionManager;
- window.Section = Section;
- window.EditState = EditState;
- window.SectionType = SectionType;
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/main-updated.js b/capabilities/testdrive-jsui/js/main-updated.js
deleted file mode 100644
index e200d0de..00000000
--- a/capabilities/testdrive-jsui/js/main-updated.js
+++ /dev/null
@@ -1,287 +0,0 @@
-/**
- * Main Markitect JavaScript Entry Point - Clean Architecture Version
- *
- * Uses ONLY the JSON configuration interface - NO Python-generated JavaScript!
- * Initializes all controls and systems when document is ready
- * Implements graceful degradation for missing dependencies
- */
-
-// Main application module
-const MarkitectMain = {
- initialized: false,
- config: null,
-
- // Initialize the complete application
- initialize: function() {
- if (this.initialized) {
- console.log('⚠️ MarkitectMain already initialized, skipping');
- return;
- }
-
- console.log('🚀 MarkitectMain initializing...');
-
- try {
- // Get configuration - if not loaded, use defaults
- this.config = window.markitectConfig;
- if (!this.config || !this.config.loaded) {
- console.warn('⚠️ Configuration not loaded, proceeding with defaults');
- this.config = {
- markdownContent: document.querySelector('#markdown-content')?.textContent || '',
- mode: 'edit',
- theme: 'github'
- };
- }
-
- // Initialize core systems
- this.initializeCoreComponents();
- this.initializeControlPanels();
- this.setupEventHandlers();
- this.renderContent();
-
- this.initialized = true;
- console.log('✅ MarkitectMain initialization complete');
-
- } catch (error) {
- console.error('❌ MarkitectMain initialization failed:', error);
- this.fallbackMode();
- }
- },
-
- // Initialize core modular components
- initializeCoreComponents: function() {
- console.log('🔧 Initializing core components...');
-
- const container = document.getElementById('markdown-content') || document.body;
-
- // Initialize section manager
- if (typeof SectionManager !== 'undefined') {
- this.sectionManager = new SectionManager();
- console.log('✅ SectionManager initialized');
- } else {
- throw new Error('SectionManager not available');
- }
-
- // Initialize DOM renderer
- if (typeof DOMRenderer !== 'undefined') {
- this.domRenderer = new DOMRenderer(this.sectionManager, container);
- console.log('✅ DOMRenderer initialized');
- } else {
- throw new Error('DOMRenderer not available');
- }
-
- // Initialize debug panel
- if (typeof DebugPanel !== 'undefined') {
- this.debugPanel = new DebugPanel();
- console.log('✅ DebugPanel initialized');
- }
-
- // Initialize document controls
- if (typeof DocumentControls !== 'undefined') {
- this.documentControls = new DocumentControls();
- this.documentControls.create();
- console.log('✅ DocumentControls initialized');
- }
- },
-
- // Initialize enhanced control panels with compass positioning
- initializeControlPanels: function() {
- console.log('🎛️ Initializing enhanced control panels with compass positioning...');
-
- // ContentsControl (Northwest)
- if (typeof ContentsControl !== 'undefined') {
- this.contentsControl = new ContentsControl();
- this.contentsControl.config.position = 'nw';
- this.contentsControl.show();
- window.contentsControl = this.contentsControl;
- console.log('✅ ContentsControl initialized (Northwest) with enhanced ControlBase');
- }
-
- // StatusControl (East)
- if (typeof StatusControl !== 'undefined') {
- this.statusControl = new StatusControl();
- this.statusControl.config.position = 'e';
- this.statusControl.show();
- window.statusControl = this.statusControl;
- console.log('✅ StatusControl initialized (East) with enhanced ControlBase');
- }
-
- // DebugControl (Southeast)
- if (typeof DebugControl !== 'undefined') {
- this.debugControl = new DebugControl();
- this.debugControl.config.position = 'se';
- this.debugControl.show();
- window.debugControl = this.debugControl;
- console.log('✅ DebugControl initialized (Southeast) with enhanced ControlBase');
- }
-
- // EditControl (Northeast)
- if (typeof EditControl !== 'undefined') {
- this.editControl = new EditControl();
- this.editControl.config.position = 'ne';
- this.editControl.show();
- window.editControl = this.editControl;
- console.log('✅ EditControl initialized (Northeast) with enhanced ControlBase');
- }
- },
-
- // Setup event handlers
- setupEventHandlers: function() {
- console.log('🔌 Setting up event handlers...');
-
- if (!this.documentControls) return;
-
- this.documentControls.setEventHandlers({
- 'save-document': () => {
- console.log('💾 Save document clicked');
- try {
- const currentMarkdown = this.sectionManager.getDocumentMarkdown();
- const now = new Date();
- const timestamp = now.toISOString().slice(0, 19).replace(/:/g, '-').replace('T', '-');
- const filename = `${this.config.originalFilename}-edited-${timestamp}.md`;
-
- const blob = new Blob([currentMarkdown], { type: 'text/markdown' });
- const url = URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = filename;
- document.body.appendChild(a);
- a.click();
- document.body.removeChild(a);
- URL.revokeObjectURL(url);
-
- if (this.debugPanel) {
- this.debugPanel.addMessage(`Document saved as: ${filename}`, 'SUCCESS');
- }
- console.log(`✅ Document saved as: ${filename}`);
-
- } catch (error) {
- if (this.debugPanel) {
- this.debugPanel.addMessage(`Save failed: ${error.message}`, 'ERROR');
- }
- console.error('❌ Save error:', error);
- }
- },
-
- 'reset-all': () => {
- console.log('🔄 Reset all clicked');
- try {
- this.domRenderer.hideCurrentEditor();
- const allSections = Array.from(this.sectionManager.sections.values());
- allSections.forEach(section => section.resetToOriginal());
- this.domRenderer.renderAllSections(allSections);
-
- if (this.debugPanel) {
- this.debugPanel.addMessage('Reset all sections to original state', 'INFO');
- }
- } catch (error) {
- console.error('❌ Reset all failed:', error);
- }
- },
-
- 'show-status': () => {
- const status = this.sectionManager.getDocumentStatus();
- alert(`Document Status:\nTotal Sections: ${status.totalSections}\nEditing Sections: ${status.editingSections}`);
- },
-
- 'toggle-debug': () => {
- if (this.debugPanel) {
- this.debugPanel.toggle();
- }
- }
- });
-
- // Setup section manager event handlers
- if (this.sectionManager && this.debugPanel) {
- this.sectionManager.on('sections-created', (data) => {
- this.debugPanel.addMessage(`Created ${data.count} sections`, 'INFO');
- });
-
- this.sectionManager.on('edit-started', (data) => {
- this.debugPanel.addMessage(`Edit started for section: ${data.sectionId}`, 'DEBUG');
- });
-
- this.sectionManager.on('changes-accepted', (data) => {
- this.debugPanel.addMessage(`Changes accepted for section: ${data.sectionId}`, 'SUCCESS');
- this.updateSectionDOM(data.sectionId);
- });
-
- this.sectionManager.on('changes-cancelled', (data) => {
- this.debugPanel.addMessage(`Changes cancelled for section: ${data.sectionId}`, 'WARNING');
- });
- }
- },
-
- // Render content using the configuration
- renderContent: function() {
- console.log('📄 Rendering markdown content...');
-
- const markdownToRender = this.config.markdownContent || '';
- if (markdownToRender.trim()) {
- const sections = this.sectionManager.createSectionsFromMarkdown(markdownToRender);
- this.domRenderer.renderAllSections(sections);
-
- if (this.debugPanel) {
- this.debugPanel.addMessage(`Initialized with ${sections.length} sections`, 'INFO');
- }
- console.log(`✅ Rendered ${sections.length} sections`);
- } else {
- if (this.debugPanel) {
- this.debugPanel.addMessage('No markdown content to initialize', 'WARNING');
- }
- console.warn('⚠️ No markdown content to render');
- }
- },
-
- // Update section DOM after changes
- updateSectionDOM: function(sectionId) {
- try {
- const section = this.sectionManager.sections.get(sectionId);
- if (section) {
- const sectionElement = this.domRenderer.findSectionElement(sectionId);
- if (sectionElement) {
- const newElement = this.domRenderer.renderSection(section);
- sectionElement.parentNode.replaceChild(newElement, sectionElement);
-
- if (this.debugPanel) {
- this.debugPanel.addMessage(`DOM updated for section: ${sectionId}`, 'INFO');
- }
- }
- }
- } catch (error) {
- console.error('❌ Failed to update section DOM:', error);
- }
- },
-
- // Fallback mode if initialization fails
- fallbackMode: function() {
- console.warn('⚠️ Running in fallback mode');
-
- // Basic content rendering fallback
- const contentDiv = document.getElementById('markdown-content');
- if (contentDiv && this.config && this.config.markdownContent) {
- const basicHtml = this.config.markdownContent
- .replace(/^# (.*$)/gim, '$1
')
- .replace(/^## (.*$)/gim, '$1
')
- .replace(/^### (.*$)/gim, '$1
')
- .replace(/\n\n/g, '
')
- .replace(/\n/g, '
');
-
- contentDiv.innerHTML = `
${basicHtml}
`;
- console.log('✅ Fallback content rendered');
- }
- }
-};
-
-// Make components globally available for debugging
-window.MarkitectMain = MarkitectMain;
-
-// Auto-initialize when DOM is ready
-if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', function() {
- // Small delay to ensure config is loaded
- setTimeout(() => MarkitectMain.initialize(), 100);
- });
-} else {
- // DOM already ready
- setTimeout(() => MarkitectMain.initialize(), 100);
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/main.js b/capabilities/testdrive-jsui/js/main.js
deleted file mode 100644
index 40f8c482..00000000
--- a/capabilities/testdrive-jsui/js/main.js
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * Main Markitect JavaScript Entry Point
- * Initializes all controls and systems when document is ready
- * Implements graceful degradation for missing dependencies
- * Supports Fail Fast strict mode for development
- */
-
-// Development mode detection
-const MARKITECT_STRICT_MODE = (
- window.location.hostname === 'localhost' ||
- window.location.hostname === '127.0.0.1' ||
- window.location.search.includes('strict=true') ||
- window.markitectStrictMode === true
-);
-
-// Utility functions for safe initialization
-const MarkitectMain = {
- // Safe dependency checking with timeout
- checkDependencies: function() {
- const dependencies = {
- debugSystem: !!window.MarkitectDebugSystem,
- control: !!window.Control,
- statusControl: !!window.StatusControl,
- debugControl: !!window.DebugControl,
- contentsControl: !!window.ContentsControl,
- editControl: !!window.EditControl
- };
-
- console.log('📋 Dependency check results:', dependencies);
- return dependencies;
- },
-
- // Safe logging that works even without debug system
- safeLog: function(message, level = 'INFO', component = 'Main', data = {}) {
- console.log(`[${level}] ${component}: ${message}`);
-
- // In strict mode, throw on errors for immediate development feedback
- if (MARKITECT_STRICT_MODE && level === 'ERROR') {
- console.error(`🚨 STRICT MODE: Throwing error for immediate diagnosis`);
- throw new Error(`${component}: ${message}`);
- }
-
- // Try to use debug system if available
- if (window.MarkitectDebugSystem && window.MarkitectDebugSystem.addMessage) {
- try {
- window.MarkitectDebugSystem.addMessage(message, level, component, { ...data, eventType: 'SYSTEM' });
- } catch (error) {
- console.warn('Debug system logging failed:', error);
- if (MARKITECT_STRICT_MODE) {
- throw error; // Fail fast in development
- }
- }
- }
- },
-
- // Safe control initialization with fallbacks
- initializeControl: function(controlClass, controlName, icon = '🔧') {
- const timeout = setTimeout(() => {
- const message = `${controlName} initialization timed out`;
- console.warn(message);
- if (MARKITECT_STRICT_MODE) {
- throw new Error(message); // Fail fast in development
- }
- }, 5000);
-
- try {
- if (!controlClass) {
- const message = `${controlName} class not available, skipping`;
- this.safeLog(message, MARKITECT_STRICT_MODE ? 'ERROR' : 'WARNING');
- clearTimeout(timeout);
- return null;
- }
-
- const controlInstance = new controlClass();
- if (!controlInstance || typeof controlInstance.createControl !== 'function') {
- throw new Error(`Invalid ${controlName} instance`);
- }
-
- const element = controlInstance.createControl();
- if (!element) {
- throw new Error(`${controlName} failed to create element`);
- }
-
- clearTimeout(timeout);
- this.safeLog(`${controlName} initialized successfully`, 'SUCCESS');
- return controlInstance;
-
- } catch (error) {
- clearTimeout(timeout);
- this.safeLog(`${controlName} initialization failed: ${error.message}`, 'ERROR');
-
- // Create minimal fallback control if core Control class exists
- if (window.Control && controlName === 'StatusControl') {
- return this.createFallbackControl(controlName, icon);
- }
-
- return null;
- }
- },
-
- // Create minimal fallback control for essential controls
- createFallbackControl: function(name, icon) {
- try {
- const fallback = Object.create(window.Control);
- fallback.config = {
- icon: icon,
- title: `${name} (Fallback)`,
- className: `${name.toLowerCase()}-fallback`,
- defaultContent: `${name} is running in fallback mode due to initialization issues.`,
- ariaLabel: `${name} Fallback Control`,
- position: 'e'
- };
-
- const element = fallback.createControl();
- if (element) {
- this.safeLog(`${name} fallback control created`, 'INFO');
- return { control: fallback };
- }
- } catch (error) {
- this.safeLog(`Fallback control creation failed: ${error.message}`, 'ERROR');
- }
- return null;
- },
-
- // Main initialization with comprehensive error handling
- initialize: function() {
- this.safeLog('🚀 Initializing Markitect controls and systems...', 'INFO');
-
- // Check dependencies first
- const deps = this.checkDependencies();
-
- if (!deps.control) {
- this.safeLog('❌ Core Control system not available, cannot initialize UI controls', 'ERROR');
- return;
- }
-
- const initializedControls = {};
- let successCount = 0;
- let totalAttempts = 0;
-
- // Initialize controls with graceful degradation
- const controlsToInit = [
- { class: window.StatusControl, name: 'StatusControl', key: 'statusControl', icon: '📊', essential: true },
- { class: window.DebugControl, name: 'DebugControl', key: 'debugControl', icon: '🪲', essential: false },
- { class: window.ContentsControl, name: 'ContentsControl', key: 'contentsControl', icon: '☰', essential: false },
- { class: window.EditControl, name: 'EditControl', key: 'editControl', icon: '✏️', essential: false }
- ];
-
- controlsToInit.forEach(({ class: controlClass, name, key, icon, essential }) => {
- totalAttempts++;
- const instance = this.initializeControl(controlClass, name, icon);
-
- if (instance) {
- initializedControls[key] = instance.control || instance;
- window[key] = initializedControls[key];
- successCount++;
- } else if (essential) {
- this.safeLog(`Essential control ${name} failed to initialize`, 'ERROR');
- }
- });
-
- // Report initialization results
- const successRate = Math.round((successCount / totalAttempts) * 100);
- if (successCount === totalAttempts) {
- this.safeLog('✅ All controls initialized successfully', 'SUCCESS');
- } else if (successCount > 0) {
- this.safeLog(`⚠️ Partial initialization: ${successCount}/${totalAttempts} controls (${successRate}%) initialized`, 'WARNING');
- } else {
- this.safeLog('❌ No controls could be initialized', 'ERROR');
- }
-
- // Set up global error handlers for runtime protection
- this.setupErrorHandlers();
-
- this.safeLog(`✅ Markitect initialization complete (${successCount}/${totalAttempts} controls active)`, 'INFO');
- },
-
- // Set up global error handlers
- setupErrorHandlers: function() {
- // Catch unhandled errors
- window.addEventListener('error', (event) => {
- this.safeLog(`Unhandled error: ${event.message} at ${event.filename}:${event.lineno}`, 'ERROR');
- });
-
- // Catch unhandled promise rejections
- window.addEventListener('unhandledrejection', (event) => {
- this.safeLog(`Unhandled promise rejection: ${event.reason}`, 'ERROR');
- event.preventDefault(); // Prevent console spam
- });
- }
-};
-
-// Initialize when DOM is ready with additional safety
-if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', () => {
- setTimeout(() => MarkitectMain.initialize(), 100); // Brief delay for dependencies
- });
-} else {
- // DOM already loaded
- setTimeout(() => MarkitectMain.initialize(), 100);
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/plugins/document-navigator-plugin.js b/capabilities/testdrive-jsui/js/plugins/document-navigator-plugin.js
deleted file mode 100644
index e95907cf..00000000
--- a/capabilities/testdrive-jsui/js/plugins/document-navigator-plugin.js
+++ /dev/null
@@ -1,207 +0,0 @@
-/**
- * DocumentNavigator Plugin Definition
- *
- * Plugin definition for the Substack-style document navigation widget.
- * Provides floating table of contents with smooth scrolling and scroll spy.
- */
-export default {
- name: 'DocumentNavigator',
- version: '1.0.0',
- description: 'Substack-style floating document navigation with table of contents',
- author: 'Markitect Core',
- category: 'navigation',
-
- // Dependencies that must be loaded first
- dependencies: ['UIWidget'],
-
- // Mixins to apply (none required for this widget)
- mixins: [],
-
- // Lazy load the actual widget class
- async load() {
- const { DocumentNavigator } = await import('../widgets/navigation/DocumentNavigator.js');
- return DocumentNavigator;
- },
-
- // Default configuration
- defaultOptions: {
- position: 'left', // 'left' or 'right' side
- collapsed: true, // Start in collapsed state
- autoHide: true, // Hide on mobile devices
- maxHeadingLevel: 3, // Include H1, H2, H3
- enableScrollSpy: true, // Highlight current section
- smoothScroll: true, // Smooth scroll to headings
- animationDuration: 300, // Animation timing in ms
- minHeadings: 2, // Minimum headings to show widget
- theme: 'default', // Theme variant
-
- // Layout options
- width: '280px', // Expanded width
- collapsedWidth: '40px', // Collapsed width
- offset: { // Position offset
- top: '80px',
- side: '20px'
- },
-
- // Accessibility
- enableKeyboard: true, // Keyboard navigation support
- ariaLabel: 'Document Navigation'
- },
-
- // Plugin lifecycle hooks
- async onLoad(instance, options) {
- console.log('DocumentNavigator plugin loaded:', {
- headings: instance.headings.length,
- position: options.position,
- collapsed: options.collapsed
- });
-
- // Auto-initialize after load
- await instance.initialize();
-
- return instance;
- },
-
- async onUnload(instance) {
- console.log('DocumentNavigator plugin unloading');
- await instance.destroy();
- },
-
- // Feature flags and capabilities
- capabilities: {
- draggable: false, // Not draggable (fixed position)
- resizable: false, // Not resizable (fixed width)
- themeable: true, // Supports themes
- persistent: false, // Rebuilds on page changes
- responsive: true, // Responsive behavior
- keyboard: true, // Keyboard accessible
- scrollSpy: true, // Scroll spy functionality
- smoothScroll: true // Smooth scroll navigation
- },
-
- // Integration requirements
- requirements: {
- container: true, // Requires container element
- headings: true, // Requires document headings
- scrollable: true // Requires scrollable content
- },
-
- // Event types emitted by this widget
- events: [
- 'rendered', // Widget rendered to DOM
- 'navigate', // User navigated to heading
- 'toggle', // Widget expanded/collapsed
- 'theme-changed', // Theme was changed
- 'destroyed' // Widget was destroyed
- ],
-
- // CSS classes used by this widget
- cssClasses: [
- 'document-navigator', // Main widget class
- 'navigator-toggle', // Toggle button
- 'navigator-list', // Navigation list
- 'navigator-item', // Navigation items
- 'navigator-link', // Navigation links
- 'navigator-header', // List header
- 'navigator-close', // Close button
- 'navigator-empty' // Empty state
- ],
-
- // Theme variants
- themes: {
- default: {
- backgroundColor: 'rgba(255, 255, 255, 0.95)',
- borderColor: '#e1e5e9',
- textColor: '#333',
- activeColor: '#1976d2',
- activeBackground: '#e3f2fd'
- },
- dark: {
- backgroundColor: 'rgba(45, 45, 45, 0.95)',
- borderColor: '#555',
- textColor: '#e0e0e0',
- activeColor: '#64b5f6',
- activeBackground: '#1e3a8a'
- },
- minimal: {
- backgroundColor: 'rgba(248, 249, 250, 0.90)',
- borderColor: '#dee2e6',
- textColor: '#495057',
- activeColor: '#007bff',
- activeBackground: '#e7f1ff'
- }
- },
-
- // Usage examples
- examples: {
- basic: {
- description: 'Basic document navigator on the left side',
- code: `
- const navigator = await widgetSystem.createWidget('DocumentNavigator');
- await navigator.show();
- `
- },
- customized: {
- description: 'Customized navigator with specific options',
- code: `
- const navigator = await widgetSystem.createWidget('DocumentNavigator', {
- position: 'right',
- collapsed: false,
- maxHeadingLevel: 4,
- theme: 'dark'
- });
- await navigator.show();
- `
- },
- withContainer: {
- description: 'Navigator for specific container content',
- code: `
- const container = document.getElementById('article-content');
- const navigator = await widgetSystem.createWidget('DocumentNavigator', {
- container: container,
- minHeadings: 1
- });
- await navigator.show();
- `
- }
- },
-
- // Development and testing helpers
- dev: {
- testHeadingStructure() {
- // Helper to create test content with headings
- const testContent = `
- Chapter 1: Introduction
- Lorem ipsum content...
- Section 1.1: Overview
- Subsection 1.1.1: Details
- Section 1.2: Implementation
- Chapter 2: Advanced Topics
- Section 2.1: Performance
- `;
-
- const container = document.createElement('div');
- container.innerHTML = testContent;
- container.style.cssText = 'height: 2000px; padding: 2rem;';
- document.body.appendChild(container);
-
- return container;
- },
-
- async createTestInstance(options = {}) {
- // Helper to create test instance with sample content
- const container = this.testHeadingStructure();
-
- const navigator = new (await this.load())({
- container,
- collapsed: false,
- ...options
- });
-
- await navigator.initialize();
- await navigator.render();
-
- return { navigator, container };
- }
- }
-};
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/button-events.test.js b/capabilities/testdrive-jsui/js/tests/button-events.test.js
deleted file mode 100644
index bf6e45fc..00000000
--- a/capabilities/testdrive-jsui/js/tests/button-events.test.js
+++ /dev/null
@@ -1,349 +0,0 @@
-/**
- * Button Functionality and DOM Events Tests
- *
- * Tests button interactions, event handling, and DOM manipulation
- * Based on functionality from history/javascript-dev-tests/test_*button*.js and test_*events*.js files
- */
-
-describe('Button Functionality and DOM Events', () => {
- let mockSection;
- let documentControls;
-
- beforeEach(() => {
- // Setup DOM with various buttons and controls
- document.body.innerHTML = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `;
-
- mockSection = document.querySelector('.section');
-
- // Load components - using legacy component for backward compatibility
- require('../components/document-controls-legacy.js');
- if (global.DocumentControlsLegacy) {
- documentControls = new global.DocumentControlsLegacy(document.getElementById('content'));
- }
- });
-
- afterEach(() => {
- document.body.innerHTML = '';
- jest.clearAllMocks();
- });
-
- describe('Section edit buttons', () => {
- test('should show accept/cancel buttons when edit is clicked', () => {
- const editBtn = document.querySelector('.edit-btn');
- const acceptBtn = document.querySelector('.accept-btn');
- const cancelBtn = document.querySelector('.cancel-btn');
-
- expect(editBtn).toBeTruthy();
-
- // Simulate edit button click
- editBtn.click();
-
- // In real implementation, accept/cancel should become visible
- expect(acceptBtn.style.display).toBe('none'); // Initially hidden
- expect(cancelBtn.style.display).toBe('none'); // Initially hidden
-
- // Test that buttons exist for functionality
- expect(acceptBtn).toBeTruthy();
- expect(cancelBtn).toBeTruthy();
- });
-
- test('should hide edit button when in edit mode', () => {
- const editBtn = document.querySelector('.edit-btn');
-
- editBtn.click();
-
- // In real implementation, edit button should be hidden
- expect(editBtn.style.display).not.toBe('block');
- });
-
- test('should restore edit button when edit is cancelled', () => {
- const editBtn = document.querySelector('.edit-btn');
- const cancelBtn = document.querySelector('.cancel-btn');
-
- // Simulate edit mode
- editBtn.style.display = 'none';
- cancelBtn.style.display = 'inline-block';
-
- cancelBtn.click();
-
- // In real implementation, should restore edit button
- expect(cancelBtn).toBeTruthy();
- expect(editBtn).toBeTruthy();
- });
- });
-
- describe('Button event propagation', () => {
- test('should prevent event bubbling for section buttons', () => {
- const editBtn = document.querySelector('.edit-btn');
- let sectionClicked = false;
-
- mockSection.addEventListener('click', () => {
- sectionClicked = true;
- });
-
- // Create event with stopPropagation mock
- const clickEvent = new Event('click', { bubbles: true });
- clickEvent.stopPropagation = jest.fn();
-
- editBtn.dispatchEvent(clickEvent);
-
- // In real implementation, should call stopPropagation
- expect(clickEvent.stopPropagation).toHaveBeenCalledWith ||
- expect(sectionClicked).toBe(false);
- });
-
- test('should handle rapid button clicks gracefully', () => {
- const editBtn = document.querySelector('.edit-btn');
-
- // Simulate rapid clicks
- for (let i = 0; i < 5; i++) {
- editBtn.click();
- }
-
- // Should not cause errors
- expect(editBtn).toBeTruthy();
- });
-
- test('should debounce button actions', () => {
- const saveBtn = document.querySelector('.save-all-btn');
- let clickCount = 0;
-
- const debouncedHandler = jest.fn(() => {
- clickCount++;
- });
-
- saveBtn.addEventListener('click', debouncedHandler);
-
- // Simulate multiple quick clicks
- saveBtn.click();
- saveBtn.click();
- saveBtn.click();
-
- expect(debouncedHandler).toHaveBeenCalledTimes(3);
- });
- });
-
- describe('Button state management', () => {
- test('should disable buttons during processing', () => {
- const acceptBtn = document.querySelector('.accept-btn');
-
- // Simulate processing state
- acceptBtn.disabled = true;
-
- expect(acceptBtn.disabled).toBe(true);
- });
-
- test('should show loading state for async operations', () => {
- const saveBtn = document.querySelector('.save-all-btn');
-
- // Simulate loading state
- const originalText = saveBtn.textContent;
- saveBtn.textContent = 'Saving...';
- saveBtn.disabled = true;
-
- expect(saveBtn.textContent).toBe('Saving...');
- expect(saveBtn.disabled).toBe(true);
-
- // Restore state
- saveBtn.textContent = originalText;
- saveBtn.disabled = false;
-
- expect(saveBtn.textContent).toBe('Save All');
- expect(saveBtn.disabled).toBe(false);
- });
-
- test('should maintain button visibility states', () => {
- const buttons = {
- edit: document.querySelector('.edit-btn'),
- accept: document.querySelector('.accept-btn'),
- cancel: document.querySelector('.cancel-btn')
- };
-
- // Default state: edit visible, accept/cancel hidden
- expect(buttons.edit.style.display).not.toBe('none');
- expect(buttons.accept.style.display).toBe('none');
- expect(buttons.cancel.style.display).toBe('none');
- });
- });
-
- describe('DOM event handling', () => {
- test('should handle click events correctly', () => {
- const addSectionBtn = document.querySelector('.add-section-btn');
- let clicked = false;
-
- addSectionBtn.addEventListener('click', () => {
- clicked = true;
- });
-
- addSectionBtn.click();
-
- expect(clicked).toBe(true);
- });
-
- test('should handle keyboard events for accessibility', () => {
- const editBtn = document.querySelector('.edit-btn');
- let keyPressed = false;
-
- editBtn.addEventListener('keydown', (event) => {
- if (event.key === 'Enter' || event.key === ' ') {
- keyPressed = true;
- }
- });
-
- // Simulate Enter key press
- const enterEvent = new KeyboardEvent('keydown', {
- key: 'Enter',
- bubbles: true
- });
-
- editBtn.dispatchEvent(enterEvent);
-
- expect(keyPressed).toBe(true);
- });
-
- test('should handle focus and blur events', () => {
- const editBtn = document.querySelector('.edit-btn');
- let focused = false;
- let blurred = false;
-
- editBtn.addEventListener('focus', () => {
- focused = true;
- });
-
- editBtn.addEventListener('blur', () => {
- blurred = true;
- });
-
- editBtn.focus();
- expect(focused).toBe(true);
-
- editBtn.blur();
- expect(blurred).toBe(true);
- });
- });
-
- describe('Button positioning and layout', () => {
- test('should position floating controls correctly', () => {
- const floatingControls = document.querySelector('.floating-controls');
-
- // Test positioning properties
- floatingControls.style.position = 'fixed';
- floatingControls.style.top = '20px';
- floatingControls.style.right = '20px';
-
- expect(floatingControls.style.position).toBe('fixed');
- expect(floatingControls.style.top).toBe('20px');
- expect(floatingControls.style.right).toBe('20px');
- });
-
- test('should handle responsive button layouts', () => {
- const sectionControls = document.querySelector('.section-controls');
-
- // Test responsive classes
- sectionControls.classList.add('responsive-controls');
-
- expect(sectionControls.classList.contains('responsive-controls')).toBe(true);
- });
-
- test('should maintain button alignment in sections', () => {
- const controls = document.querySelector('.section-controls');
- const buttons = controls.querySelectorAll('button');
-
- expect(buttons.length).toBeGreaterThan(0);
-
- // All buttons should be in the same container
- buttons.forEach(button => {
- expect(button.parentElement).toBe(controls);
- });
- });
- });
-
- describe('Button confirmation dialogs', () => {
- test('should show confirmation for destructive actions', () => {
- const deleteBtn = document.querySelector('.delete-btn');
-
- // Mock confirm dialog
- window.confirm = jest.fn(() => false);
-
- deleteBtn.addEventListener('click', () => {
- if (window.confirm('Are you sure you want to delete this section?')) {
- // Perform deletion
- }
- });
-
- deleteBtn.click();
-
- // Should show confirmation
- expect(window.confirm).toHaveBeenCalledWith('Are you sure you want to delete this section?');
- });
-
- test('should cancel action when confirmation is denied', () => {
- const deleteBtn = document.querySelector('.delete-btn');
- let deleted = false;
-
- window.confirm = jest.fn(() => false);
-
- deleteBtn.addEventListener('click', () => {
- if (window.confirm('Are you sure?')) {
- deleted = true;
- }
- });
-
- deleteBtn.click();
-
- expect(deleted).toBe(false);
- });
- });
-
- describe('DocumentControls integration', () => {
- test('should integrate with DocumentControls class', () => {
- if (documentControls) {
- expect(typeof documentControls.create).toBe('function');
- expect(typeof documentControls.addButton).toBe('function');
- expect(typeof documentControls.setEventHandlers).toBe('function');
- }
- });
-
- test('should handle button events through DocumentControls', () => {
- if (!documentControls) return;
-
- // Test that DocumentControls can manage event handlers
- expect(documentControls.eventHandlers).toBeDefined();
- expect(documentControls.eventHandlers instanceof Map).toBe(true);
- });
-
- test('should handle button actions through event delegation', () => {
- const content = document.getElementById('content');
- let actionTriggered = '';
-
- content.addEventListener('click', (event) => {
- if (event.target.matches('button[data-action]')) {
- actionTriggered = event.target.getAttribute('data-action');
- }
- });
-
- const editBtn = document.querySelector('.edit-btn');
- editBtn.click();
-
- expect(actionTriggered).toBe('edit');
- });
- });
-});
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/component-integration.test.js b/capabilities/testdrive-jsui/js/tests/component-integration.test.js
deleted file mode 100644
index 3393f3e1..00000000
--- a/capabilities/testdrive-jsui/js/tests/component-integration.test.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * Component Integration Tests (Jest Version)
- *
- * Tests that extracted components work together properly.
- * Verifies the complete workflow: Section Creation → Rendering → Editing → Saving
- */
-
-describe('Component Integration Tests', () => {
- let SectionManager, Section, DOMRenderer, FloatingMenu, EditState;
- let sectionManager, domRenderer, container;
-
- beforeAll(() => {
- // Load extracted components
- const sectionModule = require('../core/section-manager.js');
- const domModule = require('../components/dom-renderer.js');
-
- SectionManager = sectionModule.SectionManager;
- Section = sectionModule.Section;
- DOMRenderer = domModule.DOMRenderer;
- FloatingMenu = domModule.FloatingMenu;
- EditState = sectionModule.EditState;
- });
-
- beforeEach(() => {
- // Setup fresh container and components for each test
- container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- sectionManager = new SectionManager();
- domRenderer = new DOMRenderer(sectionManager, container);
- });
-
- afterEach(() => {
- // Cleanup
- if (container && container.parentNode) {
- container.parentNode.removeChild(container);
- }
- });
-
- test('should load all extracted components', () => {
- expect(SectionManager).toBeTruthy();
- expect(Section).toBeTruthy();
- expect(DOMRenderer).toBeTruthy();
- expect(FloatingMenu).toBeTruthy();
- expect(EditState).toBeTruthy();
- });
-
- test('should support complete section creation workflow', () => {
- // Test basic functionality without complex DOM manipulation
- expect(sectionManager).toBeInstanceOf(SectionManager);
- expect(domRenderer).toBeInstanceOf(DOMRenderer);
-
- // Test section creation from markdown
- const testMarkdown = `# Test Header
-
-This is test content.
-
-`;
-
- // Create sections from markdown (the right method)
- expect(() => {
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- expect(sections.length).toBeGreaterThan(0);
- }).not.toThrow();
- });
-
- test('should have core DOM rendering methods', () => {
- expect(typeof domRenderer.renderAllSections).toBe('function');
- expect(typeof domRenderer.showEditor).toBe('function');
- expect(typeof domRenderer.findSectionElement).toBe('function');
- });
-
- test('should preserve editor showing functionality', () => {
- const mockSection = {
- id: 'test-section-001',
- type: 'header',
- content: 'Test content'
- };
-
- // Test basic editor functionality
- expect(() => {
- domRenderer.showEditor(mockSection.id);
- }).not.toThrow();
- });
-});
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/image-editing.test.js b/capabilities/testdrive-jsui/js/tests/image-editing.test.js
deleted file mode 100644
index f83c52ea..00000000
--- a/capabilities/testdrive-jsui/js/tests/image-editing.test.js
+++ /dev/null
@@ -1,280 +0,0 @@
-/**
- * Image Editing Functionality Tests
- *
- * Tests image editing, positioning, and reset functionality
- * Based on functionality from history/javascript-dev-tests/test_*image*.js files
- */
-
-describe('Image Editing', () => {
- let mockImageSection;
- let mockImageElement;
-
- beforeEach(() => {
- // Setup DOM with image section
- document.body.innerHTML = `
-
-
-
-

-
-
-
-
-
-
-
-
-
-
-
-
-
- `;
-
- mockImageSection = document.querySelector('.image-section');
- mockImageElement = document.querySelector('.section-image');
- });
-
- afterEach(() => {
- document.body.innerHTML = '';
- jest.clearAllMocks();
- });
-
- describe('Image editor dialog', () => {
- test('should show image editor when edit button is clicked', () => {
- const editButton = document.querySelector('.edit-image-btn');
- const dialog = document.querySelector('.image-editor-dialog');
-
- expect(editButton).toBeTruthy();
- expect(dialog).toBeTruthy();
-
- // Simulate edit button click
- editButton.click();
-
- // In real implementation, dialog should become visible
- expect(dialog.style.display).toBe('none'); // Initially hidden
- });
-
- test('should populate current alt text and caption', () => {
- const altTextInput = document.querySelector('.alt-text-input');
- const captionInput = document.querySelector('.image-caption');
-
- expect(altTextInput).toBeTruthy();
- expect(captionInput).toBeTruthy();
-
- // Simulate populating current values
- const currentAlt = mockImageElement.alt;
- altTextInput.value = currentAlt;
-
- expect(altTextInput.value).toBe(currentAlt);
- });
-
- test('should handle dialog positioning correctly', () => {
- const dialog = document.querySelector('.image-editor-dialog');
-
- // Test that dialog positioning can be set
- dialog.style.position = 'absolute';
- dialog.style.top = '100px';
- dialog.style.left = '100px';
-
- expect(dialog.style.position).toBe('absolute');
- expect(dialog.style.top).toBe('100px');
- expect(dialog.style.left).toBe('100px');
- });
- });
-
- describe('Image modifications', () => {
- test('should update alt text when applied', () => {
- const altTextInput = document.querySelector('.alt-text-input');
- const applyButton = document.querySelector('.apply-image-changes');
-
- const newAltText = 'Updated alt text for image';
- altTextInput.value = newAltText;
-
- // Simulate apply action
- applyButton.click();
-
- // In real implementation, image alt text should be updated
- expect(altTextInput.value).toBe(newAltText);
- });
-
- test('should update image caption when applied', () => {
- const captionInput = document.querySelector('.image-caption');
- const newCaption = 'Updated image caption';
-
- captionInput.value = newCaption;
-
- expect(captionInput.value).toBe(newCaption);
- });
-
- test('should validate required fields', () => {
- const altTextInput = document.querySelector('.alt-text-input');
-
- // Test empty alt text validation
- altTextInput.value = '';
-
- const isEmpty = altTextInput.value.trim() === '';
- expect(isEmpty).toBe(true);
-
- // Test filled alt text
- altTextInput.value = 'Valid alt text';
- const isFilled = altTextInput.value.trim() !== '';
- expect(isFilled).toBe(true);
- });
- });
-
- describe('Image reset functionality', () => {
- test('should reset image to original state', () => {
- const resetButton = document.querySelector('.reset-image-btn');
- const altTextInput = document.querySelector('.alt-text-input');
-
- // Store original values
- const originalAlt = mockImageElement.alt;
-
- // Modify values
- altTextInput.value = 'Modified alt text';
- mockImageElement.alt = 'Modified alt';
-
- // Simulate reset
- resetButton.click();
-
- // In real implementation, should restore original values
- expect(resetButton).toBeTruthy();
- });
-
- test('should confirm before resetting changes', () => {
- const resetButton = document.querySelector('.reset-image-btn');
-
- // Mock confirm dialog
- window.confirm = jest.fn(() => true);
-
- resetButton.click();
-
- // In real implementation, should show confirmation
- expect(resetButton).toBeTruthy();
- });
-
- test('should preserve original image data', () => {
- // Test that original image data is stored
- const originalData = {
- src: mockImageElement.src,
- alt: mockImageElement.alt,
- caption: ''
- };
-
- expect(originalData.src).toBeTruthy();
- expect(typeof originalData.alt).toBe('string');
- expect(typeof originalData.caption).toBe('string');
- });
- });
-
- describe('Image editor UI controls', () => {
- test('should handle cancel button correctly', () => {
- const cancelButton = document.querySelector('.cancel-image-changes');
- const dialog = document.querySelector('.image-editor-dialog');
-
- cancelButton.click();
-
- // In real implementation, should close dialog without saving
- expect(cancelButton).toBeTruthy();
- expect(dialog).toBeTruthy();
- });
-
- test('should close dialog after applying changes', () => {
- const applyButton = document.querySelector('.apply-image-changes');
- const dialog = document.querySelector('.image-editor-dialog');
-
- applyButton.click();
-
- // In real implementation, should close dialog after applying
- expect(applyButton).toBeTruthy();
- expect(dialog.style.display).toBe('none');
- });
-
- test('should handle escape key to cancel', () => {
- const dialog = document.querySelector('.image-editor-dialog');
- const altTextInput = document.querySelector('.alt-text-input');
-
- // Simulate escape key press
- const escapeEvent = new KeyboardEvent('keydown', {
- key: 'Escape',
- bubbles: true
- });
-
- altTextInput.dispatchEvent(escapeEvent);
-
- // In real implementation, should close dialog
- expect(dialog).toBeTruthy();
- });
- });
-
- describe('Advanced image editor features', () => {
- test('should support image URL editing', () => {
- const imageUrl = mockImageElement.src;
-
- // Test URL validation
- const isValidUrl = /^https?:\/\//.test(imageUrl) || imageUrl.startsWith('/') || imageUrl.startsWith('./');
-
- // Local files and URLs should be valid
- expect(typeof imageUrl).toBe('string');
- });
-
- test('should handle image loading errors', () => {
- const errorHandler = jest.fn();
-
- mockImageElement.onerror = errorHandler;
- mockImageElement.src = 'invalid-image-url.jpg';
-
- // In real implementation, should handle image load errors
- expect(mockImageElement.onerror).toBe(errorHandler);
- });
-
- test('should support image alignment options', () => {
- const alignmentOptions = ['left', 'center', 'right', 'full-width'];
-
- alignmentOptions.forEach(alignment => {
- mockImageElement.className = `section-image align-${alignment}`;
- expect(mockImageElement.className).toContain(`align-${alignment}`);
- });
- });
-
- test('should handle responsive image sizing', () => {
- // Test responsive image attributes
- mockImageElement.style.maxWidth = '100%';
- mockImageElement.style.height = 'auto';
-
- expect(mockImageElement.style.maxWidth).toBe('100%');
- expect(mockImageElement.style.height).toBe('auto');
- });
- });
-
- describe('Image section integration', () => {
- test('should maintain section integrity during image editing', () => {
- const sectionId = mockImageSection.getAttribute('data-section-id');
-
- expect(sectionId).toBeTruthy();
- expect(mockImageSection.classList.contains('image-section')).toBe(true);
- });
-
- test('should handle multiple images in one section', () => {
- // Add another image to the section
- const secondImage = document.createElement('img');
- secondImage.src = 'second-image.jpg';
- secondImage.alt = 'Second image';
- secondImage.className = 'section-image';
-
- mockImageSection.querySelector('.section-content').appendChild(secondImage);
-
- const images = mockImageSection.querySelectorAll('.section-image');
- expect(images.length).toBe(2);
- });
-
- test('should preserve section order when editing images', () => {
- const sectionContent = mockImageSection.querySelector('.section-content');
- const children = Array.from(sectionContent.children);
-
- const imageIndex = children.findIndex(child => child.tagName === 'IMG');
- expect(imageIndex).toBeGreaterThanOrEqual(0);
- });
- });
-});
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/jest.setup.js b/capabilities/testdrive-jsui/js/tests/jest.setup.js
deleted file mode 100644
index 1c8eab08..00000000
--- a/capabilities/testdrive-jsui/js/tests/jest.setup.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Jest Setup File for JavaScript UI Tests
- *
- * Sets up environment and global utilities for testing.
- * Jest with jsdom environment already provides DOM globals.
- */
-
-// Add TextEncoder/TextDecoder polyfills for Node.js compatibility
-const { TextEncoder, TextDecoder } = require('util');
-global.TextEncoder = TextEncoder;
-global.TextDecoder = TextDecoder;
-
-// Mock console methods to reduce noise in tests
-const originalLog = console.log;
-console.log = (...args) => {
- // Only log if DEBUG_TESTS environment variable is set
- if (process.env.DEBUG_TESTS) {
- originalLog(...args);
- }
-};
-
-// Setup DOM fixtures after page load
-beforeEach(() => {
- // Reset document body for each test
- document.body.innerHTML = '';
-});
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/keyboard-shortcuts.test.js b/capabilities/testdrive-jsui/js/tests/keyboard-shortcuts.test.js
deleted file mode 100644
index c2df5986..00000000
--- a/capabilities/testdrive-jsui/js/tests/keyboard-shortcuts.test.js
+++ /dev/null
@@ -1,219 +0,0 @@
-/**
- * Keyboard Shortcuts Functionality Tests
- *
- * Tests keyboard shortcuts for section editing (Ctrl+Enter, Escape, etc.)
- * Based on functionality from history/javascript-dev-tests/test_keyboard_shortcuts.js
- */
-
-describe('Keyboard Shortcuts', () => {
- let domRenderer;
- let mockTextarea;
-
- beforeEach(() => {
- // Setup DOM
- document.body.innerHTML = `
-
- `;
-
- // Load components
- require('../components/dom-renderer.js');
- require('../core/section-manager.js');
-
- // Mock SectionManager with event system
- const mockSectionManager = {
- on: jest.fn(),
- emit: jest.fn(),
- handleSectionSplit: jest.fn(),
- sections: []
- };
-
- if (global.DOMRenderer) {
- // Create DOMRenderer with mocked dependencies
- try {
- domRenderer = new global.DOMRenderer(mockSectionManager, document.getElementById('content'));
- } catch (error) {
- // If constructor fails, create a mock with the methods we need
- domRenderer = {
- applyChanges: jest.fn(),
- cancelEdit: jest.fn()
- };
- }
- }
-
- mockTextarea = document.querySelector('.edit-textarea');
- });
-
- afterEach(() => {
- document.body.innerHTML = '';
- jest.clearAllMocks();
- });
-
- describe('Ctrl+Enter shortcut (Accept Changes)', () => {
- test('should apply changes when Ctrl+Enter is pressed', () => {
- if (!mockTextarea) {
- console.warn('Textarea not available, skipping test');
- return;
- }
-
- // Test that Ctrl+Enter event can be dispatched
- const ctrlEnterEvent = new KeyboardEvent('keydown', {
- key: 'Enter',
- ctrlKey: true,
- bubbles: true
- });
-
- let eventFired = false;
- mockTextarea.addEventListener('keydown', (e) => {
- if (e.ctrlKey && e.key === 'Enter') {
- eventFired = true;
- }
- });
-
- mockTextarea.dispatchEvent(ctrlEnterEvent);
-
- // Verify event was handled
- expect(eventFired).toBe(true);
- });
-
- test('should prevent default behavior on Ctrl+Enter', () => {
- if (!mockTextarea) return;
-
- const preventDefault = jest.fn();
- const ctrlEnterEvent = new KeyboardEvent('keydown', {
- key: 'Enter',
- ctrlKey: true,
- bubbles: true
- });
-
- // Mock preventDefault
- ctrlEnterEvent.preventDefault = preventDefault;
-
- mockTextarea.dispatchEvent(ctrlEnterEvent);
-
- // Note: In real implementation, preventDefault should be called
- // This test documents the expected behavior
- expect(true).toBe(true); // Placeholder for actual implementation check
- });
- });
-
- describe('Escape shortcut (Cancel Changes)', () => {
- test('should cancel changes when Escape is pressed', () => {
- if (!mockTextarea) {
- console.warn('Textarea not available, skipping test');
- return;
- }
-
- // Test that Escape event can be dispatched
- const escapeEvent = new KeyboardEvent('keydown', {
- key: 'Escape',
- bubbles: true
- });
-
- let escapePressed = false;
- mockTextarea.addEventListener('keydown', (e) => {
- if (e.key === 'Escape') {
- escapePressed = true;
- }
- });
-
- mockTextarea.dispatchEvent(escapeEvent);
-
- // Verify escape was detected
- expect(escapePressed).toBe(true);
- });
-
- test('should restore original content on Escape', () => {
- if (!mockTextarea) return;
-
- const originalContent = 'Original content';
- mockTextarea.setAttribute('data-original-content', originalContent);
- mockTextarea.value = 'Modified content';
-
- const escapeEvent = new KeyboardEvent('keydown', {
- key: 'Escape',
- bubbles: true
- });
-
- mockTextarea.dispatchEvent(escapeEvent);
-
- // In real implementation, content should be restored
- // This test documents the expected behavior
- expect(mockTextarea.getAttribute('data-original-content')).toBe(originalContent);
- });
- });
-
- describe('Keyboard shortcuts integration', () => {
- test('should bind keyboard handlers to textareas', () => {
- const textarea = document.createElement('textarea');
- textarea.className = 'edit-textarea';
- document.body.appendChild(textarea);
-
- // Check if event listeners can be added (integration test)
- let listenerAdded = false;
- const originalAddEventListener = textarea.addEventListener;
- textarea.addEventListener = jest.fn((event, handler) => {
- if (event === 'keydown') {
- listenerAdded = true;
- }
- return originalAddEventListener.call(textarea, event, handler);
- });
-
- // In real implementation, DOMRenderer should bind keydown listeners
- // This test ensures the capability exists
- expect(textarea.addEventListener).toBeDefined();
- expect(typeof textarea.addEventListener).toBe('function');
- });
-
- test('should handle multiple keyboard events correctly', () => {
- if (!mockTextarea) return;
-
- const events = [
- { key: 'Enter', ctrlKey: true },
- { key: 'Escape', ctrlKey: false },
- { key: 'Tab', ctrlKey: false }
- ];
-
- events.forEach(eventData => {
- const event = new KeyboardEvent('keydown', {
- ...eventData,
- bubbles: true
- });
-
- // Should not throw errors when handling various key events
- expect(() => {
- mockTextarea.dispatchEvent(event);
- }).not.toThrow();
- });
- });
- });
-
- describe('Keyboard shortcuts accessibility', () => {
- test('should provide keyboard alternatives to mouse actions', () => {
- // This test ensures keyboard accessibility is maintained
- const shortcuts = [
- { key: 'Enter', ctrlKey: true, action: 'apply' },
- { key: 'Escape', ctrlKey: false, action: 'cancel' }
- ];
-
- shortcuts.forEach(shortcut => {
- expect(shortcut.key).toBeDefined();
- expect(shortcut.action).toBeDefined();
- });
- });
-
- test('should work with screen readers and assistive technology', () => {
- if (!mockTextarea) return;
-
- // Test ARIA attributes and accessibility features
- mockTextarea.setAttribute('aria-label', 'Edit section content');
- mockTextarea.setAttribute('role', 'textbox');
-
- expect(mockTextarea.getAttribute('aria-label')).toBeTruthy();
- expect(mockTextarea.getAttribute('role')).toBe('textbox');
- });
- });
-});
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/refactor-test-runner.js b/capabilities/testdrive-jsui/js/tests/refactor-test-runner.js
deleted file mode 100644
index ecc97529..00000000
--- a/capabilities/testdrive-jsui/js/tests/refactor-test-runner.js
+++ /dev/null
@@ -1,216 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * TDD Test Runner for JavaScript Refactoring
- *
- * Drives component extraction and testing during architecture refactoring.
- * Ensures all functionality remains stable while achieving separation of concerns.
- */
-
-class RefactorTestRunner {
- constructor() {
- this.tests = [];
- this.passed = 0;
- this.failed = 0;
- this.currentSuite = null;
- this.setupDOM();
- }
-
- setupDOM() {
- // Set up minimal DOM environment for testing
- if (typeof document === 'undefined') {
- const { JSDOM } = require('jsdom');
- const dom = new JSDOM('', {
- url: 'http://localhost',
- pretendToBeVisual: true,
- resources: 'usable'
- });
-
- global.window = dom.window;
- global.document = dom.window.document;
- global.HTMLElement = dom.window.HTMLElement;
- global.Event = dom.window.Event;
- global.CustomEvent = dom.window.CustomEvent;
-
- // Only set navigator if it doesn't exist
- if (typeof global.navigator === 'undefined') {
- global.navigator = dom.window.navigator;
- }
- }
- }
-
- describe(suiteName, fn) {
- console.log(`\n📁 ${suiteName}`);
- this.currentSuite = suiteName;
- fn();
- this.currentSuite = null;
- }
-
- it(testName, fn) {
- const fullName = this.currentSuite ? `${this.currentSuite}: ${testName}` : testName;
-
- try {
- fn();
- console.log(` ✅ ${testName}`);
- this.passed++;
- } catch (error) {
- console.log(` ❌ ${testName}`);
- console.log(` Error: ${error.message}`);
- if (error.stack) {
- console.log(` Stack: ${error.stack.split('\n')[1]?.trim()}`);
- }
- this.failed++;
- }
- }
-
- expect(actual) {
- return {
- toBe: (expected) => {
- if (actual !== expected) {
- throw new Error(`Expected ${expected}, got ${actual}`);
- }
- },
- toBeTruthy: () => {
- if (!actual) {
- throw new Error(`Expected truthy value, got ${actual}`);
- }
- },
- toBeFalsy: () => {
- if (actual) {
- throw new Error(`Expected falsy value, got ${actual}`);
- }
- },
- toEqual: (expected) => {
- if (JSON.stringify(actual) !== JSON.stringify(expected)) {
- throw new Error(`Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
- }
- },
- toContain: (expected) => {
- if (!actual.includes(expected)) {
- throw new Error(`Expected ${actual} to contain ${expected}`);
- }
- },
- toHaveProperty: (property) => {
- if (!(property in actual)) {
- throw new Error(`Expected object to have property ${property}`);
- }
- },
- toBeInstanceOf: (expectedClass) => {
- if (!(actual instanceof expectedClass)) {
- throw new Error(`Expected instance of ${expectedClass.name}, got ${actual.constructor.name}`);
- }
- }
- };
- }
-
- /**
- * Test that a component can be extracted from the monolith without breaking functionality
- */
- testComponentExtraction(componentName, extractFn, originalTests) {
- this.describe(`Component Extraction: ${componentName}`, () => {
- this.it('should extract without syntax errors', () => {
- try {
- const component = extractFn();
- this.expect(component).toBeTruthy();
- } catch (error) {
- throw new Error(`Component extraction failed: ${error.message}`);
- }
- });
-
- this.it('should maintain original API', () => {
- const component = extractFn();
- originalTests.forEach(test => {
- try {
- test(component);
- } catch (error) {
- throw new Error(`API compatibility test failed: ${error.message}`);
- }
- });
- });
- });
- }
-
- /**
- * Test component integration after extraction
- */
- testComponentIntegration(components, integrationTests) {
- this.describe('Component Integration', () => {
- integrationTests.forEach((test, index) => {
- this.it(`integration test ${index + 1}`, () => {
- test(components);
- });
- });
- });
- }
-
- /**
- * Setup test environment with mock dependencies
- */
- setupTestEnvironment() {
- // Create test container
- const container = document.createElement('div');
- container.id = 'test-container';
- container.innerHTML = '';
- document.body.appendChild(container);
-
- // Mock any global dependencies
- global.mockSectionManager = {
- sections: new Map(),
- createSectionsFromMarkdown: () => [],
- startEditing: () => true,
- stopEditing: () => true,
- getAllSections: () => []
- };
-
- return { container };
- }
-
- /**
- * Cleanup test environment
- */
- cleanupTestEnvironment() {
- const container = document.getElementById('test-container');
- if (container) {
- container.remove();
- }
-
- // Clear any global mocks
- delete global.mockSectionManager;
- }
-
- async run() {
- console.log('🧪 TDD Refactoring Test Runner Starting...\n');
-
- const startTime = Date.now();
-
- // Run all collected tests
- // Tests will be added by importing component test files
-
- const endTime = Date.now();
- const duration = endTime - startTime;
-
- console.log(`\n📊 Test Results:`);
- console.log(` ✅ Passed: ${this.passed}`);
- console.log(` ❌ Failed: ${this.failed}`);
- console.log(` ⏱️ Duration: ${duration}ms`);
-
- if (this.failed > 0) {
- console.log(`\n❌ ${this.failed} test(s) failed. Refactoring should not proceed.`);
- process.exit(1);
- } else {
- console.log(`\n✅ All tests passed! Refactoring is safe to continue.`);
- }
- }
-}
-
-// Export for use in component tests
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = { RefactorTestRunner };
-}
-
-// Export for browser use
-if (typeof window !== 'undefined') {
- window.RefactorTestRunner = RefactorTestRunner;
-}
-
-module.exports = RefactorTestRunner;
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/section-splitting.test.js b/capabilities/testdrive-jsui/js/tests/section-splitting.test.js
deleted file mode 100644
index 993a8478..00000000
--- a/capabilities/testdrive-jsui/js/tests/section-splitting.test.js
+++ /dev/null
@@ -1,267 +0,0 @@
-/**
- * Section Splitting Functionality Tests
- *
- * Tests dynamic section splitting when headings are detected
- * Based on functionality from history/javascript-dev-tests/test_section_splitting.js
- */
-
-describe('Section Splitting', () => {
- let sectionManager;
-
- beforeEach(() => {
- // Setup DOM
- document.body.innerHTML = `
-
- `;
-
- // Load components
- require('../core/section-manager.js');
-
- if (global.SectionManager) {
- sectionManager = new global.SectionManager();
- }
- });
-
- afterEach(() => {
- document.body.innerHTML = '';
- jest.clearAllMocks();
- });
-
- describe('Heading detection', () => {
- test('should detect new headings in content', () => {
- const textWithHeading = `
- This is some content.
-
- # New Heading
-
- This should be a new section.
- `;
-
- // Test heading detection with regex
- const lines = textWithHeading.trim().split('\n');
- const headingLine = lines.find(line => /^#+ /.test(line.trim()));
- expect(headingLine).toBeTruthy();
- expect(headingLine.trim()).toBe('# New Heading');
- });
-
- test('should identify different heading levels', () => {
- const headingTests = [
- { text: '# Heading 1', level: 1 },
- { text: '## Heading 2', level: 2 },
- { text: '### Heading 3', level: 3 },
- { text: '#### Heading 4', level: 4 }
- ];
-
- headingTests.forEach(({ text, level }) => {
- const match = text.match(/^(#+) /);
- expect(match).toBeTruthy();
- if (match) {
- expect(match[1].length).toBe(level);
- }
- });
- });
-
- test('should distinguish headings from regular text', () => {
- const testCases = [
- { text: '# This is a heading', isHeading: true },
- { text: 'This is not a heading', isHeading: false },
- { text: 'Neither is this # hash in middle', isHeading: false },
- { text: '## Another heading', isHeading: true }
- ];
-
- testCases.forEach(({ text, isHeading }) => {
- const match = /^#+\s/.test(text.trim());
- expect(match).toBe(isHeading);
- });
- });
- });
-
- describe('Section splitting logic', () => {
- test('should split content when heading is detected', () => {
- const originalContent = 'Original content without headings';
- const newContent = `
- ${originalContent}
-
- # New Section
-
- New section content
- `;
-
- // Simulate section splitting logic
- const parts = newContent.split(/\n(?=#)/);
-
- if (parts.length > 1) {
- expect(parts.length).toBeGreaterThan(1);
- expect(parts[0]).toContain('Original content');
- expect(parts[1]).toContain('# New Section');
- }
- });
-
- test('should preserve content when no headings are present', () => {
- const content = 'Just regular content without any headings';
- const parts = content.split(/\n(?=#)/);
-
- expect(parts.length).toBe(1);
- expect(parts[0]).toBe(content);
- });
-
- test('should handle multiple headings correctly', () => {
- const contentWithMultipleHeadings = `Initial content
-
-# First Heading
-First section content
-
-## Second Heading
-Second section content
-
-# Third Heading
-Third section content`;
-
- // Split on lines that start with headings
- const parts = contentWithMultipleHeadings.split(/\n(?=#)/);
-
- // Should split into multiple sections
- expect(parts.length).toBeGreaterThanOrEqual(2);
-
- // Find heading lines
- const headings = contentWithMultipleHeadings.match(/^#+.*$/gm);
- expect(headings).toBeTruthy();
- expect(headings.length).toBe(3);
- });
- });
-
- describe('SectionManager integration', () => {
- test('should have handleSectionSplit method', () => {
- if (!sectionManager) {
- console.warn('SectionManager not available, skipping test');
- return;
- }
-
- expect(typeof sectionManager.handleSectionSplit).toBe('function');
- });
-
- test('should maintain section state during splits', () => {
- if (!sectionManager) return;
-
- const originalSectionCount = document.querySelectorAll('.section').length;
-
- // Mock section splitting
- const mockNewSection = document.createElement('div');
- mockNewSection.className = 'section';
- mockNewSection.setAttribute('data-section-id', 'split-section');
-
- if (originalSectionCount > 0) {
- expect(originalSectionCount).toBeGreaterThan(0);
- }
- });
- });
-
- describe('Dynamic section creation', () => {
- test('should create new section elements when splitting', () => {
- const sectionContent = `
- Original content
-
- # New Section Title
-
- New section content
- `;
-
- // Simulate section creation
- const newSection = document.createElement('div');
- newSection.className = 'section';
- newSection.setAttribute('data-section-id', 'generated-section-id');
-
- const contentDiv = document.createElement('div');
- contentDiv.className = 'section-content';
- contentDiv.textContent = 'New section content';
-
- newSection.appendChild(contentDiv);
-
- expect(newSection.className).toBe('section');
- expect(newSection.getAttribute('data-section-id')).toBeTruthy();
- expect(newSection.querySelector('.section-content')).toBeTruthy();
- });
-
- test('should generate unique section IDs', () => {
- const headingText = 'My New Section';
-
- // Simulate ID generation from heading
- const sectionId = headingText
- .toLowerCase()
- .replace(/[^a-z0-9]+/g, '-')
- .replace(/^-+|-+$/g, '');
-
- expect(sectionId).toBe('my-new-section');
- });
-
- test('should preserve section hierarchy', () => {
- const hierarchicalContent = `
- # Main Section
- Main content
-
- ## Subsection
- Sub content
-
- ### Sub-subsection
- Sub-sub content
- `;
-
- const headings = hierarchicalContent.match(/^#+.*$/gm);
-
- if (headings) {
- expect(headings.length).toBe(3);
- expect(headings[0]).toMatch(/^# /);
- expect(headings[1]).toMatch(/^## /);
- expect(headings[2]).toMatch(/^### /);
- }
- });
- });
-
- describe('Section splitting edge cases', () => {
- test('should handle empty headings gracefully', () => {
- const contentWithEmptyHeading = `
- Content before
-
- #
-
- Content after
- `;
-
- const parts = contentWithEmptyHeading.split(/\n(?=#)/);
- expect(parts.length).toBeGreaterThanOrEqual(1);
- });
-
- test('should handle headings at the start of content', () => {
- const contentStartingWithHeading = `# First Heading
- Content for first section
-
- # Second Heading
- Content for second section
- `;
-
- const parts = contentStartingWithHeading.split(/\n(?=#)/);
- expect(parts[0]).toContain('# First Heading');
- });
-
- test('should handle malformed headings', () => {
- const malformedHeadings = [
- '#NoSpace',
- '# ',
- '########## Too many hashes',
- 'Not a heading # at all'
- ];
-
- malformedHeadings.forEach(text => {
- const isValidHeading = /^#{1,6}\s+\S/.test(text);
- // Most should be invalid except properly formatted ones
- expect(typeof isValidHeading).toBe('boolean');
- });
- });
- });
-});
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/setup.js b/capabilities/testdrive-jsui/js/tests/setup.js
deleted file mode 100644
index 8f94a2b4..00000000
--- a/capabilities/testdrive-jsui/js/tests/setup.js
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * Jest Test Setup for TestDrive-JSUI
- *
- * Sets up the testing environment for JavaScript UI components.
- * Provides DOM mocking, global utilities, and test helpers.
- */
-
-// Mock DOM globals that might be missing in JSDOM
-global.ResizeObserver = jest.fn().mockImplementation(() => ({
- observe: jest.fn(),
- unobserve: jest.fn(),
- disconnect: jest.fn(),
-}));
-
-global.IntersectionObserver = jest.fn().mockImplementation(() => ({
- observe: jest.fn(),
- unobserve: jest.fn(),
- disconnect: jest.fn(),
-}));
-
-// Mock window.matchMedia
-Object.defineProperty(window, 'matchMedia', {
- writable: true,
- value: jest.fn().mockImplementation(query => ({
- matches: false,
- media: query,
- onchange: null,
- addListener: jest.fn(), // deprecated
- removeListener: jest.fn(), // deprecated
- addEventListener: jest.fn(),
- removeEventListener: jest.fn(),
- dispatchEvent: jest.fn(),
- })),
-});
-
-// Mock local storage
-const localStorageMock = {
- getItem: jest.fn(),
- setItem: jest.fn(),
- removeItem: jest.fn(),
- clear: jest.fn(),
-};
-global.localStorage = localStorageMock;
-
-// Mock session storage
-const sessionStorageMock = {
- getItem: jest.fn(),
- setItem: jest.fn(),
- removeItem: jest.fn(),
- clear: jest.fn(),
-};
-global.sessionStorage = sessionStorageMock;
-
-// Global test utilities
-global.testUtils = {
- /**
- * Create a mock DOM element with specified tag and attributes
- */
- createElement: (tag, attributes = {}) => {
- const element = document.createElement(tag);
- Object.entries(attributes).forEach(([key, value]) => {
- element.setAttribute(key, value);
- });
- return element;
- },
-
- /**
- * Create a test markdown content div
- */
- createMarkdownContent: (content = '# Test Content') => {
- const div = document.createElement('div');
- div.id = 'markdown-content';
- div.innerHTML = content;
- return div;
- },
-
- /**
- * Wait for next tick (useful for async operations)
- */
- nextTick: () => new Promise(resolve => setTimeout(resolve, 0)),
-
- /**
- * Simulate user interaction events
- */
- simulateEvent: (element, eventType, eventProperties = {}) => {
- const event = new Event(eventType, { bubbles: true, ...eventProperties });
- Object.entries(eventProperties).forEach(([key, value]) => {
- event[key] = value;
- });
- element.dispatchEvent(event);
- return event;
- },
-
- /**
- * Clean up DOM after each test
- */
- cleanupDOM: () => {
- document.body.innerHTML = '';
- document.head.innerHTML = '';
- }
-};
-
-// Setup and teardown
-beforeEach(() => {
- // Reset mocks
- jest.clearAllMocks();
-
- // Reset localStorage/sessionStorage
- localStorageMock.getItem.mockClear();
- localStorageMock.setItem.mockClear();
- localStorageMock.removeItem.mockClear();
- localStorageMock.clear.mockClear();
-
- sessionStorageMock.getItem.mockClear();
- sessionStorageMock.setItem.mockClear();
- sessionStorageMock.removeItem.mockClear();
- sessionStorageMock.clear.mockClear();
-});
-
-afterEach(() => {
- // Clean up DOM
- global.testUtils.cleanupDOM();
-
- // Clean up any timers
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
-});
-
-// Console helpers for test debugging
-global.console = {
- ...console,
- // Keep these methods for test debugging
- log: console.log,
- warn: console.warn,
- error: console.error,
- // Mock these to avoid noise in tests
- info: jest.fn(),
- debug: jest.fn(),
-};
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/test-component-integration.js b/capabilities/testdrive-jsui/js/tests/test-component-integration.js
deleted file mode 100644
index 2107dc99..00000000
--- a/capabilities/testdrive-jsui/js/tests/test-component-integration.js
+++ /dev/null
@@ -1,521 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * Comprehensive Component Integration Test
- *
- * Tests that extracted components work together properly.
- * Verifies the complete workflow: Section Creation → Rendering → Editing → Saving
- */
-
-const RefactorTestRunner = require('./refactor-test-runner.js');
-
-const runner = new RefactorTestRunner();
-
-runner.describe('Component Integration Tests', () => {
-
- runner.it('should load all extracted components', () => {
- try {
- // Load extracted components
- const sectionModule = require('../core/section-manager.js');
- const domModule = require('../components/dom-renderer.js');
-
- runner.expect(sectionModule.SectionManager).toBeTruthy();
- runner.expect(sectionModule.Section).toBeTruthy();
- runner.expect(domModule.DOMRenderer).toBeTruthy();
- runner.expect(domModule.FloatingMenu).toBeTruthy();
-
- // Set globals for other tests
- global.ExtractedSectionManager = sectionModule.SectionManager;
- global.ExtractedSection = sectionModule.Section;
- global.ExtractedDOMRenderer = domModule.DOMRenderer;
- global.ExtractedFloatingMenu = domModule.FloatingMenu;
- global.ExtractedEditState = sectionModule.EditState;
-
- } catch (error) {
- throw new Error(`Failed to load extracted components: ${error.message}`);
- }
- });
-
- runner.it('should support complete section creation workflow', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
-
- // Setup
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
-
- // Test workflow: Create sections from markdown
- const testMarkdown = `# Main Heading
-This is the introduction content.
-
-## Subheading One
-Content for first subsection.
-
-
-
-## Subheading Two
-Content for second subsection.`;
-
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
-
-
- // Verify sections were created
- // Expected: heading+paragraph, heading+paragraph, image, heading+paragraph = 4 sections
- runner.expect(sections.length).toBe(4);
- runner.expect(sections[0].type).toBe('heading');
- runner.expect(sections[2].type).toBe('image');
-
- // Verify DOM rendering
- domRenderer.renderAllSections(sections);
- const renderedElements = container.querySelectorAll('.ui-edit-section');
- runner.expect(renderedElements.length).toBe(sections.length);
-
- // Cleanup
- document.body.removeChild(container);
- });
-
- runner.it('should support complete editing workflow', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
- const EditState = global.ExtractedEditState;
-
- // Setup
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
-
- // Create and render sections
- const testMarkdown = '# Test Heading\nOriginal content here.';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- domRenderer.renderAllSections(sections);
-
- const sectionId = sections[0].id;
- const section = sectionManager.sections.get(sectionId);
-
- // Test workflow: Start editing
- runner.expect(section.state).toBe(EditState.ORIGINAL);
- runner.expect(section.isEditing()).toBeFalsy();
-
- const content = sectionManager.startEditing(sectionId);
- runner.expect(content).toContain('Test Heading');
- runner.expect(section.isEditing()).toBeTruthy();
- runner.expect(section.state).toBe(EditState.EDITING);
-
- // Test workflow: Update content
- const newContent = '# Updated Heading\nModified content here.';
- sectionManager.updateContent(sectionId, newContent);
- runner.expect(section.editingMarkdown).toBe(newContent);
-
- // Test workflow: Accept changes
- sectionManager.acceptChanges(sectionId);
- runner.expect(section.currentMarkdown).toBe(newContent);
- runner.expect(section.state).toBe(EditState.SAVED);
- runner.expect(section.isEditing()).toBeFalsy();
-
- // Cleanup
- document.body.removeChild(container);
- });
-
- runner.it('should support accept/cancel button functionality', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
-
- // Setup
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
-
- // Create and render sections
- const testMarkdown = '# Test Heading\nOriginal content here.';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- domRenderer.renderAllSections(sections);
-
- const sectionId = sections[0].id;
- const section = sectionManager.sections.get(sectionId);
-
- // Start editing to trigger floating menu with buttons
- sectionManager.startEditing(sectionId);
-
- // Check if floating menu exists
- runner.expect(domRenderer.currentFloatingMenu).toBeTruthy();
- runner.expect(domRenderer.currentFloatingMenu.isVisible).toBeTruthy();
-
- // Find buttons in the floating menu
- const menuElement = domRenderer.currentFloatingMenu.element;
- runner.expect(menuElement).toBeTruthy();
-
- const buttons = menuElement.querySelectorAll('button');
- runner.expect(buttons.length >= 2).toBeTruthy(); // At least Accept and Cancel buttons
-
- const acceptBtn = Array.from(buttons).find(btn => btn.textContent === 'Accept');
- const cancelBtn = Array.from(buttons).find(btn => btn.textContent === 'Cancel');
-
- runner.expect(acceptBtn).toBeTruthy();
- runner.expect(cancelBtn).toBeTruthy();
-
- // Test Accept button functionality
- runner.expect(section.isEditing()).toBeTruthy();
-
- // Simulate updating content and clicking Accept
- const textarea = menuElement.querySelector('textarea');
- runner.expect(textarea).toBeTruthy();
- textarea.value = '# Updated Heading\nUpdated content via button.';
-
- acceptBtn.click();
-
- // After clicking Accept, section should be saved and menu hidden
- runner.expect(section.isEditing()).toBeFalsy();
- runner.expect(section.currentMarkdown).toContain('Updated Heading');
- runner.expect(domRenderer.currentFloatingMenu).toBeFalsy();
-
- // Cleanup
- document.body.removeChild(container);
- });
-
- runner.it('should support cancel button functionality', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
-
- // Setup
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
-
- // Create and render sections
- const testMarkdown = '# Original Heading\nOriginal content here.';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- domRenderer.renderAllSections(sections);
-
- const sectionId = sections[0].id;
- const section = sectionManager.sections.get(sectionId);
-
- // Start editing
- sectionManager.startEditing(sectionId);
-
- // Find buttons in the floating menu
- const menuElement = domRenderer.currentFloatingMenu.element;
- const cancelBtn = Array.from(menuElement.querySelectorAll('button')).find(btn => btn.textContent === 'Cancel');
-
- runner.expect(cancelBtn).toBeTruthy();
- runner.expect(section.isEditing()).toBeTruthy();
-
- // Simulate changing content but then canceling
- const textarea = menuElement.querySelector('textarea');
- textarea.value = '# Changed Heading\nThis should be discarded.';
-
- cancelBtn.click();
-
- // After clicking Cancel, section should not be saved and menu hidden
- runner.expect(section.isEditing()).toBeFalsy();
- runner.expect(section.currentMarkdown).toContain('Original Heading'); // Original content preserved
- runner.expect(domRenderer.currentFloatingMenu).toBeFalsy();
-
- // Cleanup
- document.body.removeChild(container);
- });
-
- runner.it('should support event-driven communication', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
-
- // Setup
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
-
- // Track events
- let sectionsCreatedEvent = null;
- let editStartedEvent = null;
-
- sectionManager.on('sections-created', (data) => {
- sectionsCreatedEvent = data;
- });
-
- sectionManager.on('edit-started', (data) => {
- editStartedEvent = data;
- });
-
- // Test event: sections-created
- const testMarkdown = '# Test\nContent';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
-
- runner.expect(sectionsCreatedEvent).toBeTruthy();
- runner.expect(sectionsCreatedEvent.sections).toEqual(sections);
- runner.expect(sectionsCreatedEvent.count).toBe(1);
-
- // Test event: edit-started
- const sectionId = sections[0].id;
- sectionManager.startEditing(sectionId);
-
- runner.expect(editStartedEvent).toBeTruthy();
- runner.expect(editStartedEvent.sectionId).toBe(sectionId);
- runner.expect(editStartedEvent.content).toContain('Test');
-
- // Cleanup
- document.body.removeChild(container);
- });
-
- runner.it('should support section type detection and rendering', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
- const Section = global.ExtractedSection;
-
- // Setup
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
-
- // Test different section types
- const testMarkdown = `# Heading Section
-Regular paragraph content.
-
-
-
-\`\`\`javascript
-// Code section
-console.log('test');
-\`\`\``;
-
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
-
-
- // Verify type detection - adjusted for actual parsing behavior
- // Expected: heading+paragraph, image, code = 3 sections
- runner.expect(sections[0].type).toBe('heading'); // Combined heading+paragraph
- runner.expect(sections[1].type).toBe('image'); // Image section
- runner.expect(sections[2].type).toBe('code'); // Code section
-
- // Verify image detection
- runner.expect(sections[1].isImage()).toBeTruthy(); // Image is now at index 1
- runner.expect(sections[0].isImage()).toBeFalsy();
-
- // Verify rendering handles different types
- domRenderer.renderAllSections(sections);
- const renderedElements = container.querySelectorAll('.ui-edit-section');
- runner.expect(renderedElements.length).toBe(sections.length);
-
- // Cleanup
- document.body.removeChild(container);
- });
-
- runner.it('should support FloatingMenu integration', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
- const FloatingMenu = global.ExtractedFloatingMenu;
-
- // Setup
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
-
- // Create and render sections
- const testMarkdown = '# Test Heading\nTest content';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- domRenderer.renderAllSections(sections);
-
- const sectionId = sections[0].id;
-
- // Test showing editor (which uses FloatingMenu)
- domRenderer.showEditor(sectionId, 'test content');
-
- // Verify floating menu state
- runner.expect(domRenderer.currentFloatingMenu).toBeTruthy();
- runner.expect(domRenderer.currentFloatingMenu.sectionId).toBe(sectionId);
- runner.expect(domRenderer.currentFloatingMenu.isVisible).toBeTruthy();
- runner.expect(domRenderer.editingSections.has(sectionId)).toBeTruthy();
-
- // Test hiding editor
- domRenderer.hideCurrentEditor();
- runner.expect(domRenderer.currentFloatingMenu).toBeFalsy();
- runner.expect(domRenderer.editingSections.has(sectionId)).toBeFalsy();
-
- // Cleanup
- document.body.removeChild(container);
- });
-
- runner.it('should support complete click-to-edit workflow', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
-
- // Setup
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
-
- // Create and render sections
- const testMarkdown = '# Test Heading\nTest content for editing';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- domRenderer.renderAllSections(sections);
-
- const sectionId = sections[0].id;
- const element = domRenderer.findSectionElement(sectionId);
-
- // Simulate click event
- const clickEvent = new Event('click', { bubbles: true });
- Object.defineProperty(clickEvent, 'target', { value: element });
-
- // Test complete workflow
- domRenderer.handleSectionClick(clickEvent);
-
- // Verify editing state was triggered
- const section = sectionManager.sections.get(sectionId);
- runner.expect(section.isEditing()).toBeTruthy();
- runner.expect(domRenderer.editingSections.has(sectionId)).toBeTruthy();
- runner.expect(domRenderer.currentFloatingMenu).toBeTruthy();
-
- // Cleanup
- document.body.removeChild(container);
- });
-
- runner.it('should support document status tracking', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
-
- const sectionManager = new SectionManager();
- const container = document.createElement('div');
- const domRenderer = new DOMRenderer(sectionManager, container);
-
- // Test initial status
- let status = sectionManager.getDocumentStatus();
- runner.expect(status.totalSections).toBe(0);
- runner.expect(status.editingSections).toBe(0);
-
- // Create sections
- const testMarkdown = '# Section 1\nContent 1\n\n# Section 2\nContent 2';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
-
- status = sectionManager.getDocumentStatus();
- runner.expect(status.totalSections).toBe(2);
- runner.expect(status.editingSections).toBe(2); // Bug compatibility (isEditing property exists)
-
- // Test getAllSections
- const allSections = sectionManager.getAllSections();
- runner.expect(allSections.length).toBe(2);
- runner.expect(allSections[0].currentMarkdown).toContain('Section 1');
- runner.expect(allSections[1].currentMarkdown).toContain('Section 2');
- });
-
- runner.it('should support event tracking and analytics', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
-
- const container = document.createElement('div');
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
-
- // Test event tracking
- domRenderer.trackEvent('test-event', { data: 'test' });
- domRenderer.trackEvent('section-click', { sectionId: 'test-123' });
-
- const stats = domRenderer.getEventStats();
- runner.expect(stats.totalEvents).toBe(1); // Only section-click is tracked in stats
- runner.expect(stats.stats['section-click']).toBe(1);
- runner.expect(stats.recentEvents.length).toBe(2);
- runner.expect(stats.recentEvents[0].type).toBe('test-event');
- runner.expect(stats.recentEvents[1].type).toBe('section-click');
- });
-
- // Integration stress test
- runner.it('should handle complex document with multiple operations', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
-
- // Setup
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
-
- // Complex document
- const complexMarkdown = `# Document Title
-Introduction paragraph with some content.
-
-## Section A
-Content for section A with details.
-
-
-
-### Subsection A.1
-More detailed content here.
-
-\`\`\`javascript
-function test() {
- console.log('code block');
-}
-\`\`\`
-
-## Section B
-Final section content.`;
-
- // Create and render
- const sections = sectionManager.createSectionsFromMarkdown(complexMarkdown);
- domRenderer.renderAllSections(sections);
-
- runner.expect(sections.length).toBe(6); // Adjusted based on actual parsing
-
- // Test editing multiple sections
- const firstSection = sections[0];
- const imageSection = sections.find(s => s.isImage());
- const codeSection = sections.find(s => s.type === 'code');
-
- // Edit first section
- sectionManager.startEditing(firstSection.id);
- sectionManager.updateContent(firstSection.id, '# Updated Title\nUpdated intro.');
- sectionManager.acceptChanges(firstSection.id);
-
- // Edit image section
- sectionManager.startEditing(imageSection.id);
- sectionManager.updateContent(imageSection.id, '');
- sectionManager.acceptChanges(imageSection.id);
-
- // Verify changes
- runner.expect(firstSection.currentMarkdown).toContain('Updated Title');
- runner.expect(imageSection.currentMarkdown).toContain('Updated Image');
-
- // Verify document reconstruction
- const finalMarkdown = sectionManager.getDocumentMarkdown();
- runner.expect(finalMarkdown).toContain('Updated Title');
- runner.expect(finalMarkdown).toContain('Updated Image');
- runner.expect(finalMarkdown).toContain('Section B');
-
- // Cleanup
- document.body.removeChild(container);
- });
-});
-
-module.exports = runner;
-
-// Run tests if called directly
-if (require.main === module) {
- console.log('🧪 Running Component Integration Tests');
- runner.run().then(() => {
- console.log('✅ Component integration tests completed');
- });
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/test-debugpanel-extraction.js b/capabilities/testdrive-jsui/js/tests/test-debugpanel-extraction.js
deleted file mode 100644
index 5dca6cae..00000000
--- a/capabilities/testdrive-jsui/js/tests/test-debugpanel-extraction.js
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * TDD Test for Debug Panel Component Extraction
- *
- * Tests the extraction of DebugPanel from the monolithic editor.js
- * DebugPanel handles debug message display and management.
- */
-
-const RefactorTestRunner = require('./refactor-test-runner.js');
-
-const runner = new RefactorTestRunner();
-
-// Define expected DebugPanel API
-const EXPECTED_DEBUGPANEL_API = [
- 'constructor',
- 'toggle',
- 'update',
- 'clear',
- 'addMessage',
- 'show',
- 'hide',
- 'getMessageCount',
- 'getRecentMessages'
-];
-
-runner.describe('DebugPanel Component Extraction', () => {
-
- runner.it('should define expected API methods', () => {
- const expectedMethods = EXPECTED_DEBUGPANEL_API;
- runner.expect(expectedMethods.length).toBe(9);
- runner.expect(expectedMethods).toContain('toggle');
- runner.expect(expectedMethods).toContain('update');
- runner.expect(expectedMethods).toContain('addMessage');
- });
-
- runner.it('should load extracted DebugPanel component', () => {
- // Load the extracted component
- delete require.cache[require.resolve('../components/debug-panel.js')];
-
- try {
- const module = require('../components/debug-panel.js');
- runner.expect(module.DebugPanel).toBeTruthy();
-
- // Set global for other tests
- global.ExtractedDebugPanel = module.DebugPanel;
- } catch (error) {
- throw new Error(`Failed to load extracted DebugPanel: ${error.message}`);
- }
- });
-
- runner.it('should preserve constructor functionality', () => {
- const DebugPanel = global.ExtractedDebugPanel;
-
- const debugPanel = new DebugPanel();
- runner.expect(debugPanel).toBeInstanceOf(DebugPanel);
- runner.expect(debugPanel.messages).toBeInstanceOf(Array);
- runner.expect(debugPanel.isActive).toBeFalsy();
- });
-
- runner.it('should preserve message handling functionality', () => {
- const DebugPanel = global.ExtractedDebugPanel;
-
- const debugPanel = new DebugPanel();
-
- // Test adding messages
- debugPanel.addMessage('Test message', 'INFO');
- runner.expect(debugPanel.getMessageCount()).toBe(1);
-
- const recentMessages = debugPanel.getRecentMessages(1);
- runner.expect(recentMessages.length).toBe(1);
- runner.expect(recentMessages[0].message).toBe('Test message');
- runner.expect(recentMessages[0].category).toBe('INFO');
- });
-
- runner.it('should preserve toggle functionality', () => {
- const DebugPanel = global.ExtractedDebugPanel;
-
- // Create container element
- const container = document.createElement('div');
- container.id = 'debug-messages-container';
- container.style.display = 'none';
- document.body.appendChild(container);
-
- const debugButton = document.createElement('button');
- debugButton.id = 'toggle-debug';
- debugButton.textContent = '🔍 Debug';
- document.body.appendChild(debugButton);
-
- const debugPanel = new DebugPanel();
-
- // Test toggle on
- debugPanel.toggle();
- runner.expect(debugPanel.isActive).toBeTruthy();
-
- // Test toggle off
- debugPanel.toggle();
- runner.expect(debugPanel.isActive).toBeFalsy();
-
- // Cleanup
- document.body.removeChild(container);
- document.body.removeChild(debugButton);
- });
-
- runner.it('should preserve update functionality', () => {
- const DebugPanel = global.ExtractedDebugPanel;
-
- const container = document.createElement('div');
- container.id = 'debug-messages-container';
- document.body.appendChild(container);
-
- const debugButton = document.createElement('button');
- debugButton.id = 'toggle-debug';
- debugButton.textContent = '🔍 Debug';
- document.body.appendChild(debugButton);
-
- const debugPanel = new DebugPanel();
- debugPanel.show();
-
- debugPanel.addMessage('Test message 1', 'INFO');
- debugPanel.addMessage('Test message 2', 'ERROR');
- debugPanel.update();
-
- runner.expect(container.innerHTML.length > 100).toBeTruthy();
- runner.expect(container.innerHTML).toContain('Test message 1');
- runner.expect(container.innerHTML).toContain('Test message 2');
-
- // Cleanup
- document.body.removeChild(container);
- document.body.removeChild(debugButton);
- });
-
- runner.it('should preserve clear functionality', () => {
- const DebugPanel = global.ExtractedDebugPanel;
-
- const debugPanel = new DebugPanel();
-
- debugPanel.addMessage('Test message 1', 'INFO');
- debugPanel.addMessage('Test message 2', 'ERROR');
- runner.expect(debugPanel.getMessageCount()).toBe(2);
-
- debugPanel.clear();
- runner.expect(debugPanel.getMessageCount()).toBe(0);
- });
-
- runner.it('should have core debug panel methods', () => {
- const DebugPanel = global.ExtractedDebugPanel;
-
- const debugPanel = new DebugPanel();
-
- // Should have core methods
- runner.expect(typeof debugPanel.toggle === 'function').toBeTruthy();
- runner.expect(typeof debugPanel.update === 'function').toBeTruthy();
- runner.expect(typeof debugPanel.addMessage === 'function').toBeTruthy();
- runner.expect(typeof debugPanel.clear === 'function').toBeTruthy();
- });
-
- runner.it('should handle message categories properly', () => {
- const DebugPanel = global.ExtractedDebugPanel;
-
- const debugPanel = new DebugPanel();
-
- // Test different message categories
- debugPanel.addMessage('Info message', 'INFO');
- debugPanel.addMessage('Warning message', 'WARNING');
- debugPanel.addMessage('Error message', 'ERROR');
- debugPanel.addMessage('Success message', 'SUCCESS');
-
- const messages = debugPanel.getRecentMessages(4);
- runner.expect(messages.length).toBe(4);
-
- const categories = messages.map(m => m.category);
- runner.expect(categories).toContain('INFO');
- runner.expect(categories).toContain('WARNING');
- runner.expect(categories).toContain('ERROR');
- runner.expect(categories).toContain('SUCCESS');
- });
-});
-
-module.exports = {
- runner,
- EXPECTED_DEBUGPANEL_API
-};
-
-// Run tests if called directly
-if (require.main === module) {
- console.log('🧪 Testing DebugPanel Component Extraction');
- runner.run().then(() => {
- console.log('✅ DebugPanel extraction tests completed');
- });
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/test-debugpanel-integration.js b/capabilities/testdrive-jsui/js/tests/test-debugpanel-integration.js
deleted file mode 100644
index af03ff83..00000000
--- a/capabilities/testdrive-jsui/js/tests/test-debugpanel-integration.js
+++ /dev/null
@@ -1,210 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * DebugPanel Integration Test
- *
- * Tests that the extracted DebugPanel component integrates properly
- * with the existing SectionManager and DOMRenderer components.
- */
-
-const RefactorTestRunner = require('./refactor-test-runner.js');
-
-const runner = new RefactorTestRunner();
-
-runner.describe('DebugPanel Integration Tests', () => {
-
- runner.it('should load all extracted components including DebugPanel', () => {
- try {
- // Load extracted components
- const sectionModule = require('../core/section-manager.js');
- const domModule = require('../components/dom-renderer.js');
- const debugModule = require('../components/debug-panel.js');
-
- runner.expect(sectionModule.SectionManager).toBeTruthy();
- runner.expect(domModule.DOMRenderer).toBeTruthy();
- runner.expect(debugModule.DebugPanel).toBeTruthy();
-
- // Set globals for other tests
- global.ExtractedSectionManager = sectionModule.SectionManager;
- global.ExtractedDOMRenderer = domModule.DOMRenderer;
- global.ExtractedDebugPanel = debugModule.DebugPanel;
-
- } catch (error) {
- throw new Error(`Failed to load extracted components: ${error.message}`);
- }
- });
-
- runner.it('should support debug panel with section editing workflow', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
- const DebugPanel = global.ExtractedDebugPanel;
-
- // Setup DOM elements
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const debugContainer = document.createElement('div');
- debugContainer.id = 'debug-messages-container';
- debugContainer.style.display = 'none';
- document.body.appendChild(debugContainer);
-
- const debugButton = document.createElement('button');
- debugButton.id = 'toggle-debug';
- debugButton.textContent = '🔍 Debug';
- document.body.appendChild(debugButton);
-
- // Create components
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
- const debugPanel = new DebugPanel();
-
- // Test workflow: Create sections and debug them
- const testMarkdown = '# Test Heading\nTest content for debugging';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- domRenderer.renderAllSections(sections);
-
- // Add debug messages
- debugPanel.addMessage('Section created: ' + sections[0].id, 'INFO');
- debugPanel.addMessage('DOM rendered successfully', 'SUCCESS');
-
- runner.expect(debugPanel.getMessageCount()).toBe(2);
-
- // Test showing debug panel
- debugPanel.show();
- runner.expect(debugPanel.isActive).toBeTruthy();
-
- // Test debug panel content
- const messages = debugPanel.getRecentMessages(2);
- runner.expect(messages[0].message).toContain('Section created');
- runner.expect(messages[1].message).toContain('DOM rendered');
-
- // Cleanup
- document.body.removeChild(container);
- document.body.removeChild(debugContainer);
- document.body.removeChild(debugButton);
- });
-
- runner.it('should support debug panel clearing and message management', () => {
- const DebugPanel = global.ExtractedDebugPanel;
-
- const debugPanel = new DebugPanel();
-
- // Add multiple messages
- for (let i = 0; i < 10; i++) {
- debugPanel.addMessage(`Test message ${i}`, i % 2 === 0 ? 'INFO' : 'WARNING');
- }
-
- runner.expect(debugPanel.getMessageCount()).toBe(10);
-
- // Test getting recent messages
- const recentFive = debugPanel.getRecentMessages(5);
- runner.expect(recentFive.length).toBe(5);
- runner.expect(recentFive[4].message).toContain('Test message 9');
-
- // Test clearing
- debugPanel.clear();
- runner.expect(debugPanel.getMessageCount()).toBe(0);
- });
-
- runner.it('should handle debug panel DOM integration properly', () => {
- const DebugPanel = global.ExtractedDebugPanel;
-
- // Setup DOM
- const debugContainer = document.createElement('div');
- debugContainer.id = 'debug-messages-container';
- debugContainer.style.display = 'none';
- document.body.appendChild(debugContainer);
-
- const debugButton = document.createElement('button');
- debugButton.id = 'toggle-debug';
- debugButton.textContent = '🔍 Debug';
- debugButton.style.background = '#6c757d';
- document.body.appendChild(debugButton);
-
- const debugPanel = new DebugPanel();
-
- // Test initial state
- runner.expect(debugPanel.isActive).toBeFalsy();
- runner.expect(debugContainer.style.display).toBe('none');
-
- // Test toggle on
- debugPanel.toggle();
- runner.expect(debugPanel.isActive).toBeTruthy();
- runner.expect(debugContainer.style.display).toBe('block');
- runner.expect(debugButton.textContent).toContain('Debug (ON)');
-
- // Test toggle off
- debugPanel.toggle();
- runner.expect(debugPanel.isActive).toBeFalsy();
- runner.expect(debugContainer.style.display).toBe('none');
- runner.expect(debugButton.textContent).toBe('🔍 Debug');
-
- // Cleanup
- document.body.removeChild(debugContainer);
- document.body.removeChild(debugButton);
- });
-
- runner.it('should handle missing DOM elements gracefully', () => {
- const DebugPanel = global.ExtractedDebugPanel;
-
- const debugPanel = new DebugPanel();
-
- // Try to toggle without DOM elements (should not throw)
- try {
- debugPanel.toggle();
- debugPanel.show();
- debugPanel.hide();
- debugPanel.update();
- runner.expect(true).toBeTruthy(); // If we get here, no errors were thrown
- } catch (error) {
- throw new Error(`DebugPanel should handle missing DOM gracefully: ${error.message}`);
- }
- });
-
- runner.it('should support event-driven debug message addition', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DebugPanel = global.ExtractedDebugPanel;
-
- const sectionManager = new SectionManager();
- const debugPanel = new DebugPanel();
-
- // Listen to section manager events and add debug messages
- let eventCount = 0;
-
- sectionManager.on('sections-created', (data) => {
- debugPanel.addMessage(`Sections created: ${data.count} sections`, 'INFO');
- eventCount++;
- });
-
- sectionManager.on('edit-started', (data) => {
- debugPanel.addMessage(`Edit started for section: ${data.sectionId}`, 'DEBUG');
- eventCount++;
- });
-
- // Create sections
- const testMarkdown = '# Test\nContent';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
-
- // Start editing
- sectionManager.startEditing(sections[0].id);
-
- // Verify debug messages were added
- runner.expect(eventCount).toBe(2);
- runner.expect(debugPanel.getMessageCount()).toBe(2);
-
- const messages = debugPanel.getRecentMessages(2);
- runner.expect(messages[0].message).toContain('Sections created');
- runner.expect(messages[1].message).toContain('Edit started');
- });
-});
-
-module.exports = runner;
-
-// Run tests if called directly
-if (require.main === module) {
- console.log('🧪 Running DebugPanel Integration Tests');
- runner.run().then(() => {
- console.log('✅ DebugPanel integration tests completed');
- });
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/test-documentcontrols-extraction.js b/capabilities/testdrive-jsui/js/tests/test-documentcontrols-extraction.js
deleted file mode 100644
index 764313c3..00000000
--- a/capabilities/testdrive-jsui/js/tests/test-documentcontrols-extraction.js
+++ /dev/null
@@ -1,218 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * TDD Test for Document Controls Component Extraction
- *
- * Tests the extraction of DocumentControls from the monolithic editor.js
- * DocumentControls handles the floating control panel and its actions.
- */
-
-const RefactorTestRunner = require('./refactor-test-runner.js');
-
-const runner = new RefactorTestRunner();
-
-// Define expected DocumentControls API
-const EXPECTED_DOCUMENTCONTROLS_API = [
- 'constructor',
- 'create',
- 'destroy',
- 'show',
- 'hide',
- 'addButton',
- 'removeButton',
- 'setEventHandlers',
- 'updateStatus',
- 'getControlPanel'
-];
-
-runner.describe('DocumentControls Component Extraction', () => {
-
- runner.it('should define expected API methods', () => {
- const expectedMethods = EXPECTED_DOCUMENTCONTROLS_API;
- runner.expect(expectedMethods.length).toBe(10);
- runner.expect(expectedMethods).toContain('create');
- runner.expect(expectedMethods).toContain('addButton');
- runner.expect(expectedMethods).toContain('setEventHandlers');
- });
-
- runner.it('should load extracted DocumentControls component', () => {
- // Load the extracted component
- delete require.cache[require.resolve('../components/document-controls-legacy.js')];
-
- try {
- const module = require('../components/document-controls-legacy.js');
- runner.expect(module.DocumentControlsLegacy).toBeTruthy();
-
- // Set global for other tests
- global.ExtractedDocumentControls = module.DocumentControlsLegacy;
- } catch (error) {
- throw new Error(`Failed to load extracted DocumentControls: ${error.message}`);
- }
- });
-
- runner.it('should preserve constructor functionality', () => {
- const DocumentControls = global.ExtractedDocumentControls;
-
- const controls = new DocumentControls();
- runner.expect(controls).toBeInstanceOf(DocumentControls);
- runner.expect(controls.controlPanel).toBeFalsy(); // Initially null
- runner.expect(controls.buttons).toBeInstanceOf(Map);
- });
-
- runner.it('should preserve control panel creation functionality', () => {
- const DocumentControls = global.ExtractedDocumentControls;
-
- const controls = new DocumentControls();
- controls.create();
-
- const panel = controls.getControlPanel();
- runner.expect(panel).toBeTruthy();
- runner.expect(panel.id).toBe('markitect-global-controls');
-
- // Check that panel is added to DOM
- const domPanel = document.getElementById('markitect-global-controls');
- runner.expect(domPanel).toBeTruthy();
-
- // Cleanup
- controls.destroy();
- });
-
- runner.it('should preserve button creation functionality', () => {
- const DocumentControls = global.ExtractedDocumentControls;
-
- const controls = new DocumentControls();
- controls.create();
-
- // Default buttons should be created
- runner.expect(controls.buttons.has('save-document')).toBeTruthy();
- runner.expect(controls.buttons.has('reset-all')).toBeTruthy();
- runner.expect(controls.buttons.has('show-status')).toBeTruthy();
- runner.expect(controls.buttons.has('toggle-debug')).toBeTruthy();
-
- // Check DOM elements exist
- runner.expect(document.getElementById('save-document')).toBeTruthy();
- runner.expect(document.getElementById('reset-all')).toBeTruthy();
- runner.expect(document.getElementById('show-status')).toBeTruthy();
- runner.expect(document.getElementById('toggle-debug')).toBeTruthy();
-
- // Cleanup
- controls.destroy();
- });
-
- runner.it('should support custom button addition', () => {
- const DocumentControls = global.ExtractedDocumentControls;
-
- const controls = new DocumentControls();
- controls.create();
-
- // Add custom button
- const customButton = controls.addButton('custom-test', '🎯 Test', '#ff6600');
- runner.expect(customButton).toBeTruthy();
- runner.expect(customButton.id).toBe('custom-test');
- runner.expect(customButton.textContent).toBe('🎯 Test');
-
- // Check button is in map and DOM
- runner.expect(controls.buttons.has('custom-test')).toBeTruthy();
- runner.expect(document.getElementById('custom-test')).toBeTruthy();
-
- // Cleanup
- controls.destroy();
- });
-
- runner.it('should support event handler configuration', () => {
- const DocumentControls = global.ExtractedDocumentControls;
-
- const controls = new DocumentControls();
- controls.create();
-
- let saveClicked = false;
- let resetClicked = false;
-
- const handlers = {
- 'save-document': () => { saveClicked = true; },
- 'reset-all': () => { resetClicked = true; }
- };
-
- controls.setEventHandlers(handlers);
-
- // Simulate button clicks
- const saveBtn = document.getElementById('save-document');
- const resetBtn = document.getElementById('reset-all');
-
- saveBtn.click();
- resetBtn.click();
-
- runner.expect(saveClicked).toBeTruthy();
- runner.expect(resetClicked).toBeTruthy();
-
- // Cleanup
- controls.destroy();
- });
-
- runner.it('should support show/hide functionality', () => {
- const DocumentControls = global.ExtractedDocumentControls;
-
- const controls = new DocumentControls();
- controls.create();
-
- const panel = controls.getControlPanel();
-
- // Test hiding
- controls.hide();
- runner.expect(panel.style.display).toBe('none');
-
- // Test showing
- controls.show();
- runner.expect(panel.style.display).toBe('block');
-
- // Cleanup
- controls.destroy();
- });
-
- runner.it('should preserve destroy functionality', () => {
- const DocumentControls = global.ExtractedDocumentControls;
-
- const controls = new DocumentControls();
- controls.create();
-
- // Verify panel exists
- runner.expect(document.getElementById('markitect-global-controls')).toBeTruthy();
-
- // Destroy
- controls.destroy();
-
- // Verify panel is removed
- runner.expect(document.getElementById('markitect-global-controls')).toBeFalsy();
- runner.expect(controls.controlPanel).toBeFalsy();
- });
-
- runner.it('should support status updates', () => {
- const DocumentControls = global.ExtractedDocumentControls;
-
- const controls = new DocumentControls();
- controls.create();
-
- // Test status update
- controls.updateStatus({ totalSections: 5, editingSections: 2 });
-
- // The status should be reflected in the panel (implementation specific)
- const panel = controls.getControlPanel();
- runner.expect(panel).toBeTruthy();
-
- // Cleanup
- controls.destroy();
- });
-});
-
-module.exports = {
- runner,
- EXPECTED_DOCUMENTCONTROLS_API
-};
-
-// Run tests if called directly
-if (require.main === module) {
- console.log('🧪 Testing DocumentControls Component Extraction');
- runner.run().then(() => {
- console.log('✅ DocumentControls extraction tests completed');
- });
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/test-domrenderer-extraction.js b/capabilities/testdrive-jsui/js/tests/test-domrenderer-extraction.js
deleted file mode 100644
index e8aadc04..00000000
--- a/capabilities/testdrive-jsui/js/tests/test-domrenderer-extraction.js
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * TDD Test for DOMRenderer Component Extraction
- *
- * Tests the extraction of DOMRenderer from the monolithic editor.js
- * DOMRenderer handles all DOM interactions and UI rendering.
- */
-
-const RefactorTestRunner = require('./refactor-test-runner.js');
-
-const runner = new RefactorTestRunner();
-
-// Define expected DOMRenderer API
-const EXPECTED_DOMRENDERER_API = [
- 'constructor',
- 'renderAllSections',
- 'renderSection',
- 'showEditor',
- 'hideCurrentEditor',
- 'showImageEditor',
- 'findSectionElement',
- 'handleSectionClick',
- 'setupSectionElement',
- 'trackEvent',
- 'getEventStats'
- // Note: addGlobalControls and debug methods are on MarkitectCleanEditor, not DOMRenderer
-];
-
-runner.describe('DOMRenderer Component Extraction', () => {
-
- runner.it('should define expected API methods', () => {
- const expectedMethods = EXPECTED_DOMRENDERER_API;
- runner.expect(expectedMethods.length).toBe(11);
- runner.expect(expectedMethods).toContain('renderAllSections');
- runner.expect(expectedMethods).toContain('showEditor');
- runner.expect(expectedMethods).toContain('handleSectionClick');
- });
-
- runner.it('should extract from monolithic editor.js', () => {
- // Load the monolithic editor.js to extract DOMRenderer
- delete require.cache[require.resolve('/home/worsch/markitect_project/markitect/static/editor.js')];
-
- try {
- const editorModule = require('/home/worsch/markitect_project/markitect/static/editor.js');
- runner.expect(editorModule.DOMRenderer).toBeTruthy();
- // Set global for other tests
- global.DOMRenderer = editorModule.DOMRenderer;
- global.SectionManager = editorModule.SectionManager;
- } catch (error) {
- throw new Error(`Failed to load monolithic editor.js: ${error.message}`);
- }
- });
-
- runner.it('should preserve DOMRenderer constructor functionality', () => {
- const DOMRenderer = global.DOMRenderer;
- const SectionManager = global.SectionManager;
-
- const container = document.createElement('div');
- const sectionManager = new SectionManager();
-
- const renderer = new DOMRenderer(sectionManager, container);
- runner.expect(renderer).toBeInstanceOf(DOMRenderer);
- runner.expect(renderer.sectionManager).toBe(sectionManager);
- runner.expect(renderer.container).toBe(container);
- });
-
- runner.it('should preserve section rendering functionality', () => {
- const DOMRenderer = global.DOMRenderer;
- const SectionManager = global.SectionManager;
-
- const container = document.createElement('div');
- container.innerHTML = '';
-
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
-
- const testMarkdown = '# Test Heading\nTest content';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
-
- // This should not throw an error
- renderer.renderAllSections(sections);
-
- // Check that some content was rendered
- runner.expect(container.innerHTML.length).toBe(container.innerHTML.length); // Basic sanity check
- });
-
- runner.it('should preserve findSectionElement functionality', () => {
- const DOMRenderer = global.DOMRenderer;
- const SectionManager = global.SectionManager;
-
- const container = document.createElement('div');
- container.innerHTML = '';
-
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
-
- const testMarkdown = '# Test Heading\nTest content';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- renderer.renderAllSections(sections);
-
- const sectionId = sections[0].id;
- const element = renderer.findSectionElement(sectionId);
-
- // Should find an element or return null (not throw error)
- runner.expect(typeof element === 'object').toBeTruthy();
- });
-
- runner.it('should preserve event tracking functionality', () => {
- const DOMRenderer = global.DOMRenderer;
- const SectionManager = global.SectionManager;
-
- const container = document.createElement('div');
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
-
- // Should have trackEvent method
- runner.expect(typeof renderer.trackEvent === 'function').toBeTruthy();
-
- // Should be able to track an event
- renderer.trackEvent('test-event', { data: 'test' });
-
- // Should have getEventStats method
- runner.expect(typeof renderer.getEventStats === 'function').toBeTruthy();
-
- const stats = renderer.getEventStats();
- runner.expect(typeof stats === 'object').toBeTruthy();
- });
-
- runner.it('should preserve editor showing functionality', () => {
- const DOMRenderer = global.DOMRenderer;
- const SectionManager = global.SectionManager;
-
- const container = document.createElement('div');
- container.innerHTML = '';
-
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
-
- const testMarkdown = '# Test Heading\nTest content';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- renderer.renderAllSections(sections);
-
- const sectionId = sections[0].id;
-
- // showEditor should not throw error
- try {
- renderer.showEditor(sectionId, 'test content');
- runner.expect(true).toBeTruthy(); // If we get here, no error was thrown
- } catch (error) {
- // Some errors are expected if DOM structure isn't complete
- runner.expect(typeof error.message === 'string').toBeTruthy();
- }
- });
-
- runner.it('should have core DOM rendering methods', () => {
- const DOMRenderer = global.DOMRenderer;
- const SectionManager = global.SectionManager;
-
- const container = document.createElement('div');
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
-
- // Should have core methods
- runner.expect(typeof renderer.renderAllSections === 'function').toBeTruthy();
- runner.expect(typeof renderer.showEditor === 'function').toBeTruthy();
- runner.expect(typeof renderer.findSectionElement === 'function').toBeTruthy();
- runner.expect(typeof renderer.trackEvent === 'function').toBeTruthy();
- });
-});
-
-// Export API tests for use during extraction
-const DOMRENDERER_API_TESTS = [
- (DOMRenderer, SectionManager) => {
- const container = document.createElement('div');
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
- if (!renderer.sectionManager) {
- throw new Error('sectionManager property missing');
- }
- },
- (DOMRenderer, SectionManager) => {
- const container = document.createElement('div');
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
- if (typeof renderer.renderAllSections !== 'function') {
- throw new Error('renderAllSections method missing');
- }
- },
- (DOMRenderer, SectionManager) => {
- const container = document.createElement('div');
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
- if (typeof renderer.showEditor !== 'function') {
- throw new Error('showEditor method missing');
- }
- }
-];
-
-module.exports = {
- runner,
- EXPECTED_DOMRENDERER_API,
- DOMRENDERER_API_TESTS
-};
-
-// Run tests if called directly
-if (require.main === module) {
- console.log('🧪 Testing DOMRenderer Component Extraction');
- runner.run().then(() => {
- console.log('✅ DOMRenderer extraction tests completed');
- });
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/test-environment.test.js b/capabilities/testdrive-jsui/js/tests/test-environment.test.js
deleted file mode 100644
index c35e13b5..00000000
--- a/capabilities/testdrive-jsui/js/tests/test-environment.test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Environment Test - Verifies Jest setup is working correctly
- */
-
-describe('Test Environment', () => {
- test('should have JSDOM environment available', () => {
- expect(global.document).toBeDefined();
- expect(global.window).toBeDefined();
- expect(document.createElement).toBeDefined();
- });
-
- test('should be able to create DOM elements', () => {
- const div = document.createElement('div');
- div.textContent = 'Test content';
- expect(div.tagName).toBe('DIV');
- expect(div.textContent).toBe('Test content');
- });
-
- test('should have content container available', () => {
- const contentEl = document.getElementById('content');
- expect(contentEl).toBeDefined();
- expect(contentEl.tagName).toBe('DIV');
- });
-});
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/test-extracted-domrenderer.js b/capabilities/testdrive-jsui/js/tests/test-extracted-domrenderer.js
deleted file mode 100644
index d0a8990a..00000000
--- a/capabilities/testdrive-jsui/js/tests/test-extracted-domrenderer.js
+++ /dev/null
@@ -1,271 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * TDD Test for Extracted DOMRenderer Component
- *
- * Tests the extracted DOMRenderer component independently from the monolith.
- * Verifies that core functionality is preserved after extraction.
- */
-
-const RefactorTestRunner = require('./refactor-test-runner.js');
-
-const runner = new RefactorTestRunner();
-
-runner.describe('Extracted DOMRenderer Component', () => {
-
- runner.it('should load extracted DOMRenderer component', () => {
- // Load the extracted component
- delete require.cache[require.resolve('../components/dom-renderer.js')];
-
- try {
- const module = require('../components/dom-renderer.js');
- runner.expect(module.DOMRenderer).toBeTruthy();
- runner.expect(module.FloatingMenu).toBeTruthy();
-
- // Set globals for other tests
- global.ExtractedDOMRenderer = module.DOMRenderer;
- global.ExtractedFloatingMenu = module.FloatingMenu;
- } catch (error) {
- throw new Error(`Failed to load extracted DOMRenderer: ${error.message}`);
- }
- });
-
- runner.it('should preserve constructor functionality', () => {
- const DOMRenderer = global.ExtractedDOMRenderer;
-
- // Load SectionManager from our extracted core
- const sectionModule = require('../core/section-manager.js');
- const SectionManager = sectionModule.SectionManager;
-
- const container = document.createElement('div');
- const sectionManager = new SectionManager();
-
- const renderer = new DOMRenderer(sectionManager, container);
- runner.expect(renderer).toBeInstanceOf(DOMRenderer);
- runner.expect(renderer.sectionManager).toBe(sectionManager);
- runner.expect(renderer.container).toBe(container);
- runner.expect(renderer.editingSections).toBeInstanceOf(Set);
- });
-
- runner.it('should preserve section rendering functionality', () => {
- const DOMRenderer = global.ExtractedDOMRenderer;
- const sectionModule = require('../core/section-manager.js');
- const SectionManager = sectionModule.SectionManager;
-
- const container = document.createElement('div');
- container.innerHTML = '';
-
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
-
- const testMarkdown = '# Test Heading\nTest content';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
-
- // This should not throw an error
- renderer.renderAllSections(sections);
-
- // Check that content was rendered
- runner.expect(container.innerHTML.length > 100).toBeTruthy();
- runner.expect(container.innerHTML).toContain('Test Heading');
- });
-
- runner.it('should preserve findSectionElement functionality', () => {
- const DOMRenderer = global.ExtractedDOMRenderer;
- const sectionModule = require('../core/section-manager.js');
- const SectionManager = sectionModule.SectionManager;
-
- const container = document.createElement('div');
- container.innerHTML = '';
-
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
-
- const testMarkdown = '# Test Heading\nTest content';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- renderer.renderAllSections(sections);
-
- const sectionId = sections[0].id;
- const element = renderer.findSectionElement(sectionId);
-
- runner.expect(element).toBeTruthy();
- runner.expect(element.getAttribute('data-section-id')).toBe(sectionId);
- });
-
- runner.it('should preserve event tracking functionality', () => {
- const DOMRenderer = global.ExtractedDOMRenderer;
- const sectionModule = require('../core/section-manager.js');
- const SectionManager = sectionModule.SectionManager;
-
- const container = document.createElement('div');
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
-
- // Should have trackEvent method
- runner.expect(typeof renderer.trackEvent === 'function').toBeTruthy();
-
- // Should be able to track an event
- renderer.trackEvent('test-event', { data: 'test' });
-
- // Should have getEventStats method
- runner.expect(typeof renderer.getEventStats === 'function').toBeTruthy();
-
- const stats = renderer.getEventStats();
- runner.expect(typeof stats === 'object').toBeTruthy();
- runner.expect(stats).toHaveProperty('stats');
- runner.expect(stats).toHaveProperty('totalEvents');
- runner.expect(stats).toHaveProperty('recentEvents');
- });
-
- runner.it('should preserve editor showing functionality', () => {
- const DOMRenderer = global.ExtractedDOMRenderer;
- const sectionModule = require('../core/section-manager.js');
- const SectionManager = sectionModule.SectionManager;
-
- const container = document.createElement('div');
- container.innerHTML = '';
-
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
-
- const testMarkdown = '# Test Heading\nTest content';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- renderer.renderAllSections(sections);
-
- const sectionId = sections[0].id;
-
- // showEditor should not throw error
- try {
- renderer.showEditor(sectionId, 'test content');
- runner.expect(true).toBeTruthy(); // If we get here, no error was thrown
-
- // Check that editing state was set
- runner.expect(renderer.editingSections.has(sectionId)).toBeTruthy();
- } catch (error) {
- throw new Error(`showEditor failed: ${error.message}`);
- }
- });
-
- runner.it('should preserve FloatingMenu functionality', () => {
- const FloatingMenu = global.ExtractedFloatingMenu;
- const DOMRenderer = global.ExtractedDOMRenderer;
- const sectionModule = require('../core/section-manager.js');
- const SectionManager = sectionModule.SectionManager;
-
- const container = document.createElement('div');
- container.innerHTML = '';
-
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
-
- const testMarkdown = '# Test Heading\nTest content';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- renderer.renderAllSections(sections);
-
- const sectionId = sections[0].id;
- const floatingMenu = new FloatingMenu(sectionId, 'text', renderer);
-
- runner.expect(floatingMenu.sectionId).toBe(sectionId);
- runner.expect(floatingMenu.type).toBe('text');
- runner.expect(floatingMenu.renderer).toBe(renderer);
- runner.expect(floatingMenu.isVisible).toBeFalsy();
-
- // Test show/hide functionality
- const content = document.createElement('div');
- content.textContent = 'Test content';
-
- floatingMenu.show(content);
- runner.expect(floatingMenu.isVisible).toBeTruthy();
-
- floatingMenu.hide();
- runner.expect(floatingMenu.isVisible).toBeFalsy();
- });
-
- runner.it('should handle section click events', () => {
- const DOMRenderer = global.ExtractedDOMRenderer;
- const sectionModule = require('../core/section-manager.js');
- const SectionManager = sectionModule.SectionManager;
-
- const container = document.createElement('div');
- container.innerHTML = '';
-
- const sectionManager = new SectionManager();
- const renderer = new DOMRenderer(sectionManager, container);
-
- const testMarkdown = '# Test Heading\nTest content';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- renderer.renderAllSections(sections);
-
- const sectionId = sections[0].id;
- const element = renderer.findSectionElement(sectionId);
-
- // Simulate a click event
- const clickEvent = new Event('click', { bubbles: true });
- Object.defineProperty(clickEvent, 'target', { value: element });
-
- // Should not throw error
- try {
- renderer.handleSectionClick(clickEvent);
- runner.expect(true).toBeTruthy();
- } catch (error) {
- throw new Error(`handleSectionClick failed: ${error.message}`);
- }
- });
-
- // Comparative test - verify extracted component behaves similarly to original
- runner.it('should behave similarly to original monolithic component', () => {
- // Load both components
- const originalModule = require('/home/worsch/markitect_project/markitect/static/editor.js');
- const extractedModule = require('../components/dom-renderer.js');
- const sectionModule = require('../core/section-manager.js');
-
- const originalSectionManager = new originalModule.SectionManager();
- const extractedSectionManager = new sectionModule.SectionManager();
-
- const originalContainer = document.createElement('div');
- originalContainer.innerHTML = '';
-
- const extractedContainer = document.createElement('div');
- extractedContainer.innerHTML = '';
-
- const originalRenderer = new originalModule.DOMRenderer(originalSectionManager, originalContainer);
- const extractedRenderer = new extractedModule.DOMRenderer(extractedSectionManager, extractedContainer);
-
- const testMarkdown = '# Test\nContent\n\n## Subheading\nMore content';
-
- // Create sections with both
- const originalSections = originalSectionManager.createSectionsFromMarkdown(testMarkdown);
- const extractedSections = extractedSectionManager.createSectionsFromMarkdown(testMarkdown);
-
- // Render with both
- originalRenderer.renderAllSections(originalSections);
- extractedRenderer.renderAllSections(extractedSections);
-
- // Should have rendered content
- runner.expect(originalContainer.innerHTML.length > 100).toBeTruthy();
- runner.expect(extractedContainer.innerHTML.length > 100).toBeTruthy();
-
- // Should have same number of section elements
- const originalSectionElements = originalContainer.querySelectorAll('.ui-edit-section');
- const extractedSectionElements = extractedContainer.querySelectorAll('.ui-edit-section');
-
- runner.expect(extractedSectionElements.length).toBe(originalSectionElements.length);
-
- // Should have similar event stats structure
- const originalStats = originalRenderer.getEventStats();
- const extractedStats = extractedRenderer.getEventStats();
-
- runner.expect(extractedStats).toHaveProperty('stats');
- runner.expect(extractedStats).toHaveProperty('totalEvents');
- runner.expect(extractedStats).toHaveProperty('recentEvents');
- });
-});
-
-module.exports = runner;
-
-// Run tests if called directly
-if (require.main === module) {
- console.log('🧪 Testing Extracted DOMRenderer Component');
- runner.run().then(() => {
- console.log('✅ Extracted DOMRenderer tests completed');
- });
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/test-extracted-section-manager.js b/capabilities/testdrive-jsui/js/tests/test-extracted-section-manager.js
deleted file mode 100644
index 0eb51d01..00000000
--- a/capabilities/testdrive-jsui/js/tests/test-extracted-section-manager.js
+++ /dev/null
@@ -1,226 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * TDD Test for Extracted SectionManager Component
- *
- * Tests the extracted SectionManager component independently from the monolith.
- * Verifies that all functionality is preserved after extraction.
- */
-
-const RefactorTestRunner = require('./refactor-test-runner.js');
-
-const runner = new RefactorTestRunner();
-
-runner.describe('Extracted SectionManager Component', () => {
-
- runner.it('should load extracted SectionManager component', () => {
- // Load the extracted component
- delete require.cache[require.resolve('../core/section-manager.js')];
-
- try {
- const module = require('../core/section-manager.js');
- runner.expect(module.SectionManager).toBeTruthy();
- runner.expect(module.Section).toBeTruthy();
- runner.expect(module.EditState).toBeTruthy();
- runner.expect(module.SectionType).toBeTruthy();
-
- // Set globals for other tests
- global.ExtractedSectionManager = module.SectionManager;
- global.ExtractedSection = module.Section;
- global.ExtractedEditState = module.EditState;
- global.ExtractedSectionType = module.SectionType;
- } catch (error) {
- throw new Error(`Failed to load extracted SectionManager: ${error.message}`);
- }
- });
-
- runner.it('should preserve constructor functionality', () => {
- const SectionManager = global.ExtractedSectionManager;
-
- const manager = new SectionManager();
- runner.expect(manager).toBeInstanceOf(SectionManager);
- runner.expect(manager.sections).toBeInstanceOf(Map);
- runner.expect(manager.listeners).toBeInstanceOf(Map);
- });
-
- runner.it('should preserve section creation functionality', () => {
- const SectionManager = global.ExtractedSectionManager;
- const manager = new SectionManager();
-
- const testMarkdown = `# Heading 1\nContent 1\n\n## Heading 2\nContent 2`;
- const sections = manager.createSectionsFromMarkdown(testMarkdown);
-
- runner.expect(Array.isArray(sections)).toBeTruthy();
- runner.expect(sections.length).toBe(2);
- runner.expect(sections[0].currentMarkdown).toContain('Heading 1');
- runner.expect(sections[1].currentMarkdown).toContain('Heading 2');
- });
-
- runner.it('should preserve section editing functionality', () => {
- const SectionManager = global.ExtractedSectionManager;
- const manager = new SectionManager();
-
- const sections = manager.createSectionsFromMarkdown('# Test\nContent');
- const sectionId = sections[0].id;
-
- // Test start editing
- const content = manager.startEditing(sectionId);
- runner.expect(content).toContain('Test');
-
- const section = manager.sections.get(sectionId);
- runner.expect(section.isEditing()).toBeTruthy();
-
- // Test stop editing
- section.stopEditing();
- runner.expect(section.isEditing()).toBeFalsy();
- });
-
- runner.it('should preserve event system functionality', () => {
- const SectionManager = global.ExtractedSectionManager;
- const manager = new SectionManager();
-
- let eventFired = false;
- let eventData = null;
-
- manager.on('test-event', (data) => {
- eventFired = true;
- eventData = data;
- });
-
- manager.emit('test-event', { test: 'data' });
-
- runner.expect(eventFired).toBeTruthy();
- runner.expect(eventData).toEqual({ test: 'data' });
- });
-
- runner.it('should preserve document status functionality', () => {
- const SectionManager = global.ExtractedSectionManager;
- const manager = new SectionManager();
-
- manager.createSectionsFromMarkdown('# Test\nContent');
- const status = manager.getDocumentStatus();
-
- runner.expect(status).toHaveProperty('totalSections');
- runner.expect(status).toHaveProperty('editingSections');
- runner.expect(status.totalSections).toBe(1);
- });
-
- runner.it('should preserve getAllSections functionality', () => {
- const SectionManager = global.ExtractedSectionManager;
- const manager = new SectionManager();
-
- const testMarkdown = '# One\nContent\n\n# Two\nMore content';
- manager.createSectionsFromMarkdown(testMarkdown);
-
- const allSections = manager.getAllSections();
- runner.expect(Array.isArray(allSections)).toBeTruthy();
- runner.expect(allSections.length).toBe(2);
- });
-
- runner.it('should preserve section splitting functionality', () => {
- const SectionManager = global.ExtractedSectionManager;
- const manager = new SectionManager();
-
- const sections = manager.createSectionsFromMarkdown('# Original\nContent');
- const sectionId = sections[0].id;
-
- const newContent = '# Split 1\nContent 1\n\n# Split 2\nContent 2';
- const newSections = manager.handleSectionSplit(sectionId, newContent);
-
- runner.expect(Array.isArray(newSections)).toBeTruthy();
- runner.expect(newSections.length).toBe(2);
- runner.expect(manager.sections.has(sectionId)).toBeFalsy(); // Original removed
- });
-
- runner.it('should preserve Section class functionality', () => {
- const Section = global.ExtractedSection;
- const EditState = global.ExtractedEditState;
-
- const section = new Section('test-id', '# Test Content', 'heading');
-
- runner.expect(section.id).toBe('test-id');
- runner.expect(section.currentMarkdown).toBe('# Test Content');
- runner.expect(section.type).toBe('heading');
- runner.expect(section.state).toBe(EditState.ORIGINAL);
- });
-
- runner.it('should preserve Section ID generation', () => {
- const Section = global.ExtractedSection;
-
- const id1 = Section.generateId('# Test Heading', 0);
- const id2 = Section.generateId('# Different Heading', 1);
-
- runner.expect(typeof id1 === 'string').toBeTruthy();
- runner.expect(typeof id2 === 'string').toBeTruthy();
- runner.expect(id1).toContain('section-');
- runner.expect(id2).toContain('section-');
- runner.expect(id1 !== id2).toBeTruthy(); // Should be unique
- });
-
- runner.it('should preserve Section type detection', () => {
- const Section = global.ExtractedSection;
- const SectionType = global.ExtractedSectionType;
-
- runner.expect(Section.detectType('# Heading')).toBe(SectionType.HEADING);
- runner.expect(Section.detectType('')).toBe(SectionType.IMAGE);
- runner.expect(Section.detectType('```code```')).toBe(SectionType.CODE);
- runner.expect(Section.detectType('Regular paragraph')).toBe(SectionType.PARAGRAPH);
- });
-
- // Comparative test - verify extracted component behaves identically to original
- runner.it('should behave identically to original monolithic component', () => {
- // Load both components
- const originalModule = require('/home/worsch/markitect_project/markitect/static/editor.js');
- const extractedModule = require('../core/section-manager.js');
-
- const originalManager = new originalModule.SectionManager();
- const extractedManager = new extractedModule.SectionManager();
-
- const testMarkdown = '# Test\nContent\n\n## Subheading\nMore content';
-
- // Debug: Check what each component produces
- console.log('Creating sections with original component...');
- const originalSections = originalManager.createSectionsFromMarkdown(testMarkdown);
- console.log(`Original produced ${originalSections.length} sections`);
-
- console.log('Creating sections with extracted component...');
- const extractedSections = extractedManager.createSectionsFromMarkdown(testMarkdown);
- console.log(`Extracted produced ${extractedSections.length} sections`);
-
- if (originalSections.length > 0) {
- console.log('Original first section:', originalSections[0].currentMarkdown);
- }
- if (extractedSections.length > 0) {
- console.log('Extracted first section:', extractedSections[0].currentMarkdown);
- }
-
- // Should have same number of sections
- runner.expect(extractedSections.length).toBe(originalSections.length);
-
- // Should have same content
- for (let i = 0; i < originalSections.length; i++) {
- runner.expect(extractedSections[i].currentMarkdown).toBe(originalSections[i].currentMarkdown);
- runner.expect(extractedSections[i].type).toBe(originalSections[i].type);
- }
-
- // Should have same document status structure
- const originalStatus = originalManager.getDocumentStatus();
- const extractedStatus = extractedManager.getDocumentStatus();
-
- console.log('Original status:', originalStatus);
- console.log('Extracted status:', extractedStatus);
-
- runner.expect(extractedStatus.totalSections).toBe(originalStatus.totalSections);
- runner.expect(extractedStatus.editingSections).toBe(originalStatus.editingSections);
- });
-});
-
-module.exports = runner;
-
-// Run tests if called directly
-if (require.main === module) {
- console.log('🧪 Testing Extracted SectionManager Component');
- runner.run().then(() => {
- console.log('✅ Extracted SectionManager tests completed');
- });
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/test-full-integration.js b/capabilities/testdrive-jsui/js/tests/test-full-integration.js
deleted file mode 100644
index 3b06d123..00000000
--- a/capabilities/testdrive-jsui/js/tests/test-full-integration.js
+++ /dev/null
@@ -1,305 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * Full Integration Test
- *
- * Tests that all extracted components (SectionManager, DOMRenderer,
- * DebugPanel, DocumentControls) work together as a complete system.
- */
-
-const RefactorTestRunner = require('./refactor-test-runner.js');
-
-const runner = new RefactorTestRunner();
-
-runner.describe('Full Component Integration Tests', () => {
-
- runner.it('should load all extracted components', () => {
- try {
- // Load all extracted components
- const sectionModule = require('../core/section-manager.js');
- const domModule = require('../components/dom-renderer.js');
- const debugModule = require('../components/debug-panel.js');
- const controlsModule = require('../components/document-controls-legacy.js');
-
- runner.expect(sectionModule.SectionManager).toBeTruthy();
- runner.expect(domModule.DOMRenderer).toBeTruthy();
- runner.expect(debugModule.DebugPanel).toBeTruthy();
- runner.expect(controlsModule.DocumentControlsLegacy).toBeTruthy();
-
- // Set globals for other tests
- global.ExtractedSectionManager = sectionModule.SectionManager;
- global.ExtractedDOMRenderer = domModule.DOMRenderer;
- global.ExtractedDebugPanel = debugModule.DebugPanel;
- global.ExtractedDocumentControls = controlsModule.DocumentControlsLegacy;
-
- } catch (error) {
- throw new Error(`Failed to load extracted components: ${error.message}`);
- }
- });
-
- runner.it('should support complete document editing workflow with all components', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
- const DebugPanel = global.ExtractedDebugPanel;
- const DocumentControls = global.ExtractedDocumentControls;
-
- // Setup DOM container
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- // Create all components
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
- const debugPanel = new DebugPanel();
- const documentControls = new DocumentControls();
-
- // Setup document controls
- documentControls.create();
-
- // Wire up event handlers for debugging
- sectionManager.on('sections-created', (data) => {
- debugPanel.addMessage(`Created ${data.count} sections`, 'INFO');
- });
-
- sectionManager.on('edit-started', (data) => {
- debugPanel.addMessage(`Edit started for section: ${data.sectionId}`, 'DEBUG');
- });
-
- // Test workflow: Create document
- const testMarkdown = `# Document Title
-Introduction paragraph with some content.
-
-## Section A
-Content for section A with details.
-
-
-
-### Subsection A.1
-More detailed content here.`;
-
- // Create sections
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- runner.expect(sections.length).toBe(4);
-
- // Render sections
- domRenderer.renderAllSections(sections);
- const renderedElements = container.querySelectorAll('.ui-edit-section');
- runner.expect(renderedElements.length).toBe(sections.length);
-
- // Test editing workflow
- const firstSection = sections[0];
- sectionManager.startEditing(firstSection.id);
- runner.expect(firstSection.isEditing()).toBeTruthy();
-
- // Check debug messages were created
- runner.expect(debugPanel.getMessageCount()).toBe(2); // sections-created + edit-started
-
- // Test document controls functionality
- const controlPanel = documentControls.getControlPanel();
- runner.expect(controlPanel).toBeTruthy();
- runner.expect(document.getElementById('save-document')).toBeTruthy();
- runner.expect(document.getElementById('toggle-debug')).toBeTruthy();
-
- // Cleanup
- document.body.removeChild(container);
- documentControls.destroy();
- });
-
- runner.it('should support debug panel integration with document controls', () => {
- const DebugPanel = global.ExtractedDebugPanel;
- const DocumentControls = global.ExtractedDocumentControls;
-
- // Create components
- const debugPanel = new DebugPanel();
- const documentControls = new DocumentControls();
-
- // Setup document controls
- documentControls.create();
-
- // Setup debug panel toggle handler
- const handlers = {
- 'toggle-debug': () => debugPanel.toggle()
- };
- documentControls.setEventHandlers(handlers);
-
- // Test debug toggle functionality
- const debugButton = documentControls.getButton('toggle-debug');
- runner.expect(debugButton).toBeTruthy();
-
- // Add some debug messages
- debugPanel.addMessage('Test message 1', 'INFO');
- debugPanel.addMessage('Test message 2', 'ERROR');
-
- // Simulate button click to show debug panel
- debugButton.click();
- runner.expect(debugPanel.isActive).toBeTruthy();
-
- // Simulate button click to hide debug panel
- debugButton.click();
- runner.expect(debugPanel.isActive).toBeFalsy();
-
- // Cleanup
- documentControls.destroy();
- });
-
- runner.it('should support event-driven communication between all components', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
- const DebugPanel = global.ExtractedDebugPanel;
- const DocumentControls = global.ExtractedDocumentControls;
-
- // Setup container
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- // Create components
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
- const debugPanel = new DebugPanel();
- const documentControls = new DocumentControls();
-
- documentControls.create();
-
- // Setup comprehensive event handling
- let eventLog = [];
-
- sectionManager.on('sections-created', (data) => {
- eventLog.push(`sections-created: ${data.count} sections`);
- debugPanel.addMessage(`Sections created: ${data.count}`, 'INFO');
- });
-
- sectionManager.on('edit-started', (data) => {
- eventLog.push(`edit-started: ${data.sectionId}`);
- debugPanel.addMessage(`Edit started: ${data.sectionId}`, 'DEBUG');
- });
-
- sectionManager.on('changes-accepted', (data) => {
- eventLog.push(`changes-accepted: ${data.sectionId}`);
- debugPanel.addMessage(`Changes accepted: ${data.sectionId}`, 'SUCCESS');
- });
-
- // Test complete workflow
- const testMarkdown = '# Test\nContent for testing';
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- domRenderer.renderAllSections(sections);
-
- // Start editing
- sectionManager.startEditing(sections[0].id);
- sectionManager.updateContent(sections[0].id, '# Updated Test\nUpdated content');
- sectionManager.acceptChanges(sections[0].id);
-
- // Verify events were logged
- runner.expect(eventLog.length).toBe(3);
- runner.expect(eventLog[0]).toContain('sections-created');
- runner.expect(eventLog[1]).toContain('edit-started');
- runner.expect(eventLog[2]).toContain('changes-accepted');
-
- // Verify debug messages were created
- runner.expect(debugPanel.getMessageCount()).toBe(3);
-
- // Test document controls status update
- const status = sectionManager.getDocumentStatus();
- documentControls.updateStatus(status);
- runner.expect(documentControls.lastStatus).toBeTruthy();
-
- // Cleanup
- document.body.removeChild(container);
- documentControls.destroy();
- });
-
- runner.it('should handle error scenarios gracefully across components', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
- const DebugPanel = global.ExtractedDebugPanel;
- const DocumentControls = global.ExtractedDocumentControls;
-
- // Test component creation without proper DOM setup
- const debugPanel = new DebugPanel();
- const documentControls = new DocumentControls();
-
- // These should not throw errors
- try {
- debugPanel.toggle(); // No DOM elements
- debugPanel.update(); // No DOM elements
- documentControls.show(); // No control panel created yet
- documentControls.hide(); // No control panel created yet
-
- runner.expect(true).toBeTruthy(); // If we get here, no errors were thrown
- } catch (error) {
- throw new Error(`Components should handle missing DOM gracefully: ${error.message}`);
- }
-
- // Test section manager with invalid input
- const sectionManager = new SectionManager();
- const sections = sectionManager.createSectionsFromMarkdown('');
- runner.expect(sections.length).toBe(0);
-
- // Test DOM renderer with invalid container
- try {
- const invalidRenderer = new DOMRenderer(sectionManager, null);
- runner.expect(invalidRenderer.container).toBeFalsy();
- } catch (error) {
- // This is acceptable - constructor might validate input
- runner.expect(typeof error.message === 'string').toBeTruthy();
- }
- });
-
- runner.it('should support scalable architecture with component lifecycle', () => {
- const SectionManager = global.ExtractedSectionManager;
- const DOMRenderer = global.ExtractedDOMRenderer;
- const DebugPanel = global.ExtractedDebugPanel;
- const DocumentControls = global.ExtractedDocumentControls;
-
- // Test multiple instances
- const sectionManager1 = new SectionManager();
- const sectionManager2 = new SectionManager();
- const debugPanel1 = new DebugPanel();
- const debugPanel2 = new DebugPanel();
-
- // Each should be independent
- debugPanel1.addMessage('Message from panel 1', 'INFO');
- debugPanel2.addMessage('Message from panel 2', 'ERROR');
-
- runner.expect(debugPanel1.getMessageCount()).toBe(1);
- runner.expect(debugPanel2.getMessageCount()).toBe(1);
-
- // Test section managers are independent
- const sections1 = sectionManager1.createSectionsFromMarkdown('# Document 1');
- const sections2 = sectionManager2.createSectionsFromMarkdown('# Document 2');
-
- runner.expect(sections1.length).toBe(1);
- runner.expect(sections2.length).toBe(1);
- runner.expect(sections1[0]).toBeTruthy();
- runner.expect(sections2[0]).toBeTruthy();
-
- // IDs should be different (each section gets unique ID)
- const id1 = sections1[0].id;
- const id2 = sections2[0].id;
- runner.expect(id1 !== id2).toBeTruthy();
-
- // Test document controls lifecycle
- const controls1 = new DocumentControls();
- const controls2 = new DocumentControls();
-
- controls1.create();
- runner.expect(document.getElementById('markitect-global-controls')).toBeTruthy();
-
- controls2.create(); // Should replace the first one
- runner.expect(document.getElementById('markitect-global-controls')).toBeTruthy();
-
- controls2.destroy();
- runner.expect(document.getElementById('markitect-global-controls')).toBeFalsy();
- });
-});
-
-module.exports = runner;
-
-// Run tests if called directly
-if (require.main === module) {
- console.log('🧪 Running Full Component Integration Tests');
- runner.run().then(() => {
- console.log('✅ Full integration tests completed');
- });
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/test-real-user-functionality.js b/capabilities/testdrive-jsui/js/tests/test-real-user-functionality.js
deleted file mode 100644
index c5117bec..00000000
--- a/capabilities/testdrive-jsui/js/tests/test-real-user-functionality.js
+++ /dev/null
@@ -1,285 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * Real User Functionality Tests
- *
- * This test file validates the actual functionality that users experience,
- * not just internal API calls. It tests the complete user workflow.
- */
-
-const RefactorTestRunner = require('./refactor-test-runner.js');
-
-const runner = new RefactorTestRunner();
-
-runner.describe('Real User Functionality Tests', () => {
-
- runner.it('should allow users to edit content and see changes in DOM', () => {
- // Load all extracted components
- const sectionModule = require('../core/section-manager.js');
- const domModule = require('../components/dom-renderer.js');
- const debugModule = require('../components/debug-panel.js');
- const controlsModule = require('../components/document-controls-legacy.js');
-
- const { SectionManager } = sectionModule;
- const { DOMRenderer } = domModule;
- const { DebugPanel } = debugModule;
- const { DocumentControlsLegacy } = controlsModule;
-
- // Setup DOM container
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- // Create components
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
- const debugPanel = new DebugPanel();
- const documentControls = new DocumentControlsLegacy();
-
- // Setup document controls
- documentControls.create();
-
- // Create sections from test markdown
- const testMarkdown = `# Original Title\nOriginal content that should be editable.`;
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- domRenderer.renderAllSections(sections);
-
- const firstSection = sections[0];
- const sectionElement = container.querySelector(`[data-section-id="${firstSection.id}"]`);
-
- // Verify original content is rendered
- runner.expect(sectionElement.innerHTML).toContain('Original Title');
-
- // Simulate user clicking on section
- const clickEvent = new Event('click', { bubbles: true });
- sectionElement.dispatchEvent(clickEvent);
-
- // Verify editing state is active
- runner.expect(firstSection.isEditing()).toBeTruthy();
-
- // Find the floating menu and edit controls
- const floatingMenu = document.querySelector('.ui-edit-floating-menu');
- runner.expect(floatingMenu).toBeTruthy();
-
- const textarea = floatingMenu.querySelector('textarea');
- const acceptButton = Array.from(floatingMenu.querySelectorAll('button')).find(btn => btn.textContent.includes('Accept'));
-
- runner.expect(textarea).toBeTruthy();
- runner.expect(acceptButton).toBeTruthy();
-
- // Simulate user editing content
- const newContent = '# Updated Title\nCompletely new content added by user.';
- textarea.value = newContent;
-
- // Simulate user clicking accept
- acceptButton.click();
-
- // Verify section is no longer editing
- runner.expect(firstSection.isEditing()).toBeFalsy();
-
- // Verify floating menu is gone
- const menuAfterAccept = document.querySelector('.ui-edit-floating-menu');
- runner.expect(menuAfterAccept).toBeFalsy();
-
- // CRITICAL TEST: Verify DOM was actually updated with new content
- const updatedElement = container.querySelector(`[data-section-id="${firstSection.id}"]`);
- runner.expect(updatedElement.innerHTML).toContain('Updated Title');
- runner.expect(updatedElement.innerHTML).toContain('Completely new content');
- runner.expect(updatedElement.innerHTML).not.toContain('Original Title');
-
- // Cleanup
- document.body.removeChild(container);
- documentControls.destroy();
- });
-
- runner.it('should allow users to reset all changes', () => {
- // Setup similar to above
- const sectionModule = require('../core/section-manager.js');
- const domModule = require('../components/dom-renderer.js');
- const controlsModule = require('../components/document-controls-legacy.js');
-
- const { SectionManager } = sectionModule;
- const { DOMRenderer } = domModule;
- const { DocumentControlsLegacy } = controlsModule;
-
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
- const documentControls = new DocumentControlsLegacy();
-
- documentControls.create();
-
- // Create and modify content
- const testMarkdown = `# Test Section\nOriginal content for reset test.`;
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- domRenderer.renderAllSections(sections);
-
- const firstSection = sections[0];
-
- // Make changes to the section
- sectionManager.startEditing(firstSection.id);
- sectionManager.updateContent(firstSection.id, '# Modified Title\nModified content.');
- sectionManager.acceptChanges(firstSection.id);
-
- // Verify changes are applied
- let sectionElement = container.querySelector(`[data-section-id="${firstSection.id}"]`);
- runner.expect(sectionElement.innerHTML).toContain('Modified Title');
- runner.expect(firstSection.hasChanges()).toBeTruthy();
-
- // Test reset functionality
- const resetButton = documentControls.getButton('reset-all');
- runner.expect(resetButton).toBeTruthy();
-
- // Click reset button
- resetButton.click();
-
- // Verify content is reset
- sectionElement = container.querySelector(`[data-section-id="${firstSection.id}"]`);
- runner.expect(sectionElement.innerHTML).toContain('Test Section');
- runner.expect(sectionElement.innerHTML).not.toContain('Modified Title');
- runner.expect(firstSection.hasChanges()).toBeFalsy();
-
- // Cleanup
- document.body.removeChild(container);
- documentControls.destroy();
- });
-
- runner.it('should handle cancel operations correctly', () => {
- const sectionModule = require('../core/section-manager.js');
- const domModule = require('../components/dom-renderer.js');
-
- const { SectionManager } = sectionModule;
- const { DOMRenderer } = domModule;
-
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
-
- const testMarkdown = `# Cancel Test\nContent that should remain unchanged.`;
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- domRenderer.renderAllSections(sections);
-
- const firstSection = sections[0];
- const originalContent = firstSection.currentMarkdown;
-
- // Start editing
- const sectionElement = container.querySelector(`[data-section-id="${firstSection.id}"]`);
- sectionElement.click();
-
- // Make changes but cancel them
- const floatingMenu = document.querySelector('.ui-edit-floating-menu');
- const textarea = floatingMenu.querySelector('textarea');
- const cancelButton = Array.from(floatingMenu.querySelectorAll('button')).find(btn => btn.textContent.includes('Cancel'));
-
- textarea.value = '# This should be cancelled\nThis content should not appear.';
- cancelButton.click();
-
- // Verify content is unchanged
- const unchangedElement = container.querySelector(`[data-section-id="${firstSection.id}"]`);
- runner.expect(unchangedElement.innerHTML).toContain('Cancel Test');
- runner.expect(unchangedElement.innerHTML).not.toContain('This should be cancelled');
- runner.expect(firstSection.currentMarkdown).toBe(originalContent);
-
- // Cleanup
- document.body.removeChild(container);
- });
-
- runner.it('should validate the complete editing workflow', () => {
- // This test validates the entire user experience end-to-end
- const sectionModule = require('../core/section-manager.js');
- const domModule = require('../components/dom-renderer.js');
- const debugModule = require('../components/debug-panel.js');
- const controlsModule = require('../components/document-controls-legacy.js');
-
- const { SectionManager } = sectionModule;
- const { DOMRenderer } = domModule;
- const { DebugPanel } = debugModule;
- const { DocumentControlsLegacy } = controlsModule;
-
- const container = document.createElement('div');
- container.innerHTML = '';
- document.body.appendChild(container);
-
- const sectionManager = new SectionManager();
- const domRenderer = new DOMRenderer(sectionManager, container);
- const debugPanel = new DebugPanel();
- const documentControls = new DocumentControlsLegacy();
-
- documentControls.create();
-
- // Multi-section document
- const testMarkdown = `# Document Title
-Introduction paragraph.
-
-## Section A
-Content for section A.
-
-## Section B
-Content for section B.`;
-
- const sections = sectionManager.createSectionsFromMarkdown(testMarkdown);
- domRenderer.renderAllSections(sections);
-
- // Verify all sections are rendered
- const renderedSections = container.querySelectorAll('.ui-edit-section');
- runner.expect(renderedSections.length).toBe(sections.length);
-
- // Test editing multiple sections
- const firstSection = sections[0];
- const secondSection = sections[2]; // Section A
-
- // Edit first section
- renderedSections[0].click();
- let floatingMenu = document.querySelector('.ui-edit-floating-menu');
- let textarea = floatingMenu.querySelector('textarea');
- let acceptButton = Array.from(floatingMenu.querySelectorAll('button')).find(btn => btn.textContent.includes('Accept'));
-
- textarea.value = '# Updated Document Title\nUpdated introduction.';
- acceptButton.click();
-
- // Edit second section
- renderedSections[2].click();
- floatingMenu = document.querySelector('.ui-edit-floating-menu');
- textarea = floatingMenu.querySelector('textarea');
- acceptButton = Array.from(floatingMenu.querySelectorAll('button')).find(btn => btn.textContent.includes('Accept'));
-
- textarea.value = '## Updated Section A\nCompletely new content for section A.';
- acceptButton.click();
-
- // Verify both sections were updated
- const updatedSections = container.querySelectorAll('.ui-edit-section');
- runner.expect(updatedSections[0].innerHTML).toContain('Updated Document Title');
- runner.expect(updatedSections[2].innerHTML).toContain('Updated Section A');
-
- // Test reset restores all sections
- const resetButton = documentControls.getButton('reset-all');
- resetButton.click();
-
- const resetSections = container.querySelectorAll('.ui-edit-section');
- runner.expect(resetSections[0].innerHTML).toContain('Document Title');
- runner.expect(resetSections[0].innerHTML).not.toContain('Updated Document Title');
- runner.expect(resetSections[2].innerHTML).toContain('Section A');
- runner.expect(resetSections[2].innerHTML).not.toContain('Updated Section A');
-
- // Cleanup
- document.body.removeChild(container);
- documentControls.destroy();
- });
-});
-
-module.exports = runner;
-
-// Run tests if called directly
-if (require.main === module) {
- console.log('🧪 Running Real User Functionality Tests');
- runner.run().then(() => {
- console.log('✅ Real user functionality tests completed');
- console.log('These tests validate what users actually experience, not just internal APIs');
- });
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/tests/test-section-manager-extraction.js b/capabilities/testdrive-jsui/js/tests/test-section-manager-extraction.js
deleted file mode 100644
index 1eecce5d..00000000
--- a/capabilities/testdrive-jsui/js/tests/test-section-manager-extraction.js
+++ /dev/null
@@ -1,196 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * TDD Test for SectionManager Component Extraction
- *
- * Tests the extraction of SectionManager from the monolithic editor.js
- * Ensures all functionality is preserved during refactoring.
- */
-
-const RefactorTestRunner = require('./refactor-test-runner.js');
-
-const runner = new RefactorTestRunner();
-
-// First, let's define what the SectionManager API should look like
-const EXPECTED_SECTION_MANAGER_API = [
- 'constructor',
- 'createSectionsFromMarkdown',
- 'startEditing',
- 'stopEditing',
- 'getAllSections',
- 'sections', // Map property, not method
- 'getDocumentStatus',
- 'getDocumentMarkdown',
- 'on', // event system
- 'emit', // event system
- 'handleSectionSplit',
- 'updateContent',
- 'acceptChanges',
- 'cancelChanges',
- 'resetSection'
-];
-
-runner.describe('SectionManager Component Extraction', () => {
-
- runner.it('should define expected API methods', () => {
- // This test defines what we expect from the extracted SectionManager
- const expectedMethods = EXPECTED_SECTION_MANAGER_API;
- runner.expect(expectedMethods.length).toBe(15);
- runner.expect(expectedMethods).toContain('createSectionsFromMarkdown');
- runner.expect(expectedMethods).toContain('startEditing');
- runner.expect(expectedMethods).toContain('stopEditing');
- });
-
- runner.it('should extract from monolithic editor.js', () => {
- // Load the monolithic editor.js to extract SectionManager
- delete require.cache[require.resolve('/home/worsch/markitect_project/markitect/static/editor.js')];
-
- try {
- const editorModule = require('/home/worsch/markitect_project/markitect/static/editor.js');
- runner.expect(editorModule.SectionManager).toBeTruthy();
- // Set global for other tests
- global.SectionManager = editorModule.SectionManager;
- global.Section = editorModule.Section;
- global.EditState = editorModule.EditState;
- } catch (error) {
- throw new Error(`Failed to load monolithic editor.js: ${error.message}`);
- }
- });
-
- runner.it('should preserve SectionManager constructor functionality', () => {
- const SectionManager = global.SectionManager;
-
- const manager = new SectionManager();
- runner.expect(manager).toBeInstanceOf(SectionManager);
- runner.expect(manager.sections).toBeInstanceOf(Map);
- });
-
- runner.it('should preserve createSectionsFromMarkdown functionality', () => {
- const SectionManager = global.SectionManager;
- const manager = new SectionManager();
-
- const testMarkdown = `# Heading 1\nContent 1\n\n## Heading 2\nContent 2`;
- const sections = manager.createSectionsFromMarkdown(testMarkdown);
-
- runner.expect(Array.isArray(sections)).toBeTruthy();
- runner.expect(sections.length).toBe(2);
- runner.expect(sections[0].currentMarkdown).toContain('Heading 1');
- runner.expect(sections[1].currentMarkdown).toContain('Heading 2');
- });
-
- runner.it('should preserve section editing state management', () => {
- const SectionManager = global.SectionManager;
- const manager = new SectionManager();
-
- const sections = manager.createSectionsFromMarkdown('# Test\nContent');
- const sectionId = sections[0].id;
-
- // Test start editing
- runner.expect(manager.startEditing(sectionId)).toBeTruthy();
- const section = manager.sections.get(sectionId);
- runner.expect(section.isEditing()).toBeTruthy();
-
- // Test stop editing
- section.stopEditing();
- runner.expect(section.isEditing()).toBeFalsy();
- });
-
- runner.it('should preserve event system functionality', () => {
- const SectionManager = global.SectionManager;
- const manager = new SectionManager();
-
- let eventFired = false;
- let eventData = null;
-
- manager.on('test-event', (data) => {
- eventFired = true;
- eventData = data;
- });
-
- manager.emit('test-event', { test: 'data' });
-
- runner.expect(eventFired).toBeTruthy();
- runner.expect(eventData).toEqual({ test: 'data' });
- });
-
- runner.it('should preserve document status functionality', () => {
- const SectionManager = global.SectionManager;
- const manager = new SectionManager();
-
- manager.createSectionsFromMarkdown('# Test\nContent');
- const status = manager.getDocumentStatus();
-
- runner.expect(status).toHaveProperty('totalSections');
- runner.expect(status).toHaveProperty('editingSections');
- runner.expect(status.totalSections).toBe(1);
- });
-
- runner.it('should preserve getAllSections functionality', () => {
- const SectionManager = global.SectionManager;
- const manager = new SectionManager();
-
- const testMarkdown = '# One\nContent\n\n# Two\nMore content';
- manager.createSectionsFromMarkdown(testMarkdown);
-
- const allSections = manager.getAllSections();
- runner.expect(Array.isArray(allSections)).toBeTruthy();
- runner.expect(allSections.length).toBe(2);
- });
-
- runner.it('should preserve section splitting functionality', () => {
- const SectionManager = global.SectionManager;
- const manager = new SectionManager();
-
- const sections = manager.createSectionsFromMarkdown('# Original\nContent');
- const sectionId = sections[0].id;
-
- const newContent = '# Split 1\nContent 1\n\n# Split 2\nContent 2';
- const newSections = manager.handleSectionSplit(sectionId, newContent);
-
- runner.expect(Array.isArray(newSections)).toBeTruthy();
- runner.expect(newSections.length).toBe(2);
- runner.expect(manager.sections.has(sectionId)).toBeFalsy(); // Original removed
- });
-});
-
-// Export API tests for use during extraction
-const SECTION_MANAGER_API_TESTS = [
- (SectionManager) => {
- const manager = new SectionManager();
- if (!manager.sections || !(manager.sections instanceof Map)) {
- throw new Error('sections property missing or not a Map');
- }
- },
- (SectionManager) => {
- const manager = new SectionManager();
- if (typeof manager.createSectionsFromMarkdown !== 'function') {
- throw new Error('createSectionsFromMarkdown method missing');
- }
- },
- (SectionManager) => {
- const manager = new SectionManager();
- if (typeof manager.startEditing !== 'function') {
- throw new Error('startEditing method missing');
- }
- },
- (SectionManager) => {
- const manager = new SectionManager();
- if (typeof manager.stopEditing !== 'function') {
- throw new Error('stopEditing method missing');
- }
- }
-];
-
-module.exports = {
- runner,
- EXPECTED_SECTION_MANAGER_API,
- SECTION_MANAGER_API_TESTS
-};
-
-// Run tests if called directly
-if (require.main === module) {
- console.log('🧪 Testing SectionManager Component Extraction');
- runner.run().then(() => {
- console.log('✅ SectionManager extraction tests completed');
- });
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/widgets/base/UIWidget.js b/capabilities/testdrive-jsui/js/widgets/base/UIWidget.js
deleted file mode 100644
index c889d0d0..00000000
--- a/capabilities/testdrive-jsui/js/widgets/base/UIWidget.js
+++ /dev/null
@@ -1,215 +0,0 @@
-/**
- * UI Widget Base Class
- *
- * Extends Widget with DOM manipulation and visual functionality.
- * Base for all widgets that render UI elements.
- */
-import { Widget } from './Widget.js';
-
-export class UIWidget extends Widget {
- constructor(options = {}) {
- super(options);
-
- // UI properties
- this.element = null;
- this.isVisible = false;
- this.isRendered = false;
- this.theme = options.theme || 'default';
- this.cssClasses = new Set(['markitect-widget']);
-
- // Animation support
- this.animationDuration = options.animationDuration || 300;
- this.enableAnimations = options.enableAnimations !== false;
- }
-
- /**
- * Render the widget to DOM (abstract method)
- */
- async render() {
- throw new Error('render() method must be implemented by subclass');
- }
-
- /**
- * Show the widget
- */
- async show(options = {}) {
- if (!this.isRendered) {
- await this.render();
- }
-
- if (this.isVisible) {
- return this;
- }
-
- this.isVisible = true;
-
- if (this.element) {
- if (this.enableAnimations && !options.immediate) {
- await this.animateShow();
- } else {
- this.element.style.display = '';
- }
- }
-
- this.emit('shown');
- return this;
- }
-
- /**
- * Hide the widget
- */
- async hide(options = {}) {
- if (!this.isVisible) {
- return this;
- }
-
- this.isVisible = false;
-
- if (this.element) {
- if (this.enableAnimations && !options.immediate) {
- await this.animateHide();
- } else {
- this.element.style.display = 'none';
- }
- }
-
- this.emit('hidden');
- return this;
- }
-
- /**
- * Toggle visibility
- */
- async toggle(options = {}) {
- return this.isVisible ? this.hide(options) : this.show(options);
- }
-
- /**
- * Show animation (override for custom animations)
- */
- async animateShow() {
- if (!this.element) return;
-
- return new Promise(resolve => {
- this.element.style.transition = `opacity ${this.animationDuration}ms ease-in-out`;
- this.element.style.opacity = '0';
- this.element.style.display = '';
-
- // Force reflow
- this.element.offsetHeight;
-
- this.element.style.opacity = '1';
-
- setTimeout(() => {
- this.element.style.transition = '';
- resolve();
- }, this.animationDuration);
- });
- }
-
- /**
- * Hide animation (override for custom animations)
- */
- async animateHide() {
- if (!this.element) return;
-
- return new Promise(resolve => {
- this.element.style.transition = `opacity ${this.animationDuration}ms ease-in-out`;
- this.element.style.opacity = '0';
-
- setTimeout(() => {
- this.element.style.display = 'none';
- this.element.style.transition = '';
- this.element.style.opacity = '';
- resolve();
- }, this.animationDuration);
- });
- }
-
- /**
- * CSS class management
- */
- addClass(className) {
- this.cssClasses.add(className);
- if (this.element) {
- this.element.classList.add(className);
- }
- return this;
- }
-
- removeClass(className) {
- this.cssClasses.delete(className);
- if (this.element) {
- this.element.classList.remove(className);
- }
- return this;
- }
-
- hasClass(className) {
- return this.cssClasses.has(className);
- }
-
- /**
- * Apply theme styling
- */
- applyTheme(themeName) {
- const oldTheme = this.theme;
- this.theme = themeName;
-
- this.removeClass(`theme-${oldTheme}`);
- this.addClass(`theme-${themeName}`);
-
- this.emit('theme-changed', { oldTheme, newTheme: themeName });
- return this;
- }
-
- /**
- * Find child element by selector
- */
- findElement(selector) {
- return this.element ? this.element.querySelector(selector) : null;
- }
-
- /**
- * Find all child elements by selector
- */
- findElements(selector) {
- return this.element ? this.element.querySelectorAll(selector) : [];
- }
-
- /**
- * Override destroy to clean up DOM
- */
- async destroy() {
- if (this.element && this.element.parentNode) {
- this.element.parentNode.removeChild(this.element);
- }
-
- this.element = null;
- this.isRendered = false;
- this.isVisible = false;
-
- await super.destroy();
- }
-
- /**
- * Apply all CSS classes to element
- */
- applyCSSClasses(element = this.element) {
- if (element) {
- element.className = Array.from(this.cssClasses).join(' ');
- }
- }
-
- /**
- * Default configuration for UI widgets
- */
- getDefaultConfig() {
- return {
- ...super.getDefaultConfig(),
- theme: 'default',
- animationDuration: 300,
- enableAnimations: true
- };
- }
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/widgets/base/Widget.js b/capabilities/testdrive-jsui/js/widgets/base/Widget.js
deleted file mode 100644
index 1c284cf6..00000000
--- a/capabilities/testdrive-jsui/js/widgets/base/Widget.js
+++ /dev/null
@@ -1,141 +0,0 @@
-/**
- * Base Widget Class
- *
- * Foundation class for all Markitect UI widgets following the plugin architecture.
- * Provides core functionality for event handling, state management, and lifecycle.
- */
-export class Widget extends EventTarget {
- constructor(options = {}) {
- super();
-
- // Core properties
- this.id = options.id || `widget-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
- this.container = options.container || document.body;
- this.config = { ...this.getDefaultConfig(), ...options };
-
- // State management
- this.state = new Map();
- this.isInitialized = false;
- this.isDestroyed = false;
-
- // Mixin support
- this.mixins = [];
-
- // Lifecycle hooks
- this.onInitialize = options.onInitialize || (() => {});
- this.onDestroy = options.onDestroy || (() => {});
- }
-
- /**
- * Initialize the widget
- */
- async initialize() {
- if (this.isInitialized || this.isDestroyed) {
- return this;
- }
-
- try {
- await this.onInitialize(this);
- this.isInitialized = true;
- this.emit('initialized');
- return this;
- } catch (error) {
- this.emit('error', { phase: 'initialize', error });
- throw error;
- }
- }
-
- /**
- * Destroy the widget and clean up resources
- */
- async destroy() {
- if (this.isDestroyed) {
- return;
- }
-
- try {
- await this.onDestroy(this);
- this.isDestroyed = true;
- this.emit('destroyed');
- } catch (error) {
- this.emit('error', { phase: 'destroy', error });
- throw error;
- }
- }
-
- /**
- * State management
- */
- setState(key, value) {
- const oldValue = this.state.get(key);
- this.state.set(key, value);
- this.emit('state-changed', { key, value, oldValue });
- }
-
- getState(key, defaultValue = null) {
- return this.state.get(key) ?? defaultValue;
- }
-
- /**
- * Event emission wrapper
- */
- emit(eventType, data = {}) {
- const event = new CustomEvent(eventType, {
- detail: { widget: this, ...data }
- });
- this.dispatchEvent(event);
- }
-
- /**
- * Apply mixin functionality
- */
- applyMixin(mixin) {
- if (typeof mixin === 'object') {
- Object.assign(this, mixin);
- this.mixins.push(mixin);
- }
- return this;
- }
-
- /**
- * Default configuration (override in subclasses)
- */
- getDefaultConfig() {
- return {};
- }
-
- /**
- * Utility method for creating DOM elements with styling
- */
- createElement(tag, options = {}) {
- const element = document.createElement(tag);
-
- if (options.className) {
- element.className = options.className;
- }
-
- if (options.textContent) {
- element.textContent = options.textContent;
- }
-
- if (options.innerHTML) {
- element.innerHTML = options.innerHTML;
- }
-
- if (options.style) {
- if (typeof options.style === 'string') {
- element.style.cssText = options.style;
- } else {
- Object.assign(element.style, options.style);
- }
- }
-
- if (options.attributes) {
- Object.entries(options.attributes).forEach(([key, value]) => {
- element.setAttribute(key, value);
- });
- }
-
- return element;
- }
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/js/widgets/navigation/DocumentNavigator.js b/capabilities/testdrive-jsui/js/widgets/navigation/DocumentNavigator.js
deleted file mode 100644
index d25e058e..00000000
--- a/capabilities/testdrive-jsui/js/widgets/navigation/DocumentNavigator.js
+++ /dev/null
@@ -1,625 +0,0 @@
-/**
- * DocumentNavigator Widget
- *
- * Substack-style floating document navigation widget that displays a hierarchical
- * table of contents based on document headings. Supports smooth scrolling,
- * scroll spy, expand/collapse, and responsive behavior.
- */
-import { UIWidget } from '../base/UIWidget.js';
-
-export class DocumentNavigator extends UIWidget {
- constructor(options = {}) {
- super(options);
-
- // Navigation state
- this.isCollapsed = this.config.collapsed;
- this.currentSection = null;
- this.headings = [];
- this.navigationTree = [];
-
- // Scroll spy state
- this.scrollSpyEnabled = this.config.enableScrollSpy;
- this.scrollThrottle = null;
-
- // Event bindings
- this.boundScrollHandler = this.handleScroll.bind(this);
- this.boundResizeHandler = this.handleResize.bind(this);
-
- // Initialize responsive behavior
- this.mediaQuery = window.matchMedia('(max-width: 768px)');
- }
-
- getDefaultConfig() {
- return {
- ...super.getDefaultConfig(),
- position: 'left', // 'left' or 'right'
- collapsed: true, // Start collapsed
- autoHide: true, // Hide on mobile
- maxHeadingLevel: 3, // H1, H2, H3
- enableScrollSpy: true, // Highlight current section
- smoothScroll: true, // Smooth scroll behavior
- animationDuration: 300, // Animation timing
- minHeadings: 2, // Min headings to show navigator
- theme: 'default', // Theme support
-
- // Styling options
- width: '280px',
- collapsedWidth: '40px',
- offset: { top: '80px', side: '20px' },
-
- // Accessibility
- enableKeyboard: true,
- ariaLabel: 'Document Navigation'
- };
- }
-
- async initialize() {
- await super.initialize();
-
- // Extract headings from container
- this.extractHeadings();
- this.buildNavigationTree();
-
- // Set up event listeners
- if (this.scrollSpyEnabled) {
- window.addEventListener('scroll', this.boundScrollHandler, { passive: true });
- }
-
- if (this.config.autoHide) {
- window.addEventListener('resize', this.boundResizeHandler);
- this.handleResize(); // Initial check
- }
-
- return this;
- }
-
- async render() {
- if (this.isRendered) {
- return this.element;
- }
-
- // Check if we have enough headings
- if (this.headings.length < this.config.minHeadings) {
- this.isRendered = true;
- return null; // Don't render if too few headings
- }
-
- // Create main container
- this.element = this.createElement('nav', {
- className: 'document-navigator markitect-widget',
- attributes: {
- 'aria-label': this.config.ariaLabel,
- 'role': 'navigation'
- },
- style: this.getNavigatorStyle()
- });
-
- // Apply CSS classes
- this.applyCSSClasses();
- this.addClass('theme-' + this.theme);
- this.addClass('position-' + this.config.position);
-
- // Create toggle button (always visible)
- this.createToggleButton();
-
- // Create navigation list (hidden when collapsed)
- this.createNavigationList();
-
- // Set initial visibility state
- if (this.isCollapsed) {
- await this.collapse({ immediate: true });
- } else {
- await this.expand({ immediate: true });
- }
-
- // Append to container
- this.container.appendChild(this.element);
-
- // Initialize scroll spy
- if (this.scrollSpyEnabled) {
- this.updateCurrentSection();
- }
-
- this.isRendered = true;
- this.emit('rendered');
-
- return this.element;
- }
-
- createToggleButton() {
- this.toggleButton = this.createElement('button', {
- className: 'navigator-toggle',
- attributes: {
- 'type': 'button',
- 'aria-label': this.isCollapsed ? 'Expand navigation' : 'Collapse navigation',
- 'aria-expanded': !this.isCollapsed
- },
- innerHTML: this.getToggleIcon(),
- style: this.getToggleStyle()
- });
-
- // Toggle on click
- this.toggleButton.addEventListener('click', async () => {
- await this.toggle();
- });
-
- // Keyboard support
- if (this.config.enableKeyboard) {
- this.toggleButton.addEventListener('keydown', this.handleKeyboard.bind(this));
- }
-
- this.element.appendChild(this.toggleButton);
- }
-
- createNavigationList() {
- this.navigationList = this.createElement('div', {
- className: 'navigator-list',
- style: this.getListStyle()
- });
-
- if (this.headings.length === 0) {
- this.createEmptyState();
- } else {
- this.populateNavigationList();
- }
-
- this.element.appendChild(this.navigationList);
- }
-
- createEmptyState() {
- const emptyMessage = this.createElement('div', {
- className: 'navigator-empty',
- textContent: 'No headings found',
- style: {
- padding: '1rem',
- textAlign: 'center',
- color: '#666',
- fontStyle: 'italic'
- }
- });
-
- this.navigationList.appendChild(emptyMessage);
- }
-
- populateNavigationList() {
- // Create header
- const header = this.createElement('div', {
- className: 'navigator-header',
- innerHTML: `
- Contents
-
- `,
- style: {
- display: 'flex',
- justifyContent: 'space-between',
- alignItems: 'center',
- padding: '1rem 1rem 0.5rem',
- borderBottom: '1px solid #eee',
- marginBottom: '0.5rem'
- }
- });
-
- // Close button functionality
- const closeButton = header.querySelector('.navigator-close');
- closeButton.addEventListener('click', async () => {
- await this.collapse();
- });
-
- this.navigationList.appendChild(header);
-
- // Create navigation items
- const navContainer = this.createElement('div', {
- className: 'navigator-items',
- style: {
- maxHeight: '70vh',
- overflowY: 'auto',
- padding: '0 0.5rem 1rem'
- }
- });
-
- this.renderNavigationTree(navContainer, this.navigationTree);
- this.navigationList.appendChild(navContainer);
- }
-
- renderNavigationTree(container, items, level = 0) {
- items.forEach(item => {
- const navItem = this.createElement('div', {
- className: `navigator-item level-${level}`,
- style: {
- marginLeft: `${level * 1}rem`,
- marginBottom: '0.25rem'
- }
- });
-
- // Create clickable link
- const link = this.createElement('a', {
- className: 'navigator-link',
- textContent: item.text,
- attributes: {
- 'href': `#${item.id}`,
- 'data-target': item.id,
- 'data-level': item.level,
- 'role': 'button',
- 'tabindex': '0'
- },
- style: {
- display: 'block',
- padding: '0.5rem 0.75rem',
- textDecoration: 'none',
- color: '#333',
- borderRadius: '4px',
- fontSize: level === 0 ? '0.9rem' : '0.8rem',
- fontWeight: level === 0 ? '600' : '400',
- transition: 'all 0.2s ease',
- cursor: 'pointer'
- }
- });
-
- // Hover effects
- link.addEventListener('mouseenter', () => {
- link.style.backgroundColor = '#f0f0f0';
- });
-
- link.addEventListener('mouseleave', () => {
- if (!link.classList.contains('active')) {
- link.style.backgroundColor = '';
- }
- });
-
- // Click navigation
- link.addEventListener('click', (e) => {
- e.preventDefault();
- this.navigateToHeading(item.id);
- });
-
- navItem.appendChild(link);
-
- // Render children recursively
- if (item.children && item.children.length > 0) {
- this.renderNavigationTree(navItem, item.children, level + 1);
- }
-
- container.appendChild(navItem);
- });
- }
-
- extractHeadings() {
- const headingSelectors = [];
- for (let i = 1; i <= this.config.maxHeadingLevel; i++) {
- headingSelectors.push(`h${i}`);
- }
-
- const headingElements = this.container.querySelectorAll(headingSelectors.join(', '));
-
- this.headings = Array.from(headingElements).map((heading, index) => {
- // Ensure heading has an ID
- if (!heading.id) {
- heading.id = `heading-${index + 1}`;
- }
-
- return {
- element: heading,
- id: heading.id,
- text: heading.textContent.trim(),
- level: parseInt(heading.tagName.substring(1)),
- offset: heading.offsetTop
- };
- });
-
- return this.headings;
- }
-
- buildNavigationTree() {
- this.navigationTree = [];
- const stack = [];
-
- this.headings.forEach(heading => {
- const item = {
- ...heading,
- children: []
- };
-
- // Find correct parent based on heading level
- while (stack.length > 0 && stack[stack.length - 1].level >= heading.level) {
- stack.pop();
- }
-
- if (stack.length === 0) {
- // Top level item
- this.navigationTree.push(item);
- } else {
- // Child item
- stack[stack.length - 1].children.push(item);
- }
-
- stack.push(item);
- });
-
- return this.navigationTree;
- }
-
- async toggle(options = {}) {
- return this.isCollapsed ? this.expand(options) : this.collapse(options);
- }
-
- async expand(options = {}) {
- if (!this.isCollapsed) {
- return this;
- }
-
- this.isCollapsed = false;
-
- if (this.toggleButton) {
- this.toggleButton.setAttribute('aria-expanded', 'true');
- this.toggleButton.setAttribute('aria-label', 'Collapse navigation');
- this.toggleButton.innerHTML = this.getToggleIcon();
- }
-
- if (this.navigationList) {
- if (this.enableAnimations && !options.immediate) {
- await this.animateExpand();
- } else {
- this.navigationList.style.display = '';
- this.element.style.width = this.config.width;
- }
- }
-
- this.emit('toggle', { expanded: true });
- return this;
- }
-
- async collapse(options = {}) {
- if (this.isCollapsed) {
- return this;
- }
-
- this.isCollapsed = true;
-
- if (this.toggleButton) {
- this.toggleButton.setAttribute('aria-expanded', 'false');
- this.toggleButton.setAttribute('aria-label', 'Expand navigation');
- this.toggleButton.innerHTML = this.getToggleIcon();
- }
-
- if (this.navigationList) {
- if (this.enableAnimations && !options.immediate) {
- await this.animateCollapse();
- } else {
- this.navigationList.style.display = 'none';
- this.element.style.width = this.config.collapsedWidth;
- }
- }
-
- this.emit('toggle', { expanded: false });
- return this;
- }
-
- async animateExpand() {
- return new Promise(resolve => {
- this.navigationList.style.opacity = '0';
- this.navigationList.style.display = '';
-
- // Animate width and opacity
- this.element.style.transition = `width ${this.animationDuration}ms ease-in-out`;
- this.navigationList.style.transition = `opacity ${this.animationDuration}ms ease-in-out`;
-
- // Force reflow
- this.element.offsetWidth;
-
- this.element.style.width = this.config.width;
- this.navigationList.style.opacity = '1';
-
- setTimeout(() => {
- this.element.style.transition = '';
- this.navigationList.style.transition = '';
- resolve();
- }, this.animationDuration);
- });
- }
-
- async animateCollapse() {
- return new Promise(resolve => {
- this.element.style.transition = `width ${this.animationDuration}ms ease-in-out`;
- this.navigationList.style.transition = `opacity ${this.animationDuration}ms ease-in-out`;
-
- this.navigationList.style.opacity = '0';
- this.element.style.width = this.config.collapsedWidth;
-
- setTimeout(() => {
- this.navigationList.style.display = 'none';
- this.element.style.transition = '';
- this.navigationList.style.transition = '';
- resolve();
- }, this.animationDuration);
- });
- }
-
- navigateToHeading(headingId) {
- const targetElement = document.getElementById(headingId);
- if (!targetElement) {
- console.warn(`Heading with ID '${headingId}' not found`);
- return;
- }
-
- // Update active navigation item
- this.setActiveItem(headingId);
-
- // Scroll to target
- if (this.config.smoothScroll) {
- targetElement.scrollIntoView({
- behavior: 'smooth',
- block: 'start',
- inline: 'nearest'
- });
- } else {
- targetElement.scrollIntoView();
- }
-
- // Emit navigation event
- this.emit('navigate', { target: headingId, element: targetElement });
-
- // Optionally collapse after navigation on mobile
- if (this.mediaQuery.matches && this.config.autoHide) {
- setTimeout(() => this.collapse(), 500);
- }
- }
-
- setActiveItem(headingId) {
- // Remove previous active state
- const previousActive = this.findElement('.navigator-link.active');
- if (previousActive) {
- previousActive.classList.remove('active');
- previousActive.style.backgroundColor = '';
- }
-
- // Set new active state
- const newActive = this.findElement(`[data-target="${headingId}"]`);
- if (newActive) {
- newActive.classList.add('active');
- newActive.style.backgroundColor = '#e3f2fd';
- newActive.style.color = '#1976d2';
- }
-
- this.currentSection = headingId;
- }
-
- handleScroll() {
- if (!this.scrollSpyEnabled || !this.isRendered) {
- return;
- }
-
- // Throttle scroll events
- if (this.scrollThrottle) {
- return;
- }
-
- this.scrollThrottle = setTimeout(() => {
- this.updateCurrentSection();
- this.scrollThrottle = null;
- }, 100);
- }
-
- updateCurrentSection() {
- const scrollPosition = window.pageYOffset + 100; // Offset for header
- let currentHeading = null;
-
- // Find the current heading based on scroll position
- for (let i = this.headings.length - 1; i >= 0; i--) {
- const heading = this.headings[i];
- if (heading.element.offsetTop <= scrollPosition) {
- currentHeading = heading;
- break;
- }
- }
-
- if (currentHeading && currentHeading.id !== this.currentSection) {
- this.setActiveItem(currentHeading.id);
- }
- }
-
- getCurrentSection() {
- return this.currentSection;
- }
-
- handleResize() {
- if (!this.config.autoHide) {
- return;
- }
-
- if (this.mediaQuery.matches) {
- // Mobile: hide navigator
- if (this.element) {
- this.element.style.display = 'none';
- }
- } else {
- // Desktop: show navigator
- if (this.element) {
- this.element.style.display = '';
- }
- }
- }
-
- handleKeyboard(event) {
- switch (event.key) {
- case 'Enter':
- case ' ':
- event.preventDefault();
- this.toggle();
- break;
- case 'Escape':
- event.preventDefault();
- this.collapse();
- break;
- }
- }
-
- getNavigatorStyle() {
- const baseStyle = {
- position: 'fixed',
- top: this.config.offset.top,
- zIndex: '1000',
- backgroundColor: 'rgba(255, 255, 255, 0.95)',
- border: '1px solid #e1e5e9',
- borderRadius: '8px',
- boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
- backdropFilter: 'blur(8px)',
- width: this.isCollapsed ? this.config.collapsedWidth : this.config.width,
- maxHeight: '80vh',
- overflow: 'hidden',
- transition: 'width 0.3s ease-in-out'
- };
-
- // Position-specific styling
- if (this.config.position === 'left') {
- baseStyle.left = this.config.offset.side;
- } else {
- baseStyle.right = this.config.offset.side;
- }
-
- return baseStyle;
- }
-
- getToggleStyle() {
- return {
- width: '100%',
- height: this.config.collapsedWidth,
- border: 'none',
- backgroundColor: 'transparent',
- cursor: 'pointer',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- fontSize: '16px',
- color: '#666',
- transition: 'color 0.2s ease'
- };
- }
-
- getListStyle() {
- return {
- display: this.isCollapsed ? 'none' : '',
- opacity: this.isCollapsed ? '0' : '1'
- };
- }
-
- getToggleIcon() {
- if (this.isCollapsed) {
- return this.config.position === 'left' ? '☰' : '☰';
- } else {
- return '✕';
- }
- }
-
- async destroy() {
- // Remove event listeners
- window.removeEventListener('scroll', this.boundScrollHandler);
- window.removeEventListener('resize', this.boundResizeHandler);
-
- // Clear throttle
- if (this.scrollThrottle) {
- clearTimeout(this.scrollThrottle);
- }
-
- await super.destroy();
- }
-}
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/acorn b/capabilities/testdrive-jsui/node_modules/.bin/acorn
deleted file mode 120000
index cf767603..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/acorn
+++ /dev/null
@@ -1 +0,0 @@
-../acorn/bin/acorn
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/baseline-browser-mapping b/capabilities/testdrive-jsui/node_modules/.bin/baseline-browser-mapping
deleted file mode 120000
index d2961883..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/baseline-browser-mapping
+++ /dev/null
@@ -1 +0,0 @@
-../baseline-browser-mapping/dist/cli.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/browserslist b/capabilities/testdrive-jsui/node_modules/.bin/browserslist
deleted file mode 120000
index 3cd991b2..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/browserslist
+++ /dev/null
@@ -1 +0,0 @@
-../browserslist/cli.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/create-jest b/capabilities/testdrive-jsui/node_modules/.bin/create-jest
deleted file mode 120000
index 8d6301e0..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/create-jest
+++ /dev/null
@@ -1 +0,0 @@
-../create-jest/bin/create-jest.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/escodegen b/capabilities/testdrive-jsui/node_modules/.bin/escodegen
deleted file mode 120000
index 01a7c325..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/escodegen
+++ /dev/null
@@ -1 +0,0 @@
-../escodegen/bin/escodegen.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/esgenerate b/capabilities/testdrive-jsui/node_modules/.bin/esgenerate
deleted file mode 120000
index 7d0293e6..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/esgenerate
+++ /dev/null
@@ -1 +0,0 @@
-../escodegen/bin/esgenerate.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/eslint b/capabilities/testdrive-jsui/node_modules/.bin/eslint
deleted file mode 120000
index 810e4bcb..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/eslint
+++ /dev/null
@@ -1 +0,0 @@
-../eslint/bin/eslint.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/esparse b/capabilities/testdrive-jsui/node_modules/.bin/esparse
deleted file mode 120000
index 7423b18b..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/esparse
+++ /dev/null
@@ -1 +0,0 @@
-../esprima/bin/esparse.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/esvalidate b/capabilities/testdrive-jsui/node_modules/.bin/esvalidate
deleted file mode 120000
index 16069eff..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/esvalidate
+++ /dev/null
@@ -1 +0,0 @@
-../esprima/bin/esvalidate.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/import-local-fixture b/capabilities/testdrive-jsui/node_modules/.bin/import-local-fixture
deleted file mode 120000
index ff4b1048..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/import-local-fixture
+++ /dev/null
@@ -1 +0,0 @@
-../import-local/fixtures/cli.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/jest b/capabilities/testdrive-jsui/node_modules/.bin/jest
deleted file mode 120000
index 61c18615..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/jest
+++ /dev/null
@@ -1 +0,0 @@
-../jest/bin/jest.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/js-yaml b/capabilities/testdrive-jsui/node_modules/.bin/js-yaml
deleted file mode 120000
index 9dbd010d..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/js-yaml
+++ /dev/null
@@ -1 +0,0 @@
-../js-yaml/bin/js-yaml.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/jsesc b/capabilities/testdrive-jsui/node_modules/.bin/jsesc
deleted file mode 120000
index 7237604c..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/jsesc
+++ /dev/null
@@ -1 +0,0 @@
-../jsesc/bin/jsesc
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/json5 b/capabilities/testdrive-jsui/node_modules/.bin/json5
deleted file mode 120000
index 217f3798..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/json5
+++ /dev/null
@@ -1 +0,0 @@
-../json5/lib/cli.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/node-which b/capabilities/testdrive-jsui/node_modules/.bin/node-which
deleted file mode 120000
index 6f8415ec..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/node-which
+++ /dev/null
@@ -1 +0,0 @@
-../which/bin/node-which
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/parser b/capabilities/testdrive-jsui/node_modules/.bin/parser
deleted file mode 120000
index ce7bf97e..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/parser
+++ /dev/null
@@ -1 +0,0 @@
-../@babel/parser/bin/babel-parser.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/regjsparser b/capabilities/testdrive-jsui/node_modules/.bin/regjsparser
deleted file mode 120000
index 91cec777..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/regjsparser
+++ /dev/null
@@ -1 +0,0 @@
-../regjsparser/bin/parser
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/resolve b/capabilities/testdrive-jsui/node_modules/.bin/resolve
deleted file mode 120000
index b6afda6c..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/resolve
+++ /dev/null
@@ -1 +0,0 @@
-../resolve/bin/resolve
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/rimraf b/capabilities/testdrive-jsui/node_modules/.bin/rimraf
deleted file mode 120000
index 4cd49a49..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/rimraf
+++ /dev/null
@@ -1 +0,0 @@
-../rimraf/bin.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/semver b/capabilities/testdrive-jsui/node_modules/.bin/semver
deleted file mode 120000
index 5aaadf42..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/semver
+++ /dev/null
@@ -1 +0,0 @@
-../semver/bin/semver.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/tsc b/capabilities/testdrive-jsui/node_modules/.bin/tsc
deleted file mode 120000
index 0863208a..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/tsc
+++ /dev/null
@@ -1 +0,0 @@
-../typescript/bin/tsc
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/tsserver b/capabilities/testdrive-jsui/node_modules/.bin/tsserver
deleted file mode 120000
index f8f8f1a0..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/tsserver
+++ /dev/null
@@ -1 +0,0 @@
-../typescript/bin/tsserver
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.bin/update-browserslist-db b/capabilities/testdrive-jsui/node_modules/.bin/update-browserslist-db
deleted file mode 120000
index b11e16f3..00000000
--- a/capabilities/testdrive-jsui/node_modules/.bin/update-browserslist-db
+++ /dev/null
@@ -1 +0,0 @@
-../update-browserslist-db/cli.js
\ No newline at end of file
diff --git a/capabilities/testdrive-jsui/node_modules/.package-lock.json b/capabilities/testdrive-jsui/node_modules/.package-lock.json
deleted file mode 100644
index d8af3fbb..00000000
--- a/capabilities/testdrive-jsui/node_modules/.package-lock.json
+++ /dev/null
@@ -1,9213 +0,0 @@
-{
- "name": "testdrive-jsui",
- "version": "0.1.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "node_modules/@asamuzakjp/css-color": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz",
- "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==",
- "license": "MIT",
- "dependencies": {
- "@csstools/css-calc": "^2.1.3",
- "@csstools/css-color-parser": "^3.0.9",
- "@csstools/css-parser-algorithms": "^3.0.4",
- "@csstools/css-tokenizer": "^3.0.3",
- "lru-cache": "^10.4.3"
- }
- },
- "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": {
- "version": "10.4.3",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
- "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
- "license": "ISC"
- },
- "node_modules/@asamuzakjp/dom-selector": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-2.0.2.tgz",
- "integrity": "sha512-x1KXOatwofR6ZAYzXRBL5wrdV0vwNxlTCK9NCuLqAzQYARqGcvFwiJA6A1ERuh+dgeA4Dxm3JBYictIes+SqUQ==",
- "license": "MIT",
- "dependencies": {
- "bidi-js": "^1.0.3",
- "css-tree": "^2.3.1",
- "is-potential-custom-element-name": "^1.0.1"
- }
- },
- "node_modules/@babel/code-frame": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
- "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.27.1",
- "js-tokens": "^4.0.0",
- "picocolors": "^1.1.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/compat-data": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz",
- "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/core": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
- "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@babel/code-frame": "^7.27.1",
- "@babel/generator": "^7.28.5",
- "@babel/helper-compilation-targets": "^7.27.2",
- "@babel/helper-module-transforms": "^7.28.3",
- "@babel/helpers": "^7.28.4",
- "@babel/parser": "^7.28.5",
- "@babel/template": "^7.27.2",
- "@babel/traverse": "^7.28.5",
- "@babel/types": "^7.28.5",
- "@jridgewell/remapping": "^2.3.5",
- "convert-source-map": "^2.0.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.2.3",
- "semver": "^6.3.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/babel"
- }
- },
- "node_modules/@babel/generator": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz",
- "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/parser": "^7.28.5",
- "@babel/types": "^7.28.5",
- "@jridgewell/gen-mapping": "^0.3.12",
- "@jridgewell/trace-mapping": "^0.3.28",
- "jsesc": "^3.0.2"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-annotate-as-pure": {
- "version": "7.27.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz",
- "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.27.3"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-compilation-targets": {
- "version": "7.27.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
- "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/compat-data": "^7.27.2",
- "@babel/helper-validator-option": "^7.27.1",
- "browserslist": "^4.24.0",
- "lru-cache": "^5.1.1",
- "semver": "^6.3.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-create-class-features-plugin": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz",
- "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.27.3",
- "@babel/helper-member-expression-to-functions": "^7.28.5",
- "@babel/helper-optimise-call-expression": "^7.27.1",
- "@babel/helper-replace-supers": "^7.27.1",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
- "@babel/traverse": "^7.28.5",
- "semver": "^6.3.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-create-regexp-features-plugin": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz",
- "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.27.3",
- "regexpu-core": "^6.3.1",
- "semver": "^6.3.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-define-polyfill-provider": {
- "version": "0.6.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz",
- "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-compilation-targets": "^7.27.2",
- "@babel/helper-plugin-utils": "^7.27.1",
- "debug": "^4.4.1",
- "lodash.debounce": "^4.0.8",
- "resolve": "^1.22.10"
- },
- "peerDependencies": {
- "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
- }
- },
- "node_modules/@babel/helper-globals": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
- "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-member-expression-to-functions": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz",
- "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/traverse": "^7.28.5",
- "@babel/types": "^7.28.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-module-imports": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
- "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/traverse": "^7.27.1",
- "@babel/types": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-module-transforms": {
- "version": "7.28.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
- "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-module-imports": "^7.27.1",
- "@babel/helper-validator-identifier": "^7.27.1",
- "@babel/traverse": "^7.28.3"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-optimise-call-expression": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz",
- "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-plugin-utils": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
- "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-remap-async-to-generator": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz",
- "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.27.1",
- "@babel/helper-wrap-function": "^7.27.1",
- "@babel/traverse": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-replace-supers": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz",
- "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-member-expression-to-functions": "^7.27.1",
- "@babel/helper-optimise-call-expression": "^7.27.1",
- "@babel/traverse": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz",
- "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/traverse": "^7.27.1",
- "@babel/types": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-string-parser": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
- "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-identifier": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
- "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-option": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
- "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-wrap-function": {
- "version": "7.28.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz",
- "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/template": "^7.27.2",
- "@babel/traverse": "^7.28.3",
- "@babel/types": "^7.28.2"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helpers": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
- "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/template": "^7.27.2",
- "@babel/types": "^7.28.4"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/parser": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
- "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.28.5"
- },
- "bin": {
- "parser": "bin/babel-parser.js"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz",
- "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/traverse": "^7.28.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz",
- "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz",
- "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz",
- "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
- "@babel/plugin-transform-optional-chaining": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.13.0"
- }
- },
- "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": {
- "version": "7.28.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz",
- "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/traverse": "^7.28.3"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/plugin-proposal-private-property-in-object": {
- "version": "7.21.0-placeholder-for-preset-env.2",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
- "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-async-generators": {
- "version": "7.8.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
- "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-bigint": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
- "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-class-properties": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
- "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.12.13"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-class-static-block": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
- "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-import-assertions": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz",
- "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-import-attributes": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz",
- "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-import-meta": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
- "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.10.4"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-json-strings": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
- "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-jsx": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz",
- "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
- "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.10.4"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
- "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-numeric-separator": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
- "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.10.4"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-object-rest-spread": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
- "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-optional-catch-binding": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
- "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-optional-chaining": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
- "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-private-property-in-object": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
- "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-top-level-await": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
- "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-typescript": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz",
- "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-unicode-sets-regex": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz",
- "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/plugin-transform-arrow-functions": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz",
- "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-async-generator-functions": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz",
- "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/helper-remap-async-to-generator": "^7.27.1",
- "@babel/traverse": "^7.28.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-async-to-generator": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz",
- "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-module-imports": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/helper-remap-async-to-generator": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-block-scoped-functions": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz",
- "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-block-scoping": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz",
- "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-class-properties": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz",
- "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-create-class-features-plugin": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-class-static-block": {
- "version": "7.28.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz",
- "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-create-class-features-plugin": "^7.28.3",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.12.0"
- }
- },
- "node_modules/@babel/plugin-transform-classes": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz",
- "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.27.3",
- "@babel/helper-compilation-targets": "^7.27.2",
- "@babel/helper-globals": "^7.28.0",
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/helper-replace-supers": "^7.27.1",
- "@babel/traverse": "^7.28.4"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-computed-properties": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz",
- "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/template": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-destructuring": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz",
- "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/traverse": "^7.28.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-dotall-regex": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz",
- "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-duplicate-keys": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz",
- "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz",
- "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/plugin-transform-dynamic-import": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz",
- "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-explicit-resource-management": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz",
- "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/plugin-transform-destructuring": "^7.28.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-exponentiation-operator": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz",
- "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-export-namespace-from": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz",
- "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-for-of": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz",
- "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-function-name": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz",
- "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-compilation-targets": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/traverse": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-json-strings": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz",
- "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-literals": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz",
- "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-logical-assignment-operators": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz",
- "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-member-expression-literals": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz",
- "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-modules-amd": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz",
- "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-module-transforms": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-modules-commonjs": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz",
- "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-module-transforms": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-modules-systemjs": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz",
- "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-module-transforms": "^7.28.3",
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/helper-validator-identifier": "^7.28.5",
- "@babel/traverse": "^7.28.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-modules-umd": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz",
- "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-module-transforms": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz",
- "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/plugin-transform-new-target": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz",
- "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz",
- "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-numeric-separator": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz",
- "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-object-rest-spread": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz",
- "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-compilation-targets": "^7.27.2",
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/plugin-transform-destructuring": "^7.28.0",
- "@babel/plugin-transform-parameters": "^7.27.7",
- "@babel/traverse": "^7.28.4"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-object-super": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz",
- "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/helper-replace-supers": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-optional-catch-binding": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz",
- "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-optional-chaining": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz",
- "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-parameters": {
- "version": "7.27.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz",
- "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-private-methods": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz",
- "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-create-class-features-plugin": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-private-property-in-object": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz",
- "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.27.1",
- "@babel/helper-create-class-features-plugin": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-property-literals": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz",
- "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-regenerator": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz",
- "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-regexp-modifiers": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz",
- "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/plugin-transform-reserved-words": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz",
- "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-shorthand-properties": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz",
- "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-spread": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz",
- "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-sticky-regex": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz",
- "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-template-literals": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz",
- "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-typeof-symbol": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz",
- "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-unicode-escapes": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz",
- "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-unicode-property-regex": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz",
- "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-unicode-regex": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz",
- "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-unicode-sets-regex": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz",
- "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.27.1",
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/preset-env": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz",
- "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/compat-data": "^7.28.5",
- "@babel/helper-compilation-targets": "^7.27.2",
- "@babel/helper-plugin-utils": "^7.27.1",
- "@babel/helper-validator-option": "^7.27.1",
- "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5",
- "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1",
- "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1",
- "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1",
- "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3",
- "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
- "@babel/plugin-syntax-import-assertions": "^7.27.1",
- "@babel/plugin-syntax-import-attributes": "^7.27.1",
- "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
- "@babel/plugin-transform-arrow-functions": "^7.27.1",
- "@babel/plugin-transform-async-generator-functions": "^7.28.0",
- "@babel/plugin-transform-async-to-generator": "^7.27.1",
- "@babel/plugin-transform-block-scoped-functions": "^7.27.1",
- "@babel/plugin-transform-block-scoping": "^7.28.5",
- "@babel/plugin-transform-class-properties": "^7.27.1",
- "@babel/plugin-transform-class-static-block": "^7.28.3",
- "@babel/plugin-transform-classes": "^7.28.4",
- "@babel/plugin-transform-computed-properties": "^7.27.1",
- "@babel/plugin-transform-destructuring": "^7.28.5",
- "@babel/plugin-transform-dotall-regex": "^7.27.1",
- "@babel/plugin-transform-duplicate-keys": "^7.27.1",
- "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1",
- "@babel/plugin-transform-dynamic-import": "^7.27.1",
- "@babel/plugin-transform-explicit-resource-management": "^7.28.0",
- "@babel/plugin-transform-exponentiation-operator": "^7.28.5",
- "@babel/plugin-transform-export-namespace-from": "^7.27.1",
- "@babel/plugin-transform-for-of": "^7.27.1",
- "@babel/plugin-transform-function-name": "^7.27.1",
- "@babel/plugin-transform-json-strings": "^7.27.1",
- "@babel/plugin-transform-literals": "^7.27.1",
- "@babel/plugin-transform-logical-assignment-operators": "^7.28.5",
- "@babel/plugin-transform-member-expression-literals": "^7.27.1",
- "@babel/plugin-transform-modules-amd": "^7.27.1",
- "@babel/plugin-transform-modules-commonjs": "^7.27.1",
- "@babel/plugin-transform-modules-systemjs": "^7.28.5",
- "@babel/plugin-transform-modules-umd": "^7.27.1",
- "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1",
- "@babel/plugin-transform-new-target": "^7.27.1",
- "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1",
- "@babel/plugin-transform-numeric-separator": "^7.27.1",
- "@babel/plugin-transform-object-rest-spread": "^7.28.4",
- "@babel/plugin-transform-object-super": "^7.27.1",
- "@babel/plugin-transform-optional-catch-binding": "^7.27.1",
- "@babel/plugin-transform-optional-chaining": "^7.28.5",
- "@babel/plugin-transform-parameters": "^7.27.7",
- "@babel/plugin-transform-private-methods": "^7.27.1",
- "@babel/plugin-transform-private-property-in-object": "^7.27.1",
- "@babel/plugin-transform-property-literals": "^7.27.1",
- "@babel/plugin-transform-regenerator": "^7.28.4",
- "@babel/plugin-transform-regexp-modifiers": "^7.27.1",
- "@babel/plugin-transform-reserved-words": "^7.27.1",
- "@babel/plugin-transform-shorthand-properties": "^7.27.1",
- "@babel/plugin-transform-spread": "^7.27.1",
- "@babel/plugin-transform-sticky-regex": "^7.27.1",
- "@babel/plugin-transform-template-literals": "^7.27.1",
- "@babel/plugin-transform-typeof-symbol": "^7.27.1",
- "@babel/plugin-transform-unicode-escapes": "^7.27.1",
- "@babel/plugin-transform-unicode-property-regex": "^7.27.1",
- "@babel/plugin-transform-unicode-regex": "^7.27.1",
- "@babel/plugin-transform-unicode-sets-regex": "^7.27.1",
- "@babel/preset-modules": "0.1.6-no-external-plugins",
- "babel-plugin-polyfill-corejs2": "^0.4.14",
- "babel-plugin-polyfill-corejs3": "^0.13.0",
- "babel-plugin-polyfill-regenerator": "^0.6.5",
- "core-js-compat": "^3.43.0",
- "semver": "^6.3.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/preset-modules": {
- "version": "0.1.6-no-external-plugins",
- "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
- "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.0.0",
- "@babel/types": "^7.4.4",
- "esutils": "^2.0.2"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0"
- }
- },
- "node_modules/@babel/template": {
- "version": "7.27.2",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
- "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/code-frame": "^7.27.1",
- "@babel/parser": "^7.27.2",
- "@babel/types": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/traverse": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz",
- "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/code-frame": "^7.27.1",
- "@babel/generator": "^7.28.5",
- "@babel/helper-globals": "^7.28.0",
- "@babel/parser": "^7.28.5",
- "@babel/template": "^7.27.2",
- "@babel/types": "^7.28.5",
- "debug": "^4.3.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/types": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
- "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-string-parser": "^7.27.1",
- "@babel/helper-validator-identifier": "^7.28.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@bcoe/v8-coverage": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
- "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@csstools/color-helpers": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz",
- "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/csstools"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/csstools"
- }
- ],
- "license": "MIT-0",
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@csstools/css-calc": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz",
- "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/csstools"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/csstools"
- }
- ],
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@csstools/css-parser-algorithms": "^3.0.5",
- "@csstools/css-tokenizer": "^3.0.4"
- }
- },
- "node_modules/@csstools/css-color-parser": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz",
- "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/csstools"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/csstools"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "@csstools/color-helpers": "^5.1.0",
- "@csstools/css-calc": "^2.1.4"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@csstools/css-parser-algorithms": "^3.0.5",
- "@csstools/css-tokenizer": "^3.0.4"
- }
- },
- "node_modules/@csstools/css-parser-algorithms": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz",
- "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/csstools"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/csstools"
- }
- ],
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@csstools/css-tokenizer": "^3.0.4"
- }
- },
- "node_modules/@csstools/css-tokenizer": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz",
- "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/csstools"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/csstools"
- }
- ],
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@eslint-community/eslint-utils": {
- "version": "4.9.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
- "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "eslint-visitor-keys": "^3.4.3"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
- }
- },
- "node_modules/@eslint-community/regexpp": {
- "version": "4.12.2",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
- "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
- }
- },
- "node_modules/@eslint/eslintrc": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
- "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^9.6.0",
- "globals": "^13.19.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true,
- "license": "Python-2.0"
- },
- "node_modules/@eslint/eslintrc/node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/@eslint/js": {
- "version": "8.57.1",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
- "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.13.0",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
- "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
- "deprecated": "Use @eslint/config-array instead",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@humanwhocodes/object-schema": "^2.0.3",
- "debug": "^4.3.1",
- "minimatch": "^3.0.5"
- },
- "engines": {
- "node": ">=10.10.0"
- }
- },
- "node_modules/@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=12.22"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
- }
- },
- "node_modules/@humanwhocodes/object-schema": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
- "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
- "deprecated": "Use @eslint/object-schema instead",
- "dev": true,
- "license": "BSD-3-Clause"
- },
- "node_modules/@istanbuljs/load-nyc-config": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
- "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "camelcase": "^5.3.1",
- "find-up": "^4.1.0",
- "get-package-type": "^0.1.0",
- "js-yaml": "^3.13.1",
- "resolve-from": "^5.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@istanbuljs/schema": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
- "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/console": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz",
- "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/types": "^29.6.3",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "jest-message-util": "^29.7.0",
- "jest-util": "^29.7.0",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/core": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz",
- "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/console": "^29.7.0",
- "@jest/reporters": "^29.7.0",
- "@jest/test-result": "^29.7.0",
- "@jest/transform": "^29.7.0",
- "@jest/types": "^29.6.3",
- "@types/node": "*",
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "exit": "^0.1.2",
- "graceful-fs": "^4.2.9",
- "jest-changed-files": "^29.7.0",
- "jest-config": "^29.7.0",
- "jest-haste-map": "^29.7.0",
- "jest-message-util": "^29.7.0",
- "jest-regex-util": "^29.6.3",
- "jest-resolve": "^29.7.0",
- "jest-resolve-dependencies": "^29.7.0",
- "jest-runner": "^29.7.0",
- "jest-runtime": "^29.7.0",
- "jest-snapshot": "^29.7.0",
- "jest-util": "^29.7.0",
- "jest-validate": "^29.7.0",
- "jest-watcher": "^29.7.0",
- "micromatch": "^4.0.4",
- "pretty-format": "^29.7.0",
- "slash": "^3.0.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
- },
- "peerDependenciesMeta": {
- "node-notifier": {
- "optional": true
- }
- }
- },
- "node_modules/@jest/environment": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz",
- "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/fake-timers": "^29.7.0",
- "@jest/types": "^29.6.3",
- "@types/node": "*",
- "jest-mock": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/expect": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz",
- "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "expect": "^29.7.0",
- "jest-snapshot": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/expect-utils": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
- "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "jest-get-type": "^29.6.3"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/fake-timers": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz",
- "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/types": "^29.6.3",
- "@sinonjs/fake-timers": "^10.0.2",
- "@types/node": "*",
- "jest-message-util": "^29.7.0",
- "jest-mock": "^29.7.0",
- "jest-util": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/globals": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz",
- "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/environment": "^29.7.0",
- "@jest/expect": "^29.7.0",
- "@jest/types": "^29.6.3",
- "jest-mock": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/reporters": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz",
- "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@bcoe/v8-coverage": "^0.2.3",
- "@jest/console": "^29.7.0",
- "@jest/test-result": "^29.7.0",
- "@jest/transform": "^29.7.0",
- "@jest/types": "^29.6.3",
- "@jridgewell/trace-mapping": "^0.3.18",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "collect-v8-coverage": "^1.0.0",
- "exit": "^0.1.2",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.9",
- "istanbul-lib-coverage": "^3.0.0",
- "istanbul-lib-instrument": "^6.0.0",
- "istanbul-lib-report": "^3.0.0",
- "istanbul-lib-source-maps": "^4.0.0",
- "istanbul-reports": "^3.1.3",
- "jest-message-util": "^29.7.0",
- "jest-util": "^29.7.0",
- "jest-worker": "^29.7.0",
- "slash": "^3.0.0",
- "string-length": "^4.0.1",
- "strip-ansi": "^6.0.0",
- "v8-to-istanbul": "^9.0.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
- },
- "peerDependenciesMeta": {
- "node-notifier": {
- "optional": true
- }
- }
- },
- "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
- "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "@babel/core": "^7.23.9",
- "@babel/parser": "^7.23.9",
- "@istanbuljs/schema": "^0.1.3",
- "istanbul-lib-coverage": "^3.2.0",
- "semver": "^7.5.4"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@jest/reporters/node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@jest/schemas": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
- "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@sinclair/typebox": "^0.27.8"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/source-map": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz",
- "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jridgewell/trace-mapping": "^0.3.18",
- "callsites": "^3.0.0",
- "graceful-fs": "^4.2.9"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/test-result": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz",
- "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/console": "^29.7.0",
- "@jest/types": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "collect-v8-coverage": "^1.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/test-sequencer": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz",
- "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/test-result": "^29.7.0",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.7.0",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/transform": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz",
- "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/core": "^7.11.6",
- "@jest/types": "^29.6.3",
- "@jridgewell/trace-mapping": "^0.3.18",
- "babel-plugin-istanbul": "^6.1.1",
- "chalk": "^4.0.0",
- "convert-source-map": "^2.0.0",
- "fast-json-stable-stringify": "^2.1.0",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.7.0",
- "jest-regex-util": "^29.6.3",
- "jest-util": "^29.7.0",
- "micromatch": "^4.0.4",
- "pirates": "^4.0.4",
- "slash": "^3.0.0",
- "write-file-atomic": "^4.0.2"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/types": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
- "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.13",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
- "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jridgewell/sourcemap-codec": "^1.5.0",
- "@jridgewell/trace-mapping": "^0.3.24"
- }
- },
- "node_modules/@jridgewell/remapping": {
- "version": "2.3.5",
- "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
- "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jridgewell/gen-mapping": "^0.3.5",
- "@jridgewell/trace-mapping": "^0.3.24"
- }
- },
- "node_modules/@jridgewell/resolve-uri": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
- "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
- "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.31",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
- "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jridgewell/resolve-uri": "^3.1.0",
- "@jridgewell/sourcemap-codec": "^1.4.14"
- }
- },
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@rtsao/scc": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
- "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@sinclair/typebox": {
- "version": "0.27.8",
- "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
- "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@sinonjs/commons": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
- "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "type-detect": "4.0.8"
- }
- },
- "node_modules/@sinonjs/fake-timers": {
- "version": "10.3.0",
- "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
- "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "@sinonjs/commons": "^3.0.0"
- }
- },
- "node_modules/@tootallnate/once": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
- "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@types/babel__core": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
- "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/parser": "^7.20.7",
- "@babel/types": "^7.20.7",
- "@types/babel__generator": "*",
- "@types/babel__template": "*",
- "@types/babel__traverse": "*"
- }
- },
- "node_modules/@types/babel__generator": {
- "version": "7.27.0",
- "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
- "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.0.0"
- }
- },
- "node_modules/@types/babel__template": {
- "version": "7.4.4",
- "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
- "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/parser": "^7.1.0",
- "@babel/types": "^7.0.0"
- }
- },
- "node_modules/@types/babel__traverse": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
- "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.28.2"
- }
- },
- "node_modules/@types/graceful-fs": {
- "version": "4.1.9",
- "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
- "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@types/istanbul-lib-coverage": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
- "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/istanbul-lib-report": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz",
- "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/istanbul-lib-coverage": "*"
- }
- },
- "node_modules/@types/istanbul-reports": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz",
- "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/istanbul-lib-report": "*"
- }
- },
- "node_modules/@types/jsdom": {
- "version": "20.0.1",
- "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz",
- "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/node": "*",
- "@types/tough-cookie": "*",
- "parse5": "^7.0.0"
- }
- },
- "node_modules/@types/json-schema": {
- "version": "7.0.15",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
- "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/json5": {
- "version": "0.0.29",
- "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
- "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/node": {
- "version": "24.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz",
- "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~7.16.0"
- }
- },
- "node_modules/@types/semver": {
- "version": "7.7.1",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz",
- "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/stack-utils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
- "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/tough-cookie": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
- "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/yargs": {
- "version": "17.0.34",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.34.tgz",
- "integrity": "sha512-KExbHVa92aJpw9WDQvzBaGVE2/Pz+pLZQloT2hjL8IqsZnV62rlPOYvNnLmf/L2dyllfVUOVBj64M0z/46eR2A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/@types/yargs-parser": {
- "version": "21.0.3",
- "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
- "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
- "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/types": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
- "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
- "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/utils": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
- "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@types/json-schema": "^7.0.9",
- "@types/semver": "^7.3.12",
- "@typescript-eslint/scope-manager": "5.62.0",
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/typescript-estree": "5.62.0",
- "eslint-scope": "^5.1.1",
- "semver": "^7.3.7"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
- "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^4.1.1"
- },
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
- "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "5.62.0",
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@ungap/structured-clone": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
- "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/abab": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
- "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
- "deprecated": "Use your platform's native atob() and btoa() methods instead",
- "dev": true,
- "license": "BSD-3-Clause"
- },
- "node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/acorn-globals": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz",
- "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "acorn": "^8.1.0",
- "acorn-walk": "^8.0.2"
- }
- },
- "node_modules/acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "license": "MIT",
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/acorn-walk": {
- "version": "8.3.4",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
- "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "acorn": "^8.11.0"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/agent-base": {
- "version": "7.1.4",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
- "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
- "license": "MIT",
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/ansi-escapes": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
- "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "type-fest": "^0.21.3"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/ansi-escapes/node_modules/type-fest": {
- "version": "0.21.3",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
- "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
- "dev": true,
- "license": "(MIT OR CC0-1.0)",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/anymatch": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
- "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "sprintf-js": "~1.0.2"
- }
- },
- "node_modules/array-buffer-byte-length": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
- "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "is-array-buffer": "^3.0.5"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array-includes": {
- "version": "3.1.9",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
- "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.4",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.24.0",
- "es-object-atoms": "^1.1.1",
- "get-intrinsic": "^1.3.0",
- "is-string": "^1.1.1",
- "math-intrinsics": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/array.prototype.findlastindex": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
- "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.4",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.9",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.1.1",
- "es-shim-unscopables": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.flat": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
- "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.5",
- "es-shim-unscopables": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.flatmap": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
- "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.5",
- "es-shim-unscopables": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/arraybuffer.prototype.slice": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
- "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "array-buffer-byte-length": "^1.0.1",
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.5",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.6",
- "is-array-buffer": "^3.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/async-function": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
- "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
- "license": "MIT"
- },
- "node_modules/available-typed-arrays": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
- "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "possible-typed-array-names": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/babel-jest": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
- "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/transform": "^29.7.0",
- "@types/babel__core": "^7.1.14",
- "babel-plugin-istanbul": "^6.1.1",
- "babel-preset-jest": "^29.6.3",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.9",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.8.0"
- }
- },
- "node_modules/babel-plugin-istanbul": {
- "version": "6.1.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
- "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.0.0",
- "@istanbuljs/load-nyc-config": "^1.0.0",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-instrument": "^5.0.4",
- "test-exclude": "^6.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/babel-plugin-jest-hoist": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz",
- "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/template": "^7.3.3",
- "@babel/types": "^7.3.3",
- "@types/babel__core": "^7.1.14",
- "@types/babel__traverse": "^7.0.6"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/babel-plugin-polyfill-corejs2": {
- "version": "0.4.14",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz",
- "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/compat-data": "^7.27.7",
- "@babel/helper-define-polyfill-provider": "^0.6.5",
- "semver": "^6.3.1"
- },
- "peerDependencies": {
- "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
- }
- },
- "node_modules/babel-plugin-polyfill-corejs3": {
- "version": "0.13.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz",
- "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-define-polyfill-provider": "^0.6.5",
- "core-js-compat": "^3.43.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
- }
- },
- "node_modules/babel-plugin-polyfill-regenerator": {
- "version": "0.6.5",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz",
- "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-define-polyfill-provider": "^0.6.5"
- },
- "peerDependencies": {
- "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
- }
- },
- "node_modules/babel-preset-current-node-syntax": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz",
- "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/plugin-syntax-async-generators": "^7.8.4",
- "@babel/plugin-syntax-bigint": "^7.8.3",
- "@babel/plugin-syntax-class-properties": "^7.12.13",
- "@babel/plugin-syntax-class-static-block": "^7.14.5",
- "@babel/plugin-syntax-import-attributes": "^7.24.7",
- "@babel/plugin-syntax-import-meta": "^7.10.4",
- "@babel/plugin-syntax-json-strings": "^7.8.3",
- "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
- "@babel/plugin-syntax-numeric-separator": "^7.10.4",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
- "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
- "@babel/plugin-syntax-optional-chaining": "^7.8.3",
- "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
- "@babel/plugin-syntax-top-level-await": "^7.14.5"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0 || ^8.0.0-0"
- }
- },
- "node_modules/babel-preset-jest": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz",
- "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "babel-plugin-jest-hoist": "^29.6.3",
- "babel-preset-current-node-syntax": "^1.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/baseline-browser-mapping": {
- "version": "2.8.25",
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.25.tgz",
- "integrity": "sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA==",
- "dev": true,
- "license": "Apache-2.0",
- "bin": {
- "baseline-browser-mapping": "dist/cli.js"
- }
- },
- "node_modules/bidi-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
- "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
- "license": "MIT",
- "dependencies": {
- "require-from-string": "^2.0.2"
- }
- },
- "node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/braces": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fill-range": "^7.1.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/browserslist": {
- "version": "4.27.0",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz",
- "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/browserslist"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "baseline-browser-mapping": "^2.8.19",
- "caniuse-lite": "^1.0.30001751",
- "electron-to-chromium": "^1.5.238",
- "node-releases": "^2.0.26",
- "update-browserslist-db": "^1.1.4"
- },
- "bin": {
- "browserslist": "cli.js"
- },
- "engines": {
- "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
- }
- },
- "node_modules/bser": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
- "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "node-int64": "^0.4.0"
- }
- },
- "node_modules/buffer-from": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
- "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/builtin-modules": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
- "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/builtins": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz",
- "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "semver": "^7.0.0"
- }
- },
- "node_modules/builtins/node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/call-bind": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
- "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.0",
- "es-define-property": "^1.0.0",
- "get-intrinsic": "^1.2.4",
- "set-function-length": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/call-bind-apply-helpers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
- "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/call-bound": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
- "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.2",
- "get-intrinsic": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/caniuse-lite": {
- "version": "1.0.30001754",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz",
- "integrity": "sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "license": "CC-BY-4.0"
- },
- "node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/char-regex": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
- "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/ci-info": {
- "version": "3.9.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
- "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/sibiraj-s"
- }
- ],
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cjs-module-lexer": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz",
- "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/co": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
- "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "iojs": ">= 1.0.0",
- "node": ">= 0.12.0"
- }
- },
- "node_modules/collect-v8-coverage": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz",
- "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "license": "MIT",
- "dependencies": {
- "delayed-stream": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/convert-source-map": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
- "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/core-js-compat": {
- "version": "3.46.0",
- "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz",
- "integrity": "sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "browserslist": "^4.26.3"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/core-js"
- }
- },
- "node_modules/create-jest": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
- "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/types": "^29.6.3",
- "chalk": "^4.0.0",
- "exit": "^0.1.2",
- "graceful-fs": "^4.2.9",
- "jest-config": "^29.7.0",
- "jest-util": "^29.7.0",
- "prompts": "^2.0.1"
- },
- "bin": {
- "create-jest": "bin/create-jest.js"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/cross-spawn": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
- "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/css-tree": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
- "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
- "license": "MIT",
- "dependencies": {
- "mdn-data": "2.0.30",
- "source-map-js": "^1.0.1"
- },
- "engines": {
- "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
- }
- },
- "node_modules/cssom": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz",
- "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/cssstyle": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz",
- "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==",
- "license": "MIT",
- "dependencies": {
- "@asamuzakjp/css-color": "^3.2.0",
- "rrweb-cssom": "^0.8.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/cssstyle/node_modules/rrweb-cssom": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz",
- "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==",
- "license": "MIT"
- },
- "node_modules/data-urls": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
- "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
- "license": "MIT",
- "dependencies": {
- "whatwg-mimetype": "^4.0.0",
- "whatwg-url": "^14.0.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/data-view-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
- "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/data-view-byte-length": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
- "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/inspect-js"
- }
- },
- "node_modules/data-view-byte-offset": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
- "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/debug": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
- "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/decimal.js": {
- "version": "10.6.0",
- "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
- "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
- "license": "MIT"
- },
- "node_modules/dedent": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz",
- "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==",
- "dev": true,
- "license": "MIT",
- "peerDependencies": {
- "babel-plugin-macros": "^3.1.0"
- },
- "peerDependenciesMeta": {
- "babel-plugin-macros": {
- "optional": true
- }
- }
- },
- "node_modules/deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/deepmerge": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
- "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/define-data-property": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
- "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-define-property": "^1.0.0",
- "es-errors": "^1.3.0",
- "gopd": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/define-properties": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
- "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "define-data-property": "^1.0.1",
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "license": "MIT",
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/detect-newline": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
- "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/diff-sequences": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
- "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "path-type": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/domexception": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
- "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==",
- "deprecated": "Use your platform's native DOMException instead",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "webidl-conversions": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/dunder-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
- "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.1",
- "es-errors": "^1.3.0",
- "gopd": "^1.2.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/electron-to-chromium": {
- "version": "1.5.249",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.249.tgz",
- "integrity": "sha512-5vcfL3BBe++qZ5kuFhD/p8WOM1N9m3nwvJPULJx+4xf2usSlZFJ0qoNYO2fOX4hi3ocuDcmDobtA+5SFr4OmBg==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/emittery": {
- "version": "0.13.1",
- "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
- "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sindresorhus/emittery?sponsor=1"
- }
- },
- "node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/entities": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
- "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=0.12"
- },
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
- "node_modules/error-ex": {
- "version": "1.3.4",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
- "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-arrayish": "^0.2.1"
- }
- },
- "node_modules/es-abstract": {
- "version": "1.24.0",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz",
- "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "array-buffer-byte-length": "^1.0.2",
- "arraybuffer.prototype.slice": "^1.0.4",
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.4",
- "data-view-buffer": "^1.0.2",
- "data-view-byte-length": "^1.0.2",
- "data-view-byte-offset": "^1.0.1",
- "es-define-property": "^1.0.1",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.1.1",
- "es-set-tostringtag": "^2.1.0",
- "es-to-primitive": "^1.3.0",
- "function.prototype.name": "^1.1.8",
- "get-intrinsic": "^1.3.0",
- "get-proto": "^1.0.1",
- "get-symbol-description": "^1.1.0",
- "globalthis": "^1.0.4",
- "gopd": "^1.2.0",
- "has-property-descriptors": "^1.0.2",
- "has-proto": "^1.2.0",
- "has-symbols": "^1.1.0",
- "hasown": "^2.0.2",
- "internal-slot": "^1.1.0",
- "is-array-buffer": "^3.0.5",
- "is-callable": "^1.2.7",
- "is-data-view": "^1.0.2",
- "is-negative-zero": "^2.0.3",
- "is-regex": "^1.2.1",
- "is-set": "^2.0.3",
- "is-shared-array-buffer": "^1.0.4",
- "is-string": "^1.1.1",
- "is-typed-array": "^1.1.15",
- "is-weakref": "^1.1.1",
- "math-intrinsics": "^1.1.0",
- "object-inspect": "^1.13.4",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.7",
- "own-keys": "^1.0.1",
- "regexp.prototype.flags": "^1.5.4",
- "safe-array-concat": "^1.1.3",
- "safe-push-apply": "^1.0.0",
- "safe-regex-test": "^1.1.0",
- "set-proto": "^1.0.0",
- "stop-iteration-iterator": "^1.1.0",
- "string.prototype.trim": "^1.2.10",
- "string.prototype.trimend": "^1.0.9",
- "string.prototype.trimstart": "^1.0.8",
- "typed-array-buffer": "^1.0.3",
- "typed-array-byte-length": "^1.0.3",
- "typed-array-byte-offset": "^1.0.4",
- "typed-array-length": "^1.0.7",
- "unbox-primitive": "^1.1.0",
- "which-typed-array": "^1.1.19"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/es-define-property": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
- "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-errors": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
- "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-object-atoms": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
- "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-set-tostringtag": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
- "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.6",
- "has-tostringtag": "^1.0.2",
- "hasown": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-shim-unscopables": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
- "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "hasown": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-to-primitive": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
- "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-callable": "^1.2.7",
- "is-date-object": "^1.0.5",
- "is-symbol": "^1.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/escalade": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
- "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/escodegen": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
- "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "esprima": "^4.0.1",
- "estraverse": "^5.2.0",
- "esutils": "^2.0.2"
- },
- "bin": {
- "escodegen": "bin/escodegen.js",
- "esgenerate": "bin/esgenerate.js"
- },
- "engines": {
- "node": ">=6.0"
- },
- "optionalDependencies": {
- "source-map": "~0.6.1"
- }
- },
- "node_modules/eslint": {
- "version": "8.57.1",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
- "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
- "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.57.1",
- "@humanwhocodes/config-array": "^0.13.0",
- "@humanwhocodes/module-importer": "^1.0.1",
- "@nodelib/fs.walk": "^1.2.8",
- "@ungap/structured-clone": "^1.2.0",
- "ajv": "^6.12.4",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.3.2",
- "doctrine": "^3.0.0",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
- "esquery": "^1.4.2",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "find-up": "^5.0.0",
- "glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "graphemer": "^1.4.0",
- "ignore": "^5.2.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "is-path-inside": "^3.0.3",
- "js-yaml": "^4.1.0",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "strip-ansi": "^6.0.1",
- "text-table": "^0.2.0"
- },
- "bin": {
- "eslint": "bin/eslint.js"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint-compat-utils": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz",
- "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "semver": "^7.5.4"
- },
- "engines": {
- "node": ">=12"
- },
- "peerDependencies": {
- "eslint": ">=6.0.0"
- }
- },
- "node_modules/eslint-compat-utils/node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint-config-standard": {
- "version": "17.1.0",
- "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz",
- "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "engines": {
- "node": ">=12.0.0"
- },
- "peerDependencies": {
- "eslint": "^8.0.1",
- "eslint-plugin-import": "^2.25.2",
- "eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
- "eslint-plugin-promise": "^6.0.0"
- }
- },
- "node_modules/eslint-import-resolver-node": {
- "version": "0.3.9",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
- "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "debug": "^3.2.7",
- "is-core-module": "^2.13.0",
- "resolve": "^1.22.4"
- }
- },
- "node_modules/eslint-import-resolver-node/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/eslint-module-utils": {
- "version": "2.12.1",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
- "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "debug": "^3.2.7"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependenciesMeta": {
- "eslint": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-module-utils/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/eslint-plugin-es-x": {
- "version": "7.8.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz",
- "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==",
- "dev": true,
- "funding": [
- "https://github.com/sponsors/ota-meshi",
- "https://opencollective.com/eslint"
- ],
- "license": "MIT",
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.1.2",
- "@eslint-community/regexpp": "^4.11.0",
- "eslint-compat-utils": "^0.5.1"
- },
- "engines": {
- "node": "^14.18.0 || >=16.0.0"
- },
- "peerDependencies": {
- "eslint": ">=8"
- }
- },
- "node_modules/eslint-plugin-import": {
- "version": "2.32.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
- "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@rtsao/scc": "^1.1.0",
- "array-includes": "^3.1.9",
- "array.prototype.findlastindex": "^1.2.6",
- "array.prototype.flat": "^1.3.3",
- "array.prototype.flatmap": "^1.3.3",
- "debug": "^3.2.7",
- "doctrine": "^2.1.0",
- "eslint-import-resolver-node": "^0.3.9",
- "eslint-module-utils": "^2.12.1",
- "hasown": "^2.0.2",
- "is-core-module": "^2.16.1",
- "is-glob": "^4.0.3",
- "minimatch": "^3.1.2",
- "object.fromentries": "^2.0.8",
- "object.groupby": "^1.0.3",
- "object.values": "^1.2.1",
- "semver": "^6.3.1",
- "string.prototype.trimend": "^1.0.9",
- "tsconfig-paths": "^3.15.0"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/eslint-plugin-jest": {
- "version": "27.9.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz",
- "integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/utils": "^5.10.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0 || ^7.0.0",
- "eslint": "^7.0.0 || ^8.0.0",
- "jest": "*"
- },
- "peerDependenciesMeta": {
- "@typescript-eslint/eslint-plugin": {
- "optional": true
- },
- "jest": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-plugin-n": {
- "version": "16.6.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz",
- "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "builtins": "^5.0.1",
- "eslint-plugin-es-x": "^7.5.0",
- "get-tsconfig": "^4.7.0",
- "globals": "^13.24.0",
- "ignore": "^5.2.4",
- "is-builtin-module": "^3.2.1",
- "is-core-module": "^2.12.1",
- "minimatch": "^3.1.2",
- "resolve": "^1.22.2",
- "semver": "^7.5.3"
- },
- "engines": {
- "node": ">=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- },
- "peerDependencies": {
- "eslint": ">=7.0.0"
- }
- },
- "node_modules/eslint-plugin-n/node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint-plugin-promise": {
- "version": "6.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz",
- "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==",
- "dev": true,
- "license": "ISC",
- "peer": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- },
- "peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0"
- }
- },
- "node_modules/eslint-scope": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint-visitor-keys": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
- "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint/node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true,
- "license": "Python-2.0"
- },
- "node_modules/eslint/node_modules/find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/eslint/node_modules/locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-locate": "^5.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-limit": "^3.0.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/espree": {
- "version": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "acorn": "^8.9.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true,
- "license": "BSD-2-Clause",
- "bin": {
- "esparse": "bin/esparse.js",
- "esvalidate": "bin/esvalidate.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/esquery": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
- "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "estraverse": "^5.1.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/execa": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
- "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^6.0.0",
- "human-signals": "^2.1.0",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.1",
- "onetime": "^5.1.2",
- "signal-exit": "^3.0.3",
- "strip-final-newline": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sindresorhus/execa?sponsor=1"
- }
- },
- "node_modules/exit": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
- "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
- "dev": true,
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/expect": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz",
- "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/expect-utils": "^29.7.0",
- "jest-get-type": "^29.6.3",
- "jest-matcher-utils": "^29.7.0",
- "jest-message-util": "^29.7.0",
- "jest-util": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/fast-glob": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
- "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.8"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/fast-glob/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/fastq": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
- "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "reusify": "^1.0.4"
- }
- },
- "node_modules/fb-watchman": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
- "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "bser": "2.1.1"
- }
- },
- "node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "flat-cache": "^3.0.4"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/flat-cache": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
- "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "flatted": "^3.2.9",
- "keyv": "^4.5.3",
- "rimraf": "^3.0.2"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/flatted": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
- "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/for-each": {
- "version": "0.3.5",
- "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
- "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-callable": "^1.2.7"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/form-data": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
- "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
- "license": "MIT",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "es-set-tostringtag": "^2.1.0",
- "hasown": "^2.0.2",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "ideallyInert": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
- "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/function.prototype.name": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
- "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.3",
- "define-properties": "^1.2.1",
- "functions-have-names": "^1.2.3",
- "hasown": "^2.0.2",
- "is-callable": "^1.2.7"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/generator-function": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
- "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/gensync": {
- "version": "1.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
- "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": "6.* || 8.* || >= 10.*"
- }
- },
- "node_modules/get-intrinsic": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
- "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.2",
- "es-define-property": "^1.0.1",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.1.1",
- "function-bind": "^1.1.2",
- "get-proto": "^1.0.1",
- "gopd": "^1.2.0",
- "has-symbols": "^1.1.0",
- "hasown": "^2.0.2",
- "math-intrinsics": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-package-type": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
- "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/get-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
- "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
- "license": "MIT",
- "dependencies": {
- "dunder-proto": "^1.0.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/get-stream": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
- "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/get-symbol-description": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
- "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.6"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-tsconfig": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
- "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "resolve-pkg-maps": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
- }
- },
- "node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "deprecated": "Glob versions prior to v9 are no longer supported",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "is-glob": "^4.0.3"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/globalthis": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
- "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "define-properties": "^1.2.1",
- "gopd": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/gopd": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
- "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/graceful-fs": {
- "version": "4.2.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
- "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/graphemer": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
- "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/has-bigints": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
- "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/has-property-descriptors": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
- "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-define-property": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-proto": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
- "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "dunder-proto": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
- "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-tostringtag": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
- "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
- "license": "MIT",
- "dependencies": {
- "has-symbols": "^1.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/hasown": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
- "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "license": "MIT",
- "dependencies": {
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/html-encoding-sniffer": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
- "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
- "license": "MIT",
- "dependencies": {
- "whatwg-encoding": "^3.1.1"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/html-escaper": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
- "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/http-proxy-agent": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
- "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
- "license": "MIT",
- "dependencies": {
- "agent-base": "^7.1.0",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/https-proxy-agent": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
- "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
- "license": "MIT",
- "dependencies": {
- "agent-base": "^7.1.2",
- "debug": "4"
- },
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/human-signals": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
- "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=10.17.0"
- }
- },
- "node_modules/iconv-lite": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
- "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "license": "MIT",
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/ignore": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
- "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/import-fresh": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
- "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/import-fresh/node_modules/resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/import-local": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz",
- "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "pkg-dir": "^4.2.0",
- "resolve-cwd": "^3.0.0"
- },
- "bin": {
- "import-local-fixture": "fixtures/cli.js"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.8.19"
- }
- },
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/internal-slot": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
- "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "hasown": "^2.0.2",
- "side-channel": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/is-array-buffer": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
- "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.3",
- "get-intrinsic": "^1.2.6"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/is-async-function": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
- "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "async-function": "^1.0.0",
- "call-bound": "^1.0.3",
- "get-proto": "^1.0.1",
- "has-tostringtag": "^1.0.2",
- "safe-regex-test": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-bigint": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
- "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "has-bigints": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-boolean-object": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
- "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "has-tostringtag": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-builtin-module": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
- "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "builtin-modules": "^3.3.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/is-callable": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
- "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-core-module": {
- "version": "2.16.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
- "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "hasown": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-data-view": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
- "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "get-intrinsic": "^1.2.6",
- "is-typed-array": "^1.1.13"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-date-object": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
- "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "has-tostringtag": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-finalizationregistry": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
- "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-generator-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
- "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/is-generator-function": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
- "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.4",
- "generator-function": "^2.0.0",
- "get-proto": "^1.0.1",
- "has-tostringtag": "^1.0.2",
- "safe-regex-test": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-map": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
- "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-negative-zero": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
- "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "node_modules/is-number-object": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
- "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "has-tostringtag": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-potential-custom-element-name": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
- "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
- "license": "MIT"
- },
- "node_modules/is-regex": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
- "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "gopd": "^1.2.0",
- "has-tostringtag": "^1.0.2",
- "hasown": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-set": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
- "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-shared-array-buffer": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
- "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/is-string": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
- "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "has-tostringtag": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-symbol": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
- "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "has-symbols": "^1.1.0",
- "safe-regex-test": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-typed-array": {
- "version": "1.1.15",
- "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
- "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "which-typed-array": "^1.1.16"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-weakmap": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
- "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-weakref": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
- "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-weakset": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
- "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "get-intrinsic": "^1.2.6"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/isarray": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
- "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/istanbul-lib-coverage": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
- "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
- "dev": true,
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-instrument": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
- "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "@babel/core": "^7.12.3",
- "@babel/parser": "^7.14.7",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-coverage": "^3.2.0",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-report": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
- "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "istanbul-lib-coverage": "^3.0.0",
- "make-dir": "^4.0.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/istanbul-lib-source-maps": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
- "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "debug": "^4.1.1",
- "istanbul-lib-coverage": "^3.0.0",
- "source-map": "^0.6.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/istanbul-reports": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
- "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "html-escaper": "^2.0.0",
- "istanbul-lib-report": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
- "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@jest/core": "^29.7.0",
- "@jest/types": "^29.6.3",
- "import-local": "^3.0.2",
- "jest-cli": "^29.7.0"
- },
- "bin": {
- "jest": "bin/jest.js"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
- },
- "peerDependenciesMeta": {
- "node-notifier": {
- "optional": true
- }
- }
- },
- "node_modules/jest-changed-files": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz",
- "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "execa": "^5.0.0",
- "jest-util": "^29.7.0",
- "p-limit": "^3.1.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-circus": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz",
- "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/environment": "^29.7.0",
- "@jest/expect": "^29.7.0",
- "@jest/test-result": "^29.7.0",
- "@jest/types": "^29.6.3",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "co": "^4.6.0",
- "dedent": "^1.0.0",
- "is-generator-fn": "^2.0.0",
- "jest-each": "^29.7.0",
- "jest-matcher-utils": "^29.7.0",
- "jest-message-util": "^29.7.0",
- "jest-runtime": "^29.7.0",
- "jest-snapshot": "^29.7.0",
- "jest-util": "^29.7.0",
- "p-limit": "^3.1.0",
- "pretty-format": "^29.7.0",
- "pure-rand": "^6.0.0",
- "slash": "^3.0.0",
- "stack-utils": "^2.0.3"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-cli": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz",
- "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/core": "^29.7.0",
- "@jest/test-result": "^29.7.0",
- "@jest/types": "^29.6.3",
- "chalk": "^4.0.0",
- "create-jest": "^29.7.0",
- "exit": "^0.1.2",
- "import-local": "^3.0.2",
- "jest-config": "^29.7.0",
- "jest-util": "^29.7.0",
- "jest-validate": "^29.7.0",
- "yargs": "^17.3.1"
- },
- "bin": {
- "jest": "bin/jest.js"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
- },
- "peerDependenciesMeta": {
- "node-notifier": {
- "optional": true
- }
- }
- },
- "node_modules/jest-config": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz",
- "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/core": "^7.11.6",
- "@jest/test-sequencer": "^29.7.0",
- "@jest/types": "^29.6.3",
- "babel-jest": "^29.7.0",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "deepmerge": "^4.2.2",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.9",
- "jest-circus": "^29.7.0",
- "jest-environment-node": "^29.7.0",
- "jest-get-type": "^29.6.3",
- "jest-regex-util": "^29.6.3",
- "jest-resolve": "^29.7.0",
- "jest-runner": "^29.7.0",
- "jest-util": "^29.7.0",
- "jest-validate": "^29.7.0",
- "micromatch": "^4.0.4",
- "parse-json": "^5.2.0",
- "pretty-format": "^29.7.0",
- "slash": "^3.0.0",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "@types/node": "*",
- "ts-node": ">=9.0.0"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- },
- "ts-node": {
- "optional": true
- }
- }
- },
- "node_modules/jest-diff": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
- "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "chalk": "^4.0.0",
- "diff-sequences": "^29.6.3",
- "jest-get-type": "^29.6.3",
- "pretty-format": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-docblock": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz",
- "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "detect-newline": "^3.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-each": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz",
- "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/types": "^29.6.3",
- "chalk": "^4.0.0",
- "jest-get-type": "^29.6.3",
- "jest-util": "^29.7.0",
- "pretty-format": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-environment-jsdom": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz",
- "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/environment": "^29.7.0",
- "@jest/fake-timers": "^29.7.0",
- "@jest/types": "^29.6.3",
- "@types/jsdom": "^20.0.0",
- "@types/node": "*",
- "jest-mock": "^29.7.0",
- "jest-util": "^29.7.0",
- "jsdom": "^20.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "canvas": "^2.5.0"
- },
- "peerDependenciesMeta": {
- "canvas": {
- "optional": true
- }
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/agent-base": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
- "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "debug": "4"
- },
- "engines": {
- "node": ">= 6.0.0"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/cssstyle": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
- "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cssom": "~0.3.6"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/cssstyle/node_modules/cssom": {
- "version": "0.3.8",
- "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
- "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/jest-environment-jsdom/node_modules/data-urls": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz",
- "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "abab": "^2.0.6",
- "whatwg-mimetype": "^3.0.0",
- "whatwg-url": "^11.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/html-encoding-sniffer": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
- "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "whatwg-encoding": "^2.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/http-proxy-agent": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
- "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@tootallnate/once": "2",
- "agent-base": "6",
- "debug": "4"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/https-proxy-agent": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
- "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "agent-base": "6",
- "debug": "4"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/jsdom": {
- "version": "20.0.3",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz",
- "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "abab": "^2.0.6",
- "acorn": "^8.8.1",
- "acorn-globals": "^7.0.0",
- "cssom": "^0.5.0",
- "cssstyle": "^2.3.0",
- "data-urls": "^3.0.2",
- "decimal.js": "^10.4.2",
- "domexception": "^4.0.0",
- "escodegen": "^2.0.0",
- "form-data": "^4.0.0",
- "html-encoding-sniffer": "^3.0.0",
- "http-proxy-agent": "^5.0.0",
- "https-proxy-agent": "^5.0.1",
- "is-potential-custom-element-name": "^1.0.1",
- "nwsapi": "^2.2.2",
- "parse5": "^7.1.1",
- "saxes": "^6.0.0",
- "symbol-tree": "^3.2.4",
- "tough-cookie": "^4.1.2",
- "w3c-xmlserializer": "^4.0.0",
- "webidl-conversions": "^7.0.0",
- "whatwg-encoding": "^2.0.0",
- "whatwg-mimetype": "^3.0.0",
- "whatwg-url": "^11.0.0",
- "ws": "^8.11.0",
- "xml-name-validator": "^4.0.0"
- },
- "engines": {
- "node": ">=14"
- },
- "peerDependencies": {
- "canvas": "^2.5.0"
- },
- "peerDependenciesMeta": {
- "canvas": {
- "optional": true
- }
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/tr46": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
- "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "punycode": "^2.1.1"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/w3c-xmlserializer": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
- "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "xml-name-validator": "^4.0.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/whatwg-encoding": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
- "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "iconv-lite": "0.6.3"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/whatwg-mimetype": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
- "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/whatwg-url": {
- "version": "11.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
- "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "tr46": "^3.0.0",
- "webidl-conversions": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/xml-name-validator": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
- "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/jest-environment-node": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz",
- "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/environment": "^29.7.0",
- "@jest/fake-timers": "^29.7.0",
- "@jest/types": "^29.6.3",
- "@types/node": "*",
- "jest-mock": "^29.7.0",
- "jest-util": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-get-type": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
- "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-haste-map": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz",
- "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/types": "^29.6.3",
- "@types/graceful-fs": "^4.1.3",
- "@types/node": "*",
- "anymatch": "^3.0.3",
- "fb-watchman": "^2.0.0",
- "graceful-fs": "^4.2.9",
- "jest-regex-util": "^29.6.3",
- "jest-util": "^29.7.0",
- "jest-worker": "^29.7.0",
- "micromatch": "^4.0.4",
- "walker": "^1.0.8"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "optionalDependencies": {
- "fsevents": "^2.3.2"
- }
- },
- "node_modules/jest-leak-detector": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz",
- "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "jest-get-type": "^29.6.3",
- "pretty-format": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-matcher-utils": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz",
- "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "chalk": "^4.0.0",
- "jest-diff": "^29.7.0",
- "jest-get-type": "^29.6.3",
- "pretty-format": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-message-util": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
- "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/code-frame": "^7.12.13",
- "@jest/types": "^29.6.3",
- "@types/stack-utils": "^2.0.0",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.9",
- "micromatch": "^4.0.4",
- "pretty-format": "^29.7.0",
- "slash": "^3.0.0",
- "stack-utils": "^2.0.3"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-mock": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz",
- "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/types": "^29.6.3",
- "@types/node": "*",
- "jest-util": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-pnp-resolver": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
- "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- },
- "peerDependencies": {
- "jest-resolve": "*"
- },
- "peerDependenciesMeta": {
- "jest-resolve": {
- "optional": true
- }
- }
- },
- "node_modules/jest-regex-util": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz",
- "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-resolve": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz",
- "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.7.0",
- "jest-pnp-resolver": "^1.2.2",
- "jest-util": "^29.7.0",
- "jest-validate": "^29.7.0",
- "resolve": "^1.20.0",
- "resolve.exports": "^2.0.0",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-resolve-dependencies": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz",
- "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "jest-regex-util": "^29.6.3",
- "jest-snapshot": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-runner": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz",
- "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/console": "^29.7.0",
- "@jest/environment": "^29.7.0",
- "@jest/test-result": "^29.7.0",
- "@jest/transform": "^29.7.0",
- "@jest/types": "^29.6.3",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "emittery": "^0.13.1",
- "graceful-fs": "^4.2.9",
- "jest-docblock": "^29.7.0",
- "jest-environment-node": "^29.7.0",
- "jest-haste-map": "^29.7.0",
- "jest-leak-detector": "^29.7.0",
- "jest-message-util": "^29.7.0",
- "jest-resolve": "^29.7.0",
- "jest-runtime": "^29.7.0",
- "jest-util": "^29.7.0",
- "jest-watcher": "^29.7.0",
- "jest-worker": "^29.7.0",
- "p-limit": "^3.1.0",
- "source-map-support": "0.5.13"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-runtime": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz",
- "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/environment": "^29.7.0",
- "@jest/fake-timers": "^29.7.0",
- "@jest/globals": "^29.7.0",
- "@jest/source-map": "^29.6.3",
- "@jest/test-result": "^29.7.0",
- "@jest/transform": "^29.7.0",
- "@jest/types": "^29.6.3",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "cjs-module-lexer": "^1.0.0",
- "collect-v8-coverage": "^1.0.0",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.7.0",
- "jest-message-util": "^29.7.0",
- "jest-mock": "^29.7.0",
- "jest-regex-util": "^29.6.3",
- "jest-resolve": "^29.7.0",
- "jest-snapshot": "^29.7.0",
- "jest-util": "^29.7.0",
- "slash": "^3.0.0",
- "strip-bom": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-snapshot": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz",
- "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/core": "^7.11.6",
- "@babel/generator": "^7.7.2",
- "@babel/plugin-syntax-jsx": "^7.7.2",
- "@babel/plugin-syntax-typescript": "^7.7.2",
- "@babel/types": "^7.3.3",
- "@jest/expect-utils": "^29.7.0",
- "@jest/transform": "^29.7.0",
- "@jest/types": "^29.6.3",
- "babel-preset-current-node-syntax": "^1.0.0",
- "chalk": "^4.0.0",
- "expect": "^29.7.0",
- "graceful-fs": "^4.2.9",
- "jest-diff": "^29.7.0",
- "jest-get-type": "^29.6.3",
- "jest-matcher-utils": "^29.7.0",
- "jest-message-util": "^29.7.0",
- "jest-util": "^29.7.0",
- "natural-compare": "^1.4.0",
- "pretty-format": "^29.7.0",
- "semver": "^7.5.3"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-snapshot/node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/jest-util": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
- "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/types": "^29.6.3",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "graceful-fs": "^4.2.9",
- "picomatch": "^2.2.3"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-validate": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz",
- "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/types": "^29.6.3",
- "camelcase": "^6.2.0",
- "chalk": "^4.0.0",
- "jest-get-type": "^29.6.3",
- "leven": "^3.1.0",
- "pretty-format": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-validate/node_modules/camelcase": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
- "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/jest-watcher": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz",
- "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/test-result": "^29.7.0",
- "@jest/types": "^29.6.3",
- "@types/node": "*",
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.0.0",
- "emittery": "^0.13.1",
- "jest-util": "^29.7.0",
- "string-length": "^4.0.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-worker": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
- "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/node": "*",
- "jest-util": "^29.7.0",
- "merge-stream": "^2.0.0",
- "supports-color": "^8.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-worker/node_modules/supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/supports-color?sponsor=1"
- }
- },
- "node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/jsdom": {
- "version": "23.2.0",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.2.0.tgz",
- "integrity": "sha512-L88oL7D/8ufIES+Zjz7v0aes+oBMh2Xnh3ygWvL0OaICOomKEPKuPnIfBJekiXr+BHbbMjrWn/xqrDQuxFTeyA==",
- "license": "MIT",
- "dependencies": {
- "@asamuzakjp/dom-selector": "^2.0.1",
- "cssstyle": "^4.0.1",
- "data-urls": "^5.0.0",
- "decimal.js": "^10.4.3",
- "form-data": "^4.0.0",
- "html-encoding-sniffer": "^4.0.0",
- "http-proxy-agent": "^7.0.0",
- "https-proxy-agent": "^7.0.2",
- "is-potential-custom-element-name": "^1.0.1",
- "parse5": "^7.1.2",
- "rrweb-cssom": "^0.6.0",
- "saxes": "^6.0.0",
- "symbol-tree": "^3.2.4",
- "tough-cookie": "^4.1.3",
- "w3c-xmlserializer": "^5.0.0",
- "webidl-conversions": "^7.0.0",
- "whatwg-encoding": "^3.1.1",
- "whatwg-mimetype": "^4.0.0",
- "whatwg-url": "^14.0.0",
- "ws": "^8.16.0",
- "xml-name-validator": "^5.0.0"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "canvas": "^2.11.2"
- },
- "peerDependenciesMeta": {
- "canvas": {
- "optional": true
- }
- }
- },
- "node_modules/jsesc": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
- "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
- "dev": true,
- "license": "MIT",
- "bin": {
- "jsesc": "bin/jsesc"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/json-buffer": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
- "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/json-parse-even-better-errors": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
- "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/json5": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
- "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
- "dev": true,
- "license": "MIT",
- "bin": {
- "json5": "lib/cli.js"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/keyv": {
- "version": "4.5.4",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
- "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "json-buffer": "3.0.1"
- }
- },
- "node_modules/kleur": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
- "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/leven": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
- "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/lines-and-columns": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
- "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-locate": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/lodash.debounce": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
- "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lru-cache": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
- "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "yallist": "^3.0.2"
- }
- },
- "node_modules/make-dir": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
- "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "semver": "^7.5.3"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/make-dir/node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/makeerror": {
- "version": "1.0.12",
- "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
- "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "tmpl": "1.0.5"
- }
- },
- "node_modules/math-intrinsics": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
- "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/mdn-data": {
- "version": "2.0.30",
- "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
- "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
- "license": "CC0-1.0"
- },
- "node_modules/merge-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
- "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/micromatch": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
- "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "braces": "^3.0.3",
- "picomatch": "^2.3.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "license": "MIT",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/minimist": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
- "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "license": "MIT"
- },
- "node_modules/natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/node-int64": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
- "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/node-releases": {
- "version": "2.0.27",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
- "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/npm-run-path": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "path-key": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/nwsapi": {
- "version": "2.2.22",
- "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.22.tgz",
- "integrity": "sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/object-inspect": {
- "version": "1.13.4",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
- "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.assign": {
- "version": "4.1.7",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
- "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.3",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0",
- "has-symbols": "^1.1.0",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.fromentries": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
- "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.groupby": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
- "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.values": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
- "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.3",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "mimic-fn": "^2.1.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/optionator": {
- "version": "0.9.4",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
- "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.5"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/own-keys": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
- "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "get-intrinsic": "^1.2.6",
- "object-keys": "^1.1.1",
- "safe-push-apply": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-limit": "^2.2.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/p-locate/node_modules/p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-try": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "callsites": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/parse5": {
- "version": "7.3.0",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
- "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
- "license": "MIT",
- "dependencies": {
- "entities": "^6.0.0"
- },
- "funding": {
- "url": "https://github.com/inikulin/parse5?sponsor=1"
- }
- },
- "node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/picocolors": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
- "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/pirates": {
- "version": "4.0.7",
- "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
- "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "find-up": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/possible-typed-array-names": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
- "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/pretty-format": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
- "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/pretty-format/node_modules/ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/prompts": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
- "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "kleur": "^3.0.3",
- "sisteransi": "^1.0.5"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/psl": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
- "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==",
- "license": "MIT",
- "dependencies": {
- "punycode": "^2.3.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/lupomontero"
- }
- },
- "node_modules/punycode": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
- "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/pure-rand": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
- "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
- "dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/dubzzz"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/fast-check"
- }
- ],
- "license": "MIT"
- },
- "node_modules/querystringify": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
- "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
- "license": "MIT"
- },
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT"
- },
- "node_modules/react-is": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
- "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/reflect.getprototypeof": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
- "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.9",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "get-intrinsic": "^1.2.7",
- "get-proto": "^1.0.1",
- "which-builtin-type": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/regenerate": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
- "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/regenerate-unicode-properties": {
- "version": "10.2.2",
- "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz",
- "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "regenerate": "^1.4.2"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/regexp.prototype.flags": {
- "version": "1.5.4",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
- "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "es-errors": "^1.3.0",
- "get-proto": "^1.0.1",
- "gopd": "^1.2.0",
- "set-function-name": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/regexpu-core": {
- "version": "6.4.0",
- "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz",
- "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "regenerate": "^1.4.2",
- "regenerate-unicode-properties": "^10.2.2",
- "regjsgen": "^0.8.0",
- "regjsparser": "^0.13.0",
- "unicode-match-property-ecmascript": "^2.0.0",
- "unicode-match-property-value-ecmascript": "^2.2.1"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/regjsgen": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz",
- "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/regjsparser": {
- "version": "0.13.0",
- "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz",
- "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "jsesc": "~3.1.0"
- },
- "bin": {
- "regjsparser": "bin/parser"
- }
- },
- "node_modules/require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/require-from-string": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
- "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/requires-port": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
- "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
- "license": "MIT"
- },
- "node_modules/resolve": {
- "version": "1.22.11",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
- "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-core-module": "^2.16.1",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/resolve-cwd": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
- "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "resolve-from": "^5.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/resolve-pkg-maps": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
- "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
- }
- },
- "node_modules/resolve.exports": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz",
- "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/reusify": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
- "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "deprecated": "Rimraf versions prior to v4 are no longer supported",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/rrweb-cssom": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
- "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==",
- "license": "MIT"
- },
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
- "node_modules/safe-array-concat": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
- "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.2",
- "get-intrinsic": "^1.2.6",
- "has-symbols": "^1.1.0",
- "isarray": "^2.0.5"
- },
- "engines": {
- "node": ">=0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/safe-push-apply": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
- "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "isarray": "^2.0.5"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/safe-regex-test": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
- "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "es-errors": "^1.3.0",
- "is-regex": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "license": "MIT"
- },
- "node_modules/saxes": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
- "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
- "license": "ISC",
- "dependencies": {
- "xmlchars": "^2.2.0"
- },
- "engines": {
- "node": ">=v12.22.7"
- }
- },
- "node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/set-function-length": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
- "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "define-data-property": "^1.1.4",
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2",
- "get-intrinsic": "^1.2.4",
- "gopd": "^1.0.1",
- "has-property-descriptors": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/set-function-name": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
- "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "define-data-property": "^1.1.4",
- "es-errors": "^1.3.0",
- "functions-have-names": "^1.2.3",
- "has-property-descriptors": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/set-proto": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
- "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "dunder-proto": "^1.0.1",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/side-channel": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
- "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "object-inspect": "^1.13.3",
- "side-channel-list": "^1.0.0",
- "side-channel-map": "^1.0.1",
- "side-channel-weakmap": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/side-channel-list": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
- "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "object-inspect": "^1.13.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/side-channel-map": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
- "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.5",
- "object-inspect": "^1.13.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/side-channel-weakmap": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
- "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.5",
- "object-inspect": "^1.13.3",
- "side-channel-map": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/signal-exit": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/sisteransi": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
- "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/source-map-js": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
- "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/source-map-support": {
- "version": "0.5.13",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
- "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "buffer-from": "^1.0.0",
- "source-map": "^0.6.0"
- }
- },
- "node_modules/sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
- "dev": true,
- "license": "BSD-3-Clause"
- },
- "node_modules/stack-utils": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
- "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "escape-string-regexp": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/stack-utils/node_modules/escape-string-regexp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
- "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/stop-iteration-iterator": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
- "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "internal-slot": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/string-length": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
- "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "char-regex": "^1.0.2",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/string.prototype.trim": {
- "version": "1.2.10",
- "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
- "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.2",
- "define-data-property": "^1.1.4",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.5",
- "es-object-atoms": "^1.0.0",
- "has-property-descriptors": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimend": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
- "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.2",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimstart": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
- "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-bom": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
- "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-final-newline": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
- "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/symbol-tree": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
- "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
- "license": "MIT"
- },
- "node_modules/test-exclude": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
- "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "@istanbuljs/schema": "^0.1.2",
- "glob": "^7.1.4",
- "minimatch": "^3.0.4"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/tmpl": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
- "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
- "dev": true,
- "license": "BSD-3-Clause"
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/tough-cookie": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
- "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
- "license": "BSD-3-Clause",
- "dependencies": {
- "psl": "^1.1.33",
- "punycode": "^2.1.1",
- "universalify": "^0.2.0",
- "url-parse": "^1.5.3"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tr46": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
- "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
- "license": "MIT",
- "dependencies": {
- "punycode": "^2.3.1"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsconfig-paths": {
- "version": "3.15.0",
- "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
- "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/json5": "^0.0.29",
- "json5": "^1.0.2",
- "minimist": "^1.2.6",
- "strip-bom": "^3.0.0"
- }
- },
- "node_modules/tsconfig-paths/node_modules/json5": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
- "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "minimist": "^1.2.0"
- },
- "bin": {
- "json5": "lib/cli.js"
- }
- },
- "node_modules/tsconfig-paths/node_modules/strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true,
- "license": "0BSD"
- },
- "node_modules/tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "tslib": "^1.8.1"
- },
- "engines": {
- "node": ">= 6"
- },
- "peerDependencies": {
- "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
- }
- },
- "node_modules/type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "prelude-ls": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/type-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true,
- "license": "(MIT OR CC0-1.0)",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/typed-array-buffer": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
- "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "es-errors": "^1.3.0",
- "is-typed-array": "^1.1.14"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/typed-array-byte-length": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
- "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "for-each": "^0.3.3",
- "gopd": "^1.2.0",
- "has-proto": "^1.2.0",
- "is-typed-array": "^1.1.14"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/typed-array-byte-offset": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
- "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.8",
- "for-each": "^0.3.3",
- "gopd": "^1.2.0",
- "has-proto": "^1.2.0",
- "is-typed-array": "^1.1.15",
- "reflect.getprototypeof": "^1.0.9"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/typed-array-length": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
- "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "is-typed-array": "^1.1.13",
- "possible-typed-array-names": "^1.0.0",
- "reflect.getprototypeof": "^1.0.6"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/typescript": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
- "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
- "dev": true,
- "license": "Apache-2.0",
- "peer": true,
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
- "node_modules/unbox-primitive": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
- "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.1.0",
- "which-boxed-primitive": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/undici-types": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
- "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/unicode-canonical-property-names-ecmascript": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",
- "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/unicode-match-property-ecmascript": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
- "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "unicode-canonical-property-names-ecmascript": "^2.0.0",
- "unicode-property-aliases-ecmascript": "^2.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/unicode-match-property-value-ecmascript": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz",
- "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/unicode-property-aliases-ecmascript": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz",
- "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/universalify": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
- "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
- "license": "MIT",
- "engines": {
- "node": ">= 4.0.0"
- }
- },
- "node_modules/update-browserslist-db": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz",
- "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/browserslist"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "escalade": "^3.2.0",
- "picocolors": "^1.1.1"
- },
- "bin": {
- "update-browserslist-db": "cli.js"
- },
- "peerDependencies": {
- "browserslist": ">= 4.21.0"
- }
- },
- "node_modules/uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/url-parse": {
- "version": "1.5.10",
- "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
- "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
- "license": "MIT",
- "dependencies": {
- "querystringify": "^2.1.1",
- "requires-port": "^1.0.0"
- }
- },
- "node_modules/v8-to-istanbul": {
- "version": "9.3.0",
- "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
- "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "@jridgewell/trace-mapping": "^0.3.12",
- "@types/istanbul-lib-coverage": "^2.0.1",
- "convert-source-map": "^2.0.0"
- },
- "engines": {
- "node": ">=10.12.0"
- }
- },
- "node_modules/w3c-xmlserializer": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
- "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
- "license": "MIT",
- "dependencies": {
- "xml-name-validator": "^5.0.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/walker": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
- "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "makeerror": "1.0.12"
- }
- },
- "node_modules/webidl-conversions": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
- "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/whatwg-encoding": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
- "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
- "license": "MIT",
- "dependencies": {
- "iconv-lite": "0.6.3"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/whatwg-mimetype": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
- "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/whatwg-url": {
- "version": "14.2.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
- "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
- "license": "MIT",
- "dependencies": {
- "tr46": "^5.1.0",
- "webidl-conversions": "^7.0.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/which-boxed-primitive": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
- "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-bigint": "^1.1.0",
- "is-boolean-object": "^1.2.1",
- "is-number-object": "^1.1.1",
- "is-string": "^1.1.1",
- "is-symbol": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/which-builtin-type": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
- "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "function.prototype.name": "^1.1.6",
- "has-tostringtag": "^1.0.2",
- "is-async-function": "^2.0.0",
- "is-date-object": "^1.1.0",
- "is-finalizationregistry": "^1.1.0",
- "is-generator-function": "^1.0.10",
- "is-regex": "^1.2.1",
- "is-weakref": "^1.0.2",
- "isarray": "^2.0.5",
- "which-boxed-primitive": "^1.1.0",
- "which-collection": "^1.0.2",
- "which-typed-array": "^1.1.16"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/which-collection": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
- "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-map": "^2.0.3",
- "is-set": "^2.0.3",
- "is-weakmap": "^2.0.2",
- "is-weakset": "^2.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/which-typed-array": {
- "version": "1.1.19",
- "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
- "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.4",
- "for-each": "^0.3.5",
- "get-proto": "^1.0.1",
- "gopd": "^1.2.0",
- "has-tostringtag": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/word-wrap": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
- "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/write-file-atomic": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
- "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "imurmurhash": "^0.1.4",
- "signal-exit": "^3.0.7"
- },
- "engines": {
- "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
- }
- },
- "node_modules/ws": {
- "version": "8.18.3",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
- "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
- "license": "MIT",
- "engines": {
- "node": ">=10.0.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": ">=5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
- "node_modules/xml-name-validator": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
- "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
- "license": "Apache-2.0",
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/xmlchars": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
- "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
- "license": "MIT"
- },
- "node_modules/y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/yallist": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
- "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/yargs": {
- "version": "17.7.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
- "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- }
- }
-}
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/LICENSE b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/LICENSE
deleted file mode 100644
index 5ed027bd..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2024 asamuzaK (Kazz)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/README.md b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/README.md
deleted file mode 100644
index 0f964019..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/README.md
+++ /dev/null
@@ -1,316 +0,0 @@
-# CSS color
-
-[](https://github.com/asamuzaK/cssColor/actions/workflows/node.js.yml)
-[](https://github.com/asamuzaK/cssColor/actions/workflows/github-code-scanning/codeql)
-[](https://www.npmjs.com/package/@asamuzakjp/css-color)
-
-Resolve and convert CSS colors.
-
-## Install
-
-```console
-npm i @asamuzakjp/css-color
-```
-
-## Usage
-
-```javascript
-import { convert, resolve, utils } from '@asamuzakjp/css-color';
-
-const resolvedValue = resolve(
- 'color-mix(in oklab, lch(67.5345 42.5 258.2), color(srgb 0 0.5 0))'
-);
-// 'oklab(0.620754 -0.0931934 -0.00374881)'
-
-const convertedValue = covert.colorToHex('lab(46.2775% -47.5621 48.5837)');
-// '#008000'
-
-const result = utils.isColor('green');
-// true
-```
-
-
-
-### resolve(color, opt)
-
-resolves CSS color
-
-#### Parameters
-
-- `color` **[string][133]** color value
- - system colors are not supported
-- `opt` **[object][135]?** options (optional, default `{}`)
- - `opt.currentColor` **[string][133]?**
- - color to use for `currentcolor` keyword
- - if omitted, it will be treated as a missing color,
- i.e. `rgb(none none none / none)`
- - `opt.customProperty` **[object][135]?**
- - custom properties
- - pair of `--` prefixed property name as a key and it's value,
- e.g.
- ```javascript
- const opt = {
- customProperty: {
- '--some-color': '#008000',
- '--some-length': '16px'
- }
- };
- ```
- - and/or `callback` function to get the value of the custom property,
- e.g.
- ```javascript
- const node = document.getElementById('foo');
- const opt = {
- customProperty: {
- callback: node.style.getPropertyValue
- }
- };
- ```
- - `opt.dimension` **[object][135]?**
- - dimension, e.g. for converting relative length to pixels
- - pair of unit as a key and number in pixels as it's value,
- e.g. suppose `1em === 12px`, `1rem === 16px` and `100vw === 1024px`, then
- ```javascript
- const opt = {
- dimension: {
- em: 12,
- rem: 16,
- vw: 10.24
- }
- };
- ```
- - and/or `callback` function to get the value as a number in pixels,
- e.g.
- ```javascript
- const opt = {
- dimension: {
- callback: unit => {
- switch (unit) {
- case 'em':
- return 12;
- case 'rem':
- return 16;
- case 'vw':
- return 10.24;
- default:
- return;
- }
- }
- }
- };
- ```
- - `opt.format` **[string][133]?**
- - output format, one of below
- - `computedValue` (default), [computed value][139] of the color
- - `specifiedValue`, [specified value][140] of the color
- - `hex`, hex color notation, i.e. `#rrggbb`
- - `hexAlpha`, hex color notation with alpha channel, i.e. `#rrggbbaa`
-
-Returns **[string][133]?** one of `rgba?()`, `#rrggbb(aa)?`, `color-name`, `color(color-space r g b / alpha)`, `color(color-space x y z / alpha)`, `(ok)?lab(l a b / alpha)`, `(ok)?lch(l c h / alpha)`, `'(empty-string)'`, `null`
-
-- in `computedValue`, values are numbers, however `rgb()` values are integers
-- in `specifiedValue`, returns `empty string` for unknown and/or invalid color
-- in `hex`, returns `null` for `transparent`, and also returns `null` if any of `r`, `g`, `b`, `alpha` is not a number
-- in `hexAlpha`, returns `#00000000` for `transparent`, however returns `null` if any of `r`, `g`, `b`, `alpha` is not a number
-
-### convert
-
-Contains various color conversion functions.
-
-### convert.numberToHex(value)
-
-convert number to hex string
-
-#### Parameters
-
-- `value` **[number][134]** color value
-
-Returns **[string][133]** hex string: 00..ff
-
-### convert.colorToHex(value, opt)
-
-convert color to hex
-
-#### Parameters
-
-- `value` **[string][133]** color value
-- `opt` **[object][135]?** options (optional, default `{}`)
- - `opt.alpha` **[boolean][136]?** return in #rrggbbaa notation
- - `opt.customProperty` **[object][135]?**
- - custom properties, see `resolve()` function above
- - `opt.dimension` **[object][135]?**
- - dimension, see `resolve()` function above
-
-Returns **[string][133]** #rrggbb(aa)?
-
-### convert.colorToHsl(value, opt)
-
-convert color to hsl
-
-#### Parameters
-
-- `value` **[string][133]** color value
-- `opt` **[object][135]?** options (optional, default `{}`)
- - `opt.customProperty` **[object][135]?**
- - custom properties, see `resolve()` function above
- - `opt.dimension` **[object][135]?**
- - dimension, see `resolve()` function above
-
-Returns **[Array][137]<[number][134]>** \[h, s, l, alpha]
-
-### convert.colorToHwb(value, opt)
-
-convert color to hwb
-
-#### Parameters
-
-- `value` **[string][133]** color value
-- `opt` **[object][135]?** options (optional, default `{}`)
- - `opt.customProperty` **[object][135]?**
- - custom properties, see `resolve()` function above
- - `opt.dimension` **[object][135]?**
- - dimension, see `resolve()` function above
-
-Returns **[Array][137]<[number][134]>** \[h, w, b, alpha]
-
-### convert.colorToLab(value, opt)
-
-convert color to lab
-
-#### Parameters
-
-- `value` **[string][133]** color value
-- `opt` **[object][135]?** options (optional, default `{}`)
- - `opt.customProperty` **[object][135]?**
- - custom properties, see `resolve()` function above
- - `opt.dimension` **[object][135]?**
- - dimension, see `resolve()` function above
-
-Returns **[Array][137]<[number][134]>** \[l, a, b, alpha]
-
-### convert.colorToLch(value, opt)
-
-convert color to lch
-
-#### Parameters
-
-- `value` **[string][133]** color value
-- `opt` **[object][135]?** options (optional, default `{}`)
- - `opt.customProperty` **[object][135]?**
- - custom properties, see `resolve()` function above
- - `opt.dimension` **[object][135]?**
- - dimension, see `resolve()` function above
-
-Returns **[Array][137]<[number][134]>** \[l, c, h, alpha]
-
-### convert.colorToOklab(value, opt)
-
-convert color to oklab
-
-#### Parameters
-
-- `value` **[string][133]** color value
-- `opt` **[object][135]?** options (optional, default `{}`)
- - `opt.customProperty` **[object][135]?**
- - custom properties, see `resolve()` function above
- - `opt.dimension` **[object][135]?**
- - dimension, see `resolve()` function above
-
-Returns **[Array][137]<[number][134]>** \[l, a, b, alpha]
-
-### convert.colorToOklch(value, opt)
-
-convert color to oklch
-
-#### Parameters
-
-- `value` **[string][133]** color value
-- `opt` **[object][135]?** options (optional, default `{}`)
- - `opt.customProperty` **[object][135]?**
- - custom properties, see `resolve()` function above
- - `opt.dimension` **[object][135]?**
- - dimension, see `resolve()` function above
-
-Returns **[Array][137]<[number][134]>** \[l, c, h, alpha]
-
-### convert.colorToRgb(value, opt)
-
-convert color to rgb
-
-#### Parameters
-
-- `value` **[string][133]** color value
-- `opt` **[object][135]?** options (optional, default `{}`)
- - `opt.customProperty` **[object][135]?**
- - custom properties, see `resolve()` function above
- - `opt.dimension` **[object][135]?**
- - dimension, see `resolve()` function above
-
-Returns **[Array][137]<[number][134]>** \[r, g, b, alpha]
-
-### convert.colorToXyz(value, opt)
-
-convert color to xyz
-
-#### Parameters
-
-- `value` **[string][133]** color value
-- `opt` **[object][135]?** options (optional, default `{}`)
- - `opt.customProperty` **[object][135]?**
- - custom properties, see `resolve()` function above
- - `opt.dimension` **[object][135]?**
- - dimension, see `resolve()` function above
- - `opt.d50` **[boolean][136]?** xyz in d50 white point
-
-Returns **[Array][137]<[number][134]>** \[x, y, z, alpha]
-
-### convert.colorToXyzD50(value, opt)
-
-convert color to xyz-d50
-
-#### Parameters
-
-- `value` **[string][133]** color value
-- `opt` **[object][135]?** options (optional, default `{}`)
- - `opt.customProperty` **[object][135]?**
- - custom properties, see `resolve()` function above
- - `opt.dimension` **[object][135]?**
- - dimension, see `resolve()` function above
-
-Returns **[Array][137]<[number][134]>** \[x, y, z, alpha]
-
-### utils
-
-Contains utility functions.
-
-### utils.isColor(color)
-
-is valid color type
-
-#### Parameters
-
-- `color` **[string][133]** color value
- - system colors are not supported
-
-Returns **[boolean][136]**
-
-## Acknowledgments
-
-The following resources have been of great help in the development of the CSS color.
-
-- [csstools/postcss-plugins](https://github.com/csstools/postcss-plugins)
-- [lru-cache](https://github.com/isaacs/node-lru-cache)
-
----
-
-Copyright (c) 2024 [asamuzaK (Kazz)](https://github.com/asamuzaK/)
-
-[133]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
-[134]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
-[135]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
-[136]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
-[137]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
-[138]: https://w3c.github.io/csswg-drafts/css-color-4/#color-conversion-code
-[139]: https://developer.mozilla.org/en-US/docs/Web/CSS/computed_value
-[140]: https://developer.mozilla.org/en-US/docs/Web/CSS/specified_value
-[141]: https://www.npmjs.com/package/@csstools/css-calc
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/node_modules/lru-cache/LICENSE b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/node_modules/lru-cache/LICENSE
deleted file mode 100644
index f785757c..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/node_modules/lru-cache/LICENSE
+++ /dev/null
@@ -1,15 +0,0 @@
-The ISC License
-
-Copyright (c) 2010-2023 Isaac Z. Schlueter and Contributors
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
-IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/node_modules/lru-cache/README.md b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/node_modules/lru-cache/README.md
deleted file mode 100644
index 931822f3..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/node_modules/lru-cache/README.md
+++ /dev/null
@@ -1,331 +0,0 @@
-# lru-cache
-
-A cache object that deletes the least-recently-used items.
-
-Specify a max number of the most recently used items that you
-want to keep, and this cache will keep that many of the most
-recently accessed items.
-
-This is not primarily a TTL cache, and does not make strong TTL
-guarantees. There is no preemptive pruning of expired items by
-default, but you _may_ set a TTL on the cache or on a single
-`set`. If you do so, it will treat expired items as missing, and
-delete them when fetched. If you are more interested in TTL
-caching than LRU caching, check out
-[@isaacs/ttlcache](http://npm.im/@isaacs/ttlcache).
-
-As of version 7, this is one of the most performant LRU
-implementations available in JavaScript, and supports a wide
-diversity of use cases. However, note that using some of the
-features will necessarily impact performance, by causing the
-cache to have to do more work. See the "Performance" section
-below.
-
-## Installation
-
-```bash
-npm install lru-cache --save
-```
-
-## Usage
-
-```js
-// hybrid module, either works
-import { LRUCache } from 'lru-cache'
-// or:
-const { LRUCache } = require('lru-cache')
-// or in minified form for web browsers:
-import { LRUCache } from 'http://unpkg.com/lru-cache@9/dist/mjs/index.min.mjs'
-
-// At least one of 'max', 'ttl', or 'maxSize' is required, to prevent
-// unsafe unbounded storage.
-//
-// In most cases, it's best to specify a max for performance, so all
-// the required memory allocation is done up-front.
-//
-// All the other options are optional, see the sections below for
-// documentation on what each one does. Most of them can be
-// overridden for specific items in get()/set()
-const options = {
- max: 500,
-
- // for use with tracking overall storage size
- maxSize: 5000,
- sizeCalculation: (value, key) => {
- return 1
- },
-
- // for use when you need to clean up something when objects
- // are evicted from the cache
- dispose: (value, key) => {
- freeFromMemoryOrWhatever(value)
- },
-
- // how long to live in ms
- ttl: 1000 * 60 * 5,
-
- // return stale items before removing from cache?
- allowStale: false,
-
- updateAgeOnGet: false,
- updateAgeOnHas: false,
-
- // async method to use for cache.fetch(), for
- // stale-while-revalidate type of behavior
- fetchMethod: async (
- key,
- staleValue,
- { options, signal, context }
- ) => {},
-}
-
-const cache = new LRUCache(options)
-
-cache.set('key', 'value')
-cache.get('key') // "value"
-
-// non-string keys ARE fully supported
-// but note that it must be THE SAME object, not
-// just a JSON-equivalent object.
-var someObject = { a: 1 }
-cache.set(someObject, 'a value')
-// Object keys are not toString()-ed
-cache.set('[object Object]', 'a different value')
-assert.equal(cache.get(someObject), 'a value')
-// A similar object with same keys/values won't work,
-// because it's a different object identity
-assert.equal(cache.get({ a: 1 }), undefined)
-
-cache.clear() // empty the cache
-```
-
-If you put more stuff in the cache, then less recently used items
-will fall out. That's what an LRU cache is.
-
-For full description of the API and all options, please see [the
-LRUCache typedocs](https://isaacs.github.io/node-lru-cache/)
-
-## Storage Bounds Safety
-
-This implementation aims to be as flexible as possible, within
-the limits of safe memory consumption and optimal performance.
-
-At initial object creation, storage is allocated for `max` items.
-If `max` is set to zero, then some performance is lost, and item
-count is unbounded. Either `maxSize` or `ttl` _must_ be set if
-`max` is not specified.
-
-If `maxSize` is set, then this creates a safe limit on the
-maximum storage consumed, but without the performance benefits of
-pre-allocation. When `maxSize` is set, every item _must_ provide
-a size, either via the `sizeCalculation` method provided to the
-constructor, or via a `size` or `sizeCalculation` option provided
-to `cache.set()`. The size of every item _must_ be a positive
-integer.
-
-If neither `max` nor `maxSize` are set, then `ttl` tracking must
-be enabled. Note that, even when tracking item `ttl`, items are
-_not_ preemptively deleted when they become stale, unless
-`ttlAutopurge` is enabled. Instead, they are only purged the
-next time the key is requested. Thus, if `ttlAutopurge`, `max`,
-and `maxSize` are all not set, then the cache will potentially
-grow unbounded.
-
-In this case, a warning is printed to standard error. Future
-versions may require the use of `ttlAutopurge` if `max` and
-`maxSize` are not specified.
-
-If you truly wish to use a cache that is bound _only_ by TTL
-expiration, consider using a `Map` object, and calling
-`setTimeout` to delete entries when they expire. It will perform
-much better than an LRU cache.
-
-Here is an implementation you may use, under the same
-[license](./LICENSE) as this package:
-
-```js
-// a storage-unbounded ttl cache that is not an lru-cache
-const cache = {
- data: new Map(),
- timers: new Map(),
- set: (k, v, ttl) => {
- if (cache.timers.has(k)) {
- clearTimeout(cache.timers.get(k))
- }
- cache.timers.set(
- k,
- setTimeout(() => cache.delete(k), ttl)
- )
- cache.data.set(k, v)
- },
- get: k => cache.data.get(k),
- has: k => cache.data.has(k),
- delete: k => {
- if (cache.timers.has(k)) {
- clearTimeout(cache.timers.get(k))
- }
- cache.timers.delete(k)
- return cache.data.delete(k)
- },
- clear: () => {
- cache.data.clear()
- for (const v of cache.timers.values()) {
- clearTimeout(v)
- }
- cache.timers.clear()
- },
-}
-```
-
-If that isn't to your liking, check out
-[@isaacs/ttlcache](http://npm.im/@isaacs/ttlcache).
-
-## Storing Undefined Values
-
-This cache never stores undefined values, as `undefined` is used
-internally in a few places to indicate that a key is not in the
-cache.
-
-You may call `cache.set(key, undefined)`, but this is just
-an alias for `cache.delete(key)`. Note that this has the effect
-that `cache.has(key)` will return _false_ after setting it to
-undefined.
-
-```js
-cache.set(myKey, undefined)
-cache.has(myKey) // false!
-```
-
-If you need to track `undefined` values, and still note that the
-key is in the cache, an easy workaround is to use a sigil object
-of your own.
-
-```js
-import { LRUCache } from 'lru-cache'
-const undefinedValue = Symbol('undefined')
-const cache = new LRUCache(...)
-const mySet = (key, value) =>
- cache.set(key, value === undefined ? undefinedValue : value)
-const myGet = (key, value) => {
- const v = cache.get(key)
- return v === undefinedValue ? undefined : v
-}
-```
-
-## Performance
-
-As of January 2022, version 7 of this library is one of the most
-performant LRU cache implementations in JavaScript.
-
-Benchmarks can be extremely difficult to get right. In
-particular, the performance of set/get/delete operations on
-objects will vary _wildly_ depending on the type of key used. V8
-is highly optimized for objects with keys that are short strings,
-especially integer numeric strings. Thus any benchmark which
-tests _solely_ using numbers as keys will tend to find that an
-object-based approach performs the best.
-
-Note that coercing _anything_ to strings to use as object keys is
-unsafe, unless you can be 100% certain that no other type of
-value will be used. For example:
-
-```js
-const myCache = {}
-const set = (k, v) => (myCache[k] = v)
-const get = k => myCache[k]
-
-set({}, 'please hang onto this for me')
-set('[object Object]', 'oopsie')
-```
-
-Also beware of "Just So" stories regarding performance. Garbage
-collection of large (especially: deep) object graphs can be
-incredibly costly, with several "tipping points" where it
-increases exponentially. As a result, putting that off until
-later can make it much worse, and less predictable. If a library
-performs well, but only in a scenario where the object graph is
-kept shallow, then that won't help you if you are using large
-objects as keys.
-
-In general, when attempting to use a library to improve
-performance (such as a cache like this one), it's best to choose
-an option that will perform well in the sorts of scenarios where
-you'll actually use it.
-
-This library is optimized for repeated gets and minimizing
-eviction time, since that is the expected need of a LRU. Set
-operations are somewhat slower on average than a few other
-options, in part because of that optimization. It is assumed
-that you'll be caching some costly operation, ideally as rarely
-as possible, so optimizing set over get would be unwise.
-
-If performance matters to you:
-
-1. If it's at all possible to use small integer values as keys,
- and you can guarantee that no other types of values will be
- used as keys, then do that, and use a cache such as
- [lru-fast](https://npmjs.com/package/lru-fast), or
- [mnemonist's
- LRUCache](https://yomguithereal.github.io/mnemonist/lru-cache)
- which uses an Object as its data store.
-
-2. Failing that, if at all possible, use short non-numeric
- strings (ie, less than 256 characters) as your keys, and use
- [mnemonist's
- LRUCache](https://yomguithereal.github.io/mnemonist/lru-cache).
-
-3. If the types of your keys will be anything else, especially
- long strings, strings that look like floats, objects, or some
- mix of types, or if you aren't sure, then this library will
- work well for you.
-
- If you do not need the features that this library provides
- (like asynchronous fetching, a variety of TTL staleness
- options, and so on), then [mnemonist's
- LRUMap](https://yomguithereal.github.io/mnemonist/lru-map) is
- a very good option, and just slightly faster than this module
- (since it does considerably less).
-
-4. Do not use a `dispose` function, size tracking, or especially
- ttl behavior, unless absolutely needed. These features are
- convenient, and necessary in some use cases, and every attempt
- has been made to make the performance impact minimal, but it
- isn't nothing.
-
-## Breaking Changes in Version 7
-
-This library changed to a different algorithm and internal data
-structure in version 7, yielding significantly better
-performance, albeit with some subtle changes as a result.
-
-If you were relying on the internals of LRUCache in version 6 or
-before, it probably will not work in version 7 and above.
-
-## Breaking Changes in Version 8
-
-- The `fetchContext` option was renamed to `context`, and may no
- longer be set on the cache instance itself.
-- Rewritten in TypeScript, so pretty much all the types moved
- around a lot.
-- The AbortController/AbortSignal polyfill was removed. For this
- reason, **Node version 16.14.0 or higher is now required**.
-- Internal properties were moved to actual private class
- properties.
-- Keys and values must not be `null` or `undefined`.
-- Minified export available at `'lru-cache/min'`, for both CJS
- and MJS builds.
-
-## Breaking Changes in Version 9
-
-- Named export only, no default export.
-- AbortController polyfill returned, albeit with a warning when
- used.
-
-## Breaking Changes in Version 10
-
-- `cache.fetch()` return type is now `Promise`
- instead of `Promise`. This is an irrelevant change
- practically speaking, but can require changes for TypeScript
- users.
-
-For more info, see the [change log](CHANGELOG.md).
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/node_modules/lru-cache/package.json b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/node_modules/lru-cache/package.json
deleted file mode 100644
index f3cd4c0c..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/node_modules/lru-cache/package.json
+++ /dev/null
@@ -1,116 +0,0 @@
-{
- "name": "lru-cache",
- "publishConfig": {
- "tag": "legacy-v10"
- },
- "description": "A cache object that deletes the least-recently-used items.",
- "version": "10.4.3",
- "author": "Isaac Z. Schlueter ",
- "keywords": [
- "mru",
- "lru",
- "cache"
- ],
- "sideEffects": false,
- "scripts": {
- "build": "npm run prepare",
- "prepare": "tshy && bash fixup.sh",
- "pretest": "npm run prepare",
- "presnap": "npm run prepare",
- "test": "tap",
- "snap": "tap",
- "preversion": "npm test",
- "postversion": "npm publish",
- "prepublishOnly": "git push origin --follow-tags",
- "format": "prettier --write .",
- "typedoc": "typedoc --tsconfig ./.tshy/esm.json ./src/*.ts",
- "benchmark-results-typedoc": "bash scripts/benchmark-results-typedoc.sh",
- "prebenchmark": "npm run prepare",
- "benchmark": "make -C benchmark",
- "preprofile": "npm run prepare",
- "profile": "make -C benchmark profile"
- },
- "main": "./dist/commonjs/index.js",
- "types": "./dist/commonjs/index.d.ts",
- "tshy": {
- "exports": {
- ".": "./src/index.ts",
- "./min": {
- "import": {
- "types": "./dist/esm/index.d.ts",
- "default": "./dist/esm/index.min.js"
- },
- "require": {
- "types": "./dist/commonjs/index.d.ts",
- "default": "./dist/commonjs/index.min.js"
- }
- }
- }
- },
- "repository": {
- "type": "git",
- "url": "git://github.com/isaacs/node-lru-cache.git"
- },
- "devDependencies": {
- "@types/node": "^20.2.5",
- "@types/tap": "^15.0.6",
- "benchmark": "^2.1.4",
- "esbuild": "^0.17.11",
- "eslint-config-prettier": "^8.5.0",
- "marked": "^4.2.12",
- "mkdirp": "^2.1.5",
- "prettier": "^2.6.2",
- "tap": "^20.0.3",
- "tshy": "^2.0.0",
- "tslib": "^2.4.0",
- "typedoc": "^0.25.3",
- "typescript": "^5.2.2"
- },
- "license": "ISC",
- "files": [
- "dist"
- ],
- "prettier": {
- "semi": false,
- "printWidth": 70,
- "tabWidth": 2,
- "useTabs": false,
- "singleQuote": true,
- "jsxSingleQuote": false,
- "bracketSameLine": true,
- "arrowParens": "avoid",
- "endOfLine": "lf"
- },
- "tap": {
- "node-arg": [
- "--expose-gc"
- ],
- "plugin": [
- "@tapjs/clock"
- ]
- },
- "exports": {
- ".": {
- "import": {
- "types": "./dist/esm/index.d.ts",
- "default": "./dist/esm/index.js"
- },
- "require": {
- "types": "./dist/commonjs/index.d.ts",
- "default": "./dist/commonjs/index.js"
- }
- },
- "./min": {
- "import": {
- "types": "./dist/esm/index.d.ts",
- "default": "./dist/esm/index.min.js"
- },
- "require": {
- "types": "./dist/commonjs/index.d.ts",
- "default": "./dist/commonjs/index.min.js"
- }
- }
- },
- "type": "module",
- "module": "./dist/esm/index.js"
-}
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/package.json b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/package.json
deleted file mode 100644
index c0f76d6e..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/package.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "@asamuzakjp/css-color",
- "description": "CSS color - Resolve and convert CSS colors.",
- "author": "asamuzaK",
- "license": "MIT",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/asamuzaK/cssColor.git"
- },
- "homepage": "https://github.com/asamuzaK/cssColor#readme",
- "bugs": {
- "url": "https://github.com/asamuzaK/cssColor/issues"
- },
- "files": [
- "dist",
- "src"
- ],
- "type": "module",
- "types": "dist/esm/index.d.ts",
- "module": "dist/esm/index.js",
- "main": "dist/cjs/index.cjs",
- "exports": {
- ".": {
- "import": {
- "types": "./dist/esm/index.d.ts",
- "default": "./dist/esm/index.js"
- },
- "require": {
- "types": "./dist/cjs/index.d.cts",
- "default": "./dist/cjs/index.cjs"
- }
- },
- "./package.json": "./package.json"
- },
- "dependencies": {
- "@csstools/css-calc": "^2.1.3",
- "@csstools/css-color-parser": "^3.0.9",
- "@csstools/css-parser-algorithms": "^3.0.4",
- "@csstools/css-tokenizer": "^3.0.3",
- "lru-cache": "^10.4.3"
- },
- "devDependencies": {
- "@tanstack/vite-config": "^0.2.0",
- "@vitest/coverage-istanbul": "^3.1.4",
- "esbuild": "^0.25.4",
- "eslint": "^9.27.0",
- "eslint-plugin-regexp": "^2.7.0",
- "globals": "^16.1.0",
- "knip": "^5.56.0",
- "neostandard": "^0.12.1",
- "prettier": "^3.5.3",
- "publint": "^0.3.12",
- "rimraf": "^6.0.1",
- "tsup": "^8.5.0",
- "typescript": "^5.8.3",
- "vite": "^6.3.5",
- "vitest": "^3.1.4"
- },
- "packageManager": "pnpm@10.11.0",
- "pnpm": {
- "onlyBuiltDependencies": [
- "esbuild",
- "unrs-resolver"
- ]
- },
- "scripts": {
- "build": "pnpm run clean && pnpm run test && pnpm run knip && pnpm run build:prod && pnpm run build:cjs && pnpm run build:browser && pnpm run publint",
- "build:browser": "vite build -c ./vite.browser.config.ts",
- "build:prod": "vite build",
- "build:cjs": "tsup ./src/index.ts --format=cjs --platform=node --outDir=./dist/cjs/ --sourcemap --dts",
- "clean": "rimraf ./coverage ./dist",
- "knip": "knip",
- "prettier": "prettier . --ignore-unknown --write",
- "publint": "publint --strict",
- "test": "pnpm run prettier && pnpm run --stream \"/^test:.*/\"",
- "test:eslint": "eslint ./src ./test --fix",
- "test:types": "tsc",
- "test:unit": "vitest"
- },
- "version": "3.2.0"
-}
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/index.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/index.ts
deleted file mode 100644
index 97d6ebe3..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/index.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*!
- * CSS color - Resolve, parse, convert CSS color.
- * @license MIT
- * @copyright asamuzaK (Kazz)
- * @see {@link https://github.com/asamuzaK/cssColor/blob/main/LICENSE}
- */
-
-import { cssCalc as csscalc } from './js/css-calc';
-import { isGradient } from './js/css-gradient';
-import { cssVar } from './js/css-var';
-import { extractDashedIdent, isColor as iscolor, splitValue } from './js/util';
-
-export { convert } from './js/convert';
-export { resolve } from './js/resolve';
-/* utils */
-export const utils = {
- cssCalc: csscalc,
- cssVar,
- extractDashedIdent,
- isColor: iscolor,
- isGradient,
- splitValue
-};
-/* TODO: remove later */
-/* alias */
-export const isColor = utils.isColor;
-export const cssCalc = utils.cssCalc;
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/cache.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/cache.ts
deleted file mode 100644
index 86421139..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/cache.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * cache
- */
-
-import { LRUCache } from 'lru-cache';
-import { Options } from './typedef';
-import { valueToJsonString } from './util';
-
-/* numeric constants */
-const MAX_CACHE = 4096;
-
-/**
- * CacheItem
- */
-export class CacheItem {
- /* private */
- #isNull: boolean;
- #item: unknown;
-
- /**
- * constructor
- */
- constructor(item: unknown, isNull: boolean = false) {
- this.#item = item;
- this.#isNull = !!isNull;
- }
-
- get item() {
- return this.#item;
- }
-
- get isNull() {
- return this.#isNull;
- }
-}
-
-/**
- * NullObject
- */
-export class NullObject extends CacheItem {
- /**
- * constructor
- */
- constructor() {
- super(Symbol('null'), true);
- }
-}
-
-/*
- * lru cache
- */
-export const lruCache = new LRUCache({
- max: MAX_CACHE
-});
-
-/**
- * set cache
- * @param key - cache key
- * @param value - value to cache
- * @returns void
- */
-export const setCache = (key: string, value: unknown): void => {
- if (key) {
- if (value === null) {
- lruCache.set(key, new NullObject());
- } else if (value instanceof CacheItem) {
- lruCache.set(key, value);
- } else {
- lruCache.set(key, new CacheItem(value));
- }
- }
-};
-
-/**
- * get cache
- * @param key - cache key
- * @returns cached item or false otherwise
- */
-export const getCache = (key: string): CacheItem | boolean => {
- if (key && lruCache.has(key)) {
- const item = lruCache.get(key);
- if (item instanceof CacheItem) {
- return item;
- }
- // delete unexpected cached item
- lruCache.delete(key);
- return false;
- }
- return false;
-};
-
-/**
- * create cache key
- * @param keyData - key data
- * @param [opt] - options
- * @returns cache key
- */
-export const createCacheKey = (
- keyData: Record,
- opt: Options = {}
-): string => {
- const { customProperty = {}, dimension = {} } = opt;
- let cacheKey = '';
- if (
- keyData &&
- Object.keys(keyData).length &&
- typeof customProperty.callback !== 'function' &&
- typeof dimension.callback !== 'function'
- ) {
- keyData.opt = valueToJsonString(opt);
- cacheKey = valueToJsonString(keyData);
- }
- return cacheKey;
-};
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/color.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/color.ts
deleted file mode 100644
index c79a9a03..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/color.ts
+++ /dev/null
@@ -1,3459 +0,0 @@
-/**
- * color
- *
- * Ref: CSS Color Module Level 4
- * Sample code for Color Conversions
- * https://w3c.github.io/csswg-drafts/css-color-4/#color-conversion-code
- */
-
-import {
- CacheItem,
- NullObject,
- createCacheKey,
- getCache,
- setCache
-} from './cache';
-import { isString } from './common';
-import { interpolateHue, roundToPrecision } from './util';
-import {
- ColorChannels,
- ComputedColorChannels,
- Options,
- MatchedRegExp,
- SpecifiedColorChannels,
- StringColorChannels,
- StringColorSpacedChannels
-} from './typedef';
-
-/* constants */
-import {
- ANGLE,
- CS_HUE_CAPT,
- CS_MIX,
- CS_RGB,
- CS_XYZ,
- FN_COLOR,
- FN_MIX,
- NONE,
- NUM,
- PCT,
- SYN_COLOR_TYPE,
- SYN_FN_COLOR,
- SYN_HSL,
- SYN_HSL_LV3,
- SYN_LCH,
- SYN_MIX,
- SYN_MIX_CAPT,
- SYN_MIX_PART,
- SYN_MOD,
- SYN_RGB_LV3,
- VAL_COMP,
- VAL_MIX,
- VAL_SPEC
-} from './constant';
-const NAMESPACE = 'color';
-
-/* numeric constants */
-const PPTH = 0.001;
-const HALF = 0.5;
-const DUO = 2;
-const TRIA = 3;
-const QUAD = 4;
-const OCT = 8;
-const DEC = 10;
-const DOZ = 12;
-const HEX = 16;
-const SEXA = 60;
-const DEG_HALF = 180;
-const DEG = 360;
-const MAX_PCT = 100;
-const MAX_RGB = 255;
-const POW_SQR = 2;
-const POW_CUBE = 3;
-const POW_LINEAR = 2.4;
-const LINEAR_COEF = 12.92;
-const LINEAR_OFFSET = 0.055;
-const LAB_L = 116;
-const LAB_A = 500;
-const LAB_B = 200;
-const LAB_EPSILON = 216 / 24389;
-const LAB_KAPPA = 24389 / 27;
-
-/* type definitions */
-/**
- * @type NumStrColorChannels - string or numeric color channels
- */
-type NumStrColorChannels = [
- x: number | string,
- y: number | string,
- z: number | string,
- alpha: number | string
-];
-
-/**
- * @type TriColorChannels - color channels without alpha
- */
-type TriColorChannels = [x: number, y: number, z: number];
-
-/**
- * @type ColorMatrix - color matrix
- */
-type ColorMatrix = [
- r1: TriColorChannels,
- r2: TriColorChannels,
- r3: TriColorChannels
-];
-
-/* white point */
-const D50: TriColorChannels = [
- 0.3457 / 0.3585,
- 1.0,
- (1.0 - 0.3457 - 0.3585) / 0.3585
-];
-const MATRIX_D50_TO_D65: ColorMatrix = [
- [0.955473421488075, -0.02309845494876471, 0.06325924320057072],
- [-0.0283697093338637, 1.0099953980813041, 0.021041441191917323],
- [0.012314014864481998, -0.020507649298898964, 1.330365926242124]
-];
-const MATRIX_D65_TO_D50: ColorMatrix = [
- [1.0479297925449969, 0.022946870601609652, -0.05019226628920524],
- [0.02962780877005599, 0.9904344267538799, -0.017073799063418826],
- [-0.009243040646204504, 0.015055191490298152, 0.7518742814281371]
-];
-
-/* color space */
-const MATRIX_L_RGB_TO_XYZ: ColorMatrix = [
- [506752 / 1228815, 87881 / 245763, 12673 / 70218],
- [87098 / 409605, 175762 / 245763, 12673 / 175545],
- [7918 / 409605, 87881 / 737289, 1001167 / 1053270]
-];
-const MATRIX_XYZ_TO_L_RGB: ColorMatrix = [
- [12831 / 3959, -329 / 214, -1974 / 3959],
- [-851781 / 878810, 1648619 / 878810, 36519 / 878810],
- [705 / 12673, -2585 / 12673, 705 / 667]
-];
-const MATRIX_XYZ_TO_LMS: ColorMatrix = [
- [0.819022437996703, 0.3619062600528904, -0.1288737815209879],
- [0.0329836539323885, 0.9292868615863434, 0.0361446663506424],
- [0.0481771893596242, 0.2642395317527308, 0.6335478284694309]
-];
-const MATRIX_LMS_TO_XYZ: ColorMatrix = [
- [1.2268798758459243, -0.5578149944602171, 0.2813910456659647],
- [-0.0405757452148008, 1.112286803280317, -0.0717110580655164],
- [-0.0763729366746601, -0.4214933324022432, 1.5869240198367816]
-];
-const MATRIX_OKLAB_TO_LMS: ColorMatrix = [
- [1.0, 0.3963377773761749, 0.2158037573099136],
- [1.0, -0.1055613458156586, -0.0638541728258133],
- [1.0, -0.0894841775298119, -1.2914855480194092]
-];
-const MATRIX_LMS_TO_OKLAB: ColorMatrix = [
- [0.210454268309314, 0.7936177747023054, -0.0040720430116193],
- [1.9779985324311684, -2.4285922420485799, 0.450593709617411],
- [0.0259040424655478, 0.7827717124575296, -0.8086757549230774]
-];
-const MATRIX_P3_TO_XYZ: ColorMatrix = [
- [608311 / 1250200, 189793 / 714400, 198249 / 1000160],
- [35783 / 156275, 247089 / 357200, 198249 / 2500400],
- [0 / 1, 32229 / 714400, 5220557 / 5000800]
-];
-const MATRIX_REC2020_TO_XYZ: ColorMatrix = [
- [63426534 / 99577255, 20160776 / 139408157, 47086771 / 278816314],
- [26158966 / 99577255, 472592308 / 697040785, 8267143 / 139408157],
- [0 / 1, 19567812 / 697040785, 295819943 / 278816314]
-];
-const MATRIX_A98_TO_XYZ: ColorMatrix = [
- [573536 / 994567, 263643 / 1420810, 187206 / 994567],
- [591459 / 1989134, 6239551 / 9945670, 374412 / 4972835],
- [53769 / 1989134, 351524 / 4972835, 4929758 / 4972835]
-];
-const MATRIX_PROPHOTO_TO_XYZ_D50: ColorMatrix = [
- [0.7977666449006423, 0.13518129740053308, 0.0313477341283922],
- [0.2880748288194013, 0.711835234241873, 0.00008993693872564],
- [0.0, 0.0, 0.8251046025104602]
-];
-
-/* regexp */
-const REG_COLOR = new RegExp(`^(?:${SYN_COLOR_TYPE})$`);
-const REG_CS_HUE = new RegExp(`^${CS_HUE_CAPT}$`);
-const REG_CS_XYZ = /^xyz(?:-d(?:50|65))?$/;
-const REG_CURRENT = /^currentColor$/i;
-const REG_FN_COLOR = new RegExp(`^color\\(\\s*(${SYN_FN_COLOR})\\s*\\)$`);
-const REG_HSL = new RegExp(`^hsla?\\(\\s*(${SYN_HSL}|${SYN_HSL_LV3})\\s*\\)$`);
-const REG_HWB = new RegExp(`^hwb\\(\\s*(${SYN_HSL})\\s*\\)$`);
-const REG_LAB = new RegExp(`^lab\\(\\s*(${SYN_MOD})\\s*\\)$`);
-const REG_LCH = new RegExp(`^lch\\(\\s*(${SYN_LCH})\\s*\\)$`);
-const REG_MIX = new RegExp(`^${SYN_MIX}$`);
-const REG_MIX_CAPT = new RegExp(`^${SYN_MIX_CAPT}$`);
-const REG_MIX_NEST = new RegExp(`${SYN_MIX}`, 'g');
-const REG_OKLAB = new RegExp(`^oklab\\(\\s*(${SYN_MOD})\\s*\\)$`);
-const REG_OKLCH = new RegExp(`^oklch\\(\\s*(${SYN_LCH})\\s*\\)$`);
-const REG_SPEC = /^(?:specifi|comput)edValue$/;
-
-/**
- * named colors
- */
-export const NAMED_COLORS = {
- aliceblue: [0xf0, 0xf8, 0xff],
- antiquewhite: [0xfa, 0xeb, 0xd7],
- aqua: [0x00, 0xff, 0xff],
- aquamarine: [0x7f, 0xff, 0xd4],
- azure: [0xf0, 0xff, 0xff],
- beige: [0xf5, 0xf5, 0xdc],
- bisque: [0xff, 0xe4, 0xc4],
- black: [0x00, 0x00, 0x00],
- blanchedalmond: [0xff, 0xeb, 0xcd],
- blue: [0x00, 0x00, 0xff],
- blueviolet: [0x8a, 0x2b, 0xe2],
- brown: [0xa5, 0x2a, 0x2a],
- burlywood: [0xde, 0xb8, 0x87],
- cadetblue: [0x5f, 0x9e, 0xa0],
- chartreuse: [0x7f, 0xff, 0x00],
- chocolate: [0xd2, 0x69, 0x1e],
- coral: [0xff, 0x7f, 0x50],
- cornflowerblue: [0x64, 0x95, 0xed],
- cornsilk: [0xff, 0xf8, 0xdc],
- crimson: [0xdc, 0x14, 0x3c],
- cyan: [0x00, 0xff, 0xff],
- darkblue: [0x00, 0x00, 0x8b],
- darkcyan: [0x00, 0x8b, 0x8b],
- darkgoldenrod: [0xb8, 0x86, 0x0b],
- darkgray: [0xa9, 0xa9, 0xa9],
- darkgreen: [0x00, 0x64, 0x00],
- darkgrey: [0xa9, 0xa9, 0xa9],
- darkkhaki: [0xbd, 0xb7, 0x6b],
- darkmagenta: [0x8b, 0x00, 0x8b],
- darkolivegreen: [0x55, 0x6b, 0x2f],
- darkorange: [0xff, 0x8c, 0x00],
- darkorchid: [0x99, 0x32, 0xcc],
- darkred: [0x8b, 0x00, 0x00],
- darksalmon: [0xe9, 0x96, 0x7a],
- darkseagreen: [0x8f, 0xbc, 0x8f],
- darkslateblue: [0x48, 0x3d, 0x8b],
- darkslategray: [0x2f, 0x4f, 0x4f],
- darkslategrey: [0x2f, 0x4f, 0x4f],
- darkturquoise: [0x00, 0xce, 0xd1],
- darkviolet: [0x94, 0x00, 0xd3],
- deeppink: [0xff, 0x14, 0x93],
- deepskyblue: [0x00, 0xbf, 0xff],
- dimgray: [0x69, 0x69, 0x69],
- dimgrey: [0x69, 0x69, 0x69],
- dodgerblue: [0x1e, 0x90, 0xff],
- firebrick: [0xb2, 0x22, 0x22],
- floralwhite: [0xff, 0xfa, 0xf0],
- forestgreen: [0x22, 0x8b, 0x22],
- fuchsia: [0xff, 0x00, 0xff],
- gainsboro: [0xdc, 0xdc, 0xdc],
- ghostwhite: [0xf8, 0xf8, 0xff],
- gold: [0xff, 0xd7, 0x00],
- goldenrod: [0xda, 0xa5, 0x20],
- gray: [0x80, 0x80, 0x80],
- green: [0x00, 0x80, 0x00],
- greenyellow: [0xad, 0xff, 0x2f],
- grey: [0x80, 0x80, 0x80],
- honeydew: [0xf0, 0xff, 0xf0],
- hotpink: [0xff, 0x69, 0xb4],
- indianred: [0xcd, 0x5c, 0x5c],
- indigo: [0x4b, 0x00, 0x82],
- ivory: [0xff, 0xff, 0xf0],
- khaki: [0xf0, 0xe6, 0x8c],
- lavender: [0xe6, 0xe6, 0xfa],
- lavenderblush: [0xff, 0xf0, 0xf5],
- lawngreen: [0x7c, 0xfc, 0x00],
- lemonchiffon: [0xff, 0xfa, 0xcd],
- lightblue: [0xad, 0xd8, 0xe6],
- lightcoral: [0xf0, 0x80, 0x80],
- lightcyan: [0xe0, 0xff, 0xff],
- lightgoldenrodyellow: [0xfa, 0xfa, 0xd2],
- lightgray: [0xd3, 0xd3, 0xd3],
- lightgreen: [0x90, 0xee, 0x90],
- lightgrey: [0xd3, 0xd3, 0xd3],
- lightpink: [0xff, 0xb6, 0xc1],
- lightsalmon: [0xff, 0xa0, 0x7a],
- lightseagreen: [0x20, 0xb2, 0xaa],
- lightskyblue: [0x87, 0xce, 0xfa],
- lightslategray: [0x77, 0x88, 0x99],
- lightslategrey: [0x77, 0x88, 0x99],
- lightsteelblue: [0xb0, 0xc4, 0xde],
- lightyellow: [0xff, 0xff, 0xe0],
- lime: [0x00, 0xff, 0x00],
- limegreen: [0x32, 0xcd, 0x32],
- linen: [0xfa, 0xf0, 0xe6],
- magenta: [0xff, 0x00, 0xff],
- maroon: [0x80, 0x00, 0x00],
- mediumaquamarine: [0x66, 0xcd, 0xaa],
- mediumblue: [0x00, 0x00, 0xcd],
- mediumorchid: [0xba, 0x55, 0xd3],
- mediumpurple: [0x93, 0x70, 0xdb],
- mediumseagreen: [0x3c, 0xb3, 0x71],
- mediumslateblue: [0x7b, 0x68, 0xee],
- mediumspringgreen: [0x00, 0xfa, 0x9a],
- mediumturquoise: [0x48, 0xd1, 0xcc],
- mediumvioletred: [0xc7, 0x15, 0x85],
- midnightblue: [0x19, 0x19, 0x70],
- mintcream: [0xf5, 0xff, 0xfa],
- mistyrose: [0xff, 0xe4, 0xe1],
- moccasin: [0xff, 0xe4, 0xb5],
- navajowhite: [0xff, 0xde, 0xad],
- navy: [0x00, 0x00, 0x80],
- oldlace: [0xfd, 0xf5, 0xe6],
- olive: [0x80, 0x80, 0x00],
- olivedrab: [0x6b, 0x8e, 0x23],
- orange: [0xff, 0xa5, 0x00],
- orangered: [0xff, 0x45, 0x00],
- orchid: [0xda, 0x70, 0xd6],
- palegoldenrod: [0xee, 0xe8, 0xaa],
- palegreen: [0x98, 0xfb, 0x98],
- paleturquoise: [0xaf, 0xee, 0xee],
- palevioletred: [0xdb, 0x70, 0x93],
- papayawhip: [0xff, 0xef, 0xd5],
- peachpuff: [0xff, 0xda, 0xb9],
- peru: [0xcd, 0x85, 0x3f],
- pink: [0xff, 0xc0, 0xcb],
- plum: [0xdd, 0xa0, 0xdd],
- powderblue: [0xb0, 0xe0, 0xe6],
- purple: [0x80, 0x00, 0x80],
- rebeccapurple: [0x66, 0x33, 0x99],
- red: [0xff, 0x00, 0x00],
- rosybrown: [0xbc, 0x8f, 0x8f],
- royalblue: [0x41, 0x69, 0xe1],
- saddlebrown: [0x8b, 0x45, 0x13],
- salmon: [0xfa, 0x80, 0x72],
- sandybrown: [0xf4, 0xa4, 0x60],
- seagreen: [0x2e, 0x8b, 0x57],
- seashell: [0xff, 0xf5, 0xee],
- sienna: [0xa0, 0x52, 0x2d],
- silver: [0xc0, 0xc0, 0xc0],
- skyblue: [0x87, 0xce, 0xeb],
- slateblue: [0x6a, 0x5a, 0xcd],
- slategray: [0x70, 0x80, 0x90],
- slategrey: [0x70, 0x80, 0x90],
- snow: [0xff, 0xfa, 0xfa],
- springgreen: [0x00, 0xff, 0x7f],
- steelblue: [0x46, 0x82, 0xb4],
- tan: [0xd2, 0xb4, 0x8c],
- teal: [0x00, 0x80, 0x80],
- thistle: [0xd8, 0xbf, 0xd8],
- tomato: [0xff, 0x63, 0x47],
- turquoise: [0x40, 0xe0, 0xd0],
- violet: [0xee, 0x82, 0xee],
- wheat: [0xf5, 0xde, 0xb3],
- white: [0xff, 0xff, 0xff],
- whitesmoke: [0xf5, 0xf5, 0xf5],
- yellow: [0xff, 0xff, 0x00],
- yellowgreen: [0x9a, 0xcd, 0x32]
-} as const satisfies {
- [key: string]: TriColorChannels;
-};
-
-/**
- * cache invalid color value
- * @param key - cache key
- * @param nullable - is nullable
- * @returns cached value
- */
-export const cacheInvalidColorValue = (
- cacheKey: string,
- format: string,
- nullable: boolean = false
-): SpecifiedColorChannels | string | NullObject => {
- if (format === VAL_SPEC) {
- const res = '';
- setCache(cacheKey, res);
- return res;
- }
- if (nullable) {
- setCache(cacheKey, null);
- return new NullObject();
- }
- const res: SpecifiedColorChannels = ['rgb', 0, 0, 0, 0];
- setCache(cacheKey, res);
- return res;
-};
-
-/**
- * resolve invalid color value
- * @param format - output format
- * @param nullable - is nullable
- * @returns resolved value
- */
-export const resolveInvalidColorValue = (
- format: string,
- nullable: boolean = false
-): SpecifiedColorChannels | string | NullObject => {
- switch (format) {
- case 'hsl':
- case 'hwb':
- case VAL_MIX: {
- return new NullObject();
- }
- case VAL_SPEC: {
- return '';
- }
- default: {
- if (nullable) {
- return new NullObject();
- }
- return ['rgb', 0, 0, 0, 0] as SpecifiedColorChannels;
- }
- }
-};
-
-/**
- * validate color components
- * @param arr - color components
- * @param [opt] - options
- * @param [opt.alpha] - alpha channel
- * @param [opt.minLength] - min length
- * @param [opt.maxLength] - max length
- * @param [opt.minRange] - min range
- * @param [opt.maxRange] - max range
- * @param [opt.validateRange] - validate range
- * @returns result - validated color components
- */
-export const validateColorComponents = (
- arr: ColorChannels | TriColorChannels,
- opt: {
- alpha?: boolean;
- minLength?: number;
- maxLength?: number;
- minRange?: number;
- maxRange?: number;
- validateRange?: boolean;
- } = {}
-): ColorChannels | TriColorChannels => {
- if (!Array.isArray(arr)) {
- throw new TypeError(`${arr} is not an array.`);
- }
- const {
- alpha = false,
- minLength = TRIA,
- maxLength = QUAD,
- minRange = 0,
- maxRange = 1,
- validateRange = true
- } = opt;
- if (!Number.isFinite(minLength)) {
- throw new TypeError(`${minLength} is not a number.`);
- }
- if (!Number.isFinite(maxLength)) {
- throw new TypeError(`${maxLength} is not a number.`);
- }
- if (!Number.isFinite(minRange)) {
- throw new TypeError(`${minRange} is not a number.`);
- }
- if (!Number.isFinite(maxRange)) {
- throw new TypeError(`${maxRange} is not a number.`);
- }
- const l = arr.length;
- if (l < minLength || l > maxLength) {
- throw new Error(`Unexpected array length ${l}.`);
- }
- let i = 0;
- while (i < l) {
- const v = arr[i] as number;
- if (!Number.isFinite(v)) {
- throw new TypeError(`${v} is not a number.`);
- } else if (i < TRIA && validateRange && (v < minRange || v > maxRange)) {
- throw new RangeError(`${v} is not between ${minRange} and ${maxRange}.`);
- } else if (i === TRIA && (v < 0 || v > 1)) {
- throw new RangeError(`${v} is not between 0 and 1.`);
- }
- i++;
- }
- if (alpha && l === TRIA) {
- arr.push(1);
- }
- return arr;
-};
-
-/**
- * transform matrix
- * @param mtx - 3 * 3 matrix
- * @param vct - vector
- * @param [skip] - skip validate
- * @returns TriColorChannels - [p1, p2, p3]
- */
-export const transformMatrix = (
- mtx: ColorMatrix,
- vct: TriColorChannels,
- skip: boolean = false
-): TriColorChannels => {
- if (!Array.isArray(mtx)) {
- throw new TypeError(`${mtx} is not an array.`);
- } else if (mtx.length !== TRIA) {
- throw new Error(`Unexpected array length ${mtx.length}.`);
- } else if (!skip) {
- for (let i of mtx) {
- i = validateColorComponents(i as TriColorChannels, {
- maxLength: TRIA,
- validateRange: false
- }) as TriColorChannels;
- }
- }
- const [[r1c1, r1c2, r1c3], [r2c1, r2c2, r2c3], [r3c1, r3c2, r3c3]] = mtx;
- let v1, v2, v3;
- if (skip) {
- [v1, v2, v3] = vct;
- } else {
- [v1, v2, v3] = validateColorComponents(vct, {
- maxLength: TRIA,
- validateRange: false
- });
- }
- const p1 = r1c1 * v1 + r1c2 * v2 + r1c3 * v3;
- const p2 = r2c1 * v1 + r2c2 * v2 + r2c3 * v3;
- const p3 = r3c1 * v1 + r3c2 * v2 + r3c3 * v3;
- return [p1, p2, p3];
-};
-
-/**
- * normalize color components
- * @param colorA - color components [v1, v2, v3, v4]
- * @param colorB - color components [v1, v2, v3, v4]
- * @param [skip] - skip validate
- * @returns result - [colorA, colorB]
- */
-export const normalizeColorComponents = (
- colorA: [number | string, number | string, number | string, number | string],
- colorB: [number | string, number | string, number | string, number | string],
- skip: boolean = false
-): [ColorChannels, ColorChannels] => {
- if (!Array.isArray(colorA)) {
- throw new TypeError(`${colorA} is not an array.`);
- } else if (colorA.length !== QUAD) {
- throw new Error(`Unexpected array length ${colorA.length}.`);
- }
- if (!Array.isArray(colorB)) {
- throw new TypeError(`${colorB} is not an array.`);
- } else if (colorB.length !== QUAD) {
- throw new Error(`Unexpected array length ${colorB.length}.`);
- }
- let i = 0;
- while (i < QUAD) {
- if (colorA[i] === NONE && colorB[i] === NONE) {
- colorA[i] = 0;
- colorB[i] = 0;
- } else if (colorA[i] === NONE) {
- colorA[i] = colorB[i] as number;
- } else if (colorB[i] === NONE) {
- colorB[i] = colorA[i] as number;
- }
- i++;
- }
- if (skip) {
- return [colorA as ColorChannels, colorB as ColorChannels];
- }
- const validatedColorA = validateColorComponents(colorA as ColorChannels, {
- minLength: QUAD,
- validateRange: false
- });
- const validatedColorB = validateColorComponents(colorB as ColorChannels, {
- minLength: QUAD,
- validateRange: false
- });
- return [validatedColorA as ColorChannels, validatedColorB as ColorChannels];
-};
-
-/**
- * number to hex string
- * @param value - numeric value
- * @returns hex string
- */
-export const numberToHexString = (value: number): string => {
- if (!Number.isFinite(value)) {
- throw new TypeError(`${value} is not a number.`);
- } else {
- value = Math.round(value);
- if (value < 0 || value > MAX_RGB) {
- throw new RangeError(`${value} is not between 0 and ${MAX_RGB}.`);
- }
- }
- let hex = value.toString(HEX);
- if (hex.length === 1) {
- hex = `0${hex}`;
- }
- return hex;
-};
-
-/**
- * angle to deg
- * @param angle
- * @returns deg: 0..360
- */
-export const angleToDeg = (angle: string): number => {
- if (isString(angle)) {
- angle = angle.trim();
- } else {
- throw new TypeError(`${angle} is not a string.`);
- }
- const GRAD = DEG / 400;
- const RAD = DEG / (Math.PI * DUO);
- const reg = new RegExp(`^(${NUM})(${ANGLE})?$`);
- if (!reg.test(angle)) {
- throw new SyntaxError(`Invalid property value: ${angle}`);
- }
- const [, value, unit] = angle.match(reg) as MatchedRegExp;
- let deg;
- switch (unit) {
- case 'grad':
- deg = parseFloat(value) * GRAD;
- break;
- case 'rad':
- deg = parseFloat(value) * RAD;
- break;
- case 'turn':
- deg = parseFloat(value) * DEG;
- break;
- default:
- deg = parseFloat(value);
- }
- deg %= DEG;
- if (deg < 0) {
- deg += DEG;
- } else if (Object.is(deg, -0)) {
- deg = 0;
- }
- return deg;
-};
-
-/**
- * parse alpha
- * @param [alpha] - alpha value
- * @returns alpha: 0..1
- */
-export const parseAlpha = (alpha: string = ''): number => {
- if (isString(alpha)) {
- alpha = alpha.trim();
- if (!alpha) {
- alpha = '1';
- } else if (alpha === NONE) {
- alpha = '0';
- } else {
- let a;
- if (alpha.endsWith('%')) {
- a = parseFloat(alpha) / MAX_PCT;
- } else {
- a = parseFloat(alpha);
- }
- if (!Number.isFinite(a)) {
- throw new TypeError(`${a} is not a finite number.`);
- }
- if (a < PPTH) {
- alpha = '0';
- } else if (a > 1) {
- alpha = '1';
- } else {
- alpha = a.toFixed(TRIA);
- }
- }
- } else {
- alpha = '1';
- }
- return parseFloat(alpha);
-};
-
-/**
- * parse hex alpha
- * @param value - alpha value in hex string
- * @returns alpha: 0..1
- */
-export const parseHexAlpha = (value: string): number => {
- if (isString(value)) {
- if (value === '') {
- throw new SyntaxError('Invalid property value: (empty string)');
- }
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- let alpha = parseInt(value, HEX);
- if (alpha <= 0) {
- return 0;
- }
- if (alpha >= MAX_RGB) {
- return 1;
- }
- const alphaMap = new Map();
- for (let i = 1; i < MAX_PCT; i++) {
- alphaMap.set(Math.round((i * MAX_RGB) / MAX_PCT), i);
- }
- if (alphaMap.has(alpha)) {
- alpha = alphaMap.get(alpha) / MAX_PCT;
- } else {
- alpha = Math.round(alpha / MAX_RGB / PPTH) * PPTH;
- }
- return parseFloat(alpha.toFixed(TRIA));
-};
-
-/**
- * transform rgb to linear rgb
- * @param rgb - [r, g, b] r|g|b: 0..255
- * @param [skip] - skip validate
- * @returns TriColorChannels - [r, g, b] r|g|b: 0..1
- */
-export const transformRgbToLinearRgb = (
- rgb: TriColorChannels,
- skip: boolean = false
-): TriColorChannels => {
- let rr, gg, bb;
- if (skip) {
- [rr, gg, bb] = rgb;
- } else {
- [rr, gg, bb] = validateColorComponents(rgb, {
- maxLength: TRIA,
- maxRange: MAX_RGB
- });
- }
- let r = rr / MAX_RGB;
- let g = gg / MAX_RGB;
- let b = bb / MAX_RGB;
- const COND_POW = 0.04045;
- if (r > COND_POW) {
- r = Math.pow((r + LINEAR_OFFSET) / (1 + LINEAR_OFFSET), POW_LINEAR);
- } else {
- r /= LINEAR_COEF;
- }
- if (g > COND_POW) {
- g = Math.pow((g + LINEAR_OFFSET) / (1 + LINEAR_OFFSET), POW_LINEAR);
- } else {
- g /= LINEAR_COEF;
- }
- if (b > COND_POW) {
- b = Math.pow((b + LINEAR_OFFSET) / (1 + LINEAR_OFFSET), POW_LINEAR);
- } else {
- b /= LINEAR_COEF;
- }
- return [r, g, b];
-};
-
-/**
- * transform rgb to xyz
- * @param rgb - [r, g, b] r|g|b: 0..255
- * @param [skip] - skip validate
- * @returns TriColorChannels - [x, y, z]
- */
-export const transformRgbToXyz = (
- rgb: TriColorChannels,
- skip: boolean = false
-): TriColorChannels => {
- if (!skip) {
- rgb = validateColorComponents(rgb, {
- maxLength: TRIA,
- maxRange: MAX_RGB
- }) as TriColorChannels;
- }
- rgb = transformRgbToLinearRgb(rgb, true);
- const xyz = transformMatrix(MATRIX_L_RGB_TO_XYZ, rgb, true);
- return xyz;
-};
-
-/**
- * transform rgb to xyz-d50
- * @param rgb - [r, g, b] r|g|b: 0..255 alpha: 0..1
- * @returns TriColorChannels - [x, y, z]
- */
-export const transformRgbToXyzD50 = (
- rgb: TriColorChannels
-): TriColorChannels => {
- let xyz = transformRgbToXyz(rgb);
- xyz = transformMatrix(MATRIX_D65_TO_D50, xyz, true);
- return xyz;
-};
-
-/**
- * transform linear rgb to rgb
- * @param rgb - [r, g, b] r|g|b: 0..1
- * @param [round] - round result
- * @returns TriColorChannels - [r, g, b] r|g|b: 0..255
- */
-export const transformLinearRgbToRgb = (
- rgb: TriColorChannels,
- round: boolean = false
-): TriColorChannels => {
- let [r, g, b] = validateColorComponents(rgb, {
- maxLength: TRIA
- });
- const COND_POW = 809 / 258400;
- if (r > COND_POW) {
- r = Math.pow(r, 1 / POW_LINEAR) * (1 + LINEAR_OFFSET) - LINEAR_OFFSET;
- } else {
- r *= LINEAR_COEF;
- }
- r *= MAX_RGB;
- if (g > COND_POW) {
- g = Math.pow(g, 1 / POW_LINEAR) * (1 + LINEAR_OFFSET) - LINEAR_OFFSET;
- } else {
- g *= LINEAR_COEF;
- }
- g *= MAX_RGB;
- if (b > COND_POW) {
- b = Math.pow(b, 1 / POW_LINEAR) * (1 + LINEAR_OFFSET) - LINEAR_OFFSET;
- } else {
- b *= LINEAR_COEF;
- }
- b *= MAX_RGB;
- return [
- round ? Math.round(r) : r,
- round ? Math.round(g) : g,
- round ? Math.round(b) : b
- ];
-};
-
-/**
- * transform xyz to rgb
- * @param xyz - [x, y, z]
- * @param [skip] - skip validate
- * @returns TriColorChannels - [r, g, b] r|g|b: 0..255
- */
-export const transformXyzToRgb = (
- xyz: TriColorChannels,
- skip: boolean = false
-): TriColorChannels => {
- if (!skip) {
- xyz = validateColorComponents(xyz, {
- maxLength: TRIA,
- validateRange: false
- }) as TriColorChannels;
- }
- let [r, g, b] = transformMatrix(MATRIX_XYZ_TO_L_RGB, xyz, true);
- [r, g, b] = transformLinearRgbToRgb(
- [
- Math.min(Math.max(r, 0), 1),
- Math.min(Math.max(g, 0), 1),
- Math.min(Math.max(b, 0), 1)
- ],
- true
- );
- return [r, g, b];
-};
-
-/**
- * transform xyz to xyz-d50
- * @param xyz - [x, y, z]
- * @returns TriColorChannels - [x, y, z]
- */
-export const transformXyzToXyzD50 = (
- xyz: TriColorChannels
-): TriColorChannels => {
- xyz = validateColorComponents(xyz, {
- maxLength: TRIA,
- validateRange: false
- }) as TriColorChannels;
- xyz = transformMatrix(MATRIX_D65_TO_D50, xyz, true);
- return xyz;
-};
-
-/**
- * transform xyz to hsl
- * @param xyz - [x, y, z]
- * @param [skip] - skip validate
- * @returns TriColorChannels - [h, s, l]
- */
-export const transformXyzToHsl = (
- xyz: TriColorChannels,
- skip: boolean = false
-): TriColorChannels => {
- const [rr, gg, bb] = transformXyzToRgb(xyz, skip);
- const r = rr / MAX_RGB;
- const g = gg / MAX_RGB;
- const b = bb / MAX_RGB;
- const max = Math.max(r, g, b);
- const min = Math.min(r, g, b);
- const d = max - min;
- const l = (max + min) * HALF * MAX_PCT;
- let h, s;
- if (Math.round(l) === 0 || Math.round(l) === MAX_PCT) {
- h = 0;
- s = 0;
- } else {
- s = (d / (1 - Math.abs(max + min - 1))) * MAX_PCT;
- if (s === 0) {
- h = 0;
- } else {
- switch (max) {
- case r:
- h = (g - b) / d;
- break;
- case g:
- h = (b - r) / d + DUO;
- break;
- case b:
- default:
- h = (r - g) / d + QUAD;
- break;
- }
- h = (h * SEXA) % DEG;
- if (h < 0) {
- h += DEG;
- }
- }
- }
- return [h, s, l];
-};
-
-/**
- * transform xyz to hwb
- * @param xyz - [x, y, z]
- * @param [skip] - skip validate
- * @returns TriColorChannels - [h, w, b]
- */
-export const transformXyzToHwb = (
- xyz: TriColorChannels,
- skip: boolean = false
-): TriColorChannels => {
- const [r, g, b] = transformXyzToRgb(xyz, skip);
- const wh = Math.min(r, g, b) / MAX_RGB;
- const bk = 1 - Math.max(r, g, b) / MAX_RGB;
- let h;
- if (wh + bk === 1) {
- h = 0;
- } else {
- [h] = transformXyzToHsl(xyz);
- }
- return [h, wh * MAX_PCT, bk * MAX_PCT];
-};
-
-/**
- * transform xyz to oklab
- * @param xyz - [x, y, z]
- * @param [skip] - skip validate
- * @returns TriColorChannels - [l, a, b]
- */
-export const transformXyzToOklab = (
- xyz: TriColorChannels,
- skip: boolean = false
-): TriColorChannels => {
- if (!skip) {
- xyz = validateColorComponents(xyz, {
- maxLength: TRIA,
- validateRange: false
- }) as TriColorChannels;
- }
- const lms = transformMatrix(MATRIX_XYZ_TO_LMS, xyz, true);
- const xyzLms = lms.map(c => Math.cbrt(c)) as TriColorChannels;
- let [l, a, b] = transformMatrix(MATRIX_LMS_TO_OKLAB, xyzLms, true);
- l = Math.min(Math.max(l, 0), 1);
- const lPct = Math.round(parseFloat(l.toFixed(QUAD)) * MAX_PCT);
- if (lPct === 0 || lPct === MAX_PCT) {
- a = 0;
- b = 0;
- }
- return [l, a, b];
-};
-
-/**
- * transform xyz to oklch
- * @param xyz - [x, y, z]
- * @param [skip] - skip validate
- * @returns TriColorChannels - [l, c, h]
- */
-export const transformXyzToOklch = (
- xyz: TriColorChannels,
- skip: boolean = false
-): TriColorChannels => {
- const [l, a, b] = transformXyzToOklab(xyz, skip);
- let c, h;
- const lPct = Math.round(parseFloat(l.toFixed(QUAD)) * MAX_PCT);
- if (lPct === 0 || lPct === MAX_PCT) {
- c = 0;
- h = 0;
- } else {
- c = Math.max(Math.sqrt(Math.pow(a, POW_SQR) + Math.pow(b, POW_SQR)), 0);
- if (parseFloat(c.toFixed(QUAD)) === 0) {
- h = 0;
- } else {
- h = (Math.atan2(b, a) * DEG_HALF) / Math.PI;
- if (h < 0) {
- h += DEG;
- }
- }
- }
- return [l, c, h];
-};
-
-/**
- * transform xyz D50 to rgb
- * @param xyz - [x, y, z]
- * @param [skip] - skip validate
- * @returns TriColorChannels - [r, g, b] r|g|b: 0..255
- */
-export const transformXyzD50ToRgb = (
- xyz: TriColorChannels,
- skip: boolean = false
-): TriColorChannels => {
- if (!skip) {
- xyz = validateColorComponents(xyz, {
- maxLength: TRIA,
- validateRange: false
- }) as TriColorChannels;
- }
- const xyzD65 = transformMatrix(MATRIX_D50_TO_D65, xyz, true);
- const rgb = transformXyzToRgb(xyzD65, true);
- return rgb;
-};
-
-/**
- * transform xyz-d50 to lab
- * @param xyz - [x, y, z]
- * @param [skip] - skip validate
- * @returns TriColorChannels - [l, a, b]
- */
-export const transformXyzD50ToLab = (
- xyz: TriColorChannels,
- skip: boolean = false
-): TriColorChannels => {
- if (!skip) {
- xyz = validateColorComponents(xyz, {
- maxLength: TRIA,
- validateRange: false
- }) as TriColorChannels;
- }
- const xyzD50 = xyz.map((val, i) => val / (D50[i] as number));
- const [f0, f1, f2] = xyzD50.map(val =>
- val > LAB_EPSILON ? Math.cbrt(val) : (val * LAB_KAPPA + HEX) / LAB_L
- ) as TriColorChannels;
- const l = Math.min(Math.max(LAB_L * f1 - HEX, 0), MAX_PCT);
- let a, b;
- if (l === 0 || l === MAX_PCT) {
- a = 0;
- b = 0;
- } else {
- a = (f0 - f1) * LAB_A;
- b = (f1 - f2) * LAB_B;
- }
- return [l, a, b];
-};
-
-/**
- * transform xyz-d50 to lch
- * @param xyz - [x, y, z]
- * @param [skip] - skip validate
- * @returns TriColorChannels - [l, c, h]
- */
-export const transformXyzD50ToLch = (
- xyz: TriColorChannels,
- skip: boolean = false
-): TriColorChannels => {
- const [l, a, b] = transformXyzD50ToLab(xyz, skip);
- let c, h;
- if (l === 0 || l === MAX_PCT) {
- c = 0;
- h = 0;
- } else {
- c = Math.max(Math.sqrt(Math.pow(a, POW_SQR) + Math.pow(b, POW_SQR)), 0);
- h = (Math.atan2(b, a) * DEG_HALF) / Math.PI;
- if (h < 0) {
- h += DEG;
- }
- }
- return [l, c, h];
-};
-
-/**
- * convert rgb to hex color
- * @param rgb - [r, g, b, alpha] r|g|b: 0..255 alpha: 0..1
- * @returns hex color
- */
-export const convertRgbToHex = (rgb: ColorChannels): string => {
- const [r, g, b, alpha] = validateColorComponents(rgb, {
- alpha: true,
- maxRange: MAX_RGB
- }) as ColorChannels;
- const rr = numberToHexString(r);
- const gg = numberToHexString(g);
- const bb = numberToHexString(b);
- const aa = numberToHexString(alpha * MAX_RGB);
- let hex;
- if (aa === 'ff') {
- hex = `#${rr}${gg}${bb}`;
- } else {
- hex = `#${rr}${gg}${bb}${aa}`;
- }
- return hex;
-};
-
-/**
- * convert linear rgb to hex color
- * @param rgb - [r, g, b, alpha] r|g|b|alpha: 0..1
- * @param [skip] - skip validate
- * @returns hex color
- */
-export const convertLinearRgbToHex = (
- rgb: ColorChannels,
- skip: boolean = false
-): string => {
- let r, g, b, alpha;
- if (skip) {
- [r, g, b, alpha] = rgb;
- } else {
- [r, g, b, alpha] = validateColorComponents(rgb, {
- minLength: QUAD
- }) as ColorChannels;
- }
- [r, g, b] = transformLinearRgbToRgb([r, g, b], true);
- const rr = numberToHexString(r);
- const gg = numberToHexString(g);
- const bb = numberToHexString(b);
- const aa = numberToHexString(alpha * MAX_RGB);
- let hex;
- if (aa === 'ff') {
- hex = `#${rr}${gg}${bb}`;
- } else {
- hex = `#${rr}${gg}${bb}${aa}`;
- }
- return hex;
-};
-
-/**
- * convert xyz to hex color
- * @param xyz - [x, y, z, alpha]
- * @returns hex color
- */
-export const convertXyzToHex = (xyz: ColorChannels): string => {
- const [x, y, z, alpha] = validateColorComponents(xyz, {
- minLength: QUAD,
- validateRange: false
- }) as ColorChannels;
- const [r, g, b] = transformMatrix(MATRIX_XYZ_TO_L_RGB, [x, y, z], true);
- const hex = convertLinearRgbToHex(
- [
- Math.min(Math.max(r, 0), 1),
- Math.min(Math.max(g, 0), 1),
- Math.min(Math.max(b, 0), 1),
- alpha
- ],
- true
- );
- return hex;
-};
-
-/**
- * convert xyz D50 to hex color
- * @param xyz - [x, y, z, alpha]
- * @returns hex color
- */
-export const convertXyzD50ToHex = (xyz: ColorChannels): string => {
- const [x, y, z, alpha] = validateColorComponents(xyz, {
- minLength: QUAD,
- validateRange: false
- }) as ColorChannels;
- const xyzD65 = transformMatrix(MATRIX_D50_TO_D65, [x, y, z], true);
- const [r, g, b] = transformMatrix(MATRIX_XYZ_TO_L_RGB, xyzD65, true);
- const hex = convertLinearRgbToHex([
- Math.min(Math.max(r, 0), 1),
- Math.min(Math.max(g, 0), 1),
- Math.min(Math.max(b, 0), 1),
- alpha
- ]);
- return hex;
-};
-
-/**
- * convert hex color to rgb
- * @param value - hex color value
- * @returns ColorChannels - [r, g, b, alpha] r|g|b: 0..255 alpha: 0..1
- */
-export const convertHexToRgb = (value: string): ColorChannels => {
- if (isString(value)) {
- value = value.toLowerCase().trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- if (
- !(
- /^#[\da-f]{6}$/.test(value) ||
- /^#[\da-f]{3}$/.test(value) ||
- /^#[\da-f]{8}$/.test(value) ||
- /^#[\da-f]{4}$/.test(value)
- )
- ) {
- throw new SyntaxError(`Invalid property value: ${value}`);
- }
- const arr: number[] = [];
- if (/^#[\da-f]{3}$/.test(value)) {
- const [, r, g, b] = value.match(
- /^#([\da-f])([\da-f])([\da-f])$/
- ) as MatchedRegExp;
- arr.push(
- parseInt(`${r}${r}`, HEX),
- parseInt(`${g}${g}`, HEX),
- parseInt(`${b}${b}`, HEX),
- 1
- );
- } else if (/^#[\da-f]{4}$/.test(value)) {
- const [, r, g, b, alpha] = value.match(
- /^#([\da-f])([\da-f])([\da-f])([\da-f])$/
- ) as MatchedRegExp;
- arr.push(
- parseInt(`${r}${r}`, HEX),
- parseInt(`${g}${g}`, HEX),
- parseInt(`${b}${b}`, HEX),
- parseHexAlpha(`${alpha}${alpha}`)
- );
- } else if (/^#[\da-f]{8}$/.test(value)) {
- const [, r, g, b, alpha] = value.match(
- /^#([\da-f]{2})([\da-f]{2})([\da-f]{2})([\da-f]{2})$/
- ) as MatchedRegExp;
- arr.push(
- parseInt(r, HEX),
- parseInt(g, HEX),
- parseInt(b, HEX),
- parseHexAlpha(alpha)
- );
- } else {
- const [, r, g, b] = value.match(
- /^#([\da-f]{2})([\da-f]{2})([\da-f]{2})$/
- ) as MatchedRegExp;
- arr.push(parseInt(r, HEX), parseInt(g, HEX), parseInt(b, HEX), 1);
- }
- return arr as ColorChannels;
-};
-
-/**
- * convert hex color to linear rgb
- * @param value - hex color value
- * @returns ColorChannels - [r, g, b, alpha] r|g|b|alpha: 0..1
- */
-export const convertHexToLinearRgb = (value: string): ColorChannels => {
- const [rr, gg, bb, alpha] = convertHexToRgb(value);
- const [r, g, b] = transformRgbToLinearRgb([rr, gg, bb], true);
- return [r, g, b, alpha];
-};
-
-/**
- * convert hex color to xyz
- * @param value - hex color value
- * @returns ColorChannels - [x, y, z, alpha]
- */
-export const convertHexToXyz = (value: string): ColorChannels => {
- const [r, g, b, alpha] = convertHexToLinearRgb(value);
- const [x, y, z] = transformMatrix(MATRIX_L_RGB_TO_XYZ, [r, g, b], true);
- return [x, y, z, alpha];
-};
-
-/**
- * parse rgb()
- * @param value - rgb color value
- * @param [opt] - options
- * @returns parsed color - ['rgb', r, g, b, alpha], '(empty)', NullObject
- */
-export const parseRgb = (
- value: string,
- opt: Options = {}
-): SpecifiedColorChannels | string | NullObject => {
- if (isString(value)) {
- value = value.toLowerCase().trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '', nullable = false } = opt;
- const reg = new RegExp(`^rgba?\\(\\s*(${SYN_MOD}|${SYN_RGB_LV3})\\s*\\)$`);
- if (!reg.test(value)) {
- const res = resolveInvalidColorValue(format, nullable);
- if (res instanceof NullObject) {
- return res;
- }
- if (isString(res)) {
- return res as string;
- }
- return res as SpecifiedColorChannels;
- }
- const [, val] = value.match(reg) as MatchedRegExp;
- const [v1, v2, v3, v4 = ''] = val
- .replace(/[,/]/g, ' ')
- .split(/\s+/) as StringColorChannels;
- let r, g, b;
- if (v1 === NONE) {
- r = 0;
- } else {
- if (v1.endsWith('%')) {
- r = (parseFloat(v1) * MAX_RGB) / MAX_PCT;
- } else {
- r = parseFloat(v1);
- }
- r = Math.min(Math.max(roundToPrecision(r, OCT), 0), MAX_RGB);
- }
- if (v2 === NONE) {
- g = 0;
- } else {
- if (v2.endsWith('%')) {
- g = (parseFloat(v2) * MAX_RGB) / MAX_PCT;
- } else {
- g = parseFloat(v2);
- }
- g = Math.min(Math.max(roundToPrecision(g, OCT), 0), MAX_RGB);
- }
- if (v3 === NONE) {
- b = 0;
- } else {
- if (v3.endsWith('%')) {
- b = (parseFloat(v3) * MAX_RGB) / MAX_PCT;
- } else {
- b = parseFloat(v3);
- }
- b = Math.min(Math.max(roundToPrecision(b, OCT), 0), MAX_RGB);
- }
- const alpha = parseAlpha(v4);
- return ['rgb', r, g, b, format === VAL_MIX && v4 === NONE ? NONE : alpha];
-};
-
-/**
- * parse hsl()
- * @param value - hsl color value
- * @param [opt] - options
- * @returns parsed color - ['rgb', r, g, b, alpha], '(empty)', NullObject
- */
-export const parseHsl = (
- value: string,
- opt: Options = {}
-): SpecifiedColorChannels | string | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '', nullable = false } = opt;
- if (!REG_HSL.test(value)) {
- const res = resolveInvalidColorValue(format, nullable);
- if (res instanceof NullObject) {
- return res;
- }
- if (isString(res)) {
- return res as string;
- }
- return res as SpecifiedColorChannels;
- }
- const [, val] = value.match(REG_HSL) as MatchedRegExp;
- const [v1, v2, v3, v4 = ''] = val
- .replace(/[,/]/g, ' ')
- .split(/\s+/) as StringColorChannels;
- let h, s, l;
- if (v1 === NONE) {
- h = 0;
- } else {
- h = angleToDeg(v1);
- }
- if (v2 === NONE) {
- s = 0;
- } else {
- s = Math.min(Math.max(parseFloat(v2), 0), MAX_PCT);
- }
- if (v3 === NONE) {
- l = 0;
- } else {
- l = Math.min(Math.max(parseFloat(v3), 0), MAX_PCT);
- }
- const alpha = parseAlpha(v4);
- if (format === 'hsl') {
- return [
- format,
- v1 === NONE ? v1 : h,
- v2 === NONE ? v2 : s,
- v3 === NONE ? v3 : l,
- v4 === NONE ? v4 : alpha
- ];
- }
- h = (h / DEG) * DOZ;
- l /= MAX_PCT;
- const sa = (s / MAX_PCT) * Math.min(l, 1 - l);
- const rk = h % DOZ;
- const gk = (8 + h) % DOZ;
- const bk = (4 + h) % DOZ;
- const r = l - sa * Math.max(-1, Math.min(rk - TRIA, TRIA ** POW_SQR - rk, 1));
- const g = l - sa * Math.max(-1, Math.min(gk - TRIA, TRIA ** POW_SQR - gk, 1));
- const b = l - sa * Math.max(-1, Math.min(bk - TRIA, TRIA ** POW_SQR - bk, 1));
- return [
- 'rgb',
- Math.min(Math.max(roundToPrecision(r * MAX_RGB, OCT), 0), MAX_RGB),
- Math.min(Math.max(roundToPrecision(g * MAX_RGB, OCT), 0), MAX_RGB),
- Math.min(Math.max(roundToPrecision(b * MAX_RGB, OCT), 0), MAX_RGB),
- alpha
- ];
-};
-
-/**
- * parse hwb()
- * @param value - hwb color value
- * @param [opt] - options
- * @returns parsed color - ['rgb', r, g, b, alpha], '(empty)', NullObject
- */
-export const parseHwb = (
- value: string,
- opt: Options = {}
-): SpecifiedColorChannels | string | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '', nullable = false } = opt;
- if (!REG_HWB.test(value)) {
- const res = resolveInvalidColorValue(format, nullable);
- if (res instanceof NullObject) {
- return res;
- }
- if (isString(res)) {
- return res as string;
- }
- return res as SpecifiedColorChannels;
- }
- const [, val] = value.match(REG_HWB) as MatchedRegExp;
- const [v1, v2, v3, v4 = ''] = val
- .replace('/', ' ')
- .split(/\s+/) as StringColorChannels;
- let h, wh, bk;
- if (v1 === NONE) {
- h = 0;
- } else {
- h = angleToDeg(v1);
- }
- if (v2 === NONE) {
- wh = 0;
- } else {
- wh = Math.min(Math.max(parseFloat(v2), 0), MAX_PCT) / MAX_PCT;
- }
- if (v3 === NONE) {
- bk = 0;
- } else {
- bk = Math.min(Math.max(parseFloat(v3), 0), MAX_PCT) / MAX_PCT;
- }
- const alpha = parseAlpha(v4);
- if (format === 'hwb') {
- return [
- format,
- v1 === NONE ? v1 : h,
- v2 === NONE ? v2 : wh * MAX_PCT,
- v3 === NONE ? v3 : bk * MAX_PCT,
- v4 === NONE ? v4 : alpha
- ];
- }
- if (wh + bk >= 1) {
- const v = roundToPrecision((wh / (wh + bk)) * MAX_RGB, OCT);
- return ['rgb', v, v, v, alpha];
- }
- const factor = (1 - wh - bk) / MAX_RGB;
- let [, r, g, b] = parseHsl(`hsl(${h} 100 50)`) as ComputedColorChannels;
- r = roundToPrecision((r * factor + wh) * MAX_RGB, OCT);
- g = roundToPrecision((g * factor + wh) * MAX_RGB, OCT);
- b = roundToPrecision((b * factor + wh) * MAX_RGB, OCT);
- return [
- 'rgb',
- Math.min(Math.max(r, 0), MAX_RGB),
- Math.min(Math.max(g, 0), MAX_RGB),
- Math.min(Math.max(b, 0), MAX_RGB),
- alpha
- ];
-};
-
-/**
- * parse lab()
- * @param value - lab color value
- * @param [opt] - options
- * @returns parsed color
- * - [xyz-d50, x, y, z, alpha], ['lab', l, a, b, alpha], '(empty)', NullObject
- */
-export const parseLab = (
- value: string,
- opt: Options = {}
-): SpecifiedColorChannels | string | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '', nullable = false } = opt;
- if (!REG_LAB.test(value)) {
- const res = resolveInvalidColorValue(format, nullable);
- if (res instanceof NullObject) {
- return res;
- }
- if (isString(res)) {
- return res as string;
- }
- return res as SpecifiedColorChannels;
- }
- const COEF_PCT = 1.25;
- const COND_POW = 8;
- const [, val] = value.match(REG_LAB) as MatchedRegExp;
- const [v1, v2, v3, v4 = ''] = val
- .replace('/', ' ')
- .split(/\s+/) as StringColorChannels;
- let l, a, b;
- if (v1 === NONE) {
- l = 0;
- } else {
- if (v1.endsWith('%')) {
- l = parseFloat(v1);
- if (l > MAX_PCT) {
- l = MAX_PCT;
- }
- } else {
- l = parseFloat(v1);
- }
- if (l < 0) {
- l = 0;
- }
- }
- if (v2 === NONE) {
- a = 0;
- } else {
- a = v2.endsWith('%') ? parseFloat(v2) * COEF_PCT : parseFloat(v2);
- }
- if (v3 === NONE) {
- b = 0;
- } else {
- b = v3.endsWith('%') ? parseFloat(v3) * COEF_PCT : parseFloat(v3);
- }
- const alpha = parseAlpha(v4);
- if (REG_SPEC.test(format)) {
- return [
- 'lab',
- v1 === NONE ? v1 : roundToPrecision(l, HEX),
- v2 === NONE ? v2 : roundToPrecision(a, HEX),
- v3 === NONE ? v3 : roundToPrecision(b, HEX),
- v4 === NONE ? v4 : alpha
- ];
- }
- const fl = (l + HEX) / LAB_L;
- const fa = a / LAB_A + fl;
- const fb = fl - b / LAB_B;
- const powFl = Math.pow(fl, POW_CUBE);
- const powFa = Math.pow(fa, POW_CUBE);
- const powFb = Math.pow(fb, POW_CUBE);
- const xyz = [
- powFa > LAB_EPSILON ? powFa : (fa * LAB_L - HEX) / LAB_KAPPA,
- l > COND_POW ? powFl : l / LAB_KAPPA,
- powFb > LAB_EPSILON ? powFb : (fb * LAB_L - HEX) / LAB_KAPPA
- ];
- const [x, y, z] = xyz.map(
- (val, i) => val * (D50[i] as number)
- ) as TriColorChannels;
- return [
- 'xyz-d50',
- roundToPrecision(x, HEX),
- roundToPrecision(y, HEX),
- roundToPrecision(z, HEX),
- alpha
- ];
-};
-
-/**
- * parse lch()
- * @param value - lch color value
- * @param [opt] - options
- * @returns parsed color
- * - ['xyz-d50', x, y, z, alpha], ['lch', l, c, h, alpha]
- * - '(empty)', NullObject
- */
-export const parseLch = (
- value: string,
- opt: Options = {}
-): SpecifiedColorChannels | string | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '', nullable = false } = opt;
- if (!REG_LCH.test(value)) {
- const res = resolveInvalidColorValue(format, nullable);
- if (res instanceof NullObject) {
- return res;
- }
- if (isString(res)) {
- return res as string;
- }
- return res as SpecifiedColorChannels;
- }
- const COEF_PCT = 1.5;
- const [, val] = value.match(REG_LCH) as MatchedRegExp;
- const [v1, v2, v3, v4 = ''] = val
- .replace('/', ' ')
- .split(/\s+/) as StringColorChannels;
- let l, c, h;
- if (v1 === NONE) {
- l = 0;
- } else {
- l = parseFloat(v1);
- if (l < 0) {
- l = 0;
- }
- }
- if (v2 === NONE) {
- c = 0;
- } else {
- c = v2.endsWith('%') ? parseFloat(v2) * COEF_PCT : parseFloat(v2);
- }
- if (v3 === NONE) {
- h = 0;
- } else {
- h = angleToDeg(v3);
- }
- const alpha = parseAlpha(v4);
- if (REG_SPEC.test(format)) {
- return [
- 'lch',
- v1 === NONE ? v1 : roundToPrecision(l, HEX),
- v2 === NONE ? v2 : roundToPrecision(c, HEX),
- v3 === NONE ? v3 : roundToPrecision(h, HEX),
- v4 === NONE ? v4 : alpha
- ];
- }
- const a = c * Math.cos((h * Math.PI) / DEG_HALF);
- const b = c * Math.sin((h * Math.PI) / DEG_HALF);
- const [, x, y, z] = parseLab(`lab(${l} ${a} ${b})`) as ComputedColorChannels;
- return [
- 'xyz-d50',
- roundToPrecision(x, HEX),
- roundToPrecision(y, HEX),
- roundToPrecision(z, HEX),
- alpha as number
- ];
-};
-
-/**
- * parse oklab()
- * @param value - oklab color value
- * @param [opt] - options
- * @returns parsed color
- * - ['xyz-d65', x, y, z, alpha], ['oklab', l, a, b, alpha]
- * - '(empty)', NullObject
- */
-export const parseOklab = (
- value: string,
- opt: Options = {}
-): SpecifiedColorChannels | string | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '', nullable = false } = opt;
- if (!REG_OKLAB.test(value)) {
- const res = resolveInvalidColorValue(format, nullable);
- if (res instanceof NullObject) {
- return res;
- }
- if (isString(res)) {
- return res as string;
- }
- return res as SpecifiedColorChannels;
- }
- const COEF_PCT = 0.4;
- const [, val] = value.match(REG_OKLAB) as MatchedRegExp;
- const [v1, v2, v3, v4 = ''] = val
- .replace('/', ' ')
- .split(/\s+/) as StringColorChannels;
- let l, a, b;
- if (v1 === NONE) {
- l = 0;
- } else {
- l = v1.endsWith('%') ? parseFloat(v1) / MAX_PCT : parseFloat(v1);
- if (l < 0) {
- l = 0;
- }
- }
- if (v2 === NONE) {
- a = 0;
- } else if (v2.endsWith('%')) {
- a = (parseFloat(v2) * COEF_PCT) / MAX_PCT;
- } else {
- a = parseFloat(v2);
- }
- if (v3 === NONE) {
- b = 0;
- } else if (v3.endsWith('%')) {
- b = (parseFloat(v3) * COEF_PCT) / MAX_PCT;
- } else {
- b = parseFloat(v3);
- }
- const alpha = parseAlpha(v4);
- if (REG_SPEC.test(format)) {
- return [
- 'oklab',
- v1 === NONE ? v1 : roundToPrecision(l, HEX),
- v2 === NONE ? v2 : roundToPrecision(a, HEX),
- v3 === NONE ? v3 : roundToPrecision(b, HEX),
- v4 === NONE ? v4 : alpha
- ];
- }
- const lms = transformMatrix(MATRIX_OKLAB_TO_LMS, [l, a, b]);
- const xyzLms = lms.map(c => Math.pow(c, POW_CUBE)) as TriColorChannels;
- const [x, y, z] = transformMatrix(MATRIX_LMS_TO_XYZ, xyzLms, true);
- return [
- 'xyz-d65',
- roundToPrecision(x, HEX),
- roundToPrecision(y, HEX),
- roundToPrecision(z, HEX),
- alpha as number
- ];
-};
-
-/**
- * parse oklch()
- * @param value - oklch color value
- * @param [opt] - options
- * @returns parsed color
- * - ['xyz-d65', x, y, z, alpha], ['oklch', l, c, h, alpha]
- * - '(empty)', NullObject
- */
-export const parseOklch = (
- value: string,
- opt: Options = {}
-): SpecifiedColorChannels | string | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '', nullable = false } = opt;
- if (!REG_OKLCH.test(value)) {
- const res = resolveInvalidColorValue(format, nullable);
- if (res instanceof NullObject) {
- return res;
- }
- if (isString(res)) {
- return res as string;
- }
- return res as SpecifiedColorChannels;
- }
- const COEF_PCT = 0.4;
- const [, val] = value.match(REG_OKLCH) as MatchedRegExp;
- const [v1, v2, v3, v4 = ''] = val
- .replace('/', ' ')
- .split(/\s+/) as StringColorChannels;
- let l, c, h;
- if (v1 === NONE) {
- l = 0;
- } else {
- l = v1.endsWith('%') ? parseFloat(v1) / MAX_PCT : parseFloat(v1);
- if (l < 0) {
- l = 0;
- }
- }
- if (v2 === NONE) {
- c = 0;
- } else {
- if (v2.endsWith('%')) {
- c = (parseFloat(v2) * COEF_PCT) / MAX_PCT;
- } else {
- c = parseFloat(v2);
- }
- if (c < 0) {
- c = 0;
- }
- }
- if (v3 === NONE) {
- h = 0;
- } else {
- h = angleToDeg(v3);
- }
- const alpha = parseAlpha(v4);
- if (REG_SPEC.test(format)) {
- return [
- 'oklch',
- v1 === NONE ? v1 : roundToPrecision(l, HEX),
- v2 === NONE ? v2 : roundToPrecision(c, HEX),
- v3 === NONE ? v3 : roundToPrecision(h, HEX),
- v4 === NONE ? v4 : alpha
- ];
- }
- const a = c * Math.cos((h * Math.PI) / DEG_HALF);
- const b = c * Math.sin((h * Math.PI) / DEG_HALF);
- const lms = transformMatrix(MATRIX_OKLAB_TO_LMS, [l, a, b]);
- const xyzLms = lms.map(cc => Math.pow(cc, POW_CUBE)) as TriColorChannels;
- const [x, y, z] = transformMatrix(MATRIX_LMS_TO_XYZ, xyzLms, true);
- return [
- 'xyz-d65',
- roundToPrecision(x, HEX),
- roundToPrecision(y, HEX),
- roundToPrecision(z, HEX),
- alpha
- ];
-};
-
-/**
- * parse color()
- * @param value - color function value
- * @param [opt] - options
- * @returns parsed color
- * - ['xyz-(d50|d65)', x, y, z, alpha], [cs, r, g, b, alpha]
- * - '(empty)', NullObject
- */
-export const parseColorFunc = (
- value: string,
- opt: Options = {}
-): SpecifiedColorChannels | string | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { colorSpace = '', d50 = false, format = '', nullable = false } = opt;
- if (!REG_FN_COLOR.test(value)) {
- const res = resolveInvalidColorValue(format, nullable);
- if (res instanceof NullObject) {
- return res;
- }
- if (isString(res)) {
- return res as string;
- }
- return res as SpecifiedColorChannels;
- }
- const [, val] = value.match(REG_FN_COLOR) as MatchedRegExp;
- let [cs, v1, v2, v3, v4 = ''] = val
- .replace('/', ' ')
- .split(/\s+/) as StringColorSpacedChannels;
- let r, g, b;
- if (cs === 'xyz') {
- cs = 'xyz-d65';
- }
- if (v1 === NONE) {
- r = 0;
- } else {
- r = v1.endsWith('%') ? parseFloat(v1) / MAX_PCT : parseFloat(v1);
- }
- if (v2 === NONE) {
- g = 0;
- } else {
- g = v2.endsWith('%') ? parseFloat(v2) / MAX_PCT : parseFloat(v2);
- }
- if (v3 === NONE) {
- b = 0;
- } else {
- b = v3.endsWith('%') ? parseFloat(v3) / MAX_PCT : parseFloat(v3);
- }
- const alpha = parseAlpha(v4);
- if (REG_SPEC.test(format) || (format === VAL_MIX && cs === colorSpace)) {
- return [
- cs,
- v1 === NONE ? v1 : roundToPrecision(r, DEC),
- v2 === NONE ? v2 : roundToPrecision(g, DEC),
- v3 === NONE ? v3 : roundToPrecision(b, DEC),
- v4 === NONE ? v4 : alpha
- ];
- }
- let x = 0;
- let y = 0;
- let z = 0;
- // srgb-linear
- if (cs === 'srgb-linear') {
- [x, y, z] = transformMatrix(MATRIX_L_RGB_TO_XYZ, [r, g, b]);
- if (d50) {
- [x, y, z] = transformMatrix(MATRIX_D65_TO_D50, [x, y, z], true);
- }
- // display-p3
- } else if (cs === 'display-p3') {
- const linearRgb = transformRgbToLinearRgb([
- r * MAX_RGB,
- g * MAX_RGB,
- b * MAX_RGB
- ]);
- [x, y, z] = transformMatrix(MATRIX_P3_TO_XYZ, linearRgb);
- if (d50) {
- [x, y, z] = transformMatrix(MATRIX_D65_TO_D50, [x, y, z], true);
- }
- // rec2020
- } else if (cs === 'rec2020') {
- const ALPHA = 1.09929682680944;
- const BETA = 0.018053968510807;
- const REC_COEF = 0.45;
- const rgb = [r, g, b].map(c => {
- let cl;
- if (c < BETA * REC_COEF * DEC) {
- cl = c / (REC_COEF * DEC);
- } else {
- cl = Math.pow((c + ALPHA - 1) / ALPHA, 1 / REC_COEF);
- }
- return cl;
- }) as TriColorChannels;
- [x, y, z] = transformMatrix(MATRIX_REC2020_TO_XYZ, rgb);
- if (d50) {
- [x, y, z] = transformMatrix(MATRIX_D65_TO_D50, [x, y, z], true);
- }
- // a98-rgb
- } else if (cs === 'a98-rgb') {
- const POW_A98 = 563 / 256;
- const rgb = [r, g, b].map(c => {
- const cl = Math.pow(c, POW_A98);
- return cl;
- }) as TriColorChannels;
- [x, y, z] = transformMatrix(MATRIX_A98_TO_XYZ, rgb);
- if (d50) {
- [x, y, z] = transformMatrix(MATRIX_D65_TO_D50, [x, y, z], true);
- }
- // prophoto-rgb
- } else if (cs === 'prophoto-rgb') {
- const POW_PROPHOTO = 1.8;
- const rgb = [r, g, b].map(c => {
- let cl;
- if (c > 1 / (HEX * DUO)) {
- cl = Math.pow(c, POW_PROPHOTO);
- } else {
- cl = c / HEX;
- }
- return cl;
- }) as TriColorChannels;
- [x, y, z] = transformMatrix(MATRIX_PROPHOTO_TO_XYZ_D50, rgb);
- if (!d50) {
- [x, y, z] = transformMatrix(MATRIX_D50_TO_D65, [x, y, z], true);
- }
- // xyz, xyz-d50, xyz-d65
- } else if (/^xyz(?:-d(?:50|65))?$/.test(cs)) {
- [x, y, z] = [r, g, b];
- if (cs === 'xyz-d50') {
- if (!d50) {
- [x, y, z] = transformMatrix(MATRIX_D50_TO_D65, [x, y, z]);
- }
- } else if (d50) {
- [x, y, z] = transformMatrix(MATRIX_D65_TO_D50, [x, y, z], true);
- }
- // srgb
- } else {
- [x, y, z] = transformRgbToXyz([r * MAX_RGB, g * MAX_RGB, b * MAX_RGB]);
- if (d50) {
- [x, y, z] = transformMatrix(MATRIX_D65_TO_D50, [x, y, z], true);
- }
- }
- return [
- d50 ? 'xyz-d50' : 'xyz-d65',
- roundToPrecision(x, HEX),
- roundToPrecision(y, HEX),
- roundToPrecision(z, HEX),
- format === VAL_MIX && v4 === NONE ? v4 : alpha
- ];
-};
-
-/**
- * parse color value
- * @param value - CSS color value
- * @param [opt] - options
- * @returns parsed color
- * - ['xyz-(d50|d65)', x, y, z, alpha], ['rgb', r, g, b, alpha]
- * - value, '(empty)', NullObject
- */
-export const parseColorValue = (
- value: string,
- opt: Options = {}
-): SpecifiedColorChannels | string | NullObject => {
- if (isString(value)) {
- value = value.toLowerCase().trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { d50 = false, format = '', nullable = false } = opt;
- if (!REG_COLOR.test(value)) {
- const res = resolveInvalidColorValue(format, nullable);
- if (res instanceof NullObject) {
- return res;
- }
- if (isString(res)) {
- return res as string;
- }
- return res as SpecifiedColorChannels;
- }
- let x = 0;
- let y = 0;
- let z = 0;
- let alpha = 0;
- // complement currentcolor as a missing color
- if (REG_CURRENT.test(value)) {
- if (format === VAL_COMP) {
- return ['rgb', 0, 0, 0, 0];
- }
- if (format === VAL_SPEC) {
- return value;
- }
- // named-color
- } else if (/^[a-z]+$/.test(value)) {
- if (Object.prototype.hasOwnProperty.call(NAMED_COLORS, value)) {
- if (format === VAL_SPEC) {
- return value;
- }
- const [r, g, b] = NAMED_COLORS[
- value as keyof typeof NAMED_COLORS
- ] as TriColorChannels;
- alpha = 1;
- if (format === VAL_COMP) {
- return ['rgb', r, g, b, alpha];
- }
- [x, y, z] = transformRgbToXyz([r, g, b], true);
- if (d50) {
- [x, y, z] = transformMatrix(MATRIX_D65_TO_D50, [x, y, z], true);
- }
- } else {
- switch (format) {
- case VAL_COMP: {
- if (nullable && value !== 'transparent') {
- return new NullObject();
- }
- return ['rgb', 0, 0, 0, 0];
- }
- case VAL_SPEC: {
- if (value === 'transparent') {
- return value;
- }
- return '';
- }
- case VAL_MIX: {
- if (value === 'transparent') {
- return ['rgb', 0, 0, 0, 0];
- }
- return new NullObject();
- }
- default:
- }
- }
- // hex-color
- } else if (value[0] === '#') {
- if (REG_SPEC.test(format)) {
- const rgb = convertHexToRgb(value);
- return ['rgb', ...rgb];
- }
- [x, y, z, alpha] = convertHexToXyz(value);
- if (d50) {
- [x, y, z] = transformMatrix(MATRIX_D65_TO_D50, [x, y, z], true);
- }
- // lab()
- } else if (value.startsWith('lab')) {
- if (REG_SPEC.test(format)) {
- return parseLab(value, opt);
- }
- [, x, y, z, alpha] = parseLab(value) as ComputedColorChannels;
- if (!d50) {
- [x, y, z] = transformMatrix(MATRIX_D50_TO_D65, [x, y, z], true);
- }
- // lch()
- } else if (value.startsWith('lch')) {
- if (REG_SPEC.test(format)) {
- return parseLch(value, opt);
- }
- [, x, y, z, alpha] = parseLch(value) as ComputedColorChannels;
- if (!d50) {
- [x, y, z] = transformMatrix(MATRIX_D50_TO_D65, [x, y, z], true);
- }
- // oklab()
- } else if (value.startsWith('oklab')) {
- if (REG_SPEC.test(format)) {
- return parseOklab(value, opt);
- }
- [, x, y, z, alpha] = parseOklab(value) as ComputedColorChannels;
- if (d50) {
- [x, y, z] = transformMatrix(MATRIX_D65_TO_D50, [x, y, z], true);
- }
- // oklch()
- } else if (value.startsWith('oklch')) {
- if (REG_SPEC.test(format)) {
- return parseOklch(value, opt);
- }
- [, x, y, z, alpha] = parseOklch(value) as ComputedColorChannels;
- if (d50) {
- [x, y, z] = transformMatrix(MATRIX_D65_TO_D50, [x, y, z], true);
- }
- } else {
- let r, g, b;
- // hsl()
- if (value.startsWith('hsl')) {
- [, r, g, b, alpha] = parseHsl(value) as ComputedColorChannels;
- // hwb()
- } else if (value.startsWith('hwb')) {
- [, r, g, b, alpha] = parseHwb(value) as ComputedColorChannels;
- // rgb()
- } else {
- [, r, g, b, alpha] = parseRgb(value, opt) as ComputedColorChannels;
- }
- if (REG_SPEC.test(format)) {
- return ['rgb', Math.round(r), Math.round(g), Math.round(b), alpha];
- }
- [x, y, z] = transformRgbToXyz([r, g, b]);
- if (d50) {
- [x, y, z] = transformMatrix(MATRIX_D65_TO_D50, [x, y, z], true);
- }
- }
- return [
- d50 ? 'xyz-d50' : 'xyz-d65',
- roundToPrecision(x, HEX),
- roundToPrecision(y, HEX),
- roundToPrecision(z, HEX),
- alpha
- ];
-};
-
-/**
- * resolve color value
- * @param value - CSS color value
- * @param [opt] - options
- * @returns resolved color
- * - [cs, v1, v2, v3, alpha], value, '(empty)', NullObject
- */
-export const resolveColorValue = (
- value: string,
- opt: Options = {}
-): SpecifiedColorChannels | string | NullObject => {
- if (isString(value)) {
- value = value.toLowerCase().trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { colorSpace = '', format = '', nullable = false } = opt;
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'resolveColorValue',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- if (cachedResult.isNull) {
- return cachedResult as NullObject;
- }
- const cachedItem = cachedResult.item;
- if (isString(cachedItem)) {
- return cachedItem as string;
- }
- return cachedItem as SpecifiedColorChannels;
- }
- if (!REG_COLOR.test(value)) {
- const res = resolveInvalidColorValue(format, nullable);
- if (res instanceof NullObject) {
- setCache(cacheKey, null);
- return res;
- }
- setCache(cacheKey, res);
- if (isString(res)) {
- return res as string;
- }
- return res as SpecifiedColorChannels;
- }
- let cs = '';
- let r = 0;
- let g = 0;
- let b = 0;
- let alpha = 0;
- // complement currentcolor as a missing color
- if (REG_CURRENT.test(value)) {
- if (format === VAL_SPEC) {
- setCache(cacheKey, value);
- return value;
- }
- // named-color
- } else if (/^[a-z]+$/.test(value)) {
- if (Object.prototype.hasOwnProperty.call(NAMED_COLORS, value)) {
- if (format === VAL_SPEC) {
- setCache(cacheKey, value);
- return value;
- }
- [r, g, b] = NAMED_COLORS[
- value as keyof typeof NAMED_COLORS
- ] as TriColorChannels;
- alpha = 1;
- } else {
- switch (format) {
- case VAL_SPEC: {
- if (value === 'transparent') {
- setCache(cacheKey, value);
- return value;
- }
- const res = '';
- setCache(cacheKey, res);
- return res;
- }
- case VAL_MIX: {
- if (value === 'transparent') {
- const res: SpecifiedColorChannels = ['rgb', 0, 0, 0, 0];
- setCache(cacheKey, res);
- return res;
- }
- setCache(cacheKey, null);
- return new NullObject();
- }
- case VAL_COMP:
- default: {
- if (nullable && value !== 'transparent') {
- setCache(cacheKey, null);
- return new NullObject();
- }
- const res: SpecifiedColorChannels = ['rgb', 0, 0, 0, 0];
- setCache(cacheKey, res);
- return res;
- }
- }
- }
- // hex-color
- } else if (value[0] === '#') {
- [r, g, b, alpha] = convertHexToRgb(value);
- // hsl()
- } else if (value.startsWith('hsl')) {
- [, r, g, b, alpha] = parseHsl(value, opt) as ComputedColorChannels;
- // hwb()
- } else if (value.startsWith('hwb')) {
- [, r, g, b, alpha] = parseHwb(value, opt) as ComputedColorChannels;
- // lab(), lch()
- } else if (/^l(?:ab|ch)/.test(value)) {
- let x, y, z;
- if (value.startsWith('lab')) {
- [cs, x, y, z, alpha] = parseLab(value, opt) as ComputedColorChannels;
- } else {
- [cs, x, y, z, alpha] = parseLch(value, opt) as ComputedColorChannels;
- }
- if (REG_SPEC.test(format)) {
- const res: SpecifiedColorChannels = [cs, x, y, z, alpha];
- setCache(cacheKey, res);
- return res;
- }
- [r, g, b] = transformXyzD50ToRgb([x, y, z]);
- // oklab(), oklch()
- } else if (/^okl(?:ab|ch)/.test(value)) {
- let x, y, z;
- if (value.startsWith('oklab')) {
- [cs, x, y, z, alpha] = parseOklab(value, opt) as ComputedColorChannels;
- } else {
- [cs, x, y, z, alpha] = parseOklch(value, opt) as ComputedColorChannels;
- }
- if (REG_SPEC.test(format)) {
- const res: SpecifiedColorChannels = [cs, x, y, z, alpha];
- setCache(cacheKey, res);
- return res;
- }
- [r, g, b] = transformXyzToRgb([x, y, z]);
- // rgb()
- } else {
- [, r, g, b, alpha] = parseRgb(value, opt) as ComputedColorChannels;
- }
- if (format === VAL_MIX && colorSpace === 'srgb') {
- const res: SpecifiedColorChannels = [
- 'srgb',
- r / MAX_RGB,
- g / MAX_RGB,
- b / MAX_RGB,
- alpha
- ];
- setCache(cacheKey, res);
- return res;
- }
- const res: SpecifiedColorChannels = [
- 'rgb',
- Math.round(r),
- Math.round(g),
- Math.round(b),
- alpha
- ];
- setCache(cacheKey, res);
- return res;
-};
-
-/**
- * resolve color()
- * @param value - color function value
- * @param [opt] - options
- * @returns resolved color - [cs, v1, v2, v3, alpha], '(empty)', NullObject
- */
-export const resolveColorFunc = (
- value: string,
- opt: Options = {}
-): SpecifiedColorChannels | string | NullObject => {
- if (isString(value)) {
- value = value.toLowerCase().trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { colorSpace = '', format = '', nullable = false } = opt;
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'resolveColorFunc',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- if (cachedResult.isNull) {
- return cachedResult as NullObject;
- }
- const cachedItem = cachedResult.item;
- if (isString(cachedItem)) {
- return cachedItem as string;
- }
- return cachedItem as SpecifiedColorChannels;
- }
- if (!REG_FN_COLOR.test(value)) {
- const res = resolveInvalidColorValue(format, nullable);
- if (res instanceof NullObject) {
- setCache(cacheKey, null);
- return res;
- }
- setCache(cacheKey, res);
- if (isString(res)) {
- return res as string;
- }
- return res as SpecifiedColorChannels;
- }
- const [cs, v1, v2, v3, v4] = parseColorFunc(
- value,
- opt
- ) as SpecifiedColorChannels;
- if (REG_SPEC.test(format) || (format === VAL_MIX && cs === colorSpace)) {
- const res: SpecifiedColorChannels = [cs, v1, v2, v3, v4];
- setCache(cacheKey, res);
- return res;
- }
- const x = parseFloat(`${v1}`);
- const y = parseFloat(`${v2}`);
- const z = parseFloat(`${v3}`);
- const alpha = parseAlpha(`${v4}`);
- const [r, g, b] = transformXyzToRgb([x, y, z], true);
- const res: SpecifiedColorChannels = ['rgb', r, g, b, alpha];
- setCache(cacheKey, res);
- return res;
-};
-
-/**
- * convert color value to linear rgb
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels | NullObject - [r, g, b, alpha] r|g|b|alpha: 0..1
- */
-export const convertColorToLinearRgb = (
- value: string,
- opt: {
- colorSpace?: string;
- format?: string;
- } = {}
-): ColorChannels | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { colorSpace = '', format = '' } = opt;
- let cs = '';
- let r, g, b, alpha, x, y, z;
- if (format === VAL_MIX) {
- let xyz;
- if (value.startsWith(FN_COLOR)) {
- xyz = parseColorFunc(value, opt);
- } else {
- xyz = parseColorValue(value, opt);
- }
- if (xyz instanceof NullObject) {
- return xyz;
- }
- [cs, x, y, z, alpha] = xyz as ComputedColorChannels;
- if (cs === colorSpace) {
- return [x, y, z, alpha];
- }
- [r, g, b] = transformMatrix(MATRIX_XYZ_TO_L_RGB, [x, y, z], true);
- } else if (value.startsWith(FN_COLOR)) {
- const [, val] = value.match(REG_FN_COLOR) as MatchedRegExp;
- const [cs] = val
- .replace('/', ' ')
- .split(/\s+/) as StringColorSpacedChannels;
- if (cs === 'srgb-linear') {
- [, r, g, b, alpha] = resolveColorFunc(value, {
- format: VAL_COMP
- }) as ComputedColorChannels;
- } else {
- [, x, y, z, alpha] = parseColorFunc(value) as ComputedColorChannels;
- [r, g, b] = transformMatrix(MATRIX_XYZ_TO_L_RGB, [x, y, z], true);
- }
- } else {
- [, x, y, z, alpha] = parseColorValue(value) as ComputedColorChannels;
- [r, g, b] = transformMatrix(MATRIX_XYZ_TO_L_RGB, [x, y, z], true);
- }
- return [
- Math.min(Math.max(r, 0), 1),
- Math.min(Math.max(g, 0), 1),
- Math.min(Math.max(b, 0), 1),
- alpha
- ];
-};
-
-/**
- * convert color value to rgb
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels | NullObject
- * - [r, g, b, alpha] r|g|b: 0..255 alpha: 0..1
- */
-export const convertColorToRgb = (
- value: string,
- opt: Options = {}
-): ColorChannels | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '' } = opt;
- let r, g, b, alpha;
- if (format === VAL_MIX) {
- let rgb;
- if (value.startsWith(FN_COLOR)) {
- rgb = resolveColorFunc(value, opt);
- } else {
- rgb = resolveColorValue(value, opt);
- }
- if (rgb instanceof NullObject) {
- return rgb;
- }
- [, r, g, b, alpha] = rgb as ComputedColorChannels;
- } else if (value.startsWith(FN_COLOR)) {
- const [, val] = value.match(REG_FN_COLOR) as MatchedRegExp;
- const [cs] = val
- .replace('/', ' ')
- .split(/\s+/) as StringColorSpacedChannels;
- if (cs === 'srgb') {
- [, r, g, b, alpha] = resolveColorFunc(value, {
- format: VAL_COMP
- }) as ComputedColorChannels;
- r *= MAX_RGB;
- g *= MAX_RGB;
- b *= MAX_RGB;
- } else {
- [, r, g, b, alpha] = resolveColorFunc(value) as ComputedColorChannels;
- }
- } else if (/^(?:ok)?l(?:ab|ch)/.test(value)) {
- [r, g, b, alpha] = convertColorToLinearRgb(value) as ColorChannels;
- [r, g, b] = transformLinearRgbToRgb([r, g, b]);
- } else {
- [, r, g, b, alpha] = resolveColorValue(value, {
- format: VAL_COMP
- }) as ComputedColorChannels;
- }
- return [r, g, b, alpha];
-};
-
-/**
- * convert color value to xyz
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels | NullObject - [x, y, z, alpha]
- */
-export const convertColorToXyz = (
- value: string,
- opt: Options = {}
-): ColorChannels | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { d50 = false, format = '' } = opt;
- let x, y, z, alpha;
- if (format === VAL_MIX) {
- let xyz;
- if (value.startsWith(FN_COLOR)) {
- xyz = parseColorFunc(value, opt);
- } else {
- xyz = parseColorValue(value, opt);
- }
- if (xyz instanceof NullObject) {
- return xyz;
- }
- [, x, y, z, alpha] = xyz as ComputedColorChannels;
- } else if (value.startsWith(FN_COLOR)) {
- const [, val] = value.match(REG_FN_COLOR) as MatchedRegExp;
- const [cs] = val
- .replace('/', ' ')
- .split(/\s+/) as StringColorSpacedChannels;
- if (d50) {
- if (cs === 'xyz-d50') {
- [, x, y, z, alpha] = resolveColorFunc(value, {
- format: VAL_COMP
- }) as ComputedColorChannels;
- } else {
- [, x, y, z, alpha] = parseColorFunc(
- value,
- opt
- ) as ComputedColorChannels;
- }
- } else if (/^xyz(?:-d65)?$/.test(cs)) {
- [, x, y, z, alpha] = resolveColorFunc(value, {
- format: VAL_COMP
- }) as ComputedColorChannels;
- } else {
- [, x, y, z, alpha] = parseColorFunc(value) as ComputedColorChannels;
- }
- } else {
- [, x, y, z, alpha] = parseColorValue(value, opt) as ComputedColorChannels;
- }
- return [x, y, z, alpha];
-};
-
-/**
- * convert color value to hsl
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels | NullObject - [h, s, l, alpha], hue may be powerless
- */
-export const convertColorToHsl = (
- value: string,
- opt: Options = {}
-): ColorChannels | [number | string, number, number, number] | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '' } = opt;
- let h, s, l, alpha;
- if (REG_HSL.test(value)) {
- [, h, s, l, alpha] = parseHsl(value, {
- format: 'hsl'
- }) as ComputedColorChannels;
- if (format === 'hsl') {
- return [Math.round(h), Math.round(s), Math.round(l), alpha];
- }
- return [h, s, l, alpha];
- }
- let x, y, z;
- if (format === VAL_MIX) {
- let xyz;
- if (value.startsWith(FN_COLOR)) {
- xyz = parseColorFunc(value, opt);
- } else {
- xyz = parseColorValue(value, opt);
- }
- if (xyz instanceof NullObject) {
- return xyz;
- }
- [, x, y, z, alpha] = xyz as ComputedColorChannels;
- } else if (value.startsWith(FN_COLOR)) {
- [, x, y, z, alpha] = parseColorFunc(value) as ComputedColorChannels;
- } else {
- [, x, y, z, alpha] = parseColorValue(value) as ComputedColorChannels;
- }
- [h, s, l] = transformXyzToHsl([x, y, z], true) as TriColorChannels;
- if (format === 'hsl') {
- return [Math.round(h), Math.round(s), Math.round(l), alpha];
- }
- return [format === VAL_MIX && s === 0 ? NONE : h, s, l, alpha];
-};
-
-/**
- * convert color value to hwb
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels | NullObject - [h, w, b, alpha], hue may be powerless
- */
-export const convertColorToHwb = (
- value: string,
- opt: Options = {}
-): ColorChannels | [number | string, number, number, number] | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '' } = opt;
- let h, w, b, alpha;
- if (REG_HWB.test(value)) {
- [, h, w, b, alpha] = parseHwb(value, {
- format: 'hwb'
- }) as ComputedColorChannels;
- if (format === 'hwb') {
- return [Math.round(h), Math.round(w), Math.round(b), alpha];
- }
- return [h, w, b, alpha];
- }
- let x, y, z;
- if (format === VAL_MIX) {
- let xyz;
- if (value.startsWith(FN_COLOR)) {
- xyz = parseColorFunc(value, opt);
- } else {
- xyz = parseColorValue(value, opt);
- }
- if (xyz instanceof NullObject) {
- return xyz;
- }
- [, x, y, z, alpha] = xyz as ComputedColorChannels;
- } else if (value.startsWith(FN_COLOR)) {
- [, x, y, z, alpha] = parseColorFunc(value) as ComputedColorChannels;
- } else {
- [, x, y, z, alpha] = parseColorValue(value) as ComputedColorChannels;
- }
- [h, w, b] = transformXyzToHwb([x, y, z], true) as TriColorChannels;
- if (format === 'hwb') {
- return [Math.round(h), Math.round(w), Math.round(b), alpha];
- }
- return [format === VAL_MIX && w + b >= 100 ? NONE : h, w, b, alpha];
-};
-
-/**
- * convert color value to lab
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels | NullObject - [l, a, b, alpha]
- */
-export const convertColorToLab = (
- value: string,
- opt: Options = {}
-): ColorChannels | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '' } = opt;
- let l, a, b, alpha;
- if (REG_LAB.test(value)) {
- [, l, a, b, alpha] = parseLab(value, {
- format: VAL_COMP
- }) as ComputedColorChannels;
- return [l, a, b, alpha];
- }
- let x, y, z;
- if (format === VAL_MIX) {
- let xyz;
- opt.d50 = true;
- if (value.startsWith(FN_COLOR)) {
- xyz = parseColorFunc(value, opt);
- } else {
- xyz = parseColorValue(value, opt);
- }
- if (xyz instanceof NullObject) {
- return xyz;
- }
- [, x, y, z, alpha] = xyz as ComputedColorChannels;
- } else if (value.startsWith(FN_COLOR)) {
- [, x, y, z, alpha] = parseColorFunc(value, {
- d50: true
- }) as ComputedColorChannels;
- } else {
- [, x, y, z, alpha] = parseColorValue(value, {
- d50: true
- }) as ComputedColorChannels;
- }
- [l, a, b] = transformXyzD50ToLab([x, y, z], true);
- return [l, a, b, alpha];
-};
-
-/**
- * convert color value to lch
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels | NullObject - [l, c, h, alpha], hue may be powerless
- */
-export const convertColorToLch = (
- value: string,
- opt: Options = {}
-): ColorChannels | [number, number, number | string, number] | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '' } = opt;
- let l, c, h, alpha;
- if (REG_LCH.test(value)) {
- [, l, c, h, alpha] = parseLch(value, {
- format: VAL_COMP
- }) as ComputedColorChannels;
- return [l, c, h, alpha];
- }
- let x, y, z;
- if (format === VAL_MIX) {
- let xyz;
- opt.d50 = true;
- if (value.startsWith(FN_COLOR)) {
- xyz = parseColorFunc(value, opt);
- } else {
- xyz = parseColorValue(value, opt);
- }
- if (xyz instanceof NullObject) {
- return xyz;
- }
- [, x, y, z, alpha] = xyz as ComputedColorChannels;
- } else if (value.startsWith(FN_COLOR)) {
- [, x, y, z, alpha] = parseColorFunc(value, {
- d50: true
- }) as ComputedColorChannels;
- } else {
- [, x, y, z, alpha] = parseColorValue(value, {
- d50: true
- }) as ComputedColorChannels;
- }
- [l, c, h] = transformXyzD50ToLch([x, y, z], true);
- return [l, c, format === VAL_MIX && c === 0 ? NONE : h, alpha];
-};
-
-/**
- * convert color value to oklab
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels | NullObject - [l, a, b, alpha]
- */
-export const convertColorToOklab = (
- value: string,
- opt: Options = {}
-): ColorChannels | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '' } = opt;
- let l, a, b, alpha;
- if (REG_OKLAB.test(value)) {
- [, l, a, b, alpha] = parseOklab(value, {
- format: VAL_COMP
- }) as ComputedColorChannels;
- return [l, a, b, alpha];
- }
- let x, y, z;
- if (format === VAL_MIX) {
- let xyz;
- if (value.startsWith(FN_COLOR)) {
- xyz = parseColorFunc(value, opt);
- } else {
- xyz = parseColorValue(value, opt);
- }
- if (xyz instanceof NullObject) {
- return xyz;
- }
- [, x, y, z, alpha] = xyz as ComputedColorChannels;
- } else if (value.startsWith(FN_COLOR)) {
- [, x, y, z, alpha] = parseColorFunc(value) as ComputedColorChannels;
- } else {
- [, x, y, z, alpha] = parseColorValue(value) as ComputedColorChannels;
- }
- [l, a, b] = transformXyzToOklab([x, y, z], true);
- return [l, a, b, alpha];
-};
-
-/**
- * convert color value to oklch
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels | NullObject - [l, c, h, alpha], hue may be powerless
- */
-export const convertColorToOklch = (
- value: string,
- opt: Options = {}
-): ColorChannels | [number, number, number | string, number] | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '' } = opt;
- let l, c, h, alpha;
- if (REG_OKLCH.test(value)) {
- [, l, c, h, alpha] = parseOklch(value, {
- format: VAL_COMP
- }) as ComputedColorChannels;
- return [l, c, h, alpha];
- }
- let x, y, z;
- if (format === VAL_MIX) {
- let xyz;
- if (value.startsWith(FN_COLOR)) {
- xyz = parseColorFunc(value, opt);
- } else {
- xyz = parseColorValue(value, opt);
- }
- if (xyz instanceof NullObject) {
- return xyz;
- }
- [, x, y, z, alpha] = xyz as ComputedColorChannels;
- } else if (value.startsWith(FN_COLOR)) {
- [, x, y, z, alpha] = parseColorFunc(value) as ComputedColorChannels;
- } else {
- [, x, y, z, alpha] = parseColorValue(value) as ComputedColorChannels;
- }
- [l, c, h] = transformXyzToOklch([x, y, z], true) as TriColorChannels;
- return [l, c, format === VAL_MIX && c === 0 ? NONE : h, alpha];
-};
-
-/**
- * resolve color-mix()
- * @param value - color-mix color value
- * @param [opt] - options
- * @returns resolved color - [cs, v1, v2, v3, alpha], '(empty)'
- */
-export const resolveColorMix = (
- value: string,
- opt: Options = {}
-): SpecifiedColorChannels | string | NullObject => {
- if (isString(value)) {
- value = value.toLowerCase().trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { format = '', nullable = false } = opt;
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'resolveColorMix',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- if (cachedResult.isNull) {
- return cachedResult as NullObject;
- }
- const cachedItem = cachedResult.item;
- if (isString(cachedItem)) {
- return cachedItem as string;
- }
- return cachedItem as SpecifiedColorChannels;
- }
- const nestedItems = [];
- if (!REG_MIX.test(value)) {
- if (value.startsWith(FN_MIX) && REG_MIX_NEST.test(value)) {
- const regColorSpace = new RegExp(`^(?:${CS_RGB}|${CS_XYZ})$`);
- const items = value.match(REG_MIX_NEST) as RegExpMatchArray;
- for (const item of items) {
- if (item) {
- let val = resolveColorMix(item, {
- format: format === VAL_SPEC ? format : VAL_COMP
- }) as ComputedColorChannels | string;
- // computed value
- if (Array.isArray(val)) {
- const [cs, v1, v2, v3, v4] = val as ComputedColorChannels;
- if (v1 === 0 && v2 === 0 && v3 === 0 && v4 === 0) {
- value = '';
- break;
- }
- if (regColorSpace.test(cs)) {
- if (v4 === 1) {
- val = `color(${cs} ${v1} ${v2} ${v3})`;
- } else {
- val = `color(${cs} ${v1} ${v2} ${v3} / ${v4})`;
- }
- } else if (v4 === 1) {
- val = `${cs}(${v1} ${v2} ${v3})`;
- } else {
- val = `${cs}(${v1} ${v2} ${v3} / ${v4})`;
- }
- } else if (!REG_MIX.test(val)) {
- value = '';
- break;
- }
- nestedItems.push(val);
- value = value.replace(item, val);
- }
- }
- if (!value) {
- const res = cacheInvalidColorValue(cacheKey, format, nullable);
- return res;
- }
- } else {
- const res = cacheInvalidColorValue(cacheKey, format, nullable);
- return res;
- }
- }
- let colorSpace = '';
- let hueArc = '';
- let colorA = '';
- let pctA = '';
- let colorB = '';
- let pctB = '';
- if (nestedItems.length && format === VAL_SPEC) {
- const regColorSpace = new RegExp(`^color-mix\\(\\s*in\\s+(${CS_MIX})\\s*,`);
- const [, cs] = value.match(regColorSpace) as MatchedRegExp;
- if (REG_CS_HUE.test(cs)) {
- [, colorSpace, hueArc] = cs.match(REG_CS_HUE) as MatchedRegExp;
- } else {
- colorSpace = cs;
- }
- if (nestedItems.length === 2) {
- let [itemA, itemB] = nestedItems as [string, string];
- itemA = itemA.replace(/(?=[()])/g, '\\');
- itemB = itemB.replace(/(?=[()])/g, '\\');
- const regA = new RegExp(`(${itemA})(?:\\s+(${PCT}))?`);
- const regB = new RegExp(`(${itemB})(?:\\s+(${PCT}))?`);
- [, colorA, pctA] = value.match(regA) as MatchedRegExp;
- [, colorB, pctB] = value.match(regB) as MatchedRegExp;
- } else {
- let [item] = nestedItems as [string];
- item = item.replace(/(?=[()])/g, '\\');
- const itemPart = `${item}(?:\\s+${PCT})?`;
- const itemPartCapt = `(${item})(?:\\s+(${PCT}))?`;
- const regItemPart = new RegExp(`^${itemPartCapt}$`);
- const regLastItem = new RegExp(`${itemPartCapt}\\s*\\)$`);
- const regColorPart = new RegExp(`^(${SYN_COLOR_TYPE})(?:\\s+(${PCT}))?$`);
- // item is at the end
- if (regLastItem.test(value)) {
- const reg = new RegExp(
- `(${SYN_MIX_PART})\\s*,\\s*(${itemPart})\\s*\\)$`
- );
- const [, colorPartA, colorPartB] = value.match(reg) as MatchedRegExp;
- [, colorA, pctA] = colorPartA.match(regColorPart) as MatchedRegExp;
- [, colorB, pctB] = colorPartB.match(regItemPart) as MatchedRegExp;
- } else {
- const reg = new RegExp(
- `(${itemPart})\\s*,\\s*(${SYN_MIX_PART})\\s*\\)$`
- );
- const [, colorPartA, colorPartB] = value.match(reg) as MatchedRegExp;
- [, colorA, pctA] = colorPartA.match(regItemPart) as MatchedRegExp;
- [, colorB, pctB] = colorPartB.match(regColorPart) as MatchedRegExp;
- }
- }
- } else {
- const [, cs, colorPartA, colorPartB] = value.match(
- REG_MIX_CAPT
- ) as MatchedRegExp;
- const reg = new RegExp(`^(${SYN_COLOR_TYPE})(?:\\s+(${PCT}))?$`);
- [, colorA, pctA] = colorPartA.match(reg) as MatchedRegExp;
- [, colorB, pctB] = colorPartB.match(reg) as MatchedRegExp;
- if (REG_CS_HUE.test(cs)) {
- [, colorSpace, hueArc] = cs.match(REG_CS_HUE) as MatchedRegExp;
- } else {
- colorSpace = cs;
- }
- }
- // normalize percentages and set multipler
- let pA, pB, m;
- if (pctA && pctB) {
- const p1 = parseFloat(pctA) / MAX_PCT;
- const p2 = parseFloat(pctB) / MAX_PCT;
- if (p1 < 0 || p1 > 1 || p2 < 0 || p2 > 1) {
- const res = cacheInvalidColorValue(cacheKey, format, nullable);
- return res;
- }
- const factor = p1 + p2;
- if (factor === 0) {
- const res = cacheInvalidColorValue(cacheKey, format, nullable);
- return res;
- }
- pA = p1 / factor;
- pB = p2 / factor;
- m = factor < 1 ? factor : 1;
- } else {
- if (pctA) {
- pA = parseFloat(pctA) / MAX_PCT;
- if (pA < 0 || pA > 1) {
- const res = cacheInvalidColorValue(cacheKey, format, nullable);
- return res;
- }
- pB = 1 - pA;
- } else if (pctB) {
- pB = parseFloat(pctB) / MAX_PCT;
- if (pB < 0 || pB > 1) {
- const res = cacheInvalidColorValue(cacheKey, format, nullable);
- return res;
- }
- pA = 1 - pB;
- } else {
- pA = HALF;
- pB = HALF;
- }
- m = 1;
- }
- if (colorSpace === 'xyz') {
- colorSpace = 'xyz-d65';
- }
- // specified value
- if (format === VAL_SPEC) {
- let valueA = '';
- let valueB = '';
- if (colorA.startsWith(FN_MIX)) {
- valueA = colorA;
- } else if (colorA.startsWith(FN_COLOR)) {
- const [cs, v1, v2, v3, v4] = parseColorFunc(
- colorA,
- opt
- ) as SpecifiedColorChannels;
- if (v4 === 1) {
- valueA = `color(${cs} ${v1} ${v2} ${v3})`;
- } else {
- valueA = `color(${cs} ${v1} ${v2} ${v3} / ${v4})`;
- }
- } else {
- const val = parseColorValue(colorA, opt);
- if (Array.isArray(val)) {
- const [cs, v1, v2, v3, v4] = val;
- if (v4 === 1) {
- if (cs === 'rgb') {
- valueA = `${cs}(${v1}, ${v2}, ${v3})`;
- } else {
- valueA = `${cs}(${v1} ${v2} ${v3})`;
- }
- } else if (cs === 'rgb') {
- valueA = `${cs}a(${v1}, ${v2}, ${v3}, ${v4})`;
- } else {
- valueA = `${cs}(${v1} ${v2} ${v3} / ${v4})`;
- }
- } else {
- if (!isString(val) || !val) {
- setCache(cacheKey, '');
- return '';
- }
- valueA = val;
- }
- }
- if (colorB.startsWith(FN_MIX)) {
- valueB = colorB;
- } else if (colorB.startsWith(FN_COLOR)) {
- const [cs, v1, v2, v3, v4] = parseColorFunc(
- colorB,
- opt
- ) as SpecifiedColorChannels;
- if (v4 === 1) {
- valueB = `color(${cs} ${v1} ${v2} ${v3})`;
- } else {
- valueB = `color(${cs} ${v1} ${v2} ${v3} / ${v4})`;
- }
- } else {
- const val = parseColorValue(colorB, opt);
- if (Array.isArray(val)) {
- const [cs, v1, v2, v3, v4] = val;
- if (v4 === 1) {
- if (cs === 'rgb') {
- valueB = `${cs}(${v1}, ${v2}, ${v3})`;
- } else {
- valueB = `${cs}(${v1} ${v2} ${v3})`;
- }
- } else if (cs === 'rgb') {
- valueB = `${cs}a(${v1}, ${v2}, ${v3}, ${v4})`;
- } else {
- valueB = `${cs}(${v1} ${v2} ${v3} / ${v4})`;
- }
- } else {
- if (!isString(val) || !val) {
- setCache(cacheKey, '');
- return '';
- }
- valueB = val;
- }
- }
- if (pctA && pctB) {
- valueA += ` ${parseFloat(pctA)}%`;
- valueB += ` ${parseFloat(pctB)}%`;
- } else if (pctA) {
- const pA = parseFloat(pctA);
- if (pA !== MAX_PCT * HALF) {
- valueA += ` ${pA}%`;
- }
- } else if (pctB) {
- const pA = MAX_PCT - parseFloat(pctB);
- if (pA !== MAX_PCT * HALF) {
- valueA += ` ${pA}%`;
- }
- }
- if (hueArc) {
- const res = `color-mix(in ${colorSpace} ${hueArc} hue, ${valueA}, ${valueB})`;
- setCache(cacheKey, res);
- return res;
- } else {
- const res = `color-mix(in ${colorSpace}, ${valueA}, ${valueB})`;
- setCache(cacheKey, res);
- return res;
- }
- }
- let r = 0;
- let g = 0;
- let b = 0;
- let alpha = 0;
- // in srgb, srgb-linear
- if (/^srgb(?:-linear)?$/.test(colorSpace)) {
- let rgbA, rgbB;
- if (colorSpace === 'srgb') {
- if (REG_CURRENT.test(colorA)) {
- rgbA = [NONE, NONE, NONE, NONE];
- } else {
- rgbA = convertColorToRgb(colorA, {
- colorSpace,
- format: VAL_MIX
- });
- }
- if (REG_CURRENT.test(colorB)) {
- rgbB = [NONE, NONE, NONE, NONE];
- } else {
- rgbB = convertColorToRgb(colorB, {
- colorSpace,
- format: VAL_MIX
- });
- }
- } else {
- if (REG_CURRENT.test(colorA)) {
- rgbA = [NONE, NONE, NONE, NONE];
- } else {
- rgbA = convertColorToLinearRgb(colorA, {
- colorSpace,
- format: VAL_MIX
- });
- }
- if (REG_CURRENT.test(colorB)) {
- rgbB = [NONE, NONE, NONE, NONE];
- } else {
- rgbB = convertColorToLinearRgb(colorB, {
- colorSpace,
- format: VAL_MIX
- });
- }
- }
- if (rgbA instanceof NullObject || rgbB instanceof NullObject) {
- const res = cacheInvalidColorValue(cacheKey, format, nullable);
- return res;
- }
- const [rrA, ggA, bbA, aaA] = rgbA as NumStrColorChannels;
- const [rrB, ggB, bbB, aaB] = rgbB as NumStrColorChannels;
- const rNone = rrA === NONE && rrB === NONE;
- const gNone = ggA === NONE && ggB === NONE;
- const bNone = bbA === NONE && bbB === NONE;
- const alphaNone = aaA === NONE && aaB === NONE;
- const [[rA, gA, bA, alphaA], [rB, gB, bB, alphaB]] =
- normalizeColorComponents(
- [rrA, ggA, bbA, aaA],
- [rrB, ggB, bbB, aaB],
- true
- );
- const factorA = alphaA * pA;
- const factorB = alphaB * pB;
- alpha = factorA + factorB;
- if (alpha === 0) {
- r = rA * pA + rB * pB;
- g = gA * pA + gB * pB;
- b = bA * pA + bB * pB;
- } else {
- r = (rA * factorA + rB * factorB) / alpha;
- g = (gA * factorA + gB * factorB) / alpha;
- b = (bA * factorA + bB * factorB) / alpha;
- alpha = parseFloat(alpha.toFixed(3));
- }
- if (format === VAL_COMP) {
- const res: SpecifiedColorChannels = [
- colorSpace,
- rNone ? NONE : roundToPrecision(r, HEX),
- gNone ? NONE : roundToPrecision(g, HEX),
- bNone ? NONE : roundToPrecision(b, HEX),
- alphaNone ? NONE : alpha * m
- ];
- setCache(cacheKey, res);
- return res;
- }
- r *= MAX_RGB;
- g *= MAX_RGB;
- b *= MAX_RGB;
- // in xyz, xyz-d65, xyz-d50
- } else if (REG_CS_XYZ.test(colorSpace)) {
- let xyzA, xyzB;
- if (REG_CURRENT.test(colorA)) {
- xyzA = [NONE, NONE, NONE, NONE];
- } else {
- xyzA = convertColorToXyz(colorA, {
- colorSpace,
- d50: colorSpace === 'xyz-d50',
- format: VAL_MIX
- });
- }
- if (REG_CURRENT.test(colorB)) {
- xyzB = [NONE, NONE, NONE, NONE];
- } else {
- xyzB = convertColorToXyz(colorB, {
- colorSpace,
- d50: colorSpace === 'xyz-d50',
- format: VAL_MIX
- });
- }
- if (xyzA instanceof NullObject || xyzB instanceof NullObject) {
- const res = cacheInvalidColorValue(cacheKey, format, nullable);
- return res;
- }
- const [xxA, yyA, zzA, aaA] = xyzA;
- const [xxB, yyB, zzB, aaB] = xyzB;
- const xNone = xxA === NONE && xxB === NONE;
- const yNone = yyA === NONE && yyB === NONE;
- const zNone = zzA === NONE && zzB === NONE;
- const alphaNone = aaA === NONE && aaB === NONE;
- const [[xA, yA, zA, alphaA], [xB, yB, zB, alphaB]] =
- normalizeColorComponents(
- [xxA, yyA, zzA, aaA],
- [xxB, yyB, zzB, aaB],
- true
- );
- const factorA = alphaA * pA;
- const factorB = alphaB * pB;
- alpha = factorA + factorB;
- let x, y, z;
- if (alpha === 0) {
- x = xA * pA + xB * pB;
- y = yA * pA + yB * pB;
- z = zA * pA + zB * pB;
- } else {
- x = (xA * factorA + xB * factorB) / alpha;
- y = (yA * factorA + yB * factorB) / alpha;
- z = (zA * factorA + zB * factorB) / alpha;
- alpha = parseFloat(alpha.toFixed(3));
- }
- if (format === VAL_COMP) {
- const res: SpecifiedColorChannels = [
- colorSpace,
- xNone ? NONE : roundToPrecision(x, HEX),
- yNone ? NONE : roundToPrecision(y, HEX),
- zNone ? NONE : roundToPrecision(z, HEX),
- alphaNone ? NONE : alpha * m
- ];
- setCache(cacheKey, res);
- return res;
- }
- if (colorSpace === 'xyz-d50') {
- [r, g, b] = transformXyzD50ToRgb([x, y, z], true);
- } else {
- [r, g, b] = transformXyzToRgb([x, y, z], true);
- }
- // in hsl, hwb
- } else if (/^h(?:sl|wb)$/.test(colorSpace)) {
- let hslA, hslB;
- if (colorSpace === 'hsl') {
- if (REG_CURRENT.test(colorA)) {
- hslA = [NONE, NONE, NONE, NONE];
- } else {
- hslA = convertColorToHsl(colorA, {
- colorSpace,
- format: VAL_MIX
- });
- }
- if (REG_CURRENT.test(colorB)) {
- hslB = [NONE, NONE, NONE, NONE];
- } else {
- hslB = convertColorToHsl(colorB, {
- colorSpace,
- format: VAL_MIX
- });
- }
- } else {
- if (REG_CURRENT.test(colorA)) {
- hslA = [NONE, NONE, NONE, NONE];
- } else {
- hslA = convertColorToHwb(colorA, {
- colorSpace,
- format: VAL_MIX
- });
- }
- if (REG_CURRENT.test(colorB)) {
- hslB = [NONE, NONE, NONE, NONE];
- } else {
- hslB = convertColorToHwb(colorB, {
- colorSpace,
- format: VAL_MIX
- });
- }
- }
- if (hslA instanceof NullObject || hslB instanceof NullObject) {
- const res = cacheInvalidColorValue(cacheKey, format, nullable);
- return res;
- }
- const [hhA, ssA, llA, aaA] = hslA;
- const [hhB, ssB, llB, aaB] = hslB;
- const alphaNone = aaA === NONE && aaB === NONE;
- let [[hA, sA, lA, alphaA], [hB, sB, lB, alphaB]] = normalizeColorComponents(
- [hhA, ssA, llA, aaA],
- [hhB, ssB, llB, aaB],
- true
- );
- if (hueArc) {
- [hA, hB] = interpolateHue(hA, hB, hueArc);
- }
- const factorA = alphaA * pA;
- const factorB = alphaB * pB;
- alpha = factorA + factorB;
- const h = (hA * pA + hB * pB) % DEG;
- let s, l;
- if (alpha === 0) {
- s = sA * pA + sB * pB;
- l = lA * pA + lB * pB;
- } else {
- s = (sA * factorA + sB * factorB) / alpha;
- l = (lA * factorA + lB * factorB) / alpha;
- alpha = parseFloat(alpha.toFixed(3));
- }
- [r, g, b] = convertColorToRgb(
- `${colorSpace}(${h} ${s} ${l})`
- ) as ColorChannels;
- if (format === VAL_COMP) {
- const res: SpecifiedColorChannels = [
- 'srgb',
- roundToPrecision(r / MAX_RGB, HEX),
- roundToPrecision(g / MAX_RGB, HEX),
- roundToPrecision(b / MAX_RGB, HEX),
- alphaNone ? NONE : alpha * m
- ];
- setCache(cacheKey, res);
- return res;
- }
- // in lch, oklch
- } else if (/^(?:ok)?lch$/.test(colorSpace)) {
- let lchA, lchB;
- if (colorSpace === 'lch') {
- if (REG_CURRENT.test(colorA)) {
- lchA = [NONE, NONE, NONE, NONE];
- } else {
- lchA = convertColorToLch(colorA, {
- colorSpace,
- format: VAL_MIX
- });
- }
- if (REG_CURRENT.test(colorB)) {
- lchB = [NONE, NONE, NONE, NONE];
- } else {
- lchB = convertColorToLch(colorB, {
- colorSpace,
- format: VAL_MIX
- });
- }
- } else {
- if (REG_CURRENT.test(colorA)) {
- lchA = [NONE, NONE, NONE, NONE];
- } else {
- lchA = convertColorToOklch(colorA, {
- colorSpace,
- format: VAL_MIX
- });
- }
- if (REG_CURRENT.test(colorB)) {
- lchB = [NONE, NONE, NONE, NONE];
- } else {
- lchB = convertColorToOklch(colorB, {
- colorSpace,
- format: VAL_MIX
- });
- }
- }
- if (lchA instanceof NullObject || lchB instanceof NullObject) {
- const res = cacheInvalidColorValue(cacheKey, format, nullable);
- return res;
- }
- const [llA, ccA, hhA, aaA] = lchA;
- const [llB, ccB, hhB, aaB] = lchB;
- const lNone = llA === NONE && llB === NONE;
- const cNone = ccA === NONE && ccB === NONE;
- const hNone = hhA === NONE && hhB === NONE;
- const alphaNone = aaA === NONE && aaB === NONE;
- let [[lA, cA, hA, alphaA], [lB, cB, hB, alphaB]] = normalizeColorComponents(
- [llA, ccA, hhA, aaA],
- [llB, ccB, hhB, aaB],
- true
- );
- if (hueArc) {
- [hA, hB] = interpolateHue(hA, hB, hueArc);
- }
- const factorA = alphaA * pA;
- const factorB = alphaB * pB;
- alpha = factorA + factorB;
- const h = (hA * pA + hB * pB) % DEG;
- let l, c;
- if (alpha === 0) {
- l = lA * pA + lB * pB;
- c = cA * pA + cB * pB;
- } else {
- l = (lA * factorA + lB * factorB) / alpha;
- c = (cA * factorA + cB * factorB) / alpha;
- alpha = parseFloat(alpha.toFixed(3));
- }
- if (format === VAL_COMP) {
- const res: SpecifiedColorChannels = [
- colorSpace,
- lNone ? NONE : roundToPrecision(l, HEX),
- cNone ? NONE : roundToPrecision(c, HEX),
- hNone ? NONE : roundToPrecision(h, HEX),
- alphaNone ? NONE : alpha * m
- ];
- setCache(cacheKey, res);
- return res;
- }
- [, r, g, b] = resolveColorValue(
- `${colorSpace}(${l} ${c} ${h})`
- ) as ComputedColorChannels;
- // in lab, oklab
- } else {
- let labA, labB;
- if (colorSpace === 'lab') {
- if (REG_CURRENT.test(colorA)) {
- labA = [NONE, NONE, NONE, NONE];
- } else {
- labA = convertColorToLab(colorA, {
- colorSpace,
- format: VAL_MIX
- });
- }
- if (REG_CURRENT.test(colorB)) {
- labB = [NONE, NONE, NONE, NONE];
- } else {
- labB = convertColorToLab(colorB, {
- colorSpace,
- format: VAL_MIX
- });
- }
- } else {
- if (REG_CURRENT.test(colorA)) {
- labA = [NONE, NONE, NONE, NONE];
- } else {
- labA = convertColorToOklab(colorA, {
- colorSpace,
- format: VAL_MIX
- });
- }
- if (REG_CURRENT.test(colorB)) {
- labB = [NONE, NONE, NONE, NONE];
- } else {
- labB = convertColorToOklab(colorB, {
- colorSpace,
- format: VAL_MIX
- });
- }
- }
- if (labA instanceof NullObject || labB instanceof NullObject) {
- const res = cacheInvalidColorValue(cacheKey, format, nullable);
- return res;
- }
- const [llA, aaA, bbA, alA] = labA;
- const [llB, aaB, bbB, alB] = labB;
- const lNone = llA === NONE && llB === NONE;
- const aNone = aaA === NONE && aaB === NONE;
- const bNone = bbA === NONE && bbB === NONE;
- const alphaNone = alA === NONE && alB === NONE;
- const [[lA, aA, bA, alphaA], [lB, aB, bB, alphaB]] =
- normalizeColorComponents(
- [llA, aaA, bbA, alA],
- [llB, aaB, bbB, alB],
- true
- );
- const factorA = alphaA * pA;
- const factorB = alphaB * pB;
- alpha = factorA + factorB;
- let l, aO, bO;
- if (alpha === 0) {
- l = lA * pA + lB * pB;
- aO = aA * pA + aB * pB;
- bO = bA * pA + bB * pB;
- } else {
- l = (lA * factorA + lB * factorB) / alpha;
- aO = (aA * factorA + aB * factorB) / alpha;
- bO = (bA * factorA + bB * factorB) / alpha;
- alpha = parseFloat(alpha.toFixed(3));
- }
- if (format === VAL_COMP) {
- const res: SpecifiedColorChannels = [
- colorSpace,
- lNone ? NONE : roundToPrecision(l, HEX),
- aNone ? NONE : roundToPrecision(aO, HEX),
- bNone ? NONE : roundToPrecision(bO, HEX),
- alphaNone ? NONE : alpha * m
- ];
- setCache(cacheKey, res);
- return res;
- }
- [, r, g, b] = resolveColorValue(
- `${colorSpace}(${l} ${aO} ${bO})`
- ) as ComputedColorChannels;
- }
- const res: SpecifiedColorChannels = [
- 'rgb',
- Math.round(r),
- Math.round(g),
- Math.round(b),
- parseFloat((alpha * m).toFixed(3))
- ];
- setCache(cacheKey, res);
- return res;
-};
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/common.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/common.ts
deleted file mode 100644
index 32bf8bdc..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/common.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * common
- */
-
-/* numeric constants */
-const TYPE_FROM = 8;
-const TYPE_TO = -1;
-
-/**
- * get type
- * @param o - object to check
- * @returns type of object
- */
-export const getType = (o: unknown): string =>
- Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);
-
-/**
- * is string
- * @param o - object to check
- * @returns result
- */
-export const isString = (o: unknown): o is string =>
- typeof o === 'string' || o instanceof String;
-
-/**
- * is string or number
- * @param o - object to check
- * @returns result
- */
-export const isStringOrNumber = (o: unknown): boolean =>
- isString(o) || typeof o === 'number';
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/constant.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/constant.ts
deleted file mode 100644
index e834e8c9..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/constant.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * constant
- */
-
-/* values and units */
-const _DIGIT = '(?:0|[1-9]\\d*)';
-const _COMPARE = 'clamp|max|min';
-const _EXPO = 'exp|hypot|log|pow|sqrt';
-const _SIGN = 'abs|sign';
-const _STEP = 'mod|rem|round';
-const _TRIG = 'a?(?:cos|sin|tan)|atan2';
-const _MATH = `${_COMPARE}|${_EXPO}|${_SIGN}|${_STEP}|${_TRIG}`;
-const _CALC = `calc|${_MATH}`;
-const _VAR = `var|${_CALC}`;
-export const ANGLE = 'deg|g?rad|turn';
-export const LENGTH =
- '[cm]m|[dls]?v(?:[bhiw]|max|min)|in|p[ctx]|q|r?(?:[cl]h|cap|e[mx]|ic)';
-export const NUM = `[+-]?(?:${_DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${_DIGIT})?`;
-export const NUM_POSITIVE = `\\+?(?:${_DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${_DIGIT})?`;
-export const NONE = 'none';
-export const PCT = `${NUM}%`;
-export const SYN_FN_CALC = `^(?:${_CALC})\\(|(?<=[*\\/\\s\\(])(?:${_CALC})\\(`;
-export const SYN_FN_MATH_START = `^(?:${_MATH})\\($`;
-export const SYN_FN_VAR = '^var\\(|(?<=[*\\/\\s\\(])var\\(';
-export const SYN_FN_VAR_START = `^(?:${_VAR})\\(`;
-
-/* colors */
-const _ALPHA = `(?:\\s*\\/\\s*(?:${NUM}|${PCT}|${NONE}))?`;
-const _ALPHA_LV3 = `(?:\\s*,\\s*(?:${NUM}|${PCT}))?`;
-const _COLOR_FUNC = '(?:ok)?l(?:ab|ch)|color|hsla?|hwb|rgba?';
-const _COLOR_KEY = '[a-z]+|#[\\da-f]{3}|#[\\da-f]{4}|#[\\da-f]{6}|#[\\da-f]{8}';
-const _CS_HUE = '(?:ok)?lch|hsl|hwb';
-const _CS_HUE_ARC = '(?:de|in)creasing|longer|shorter';
-const _NUM_ANGLE = `${NUM}(?:${ANGLE})?`;
-const _NUM_ANGLE_NONE = `(?:${NUM}(?:${ANGLE})?|${NONE})`;
-const _NUM_PCT_NONE = `(?:${NUM}|${PCT}|${NONE})`;
-export const CS_HUE = `(?:${_CS_HUE})(?:\\s(?:${_CS_HUE_ARC})\\shue)?`;
-export const CS_HUE_CAPT = `(${_CS_HUE})(?:\\s(${_CS_HUE_ARC})\\shue)?`;
-export const CS_LAB = '(?:ok)?lab';
-export const CS_LCH = '(?:ok)?lch';
-export const CS_SRGB = 'srgb(?:-linear)?';
-export const CS_RGB = `(?:a98|prophoto)-rgb|display-p3|rec2020|${CS_SRGB}`;
-export const CS_XYZ = 'xyz(?:-d(?:50|65))?';
-export const CS_RECT = `${CS_LAB}|${CS_RGB}|${CS_XYZ}`;
-export const CS_MIX = `${CS_HUE}|${CS_RECT}`;
-export const FN_COLOR = 'color(';
-export const FN_MIX = 'color-mix(';
-export const FN_REL = `(?:${_COLOR_FUNC})\\(\\s*from\\s+`;
-export const FN_REL_CAPT = `(${_COLOR_FUNC})\\(\\s*from\\s+`;
-export const FN_VAR = 'var(';
-export const SYN_FN_COLOR = `(?:${CS_RGB}|${CS_XYZ})(?:\\s+${_NUM_PCT_NONE}){3}${_ALPHA}`;
-export const SYN_FN_REL = `^${FN_REL}|(?<=[\\s])${FN_REL}`;
-export const SYN_HSL = `${_NUM_ANGLE_NONE}(?:\\s+${_NUM_PCT_NONE}){2}${_ALPHA}`;
-export const SYN_HSL_LV3 = `${_NUM_ANGLE}(?:\\s*,\\s*${PCT}){2}${_ALPHA_LV3}`;
-export const SYN_LCH = `(?:${_NUM_PCT_NONE}\\s+){2}${_NUM_ANGLE_NONE}${_ALPHA}`;
-export const SYN_MOD = `${_NUM_PCT_NONE}(?:\\s+${_NUM_PCT_NONE}){2}${_ALPHA}`;
-export const SYN_RGB_LV3 = `(?:${NUM}(?:\\s*,\\s*${NUM}){2}|${PCT}(?:\\s*,\\s*${PCT}){2})${_ALPHA_LV3}`;
-export const SYN_COLOR_TYPE = `${_COLOR_KEY}|hsla?\\(\\s*${SYN_HSL_LV3}\\s*\\)|rgba?\\(\\s*${SYN_RGB_LV3}\\s*\\)|(?:hsla?|hwb)\\(\\s*${SYN_HSL}\\s*\\)|(?:(?:ok)?lab|rgba?)\\(\\s*${SYN_MOD}\\s*\\)|(?:ok)?lch\\(\\s*${SYN_LCH}\\s*\\)|color\\(\\s*${SYN_FN_COLOR}\\s*\\)`;
-export const SYN_MIX_PART = `(?:${SYN_COLOR_TYPE})(?:\\s+${PCT})?`;
-export const SYN_MIX = `color-mix\\(\\s*in\\s+(?:${CS_MIX})\\s*,\\s*${SYN_MIX_PART}\\s*,\\s*${SYN_MIX_PART}\\s*\\)`;
-export const SYN_MIX_CAPT = `color-mix\\(\\s*in\\s+(${CS_MIX})\\s*,\\s*(${SYN_MIX_PART})\\s*,\\s*(${SYN_MIX_PART})\\s*\\)`;
-
-/* formats */
-export const VAL_COMP = 'computedValue';
-export const VAL_MIX = 'mixValue';
-export const VAL_SPEC = 'specifiedValue';
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/convert.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/convert.ts
deleted file mode 100644
index bcde6db2..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/convert.ts
+++ /dev/null
@@ -1,469 +0,0 @@
-/**
- * convert
- */
-
-import {
- CacheItem,
- NullObject,
- createCacheKey,
- getCache,
- setCache
-} from './cache';
-import {
- convertColorToHsl,
- convertColorToHwb,
- convertColorToLab,
- convertColorToLch,
- convertColorToOklab,
- convertColorToOklch,
- convertColorToRgb,
- numberToHexString,
- parseColorFunc,
- parseColorValue
-} from './color';
-import { isString } from './common';
-import { cssCalc } from './css-calc';
-import { resolveVar } from './css-var';
-import { resolveRelativeColor } from './relative-color';
-import { resolveColor } from './resolve';
-import { ColorChannels, ComputedColorChannels, Options } from './typedef';
-
-/* constants */
-import { SYN_FN_CALC, SYN_FN_REL, SYN_FN_VAR, VAL_COMP } from './constant';
-const NAMESPACE = 'convert';
-
-/* regexp */
-const REG_FN_CALC = new RegExp(SYN_FN_CALC);
-const REG_FN_REL = new RegExp(SYN_FN_REL);
-const REG_FN_VAR = new RegExp(SYN_FN_VAR);
-
-/**
- * pre process
- * @param value - CSS color value
- * @param [opt] - options
- * @returns value
- */
-export const preProcess = (
- value: string,
- opt: Options = {}
-): string | NullObject => {
- if (isString(value)) {
- value = value.trim();
- if (!value) {
- return new NullObject();
- }
- } else {
- return new NullObject();
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'preProcess',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- if (cachedResult.isNull) {
- return cachedResult as NullObject;
- }
- return cachedResult.item as string;
- }
- if (REG_FN_VAR.test(value)) {
- const resolvedValue = resolveVar(value, opt);
- if (isString(resolvedValue)) {
- value = resolvedValue;
- } else {
- setCache(cacheKey, null);
- return new NullObject();
- }
- }
- if (REG_FN_REL.test(value)) {
- const resolvedValue = resolveRelativeColor(value, opt);
- if (isString(resolvedValue)) {
- value = resolvedValue;
- } else {
- setCache(cacheKey, null);
- return new NullObject();
- }
- } else if (REG_FN_CALC.test(value)) {
- value = cssCalc(value, opt);
- }
- if (value.startsWith('color-mix')) {
- const clonedOpt = structuredClone(opt);
- clonedOpt.format = VAL_COMP;
- clonedOpt.nullable = true;
- const resolvedValue = resolveColor(value, clonedOpt);
- setCache(cacheKey, resolvedValue);
- return resolvedValue;
- }
- setCache(cacheKey, value);
- return value;
-};
-
-/**
- * convert number to hex string
- * @param value - numeric value
- * @returns hex string: 00..ff
- */
-export const numberToHex = (value: number): string => {
- const hex = numberToHexString(value);
- return hex;
-};
-
-/**
- * convert color to hex
- * @param value - CSS color value
- * @param [opt] - options
- * @param [opt.alpha] - enable alpha channel
- * @returns #rrggbb | #rrggbbaa | null
- */
-export const colorToHex = (value: string, opt: Options = {}): string | null => {
- if (isString(value)) {
- const resolvedValue = preProcess(value, opt);
- if (resolvedValue instanceof NullObject) {
- return null;
- }
- value = resolvedValue.toLowerCase();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { alpha = false } = opt;
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'colorToHex',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- if (cachedResult.isNull) {
- return null;
- }
- return cachedResult.item as string;
- }
- let hex;
- opt.nullable = true;
- if (alpha) {
- opt.format = 'hexAlpha';
- hex = resolveColor(value, opt);
- } else {
- opt.format = 'hex';
- hex = resolveColor(value, opt);
- }
- if (isString(hex)) {
- setCache(cacheKey, hex);
- return hex;
- }
- setCache(cacheKey, null);
- return null;
-};
-
-/**
- * convert color to hsl
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels - [h, s, l, alpha]
- */
-export const colorToHsl = (value: string, opt: Options = {}): ColorChannels => {
- if (isString(value)) {
- const resolvedValue = preProcess(value, opt);
- if (resolvedValue instanceof NullObject) {
- return [0, 0, 0, 0];
- }
- value = resolvedValue.toLowerCase();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'colorToHsl',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- return cachedResult.item as ColorChannels;
- }
- opt.format = 'hsl';
- const hsl = convertColorToHsl(value, opt) as ColorChannels;
- setCache(cacheKey, hsl);
- return hsl;
-};
-
-/**
- * convert color to hwb
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels - [h, w, b, alpha]
- */
-export const colorToHwb = (value: string, opt: Options = {}): ColorChannels => {
- if (isString(value)) {
- const resolvedValue = preProcess(value, opt);
- if (resolvedValue instanceof NullObject) {
- return [0, 0, 0, 0];
- }
- value = resolvedValue.toLowerCase();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'colorToHwb',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- return cachedResult.item as ColorChannels;
- }
- opt.format = 'hwb';
- const hwb = convertColorToHwb(value, opt) as ColorChannels;
- setCache(cacheKey, hwb);
- return hwb;
-};
-
-/**
- * convert color to lab
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels - [l, a, b, alpha]
- */
-export const colorToLab = (value: string, opt: Options = {}): ColorChannels => {
- if (isString(value)) {
- const resolvedValue = preProcess(value, opt);
- if (resolvedValue instanceof NullObject) {
- return [0, 0, 0, 0];
- }
- value = resolvedValue.toLowerCase();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'colorToLab',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- return cachedResult.item as ColorChannels;
- }
- const lab = convertColorToLab(value, opt) as ColorChannels;
- setCache(cacheKey, lab);
- return lab;
-};
-
-/**
- * convert color to lch
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels - [l, c, h, alpha]
- */
-export const colorToLch = (value: string, opt: Options = {}): ColorChannels => {
- if (isString(value)) {
- const resolvedValue = preProcess(value, opt);
- if (resolvedValue instanceof NullObject) {
- return [0, 0, 0, 0];
- }
- value = resolvedValue.toLowerCase();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'colorToLch',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- return cachedResult.item as ColorChannels;
- }
- const lch = convertColorToLch(value, opt) as ColorChannels;
- setCache(cacheKey, lch);
- return lch;
-};
-
-/**
- * convert color to oklab
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels - [l, a, b, alpha]
- */
-export const colorToOklab = (
- value: string,
- opt: Options = {}
-): ColorChannels => {
- if (isString(value)) {
- const resolvedValue = preProcess(value, opt);
- if (resolvedValue instanceof NullObject) {
- return [0, 0, 0, 0];
- }
- value = resolvedValue.toLowerCase();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'colorToOklab',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- return cachedResult.item as ColorChannels;
- }
- const lab = convertColorToOklab(value, opt) as ColorChannels;
- setCache(cacheKey, lab);
- return lab;
-};
-
-/**
- * convert color to oklch
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels - [l, c, h, alpha]
- */
-export const colorToOklch = (
- value: string,
- opt: Options = {}
-): ColorChannels => {
- if (isString(value)) {
- const resolvedValue = preProcess(value, opt);
- if (resolvedValue instanceof NullObject) {
- return [0, 0, 0, 0];
- }
- value = resolvedValue.toLowerCase();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'colorToOklch',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- return cachedResult.item as ColorChannels;
- }
- const lch = convertColorToOklch(value, opt) as ColorChannels;
- setCache(cacheKey, lch);
- return lch;
-};
-
-/**
- * convert color to rgb
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels - [r, g, b, alpha]
- */
-export const colorToRgb = (value: string, opt: Options = {}): ColorChannels => {
- if (isString(value)) {
- const resolvedValue = preProcess(value, opt);
- if (resolvedValue instanceof NullObject) {
- return [0, 0, 0, 0];
- }
- value = resolvedValue.toLowerCase();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'colorToRgb',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- return cachedResult.item as ColorChannels;
- }
- const rgb = convertColorToRgb(value, opt) as ColorChannels;
- setCache(cacheKey, rgb);
- return rgb;
-};
-
-/**
- * convert color to xyz
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels - [x, y, z, alpha]
- */
-export const colorToXyz = (value: string, opt: Options = {}): ColorChannels => {
- if (isString(value)) {
- const resolvedValue = preProcess(value, opt);
- if (resolvedValue instanceof NullObject) {
- return [0, 0, 0, 0];
- }
- value = resolvedValue.toLowerCase();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'colorToXyz',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- return cachedResult.item as ColorChannels;
- }
- let xyz;
- if (value.startsWith('color(')) {
- [, ...xyz] = parseColorFunc(value, opt) as ComputedColorChannels;
- } else {
- [, ...xyz] = parseColorValue(value, opt) as ComputedColorChannels;
- }
- setCache(cacheKey, xyz);
- return xyz as ColorChannels;
-};
-
-/**
- * convert color to xyz-d50
- * @param value - CSS color value
- * @param [opt] - options
- * @returns ColorChannels - [x, y, z, alpha]
- */
-export const colorToXyzD50 = (
- value: string,
- opt: Options = {}
-): ColorChannels => {
- opt.d50 = true;
- return colorToXyz(value, opt);
-};
-
-/* convert */
-export const convert = {
- colorToHex,
- colorToHsl,
- colorToHwb,
- colorToLab,
- colorToLch,
- colorToOklab,
- colorToOklch,
- colorToRgb,
- colorToXyz,
- colorToXyzD50,
- numberToHex
-};
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/css-calc.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/css-calc.ts
deleted file mode 100644
index 2361645b..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/css-calc.ts
+++ /dev/null
@@ -1,965 +0,0 @@
-/**
- * css-calc
- */
-
-import { calc } from '@csstools/css-calc';
-import { CSSToken, TokenType, tokenize } from '@csstools/css-tokenizer';
-import {
- CacheItem,
- NullObject,
- createCacheKey,
- getCache,
- setCache
-} from './cache';
-import { isString, isStringOrNumber } from './common';
-import { resolveVar } from './css-var';
-import { roundToPrecision } from './util';
-import { MatchedRegExp, Options } from './typedef';
-
-/* constants */
-import {
- ANGLE,
- LENGTH,
- NUM,
- SYN_FN_CALC,
- SYN_FN_MATH_START,
- SYN_FN_VAR,
- SYN_FN_VAR_START,
- VAL_SPEC
-} from './constant';
-const {
- CloseParen: PAREN_CLOSE,
- Comment: COMMENT,
- Dimension: DIM,
- EOF,
- Function: FUNC,
- OpenParen: PAREN_OPEN,
- Whitespace: W_SPACE
-} = TokenType;
-const NAMESPACE = 'css-calc';
-
-/* numeric constants */
-const TRIA = 3;
-const HEX = 16;
-const MAX_PCT = 100;
-
-/* regexp */
-const REG_FN_CALC = new RegExp(SYN_FN_CALC);
-const REG_FN_CALC_NUM = new RegExp(`^calc\\((${NUM})\\)$`);
-const REG_FN_MATH_START = new RegExp(SYN_FN_MATH_START);
-const REG_FN_VAR = new RegExp(SYN_FN_VAR);
-const REG_FN_VAR_START = new RegExp(SYN_FN_VAR_START);
-const REG_OPERATOR = /\s[*+/-]\s/;
-const REG_TYPE_DIM = new RegExp(`^(${NUM})(${ANGLE}|${LENGTH})$`);
-const REG_TYPE_DIM_PCT = new RegExp(`^(${NUM})(${ANGLE}|${LENGTH}|%)$`);
-const REG_TYPE_PCT = new RegExp(`^(${NUM})%$`);
-
-/**
- * Calclator
- */
-export class Calculator {
- /* private */
- // number
- #hasNum: boolean;
- #numSum: number[];
- #numMul: number[];
- // percentage
- #hasPct: boolean;
- #pctSum: number[];
- #pctMul: number[];
- // dimension
- #hasDim: boolean;
- #dimSum: string[];
- #dimSub: string[];
- #dimMul: string[];
- #dimDiv: string[];
- // et cetra
- #hasEtc: boolean;
- #etcSum: string[];
- #etcSub: string[];
- #etcMul: string[];
- #etcDiv: string[];
-
- /**
- * constructor
- */
- constructor() {
- // number
- this.#hasNum = false;
- this.#numSum = [];
- this.#numMul = [];
- // percentage
- this.#hasPct = false;
- this.#pctSum = [];
- this.#pctMul = [];
- // dimension
- this.#hasDim = false;
- this.#dimSum = [];
- this.#dimSub = [];
- this.#dimMul = [];
- this.#dimDiv = [];
- // et cetra
- this.#hasEtc = false;
- this.#etcSum = [];
- this.#etcSub = [];
- this.#etcMul = [];
- this.#etcDiv = [];
- }
-
- get hasNum() {
- return this.#hasNum;
- }
-
- set hasNum(value: boolean) {
- this.#hasNum = !!value;
- }
-
- get numSum() {
- return this.#numSum;
- }
-
- get numMul() {
- return this.#numMul;
- }
-
- get hasPct() {
- return this.#hasPct;
- }
-
- set hasPct(value: boolean) {
- this.#hasPct = !!value;
- }
-
- get pctSum() {
- return this.#pctSum;
- }
-
- get pctMul() {
- return this.#pctMul;
- }
-
- get hasDim() {
- return this.#hasDim;
- }
-
- set hasDim(value: boolean) {
- this.#hasDim = !!value;
- }
-
- get dimSum() {
- return this.#dimSum;
- }
-
- get dimSub() {
- return this.#dimSub;
- }
-
- get dimMul() {
- return this.#dimMul;
- }
-
- get dimDiv() {
- return this.#dimDiv;
- }
-
- get hasEtc() {
- return this.#hasEtc;
- }
-
- set hasEtc(value: boolean) {
- this.#hasEtc = !!value;
- }
-
- get etcSum() {
- return this.#etcSum;
- }
-
- get etcSub() {
- return this.#etcSub;
- }
-
- get etcMul() {
- return this.#etcMul;
- }
-
- get etcDiv() {
- return this.#etcDiv;
- }
-
- /**
- * clear values
- * @returns void
- */
- clear() {
- // number
- this.#hasNum = false;
- this.#numSum = [];
- this.#numMul = [];
- // percentage
- this.#hasPct = false;
- this.#pctSum = [];
- this.#pctMul = [];
- // dimension
- this.#hasDim = false;
- this.#dimSum = [];
- this.#dimSub = [];
- this.#dimMul = [];
- this.#dimDiv = [];
- // et cetra
- this.#hasEtc = false;
- this.#etcSum = [];
- this.#etcSub = [];
- this.#etcMul = [];
- this.#etcDiv = [];
- }
-
- /**
- * sort values
- * @param values - values
- * @returns sorted values
- */
- sort(values: string[] = []): string[] {
- const arr = [...values];
- if (arr.length > 1) {
- arr.sort((a, b) => {
- let res;
- if (REG_TYPE_DIM_PCT.test(a) && REG_TYPE_DIM_PCT.test(b)) {
- const [, valA, unitA] = a.match(REG_TYPE_DIM_PCT) as MatchedRegExp;
- const [, valB, unitB] = b.match(REG_TYPE_DIM_PCT) as MatchedRegExp;
- if (unitA === unitB) {
- if (Number(valA) === Number(valB)) {
- res = 0;
- } else if (Number(valA) > Number(valB)) {
- res = 1;
- } else {
- res = -1;
- }
- } else if (unitA > unitB) {
- res = 1;
- } else {
- res = -1;
- }
- } else {
- if (a === b) {
- res = 0;
- } else if (a > b) {
- res = 1;
- } else {
- res = -1;
- }
- }
- return res;
- });
- }
- return arr;
- }
-
- /**
- * multiply values
- * @returns resolved value
- */
- multiply(): string {
- const value = [];
- let num;
- if (this.#hasNum) {
- num = 1;
- for (const i of this.#numMul) {
- num *= i;
- if (num === 0 || !Number.isFinite(num) || Number.isNaN(num)) {
- break;
- }
- }
- if (!this.#hasPct && !this.#hasDim && !this.hasEtc) {
- if (Number.isFinite(num)) {
- num = roundToPrecision(num, HEX);
- }
- value.push(num);
- }
- }
- if (this.#hasPct) {
- if (typeof num !== 'number') {
- num = 1;
- }
- for (const i of this.#pctMul) {
- num *= i;
- if (num === 0 || !Number.isFinite(num) || Number.isNaN(num)) {
- break;
- }
- }
- if (Number.isFinite(num)) {
- num = `${roundToPrecision(num, HEX)}%`;
- }
- if (!this.#hasDim && !this.hasEtc) {
- value.push(num);
- }
- }
- if (this.#hasDim) {
- let dim = '';
- let mul = '';
- let div = '';
- if (this.#dimMul.length) {
- if (this.#dimMul.length === 1) {
- [mul] = this.#dimMul as [string];
- } else {
- mul = `${this.sort(this.#dimMul).join(' * ')}`;
- }
- }
- if (this.#dimDiv.length) {
- if (this.#dimDiv.length === 1) {
- [div] = this.#dimDiv as [string];
- } else {
- div = `${this.sort(this.#dimDiv).join(' * ')}`;
- }
- }
- if (Number.isFinite(num)) {
- if (mul) {
- if (div) {
- if (div.includes('*')) {
- dim = calc(`calc(${num} * ${mul} / (${div}))`, {
- toCanonicalUnits: true
- });
- } else {
- dim = calc(`calc(${num} * ${mul} / ${div})`, {
- toCanonicalUnits: true
- });
- }
- } else {
- dim = calc(`calc(${num} * ${mul})`, {
- toCanonicalUnits: true
- });
- }
- } else if (div.includes('*')) {
- dim = calc(`calc(${num} / (${div}))`, {
- toCanonicalUnits: true
- });
- } else {
- dim = calc(`calc(${num} / ${div})`, {
- toCanonicalUnits: true
- });
- }
- value.push(dim.replace(/^calc/, ''));
- } else {
- if (!value.length && num !== undefined) {
- value.push(num);
- }
- if (mul) {
- if (div) {
- if (div.includes('*')) {
- dim = calc(`calc(${mul} / (${div}))`, {
- toCanonicalUnits: true
- });
- } else {
- dim = calc(`calc(${mul} / ${div})`, {
- toCanonicalUnits: true
- });
- }
- } else {
- dim = calc(`calc(${mul})`, {
- toCanonicalUnits: true
- });
- }
- if (value.length) {
- value.push('*', dim.replace(/^calc/, ''));
- } else {
- value.push(dim.replace(/^calc/, ''));
- }
- } else {
- dim = calc(`calc(${div})`, {
- toCanonicalUnits: true
- });
- if (value.length) {
- value.push('/', dim.replace(/^calc/, ''));
- } else {
- value.push('1', '/', dim.replace(/^calc/, ''));
- }
- }
- }
- }
- if (this.#hasEtc) {
- if (this.#etcMul.length) {
- if (!value.length && num !== undefined) {
- value.push(num);
- }
- const mul = this.sort(this.#etcMul).join(' * ');
- if (value.length) {
- value.push(`* ${mul}`);
- } else {
- value.push(`${mul}`);
- }
- }
- if (this.#etcDiv.length) {
- const div = this.sort(this.#etcDiv).join(' * ');
- if (div.includes('*')) {
- if (value.length) {
- value.push(`/ (${div})`);
- } else {
- value.push(`1 / (${div})`);
- }
- } else if (value.length) {
- value.push(`/ ${div}`);
- } else {
- value.push(`1 / ${div}`);
- }
- }
- }
- if (value.length) {
- return value.join(' ');
- }
- return '';
- }
-
- /**
- * sum values
- * @returns resolved value
- */
- sum(): string {
- const value = [];
- if (this.#hasNum) {
- let num = 0;
- for (const i of this.#numSum) {
- num += i;
- if (!Number.isFinite(num) || Number.isNaN(num)) {
- break;
- }
- }
- value.push(num);
- }
- if (this.#hasPct) {
- let num: number | string = 0;
- for (const i of this.#pctSum) {
- num += i;
- if (!Number.isFinite(num)) {
- break;
- }
- }
- if (Number.isFinite(num)) {
- num = `${num}%`;
- }
- if (value.length) {
- value.push(`+ ${num}`);
- } else {
- value.push(num);
- }
- }
- if (this.#hasDim) {
- let dim, sum, sub;
- if (this.#dimSum.length) {
- sum = this.sort(this.#dimSum).join(' + ');
- }
- if (this.#dimSub.length) {
- sub = this.sort(this.#dimSub).join(' + ');
- }
- if (sum) {
- if (sub) {
- if (sub.includes('-')) {
- dim = calc(`calc(${sum} - (${sub}))`, {
- toCanonicalUnits: true
- });
- } else {
- dim = calc(`calc(${sum} - ${sub})`, {
- toCanonicalUnits: true
- });
- }
- } else {
- dim = calc(`calc(${sum})`, {
- toCanonicalUnits: true
- });
- }
- } else {
- dim = calc(`calc(-1 * (${sub}))`, {
- toCanonicalUnits: true
- });
- }
- if (value.length) {
- value.push('+', dim.replace(/^calc/, ''));
- } else {
- value.push(dim.replace(/^calc/, ''));
- }
- }
- if (this.#hasEtc) {
- if (this.#etcSum.length) {
- const sum = this.sort(this.#etcSum)
- .map(item => {
- let res;
- if (
- REG_OPERATOR.test(item) &&
- !item.startsWith('(') &&
- !item.endsWith(')')
- ) {
- res = `(${item})`;
- } else {
- res = item;
- }
- return res;
- })
- .join(' + ');
- if (value.length) {
- if (this.#etcSum.length > 1) {
- value.push(`+ (${sum})`);
- } else {
- value.push(`+ ${sum}`);
- }
- } else {
- value.push(`${sum}`);
- }
- }
- if (this.#etcSub.length) {
- const sub = this.sort(this.#etcSub)
- .map(item => {
- let res;
- if (
- REG_OPERATOR.test(item) &&
- !item.startsWith('(') &&
- !item.endsWith(')')
- ) {
- res = `(${item})`;
- } else {
- res = item;
- }
- return res;
- })
- .join(' + ');
- if (value.length) {
- if (this.#etcSub.length > 1) {
- value.push(`- (${sub})`);
- } else {
- value.push(`- ${sub}`);
- }
- } else if (this.#etcSub.length > 1) {
- value.push(`-1 * (${sub})`);
- } else {
- value.push(`-1 * ${sub}`);
- }
- }
- }
- if (value.length) {
- return value.join(' ');
- }
- return '';
- }
-}
-
-/**
- * sort calc values
- * @param values - values to sort
- * @param [finalize] - finalize values
- * @returns sorted values
- */
-export const sortCalcValues = (
- values: (number | string)[] = [],
- finalize: boolean = false
-): string => {
- if (values.length < TRIA) {
- throw new Error(`Unexpected array length ${values.length}.`);
- }
- const start = values.shift();
- if (!isString(start) || !start.endsWith('(')) {
- throw new Error(`Unexpected token ${start}.`);
- }
- const end = values.pop();
- if (end !== ')') {
- throw new Error(`Unexpected token ${end}.`);
- }
- if (values.length === 1) {
- const [value] = values;
- if (!isStringOrNumber(value)) {
- throw new Error(`Unexpected token ${value}.`);
- }
- return `${start}${value}${end}`;
- }
- const sortedValues = [];
- const cal = new Calculator();
- let operator: string = '';
- const l = values.length;
- for (let i = 0; i < l; i++) {
- const value = values[i];
- if (!isStringOrNumber(value)) {
- throw new Error(`Unexpected token ${value}.`);
- }
- if (value === '*' || value === '/') {
- operator = value;
- } else if (value === '+' || value === '-') {
- const sortedValue = cal.multiply();
- if (sortedValue) {
- sortedValues.push(sortedValue, value);
- }
- cal.clear();
- operator = '';
- } else {
- const numValue = Number(value);
- const strValue = `${value}`;
- switch (operator) {
- case '/': {
- if (Number.isFinite(numValue)) {
- cal.hasNum = true;
- cal.numMul.push(1 / numValue);
- } else if (REG_TYPE_PCT.test(strValue)) {
- const [, val] = strValue.match(REG_TYPE_PCT) as MatchedRegExp;
- cal.hasPct = true;
- cal.pctMul.push((MAX_PCT * MAX_PCT) / Number(val));
- } else if (REG_TYPE_DIM.test(strValue)) {
- cal.hasDim = true;
- cal.dimDiv.push(strValue);
- } else {
- cal.hasEtc = true;
- cal.etcDiv.push(strValue);
- }
- break;
- }
- case '*':
- default: {
- if (Number.isFinite(numValue)) {
- cal.hasNum = true;
- cal.numMul.push(numValue);
- } else if (REG_TYPE_PCT.test(strValue)) {
- const [, val] = strValue.match(REG_TYPE_PCT) as MatchedRegExp;
- cal.hasPct = true;
- cal.pctMul.push(Number(val));
- } else if (REG_TYPE_DIM.test(strValue)) {
- cal.hasDim = true;
- cal.dimMul.push(strValue);
- } else {
- cal.hasEtc = true;
- cal.etcMul.push(strValue);
- }
- }
- }
- }
- if (i === l - 1) {
- const sortedValue = cal.multiply();
- if (sortedValue) {
- sortedValues.push(sortedValue);
- }
- cal.clear();
- operator = '';
- }
- }
- let resolvedValue = '';
- if (finalize && (sortedValues.includes('+') || sortedValues.includes('-'))) {
- const finalizedValues = [];
- cal.clear();
- operator = '';
- const l = sortedValues.length;
- for (let i = 0; i < l; i++) {
- const value = sortedValues[i];
- if (isStringOrNumber(value)) {
- if (value === '+' || value === '-') {
- operator = value;
- } else {
- const numValue = Number(value);
- const strValue = `${value}`;
- switch (operator) {
- case '-': {
- if (Number.isFinite(numValue)) {
- cal.hasNum = true;
- cal.numSum.push(-1 * numValue);
- } else if (REG_TYPE_PCT.test(strValue)) {
- const [, val] = strValue.match(REG_TYPE_PCT) as MatchedRegExp;
- cal.hasPct = true;
- cal.pctSum.push(-1 * Number(val));
- } else if (REG_TYPE_DIM.test(strValue)) {
- cal.hasDim = true;
- cal.dimSub.push(strValue);
- } else {
- cal.hasEtc = true;
- cal.etcSub.push(strValue);
- }
- break;
- }
- case '+':
- default: {
- if (Number.isFinite(numValue)) {
- cal.hasNum = true;
- cal.numSum.push(numValue);
- } else if (REG_TYPE_PCT.test(strValue)) {
- const [, val] = strValue.match(REG_TYPE_PCT) as MatchedRegExp;
- cal.hasPct = true;
- cal.pctSum.push(Number(val));
- } else if (REG_TYPE_DIM.test(strValue)) {
- cal.hasDim = true;
- cal.dimSum.push(strValue);
- } else {
- cal.hasEtc = true;
- cal.etcSum.push(strValue);
- }
- }
- }
- }
- }
- if (i === l - 1) {
- const sortedValue = cal.sum();
- if (sortedValue) {
- finalizedValues.push(sortedValue);
- }
- cal.clear();
- operator = '';
- }
- }
- resolvedValue = finalizedValues.join(' ').replace(/\+\s-/g, '- ');
- } else {
- resolvedValue = sortedValues.join(' ').replace(/\+\s-/g, '- ');
- }
- if (
- resolvedValue.startsWith('(') &&
- resolvedValue.endsWith(')') &&
- resolvedValue.lastIndexOf('(') === 0 &&
- resolvedValue.indexOf(')') === resolvedValue.length - 1
- ) {
- resolvedValue = resolvedValue.replace(/^\(/, '').replace(/\)$/, '');
- }
- return `${start}${resolvedValue}${end}`;
-};
-
-/**
- * serialize calc
- * @param value - CSS value
- * @param [opt] - options
- * @returns serialized value
- */
-export const serializeCalc = (value: string, opt: Options = {}): string => {
- const { format = '' } = opt;
- if (isString(value)) {
- if (!REG_FN_VAR_START.test(value) || format !== VAL_SPEC) {
- return value;
- }
- value = value.toLowerCase().trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'serializeCalc',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- return cachedResult.item as string;
- }
- const items: string[] = tokenize({ css: value })
- .map((token: CSSToken): string => {
- const [type, value] = token as [TokenType, string];
- let res = '';
- if (type !== W_SPACE && type !== COMMENT) {
- res = value;
- }
- return res;
- })
- .filter(v => v);
- let startIndex = items.findLastIndex((item: string) => /\($/.test(item));
- while (startIndex) {
- const endIndex = items.findIndex((item: unknown, index: number) => {
- return item === ')' && index > startIndex;
- });
- const slicedValues: string[] = items.slice(startIndex, endIndex + 1);
- let serializedValue: string = sortCalcValues(slicedValues);
- if (REG_FN_VAR_START.test(serializedValue)) {
- serializedValue = calc(serializedValue, {
- toCanonicalUnits: true
- });
- }
- items.splice(startIndex, endIndex - startIndex + 1, serializedValue);
- startIndex = items.findLastIndex((item: string) => /\($/.test(item));
- }
- const serializedCalc = sortCalcValues(items, true);
- setCache(cacheKey, serializedCalc);
- return serializedCalc;
-};
-
-/**
- * resolve dimension
- * @param token - CSS token
- * @param [opt] - options
- * @returns resolved value
- */
-export const resolveDimension = (
- token: CSSToken,
- opt: Options = {}
-): string | NullObject => {
- if (!Array.isArray(token)) {
- throw new TypeError(`${token} is not an array.`);
- }
- const [, , , , detail = {}] = token;
- const { unit, value } = detail as {
- unit: string;
- value: number;
- };
- const { dimension = {} } = opt;
- if (unit === 'px') {
- return `${value}${unit}`;
- }
- const relativeValue = Number(value);
- if (unit && Number.isFinite(relativeValue)) {
- let pixelValue;
- if (Object.hasOwnProperty.call(dimension, unit)) {
- pixelValue = dimension[unit];
- } else if (typeof dimension.callback === 'function') {
- pixelValue = dimension.callback(unit);
- }
- pixelValue = Number(pixelValue);
- if (Number.isFinite(pixelValue)) {
- return `${relativeValue * pixelValue}px`;
- }
- }
- return new NullObject();
-};
-
-/**
- * parse tokens
- * @param tokens - CSS tokens
- * @param [opt] - options
- * @returns parsed tokens
- */
-export const parseTokens = (
- tokens: CSSToken[],
- opt: Options = {}
-): string[] => {
- if (!Array.isArray(tokens)) {
- throw new TypeError(`${tokens} is not an array.`);
- }
- const { format = '' } = opt;
- const mathFunc = new Set();
- let nest = 0;
- const res: string[] = [];
- while (tokens.length) {
- const token = tokens.shift();
- if (!Array.isArray(token)) {
- throw new TypeError(`${token} is not an array.`);
- }
- const [type = '', value = ''] = token as [TokenType, string];
- switch (type) {
- case DIM: {
- if (format === VAL_SPEC && !mathFunc.has(nest)) {
- res.push(value);
- } else {
- const resolvedValue = resolveDimension(token, opt);
- if (isString(resolvedValue)) {
- res.push(resolvedValue);
- } else {
- res.push(value);
- }
- }
- break;
- }
- case FUNC:
- case PAREN_OPEN: {
- res.push(value);
- nest++;
- if (REG_FN_MATH_START.test(value)) {
- mathFunc.add(nest);
- }
- break;
- }
- case PAREN_CLOSE: {
- if (res.length) {
- const lastValue = res[res.length - 1];
- if (lastValue === ' ') {
- res.splice(-1, 1, value);
- } else {
- res.push(value);
- }
- } else {
- res.push(value);
- }
- if (mathFunc.has(nest)) {
- mathFunc.delete(nest);
- }
- nest--;
- break;
- }
- case W_SPACE: {
- if (res.length) {
- const lastValue = res[res.length - 1];
- if (
- isString(lastValue) &&
- !lastValue.endsWith('(') &&
- lastValue !== ' '
- ) {
- res.push(value);
- }
- }
- break;
- }
- default: {
- if (type !== COMMENT && type !== EOF) {
- res.push(value);
- }
- }
- }
- }
- return res;
-};
-
-/**
- * CSS calc()
- * @param value - CSS value including calc()
- * @param [opt] - options
- * @returns resolved value
- */
-export const cssCalc = (value: string, opt: Options = {}): string => {
- const { format = '' } = opt;
- if (isString(value)) {
- if (REG_FN_VAR.test(value)) {
- if (format === VAL_SPEC) {
- return value;
- } else {
- const resolvedValue = resolveVar(value, opt);
- if (isString(resolvedValue)) {
- return resolvedValue;
- } else {
- return '';
- }
- }
- } else if (!REG_FN_CALC.test(value)) {
- return value;
- }
- value = value.toLowerCase().trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'cssCalc',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- return cachedResult.item as string;
- }
- const tokens = tokenize({ css: value });
- const values = parseTokens(tokens, opt);
- let resolvedValue: string = calc(values.join(''), {
- toCanonicalUnits: true
- });
- if (REG_FN_VAR_START.test(value)) {
- if (REG_TYPE_DIM_PCT.test(resolvedValue)) {
- const [, val, unit] = resolvedValue.match(
- REG_TYPE_DIM_PCT
- ) as MatchedRegExp;
- resolvedValue = `${roundToPrecision(Number(val), HEX)}${unit}`;
- }
- // wrap with `calc()`
- if (
- resolvedValue &&
- !REG_FN_VAR_START.test(resolvedValue) &&
- format === VAL_SPEC
- ) {
- resolvedValue = `calc(${resolvedValue})`;
- }
- }
- if (format === VAL_SPEC) {
- if (/\s[-+*/]\s/.test(resolvedValue) && !resolvedValue.includes('NaN')) {
- resolvedValue = serializeCalc(resolvedValue, opt);
- } else if (REG_FN_CALC_NUM.test(resolvedValue)) {
- const [, val] = resolvedValue.match(REG_FN_CALC_NUM) as MatchedRegExp;
- resolvedValue = `calc(${roundToPrecision(Number(val), HEX)})`;
- }
- }
- setCache(cacheKey, resolvedValue);
- return resolvedValue;
-};
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/css-gradient.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/css-gradient.ts
deleted file mode 100644
index bb284c0a..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/css-gradient.ts
+++ /dev/null
@@ -1,289 +0,0 @@
-/**
- * css-gradient
- */
-
-import { CacheItem, createCacheKey, getCache, setCache } from './cache';
-import { isString } from './common';
-import { MatchedRegExp, Options } from './typedef';
-import { isColor, splitValue } from './util';
-
-/* constants */
-import {
- ANGLE,
- CS_HUE,
- CS_RECT,
- LENGTH,
- NUM,
- NUM_POSITIVE,
- PCT
-} from './constant';
-const NAMESPACE = 'css-gradient';
-const DIM_ANGLE = `${NUM}(?:${ANGLE})`;
-const DIM_ANGLE_PCT = `${DIM_ANGLE}|${PCT}`;
-const DIM_LEN = `${NUM}(?:${LENGTH})|0`;
-const DIM_LEN_PCT = `${DIM_LEN}|${PCT}`;
-const DIM_LEN_PCT_POSI = `${NUM_POSITIVE}(?:${LENGTH}|%)|0`;
-const DIM_LEN_POSI = `${NUM_POSITIVE}(?:${LENGTH})|0`;
-const CTR = 'center';
-const L_R = 'left|right';
-const T_B = 'top|bottom';
-const S_E = 'start|end';
-const AXIS_X = `${L_R}|x-(?:${S_E})`;
-const AXIS_Y = `${T_B}|y-(?:${S_E})`;
-const BLOCK = `block-(?:${S_E})`;
-const INLINE = `inline-(?:${S_E})`;
-const POS_1 = `${CTR}|${AXIS_X}|${AXIS_Y}|${BLOCK}|${INLINE}|${DIM_LEN_PCT}`;
-const POS_2 = [
- `(?:${CTR}|${AXIS_X})\\s+(?:${CTR}|${AXIS_Y})`,
- `(?:${CTR}|${AXIS_Y})\\s+(?:${CTR}|${AXIS_X})`,
- `(?:${CTR}|${AXIS_X}|${DIM_LEN_PCT})\\s+(?:${CTR}|${AXIS_Y}|${DIM_LEN_PCT})`,
- `(?:${CTR}|${BLOCK})\\s+(?:${CTR}|${INLINE})`,
- `(?:${CTR}|${INLINE})\\s+(?:${CTR}|${BLOCK})`,
- `(?:${CTR}|${S_E})\\s+(?:${CTR}|${S_E})`
-].join('|');
-const POS_4 = [
- `(?:${AXIS_X})\\s+(?:${DIM_LEN_PCT})\\s+(?:${AXIS_Y})\\s+(?:${DIM_LEN_PCT})`,
- `(?:${AXIS_Y})\\s+(?:${DIM_LEN_PCT})\\s+(?:${AXIS_X})\\s+(?:${DIM_LEN_PCT})`,
- `(?:${BLOCK})\\s+(?:${DIM_LEN_PCT})\\s+(?:${INLINE})\\s+(?:${DIM_LEN_PCT})`,
- `(?:${INLINE})\\s+(?:${DIM_LEN_PCT})\\s+(?:${BLOCK})\\s+(?:${DIM_LEN_PCT})`,
- `(?:${S_E})\\s+(?:${DIM_LEN_PCT})\\s+(?:${S_E})\\s+(?:${DIM_LEN_PCT})`
-].join('|');
-const RAD_EXTENT = '(?:clos|farth)est-(?:corner|side)';
-const RAD_SIZE = [
- `${RAD_EXTENT}(?:\\s+${RAD_EXTENT})?`,
- `${DIM_LEN_POSI}`,
- `(?:${DIM_LEN_PCT_POSI})\\s+(?:${DIM_LEN_PCT_POSI})`
-].join('|');
-const RAD_SHAPE = 'circle|ellipse';
-const FROM_ANGLE = `from\\s+${DIM_ANGLE}`;
-const AT_POSITION = `at\\s+(?:${POS_1}|${POS_2}|${POS_4})`;
-const TO_SIDE_CORNER = `to\\s+(?:(?:${L_R})(?:\\s(?:${T_B}))?|(?:${T_B})(?:\\s(?:${L_R}))?)`;
-const IN_COLOR_SPACE = `in\\s+(?:${CS_RECT}|${CS_HUE})`;
-
-/* type definitions */
-/**
- * @type ColorStopList - list of color stops
- */
-type ColorStopList = [string, string, ...string[]];
-
-/**
- * @typedef Gradient - parsed CSS gradient
- * @property value - input value
- * @property type - gradient type
- * @property [gradientLine] - gradient line
- * @property colorStopList - list of color stops
- */
-interface Gradient {
- value: string;
- type: string;
- gradientLine?: string;
- colorStopList: ColorStopList;
-}
-
-/* regexp */
-const REG_GRAD = /^(?:repeating-)?(?:conic|linear|radial)-gradient\(/;
-const REG_GRAD_CAPT = /^((?:repeating-)?(?:conic|linear|radial)-gradient)\(/;
-
-/**
- * get gradient type
- * @param value - gradient value
- * @returns gradient type
- */
-export const getGradientType = (value: string): string => {
- if (isString(value)) {
- value = value.trim();
- if (REG_GRAD.test(value)) {
- const [, type] = value.match(REG_GRAD_CAPT) as MatchedRegExp;
- return type;
- }
- }
- return '';
-};
-
-/**
- * validate gradient line
- * @param value - gradient line value
- * @param type - gradient type
- * @returns result
- */
-export const validateGradientLine = (value: string, type: string): boolean => {
- if (isString(value) && isString(type)) {
- value = value.trim();
- type = type.trim();
- let lineSyntax = '';
- if (/^(?:repeating-)?linear-gradient$/.test(type)) {
- /*
- * = [
- * [ | to ] ||
- *
- * ]
- */
- lineSyntax = [
- `(?:${DIM_ANGLE}|${TO_SIDE_CORNER})(?:\\s+${IN_COLOR_SPACE})?`,
- `${IN_COLOR_SPACE}(?:\\s+(?:${DIM_ANGLE}|${TO_SIDE_CORNER}))?`
- ].join('|');
- } else if (/^(?:repeating-)?radial-gradient$/.test(type)) {
- /*
- * = [
- * [ [ || ]? [ at ]? ] ||
- * ]?
- */
- lineSyntax = [
- `(?:${RAD_SHAPE})(?:\\s+(?:${RAD_SIZE}))?(?:\\s+${AT_POSITION})?(?:\\s+${IN_COLOR_SPACE})?`,
- `(?:${RAD_SIZE})(?:\\s+(?:${RAD_SHAPE}))?(?:\\s+${AT_POSITION})?(?:\\s+${IN_COLOR_SPACE})?`,
- `${AT_POSITION}(?:\\s+${IN_COLOR_SPACE})?`,
- `${IN_COLOR_SPACE}(?:\\s+${RAD_SHAPE})(?:\\s+(?:${RAD_SIZE}))?(?:\\s+${AT_POSITION})?`,
- `${IN_COLOR_SPACE}(?:\\s+${RAD_SIZE})(?:\\s+(?:${RAD_SHAPE}))?(?:\\s+${AT_POSITION})?`,
- `${IN_COLOR_SPACE}(?:\\s+${AT_POSITION})?`
- ].join('|');
- } else if (/^(?:repeating-)?conic-gradient$/.test(type)) {
- /*
- * = [
- * [ [ from ]? [ at ]? ] ||
- *
- * ]
- */
- lineSyntax = [
- `${FROM_ANGLE}(?:\\s+${AT_POSITION})?(?:\\s+${IN_COLOR_SPACE})?`,
- `${AT_POSITION}(?:\\s+${IN_COLOR_SPACE})?`,
- `${IN_COLOR_SPACE}(?:\\s+${FROM_ANGLE})?(?:\\s+${AT_POSITION})?`
- ].join('|');
- }
- if (lineSyntax) {
- const reg = new RegExp(`^(?:${lineSyntax})$`);
- return reg.test(value);
- }
- }
- return false;
-};
-
-/**
- * validate color stop list
- * @param list
- * @param type
- * @param [opt]
- * @returns result
- */
-export const validateColorStopList = (
- list: string[],
- type: string,
- opt: Options = {}
-): boolean => {
- if (Array.isArray(list) && list.length > 1) {
- const dimension = /^(?:repeating-)?conic-gradient$/.test(type)
- ? DIM_ANGLE_PCT
- : DIM_LEN_PCT;
- const regColorHint = new RegExp(`^(?:${dimension})$`);
- const regDimension = new RegExp(`(?:\\s+(?:${dimension})){1,2}$`);
- const arr = [];
- for (const item of list) {
- if (isString(item)) {
- if (regColorHint.test(item)) {
- arr.push('hint');
- } else {
- const color = item.replace(regDimension, '');
- if (isColor(color, opt)) {
- arr.push('color');
- } else {
- return false;
- }
- }
- }
- }
- const value = arr.join(',');
- return /^color(?:,(?:hint,)?color)+$/.test(value);
- }
- return false;
-};
-
-/**
- * parse CSS gradient
- * @param value - gradient value
- * @param [opt] - options
- * @returns parsed result
- */
-export const parseGradient = (
- value: string,
- opt: Options = {}
-): Gradient | null => {
- if (isString(value)) {
- value = value.trim();
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'parseGradient',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- if (cachedResult.isNull) {
- return null;
- }
- return cachedResult.item as Gradient;
- }
- const type = getGradientType(value);
- const gradValue = value.replace(REG_GRAD, '').replace(/\)$/, '');
- if (type && gradValue) {
- const [lineOrColorStop = '', ...colorStops] = splitValue(gradValue, {
- delimiter: ','
- });
- const dimension = /^(?:repeating-)?conic-gradient$/.test(type)
- ? DIM_ANGLE_PCT
- : DIM_LEN_PCT;
- const regDimension = new RegExp(`(?:\\s+(?:${dimension})){1,2}$`);
- let isColorStop = false;
- if (regDimension.test(lineOrColorStop)) {
- const colorStop = lineOrColorStop.replace(regDimension, '');
- if (isColor(colorStop, opt)) {
- isColorStop = true;
- }
- } else if (isColor(lineOrColorStop, opt)) {
- isColorStop = true;
- }
- if (isColorStop) {
- colorStops.unshift(lineOrColorStop);
- const valid = validateColorStopList(colorStops, type, opt);
- if (valid) {
- const res: Gradient = {
- value,
- type,
- colorStopList: colorStops as ColorStopList
- };
- setCache(cacheKey, res);
- return res;
- }
- } else if (colorStops.length > 1) {
- const gradientLine = lineOrColorStop;
- const valid =
- validateGradientLine(gradientLine, type) &&
- validateColorStopList(colorStops, type, opt);
- if (valid) {
- const res: Gradient = {
- value,
- type,
- gradientLine,
- colorStopList: colorStops as ColorStopList
- };
- setCache(cacheKey, res);
- return res;
- }
- }
- }
- setCache(cacheKey, null);
- return null;
- }
- return null;
-};
-
-/**
- * is CSS gradient
- * @param value - CSS value
- * @param [opt] - options
- * @returns result
- */
-export const isGradient = (value: string, opt: Options = {}): boolean => {
- const gradient = parseGradient(value, opt);
- return gradient !== null;
-};
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/css-var.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/css-var.ts
deleted file mode 100644
index 160253d9..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/css-var.ts
+++ /dev/null
@@ -1,250 +0,0 @@
-/**
- * css-var
- */
-
-import { CSSToken, TokenType, tokenize } from '@csstools/css-tokenizer';
-import {
- CacheItem,
- NullObject,
- createCacheKey,
- getCache,
- setCache
-} from './cache';
-import { isString } from './common';
-import { cssCalc } from './css-calc';
-import { isColor } from './util';
-import { Options } from './typedef';
-
-/* constants */
-import { FN_VAR, SYN_FN_CALC, SYN_FN_VAR, VAL_SPEC } from './constant';
-const {
- CloseParen: PAREN_CLOSE,
- Comment: COMMENT,
- EOF,
- Ident: IDENT,
- Whitespace: W_SPACE
-} = TokenType;
-const NAMESPACE = 'css-var';
-
-/* regexp */
-const REG_FN_CALC = new RegExp(SYN_FN_CALC);
-const REG_FN_VAR = new RegExp(SYN_FN_VAR);
-
-/**
- * resolve custom property
- * @param tokens - CSS tokens
- * @param [opt] - options
- * @returns result - [tokens, resolvedValue]
- */
-export function resolveCustomProperty(
- tokens: CSSToken[],
- opt: Options = {}
-): [CSSToken[], string] {
- if (!Array.isArray(tokens)) {
- throw new TypeError(`${tokens} is not an array.`);
- }
- const { customProperty = {} } = opt;
- const items: string[] = [];
- while (tokens.length) {
- const token = tokens.shift();
- if (!Array.isArray(token)) {
- throw new TypeError(`${token} is not an array.`);
- }
- const [type, value] = token as [TokenType, string];
- // end of var()
- if (type === PAREN_CLOSE) {
- break;
- }
- // nested var()
- if (value === FN_VAR) {
- const [restTokens, item] = resolveCustomProperty(tokens, opt);
- tokens = restTokens;
- if (item) {
- items.push(item);
- }
- } else if (type === IDENT) {
- if (value.startsWith('--')) {
- let item;
- if (Object.hasOwnProperty.call(customProperty, value)) {
- item = customProperty[value] as string;
- } else if (typeof customProperty.callback === 'function') {
- item = customProperty.callback(value);
- }
- if (item) {
- items.push(item);
- }
- } else if (value) {
- items.push(value);
- }
- }
- }
- let resolveAsColor = false;
- if (items.length > 1) {
- const lastValue = items[items.length - 1];
- resolveAsColor = isColor(lastValue);
- }
- let resolvedValue = '';
- for (let item of items) {
- item = item.trim();
- if (REG_FN_VAR.test(item)) {
- // recurse resolveVar()
- const resolvedItem = resolveVar(item, opt);
- if (isString(resolvedItem)) {
- if (resolveAsColor) {
- if (isColor(resolvedItem)) {
- resolvedValue = resolvedItem;
- }
- } else {
- resolvedValue = resolvedItem;
- }
- }
- } else if (REG_FN_CALC.test(item)) {
- item = cssCalc(item, opt);
- if (resolveAsColor) {
- if (isColor(item)) {
- resolvedValue = item;
- }
- } else {
- resolvedValue = item;
- }
- } else if (
- item &&
- !/^(?:inherit|initial|revert(?:-layer)?|unset)$/.test(item)
- ) {
- if (resolveAsColor) {
- if (isColor(item)) {
- resolvedValue = item;
- }
- } else {
- resolvedValue = item;
- }
- }
- if (resolvedValue) {
- break;
- }
- }
- return [tokens, resolvedValue];
-}
-
-/**
- * parse tokens
- * @param tokens - CSS tokens
- * @param [opt] - options
- * @returns parsed tokens
- */
-export function parseTokens(
- tokens: CSSToken[],
- opt: Options = {}
-): string[] | NullObject {
- const res: string[] = [];
- while (tokens.length) {
- const token = tokens.shift();
- const [type = '', value = ''] = token as [TokenType, string];
- if (value === FN_VAR) {
- const [restTokens, resolvedValue] = resolveCustomProperty(tokens, opt);
- if (!resolvedValue) {
- return new NullObject();
- }
- tokens = restTokens;
- res.push(resolvedValue);
- } else {
- switch (type) {
- case PAREN_CLOSE: {
- if (res.length) {
- const lastValue = res[res.length - 1];
- if (lastValue === ' ') {
- res.splice(-1, 1, value);
- } else {
- res.push(value);
- }
- } else {
- res.push(value);
- }
- break;
- }
- case W_SPACE: {
- if (res.length) {
- const lastValue = res[res.length - 1];
- if (
- isString(lastValue) &&
- !lastValue.endsWith('(') &&
- lastValue !== ' '
- ) {
- res.push(value);
- }
- }
- break;
- }
- default: {
- if (type !== COMMENT && type !== EOF) {
- res.push(value);
- }
- }
- }
- }
- }
- return res;
-}
-
-/**
- * resolve CSS var()
- * @param value - CSS value including var()
- * @param [opt] - options
- * @returns resolved value
- */
-export function resolveVar(
- value: string,
- opt: Options = {}
-): string | NullObject {
- const { format = '' } = opt;
- if (isString(value)) {
- if (!REG_FN_VAR.test(value) || format === VAL_SPEC) {
- return value;
- }
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'resolveVar',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- if (cachedResult.isNull) {
- return cachedResult as NullObject;
- }
- return cachedResult.item as string;
- }
- const tokens = tokenize({ css: value });
- const values = parseTokens(tokens, opt);
- if (Array.isArray(values)) {
- let color = values.join('');
- if (REG_FN_CALC.test(color)) {
- color = cssCalc(color, opt);
- }
- setCache(cacheKey, color);
- return color;
- } else {
- setCache(cacheKey, null);
- return new NullObject();
- }
-}
-
-/**
- * CSS var()
- * @param value - CSS value including var()
- * @param [opt] - options
- * @returns resolved value
- */
-export const cssVar = (value: string, opt: Options = {}): string => {
- const resolvedValue = resolveVar(value, opt);
- if (isString(resolvedValue)) {
- return resolvedValue;
- }
- return '';
-};
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/relative-color.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/relative-color.ts
deleted file mode 100644
index 6fbacd19..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/relative-color.ts
+++ /dev/null
@@ -1,580 +0,0 @@
-/**
- * relative-color
- */
-
-import { SyntaxFlag, color as colorParser } from '@csstools/css-color-parser';
-import {
- ComponentValue,
- parseComponentValue
-} from '@csstools/css-parser-algorithms';
-import { CSSToken, TokenType, tokenize } from '@csstools/css-tokenizer';
-import {
- CacheItem,
- NullObject,
- createCacheKey,
- getCache,
- setCache
-} from './cache';
-import { NAMED_COLORS, convertColorToRgb } from './color';
-import { isString, isStringOrNumber } from './common';
-import { resolveDimension, serializeCalc } from './css-calc';
-import { resolveColor } from './resolve';
-import { roundToPrecision } from './util';
-import {
- ColorChannels,
- MatchedRegExp,
- Options,
- StringColorChannels
-} from './typedef';
-
-/* constants */
-import {
- CS_LAB,
- CS_LCH,
- FN_REL,
- FN_REL_CAPT,
- FN_VAR,
- NONE,
- SYN_COLOR_TYPE,
- SYN_FN_MATH_START,
- SYN_FN_VAR,
- SYN_MIX,
- VAL_SPEC
-} from './constant';
-const {
- CloseParen: PAREN_CLOSE,
- Comment: COMMENT,
- Dimension: DIM,
- EOF,
- Function: FUNC,
- Ident: IDENT,
- Number: NUM,
- OpenParen: PAREN_OPEN,
- Percentage: PCT,
- Whitespace: W_SPACE
-} = TokenType;
-const { HasNoneKeywords: KEY_NONE } = SyntaxFlag;
-const NAMESPACE = 'relative-color';
-
-/* numeric constants */
-const OCT = 8;
-const DEC = 10;
-const HEX = 16;
-const MAX_PCT = 100;
-const MAX_RGB = 255;
-
-/* type definitions */
-/**
- * @type NumberOrStringColorChannels - color channel
- */
-type NumberOrStringColorChannels = ColorChannels & StringColorChannels;
-
-/* regexp */
-const REG_COLOR_CAPT = new RegExp(
- `^${FN_REL}(${SYN_COLOR_TYPE}|${SYN_MIX})\\s+`
-);
-const REG_CS_HSL = /(?:hsla?|hwb)$/;
-const REG_CS_CIE = new RegExp(`^(?:${CS_LAB}|${CS_LCH})$`);
-const REG_FN_MATH_START = new RegExp(SYN_FN_MATH_START);
-const REG_FN_REL = new RegExp(FN_REL);
-const REG_FN_REL_CAPT = new RegExp(`^${FN_REL_CAPT}`);
-const REG_FN_REL_START = new RegExp(`^${FN_REL}`);
-const REG_FN_VAR = new RegExp(SYN_FN_VAR);
-
-/**
- * resolve relative color channels
- * @param tokens - CSS tokens
- * @param [opt] - options
- * @returns resolved color channels
- */
-export function resolveColorChannels(
- tokens: CSSToken[],
- opt: Options = {}
-): NumberOrStringColorChannels | NullObject {
- if (!Array.isArray(tokens)) {
- throw new TypeError(`${tokens} is not an array.`);
- }
- const { colorSpace = '', format = '' } = opt;
- const colorChannels = new Map([
- ['color', ['r', 'g', 'b', 'alpha']],
- ['hsl', ['h', 's', 'l', 'alpha']],
- ['hsla', ['h', 's', 'l', 'alpha']],
- ['hwb', ['h', 'w', 'b', 'alpha']],
- ['lab', ['l', 'a', 'b', 'alpha']],
- ['lch', ['l', 'c', 'h', 'alpha']],
- ['oklab', ['l', 'a', 'b', 'alpha']],
- ['oklch', ['l', 'c', 'h', 'alpha']],
- ['rgb', ['r', 'g', 'b', 'alpha']],
- ['rgba', ['r', 'g', 'b', 'alpha']]
- ]);
- const colorChannel = colorChannels.get(colorSpace);
- // invalid color channel
- if (!colorChannel) {
- return new NullObject();
- }
- const mathFunc = new Set();
- const channels: [
- (number | string)[],
- (number | string)[],
- (number | string)[],
- (number | string)[]
- ] = [[], [], [], []];
- let i = 0;
- let nest = 0;
- let func = false;
- while (tokens.length) {
- const token = tokens.shift();
- if (!Array.isArray(token)) {
- throw new TypeError(`${token} is not an array.`);
- }
- const [type, value, , , detail] = token as [
- TokenType,
- string,
- number,
- number,
- { value: string | number } | undefined
- ];
- const channel = channels[i];
- if (Array.isArray(channel)) {
- switch (type) {
- case DIM: {
- const resolvedValue = resolveDimension(token, opt);
- if (isString(resolvedValue)) {
- channel.push(resolvedValue);
- } else {
- channel.push(value);
- }
- break;
- }
- case FUNC: {
- channel.push(value);
- func = true;
- nest++;
- if (REG_FN_MATH_START.test(value)) {
- mathFunc.add(nest);
- }
- break;
- }
- case IDENT: {
- // invalid channel key
- if (!colorChannel.includes(value)) {
- return new NullObject();
- }
- channel.push(value);
- if (!func) {
- i++;
- }
- break;
- }
- case NUM: {
- channel.push(Number(detail?.value));
- if (!func) {
- i++;
- }
- break;
- }
- case PAREN_OPEN: {
- channel.push(value);
- nest++;
- break;
- }
- case PAREN_CLOSE: {
- if (func) {
- const lastValue = channel[channel.length - 1];
- if (lastValue === ' ') {
- channel.splice(-1, 1, value);
- } else {
- channel.push(value);
- }
- if (mathFunc.has(nest)) {
- mathFunc.delete(nest);
- }
- nest--;
- if (nest === 0) {
- func = false;
- i++;
- }
- }
- break;
- }
- case PCT: {
- channel.push(Number(detail?.value) / MAX_PCT);
- if (!func) {
- i++;
- }
- break;
- }
- case W_SPACE: {
- if (channel.length && func) {
- const lastValue = channel[channel.length - 1];
- if (typeof lastValue === 'number') {
- channel.push(value);
- } else if (
- isString(lastValue) &&
- !lastValue.endsWith('(') &&
- lastValue !== ' '
- ) {
- channel.push(value);
- }
- }
- break;
- }
- default: {
- if (type !== COMMENT && type !== EOF && func) {
- channel.push(value);
- }
- }
- }
- }
- }
- const channelValues = [];
- for (const channel of channels) {
- if (channel.length === 1) {
- const [resolvedValue] = channel;
- if (isStringOrNumber(resolvedValue)) {
- channelValues.push(resolvedValue);
- }
- } else if (channel.length) {
- const resolvedValue = serializeCalc(channel.join(''), {
- format
- });
- channelValues.push(resolvedValue);
- }
- }
- return channelValues as NumberOrStringColorChannels;
-}
-
-/**
- * extract origin color
- * @param value - CSS color value
- * @param [opt] - options
- * @returns origin color value
- */
-export function extractOriginColor(
- value: string,
- opt: Options = {}
-): string | NullObject {
- const { currentColor = '', format = '' } = opt;
- if (isString(value)) {
- value = value.toLowerCase().trim();
- if (!value) {
- return new NullObject();
- }
- if (!REG_FN_REL_START.test(value)) {
- return value;
- }
- } else {
- return new NullObject();
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'extractOriginColor',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- if (cachedResult.isNull) {
- return cachedResult as NullObject;
- }
- return cachedResult.item as string;
- }
- if (/currentcolor/.test(value)) {
- if (currentColor) {
- value = value.replace(/currentcolor/g, currentColor);
- } else {
- setCache(cacheKey, null);
- return new NullObject();
- }
- }
- let colorSpace = '';
- if (REG_FN_REL_CAPT.test(value)) {
- [, colorSpace] = value.match(REG_FN_REL_CAPT) as MatchedRegExp;
- }
- opt.colorSpace = colorSpace;
- if (REG_COLOR_CAPT.test(value)) {
- const [, originColor] = value.match(REG_COLOR_CAPT) as MatchedRegExp;
- const [, restValue] = value.split(originColor) as MatchedRegExp;
- if (/^[a-z]+$/.test(originColor)) {
- if (
- !/^transparent$/.test(originColor) &&
- !Object.prototype.hasOwnProperty.call(NAMED_COLORS, originColor)
- ) {
- setCache(cacheKey, null);
- return new NullObject();
- }
- } else if (format === VAL_SPEC) {
- const resolvedOriginColor = resolveColor(originColor, opt);
- if (isString(resolvedOriginColor)) {
- value = value.replace(originColor, resolvedOriginColor);
- }
- }
- if (format === VAL_SPEC) {
- const tokens = tokenize({ css: restValue });
- const channelValues = resolveColorChannels(tokens, opt);
- if (channelValues instanceof NullObject) {
- setCache(cacheKey, null);
- return channelValues;
- }
- const [v1, v2, v3, v4] = channelValues;
- let channelValue = '';
- if (isStringOrNumber(v4)) {
- channelValue = ` ${v1} ${v2} ${v3} / ${v4})`;
- } else {
- channelValue = ` ${channelValues.join(' ')})`;
- }
- if (restValue !== channelValue) {
- value = value.replace(restValue, channelValue);
- }
- }
- // nested relative color
- } else {
- const [, restValue] = value.split(REG_FN_REL_START) as MatchedRegExp;
- const tokens = tokenize({ css: restValue });
- const originColor: string[] = [];
- let nest = 0;
- while (tokens.length) {
- const [type, tokenValue] = tokens.shift() as [TokenType, string];
- switch (type) {
- case FUNC:
- case PAREN_OPEN: {
- originColor.push(tokenValue);
- nest++;
- break;
- }
- case PAREN_CLOSE: {
- const lastValue = originColor[originColor.length - 1];
- if (lastValue === ' ') {
- originColor.splice(-1, 1, tokenValue);
- } else if (isString(lastValue)) {
- originColor.push(tokenValue);
- }
- nest--;
- break;
- }
- case W_SPACE: {
- const lastValue = originColor[originColor.length - 1];
- if (
- isString(lastValue) &&
- !lastValue.endsWith('(') &&
- lastValue !== ' '
- ) {
- originColor.push(tokenValue);
- }
- break;
- }
- default: {
- if (type !== COMMENT && type !== EOF) {
- originColor.push(tokenValue);
- }
- }
- }
- if (nest === 0) {
- break;
- }
- }
- const resolvedOriginColor = resolveRelativeColor(
- originColor.join('').trim(),
- opt
- );
- if (resolvedOriginColor instanceof NullObject) {
- setCache(cacheKey, null);
- return resolvedOriginColor;
- }
- const channelValues = resolveColorChannels(tokens, opt);
- if (channelValues instanceof NullObject) {
- setCache(cacheKey, null);
- return channelValues;
- }
- const [v1, v2, v3, v4] = channelValues;
- let channelValue = '';
- if (isStringOrNumber(v4)) {
- channelValue = ` ${v1} ${v2} ${v3} / ${v4})`;
- } else {
- channelValue = ` ${channelValues.join(' ')})`;
- }
- value = value.replace(restValue, `${resolvedOriginColor}${channelValue}`);
- }
- setCache(cacheKey, value);
- return value;
-}
-
-/**
- * resolve relative color
- * @param value - CSS relative color value
- * @param [opt] - options
- * @returns resolved value
- */
-export function resolveRelativeColor(
- value: string,
- opt: Options = {}
-): string | NullObject {
- const { format = '' } = opt;
- if (isString(value)) {
- if (REG_FN_VAR.test(value)) {
- if (format === VAL_SPEC) {
- return value;
- // var() must be resolved before resolveRelativeColor()
- } else {
- throw new SyntaxError(`Unexpected token ${FN_VAR} found.`);
- }
- } else if (!REG_FN_REL.test(value)) {
- return value;
- }
- value = value.toLowerCase().trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'resolveRelativeColor',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- if (cachedResult.isNull) {
- return cachedResult as NullObject;
- }
- return cachedResult.item as string;
- }
- const originColor = extractOriginColor(value, opt);
- if (originColor instanceof NullObject) {
- setCache(cacheKey, null);
- return originColor;
- }
- value = originColor;
- if (format === VAL_SPEC) {
- if (value.startsWith('rgba(')) {
- value = value.replace(/^rgba\(/, 'rgb(');
- } else if (value.startsWith('hsla(')) {
- value = value.replace(/^hsla\(/, 'hsl(');
- }
- return value;
- }
- const tokens = tokenize({ css: value });
- const components = parseComponentValue(tokens) as ComponentValue;
- const parsedComponents = colorParser(components);
- if (!parsedComponents) {
- setCache(cacheKey, null);
- return new NullObject();
- }
- const {
- alpha: alphaComponent,
- channels: channelsComponent,
- colorNotation,
- syntaxFlags
- } = parsedComponents;
- let alpha: number | string;
- if (Number.isNaN(Number(alphaComponent))) {
- if (syntaxFlags instanceof Set && syntaxFlags.has(KEY_NONE)) {
- alpha = NONE;
- } else {
- alpha = 0;
- }
- } else {
- alpha = roundToPrecision(Number(alphaComponent), OCT);
- }
- let v1: number | string;
- let v2: number | string;
- let v3: number | string;
- [v1, v2, v3] = channelsComponent;
- let resolvedValue;
- if (REG_CS_CIE.test(colorNotation)) {
- const hasNone = syntaxFlags instanceof Set && syntaxFlags.has(KEY_NONE);
- if (Number.isNaN(v1)) {
- if (hasNone) {
- v1 = NONE;
- } else {
- v1 = 0;
- }
- } else {
- v1 = roundToPrecision(v1, HEX);
- }
- if (Number.isNaN(v2)) {
- if (hasNone) {
- v2 = NONE;
- } else {
- v2 = 0;
- }
- } else {
- v2 = roundToPrecision(v2, HEX);
- }
- if (Number.isNaN(v3)) {
- if (hasNone) {
- v3 = NONE;
- } else {
- v3 = 0;
- }
- } else {
- v3 = roundToPrecision(v3, HEX);
- }
- if (alpha === 1) {
- resolvedValue = `${colorNotation}(${v1} ${v2} ${v3})`;
- } else {
- resolvedValue = `${colorNotation}(${v1} ${v2} ${v3} / ${alpha})`;
- }
- } else if (REG_CS_HSL.test(colorNotation)) {
- if (Number.isNaN(v1)) {
- v1 = 0;
- }
- if (Number.isNaN(v2)) {
- v2 = 0;
- }
- if (Number.isNaN(v3)) {
- v3 = 0;
- }
- let [r, g, b] = convertColorToRgb(
- `${colorNotation}(${v1} ${v2} ${v3} / ${alpha})`
- ) as ColorChannels;
- r = roundToPrecision(r / MAX_RGB, DEC);
- g = roundToPrecision(g / MAX_RGB, DEC);
- b = roundToPrecision(b / MAX_RGB, DEC);
- if (alpha === 1) {
- resolvedValue = `color(srgb ${r} ${g} ${b})`;
- } else {
- resolvedValue = `color(srgb ${r} ${g} ${b} / ${alpha})`;
- }
- } else {
- const cs = colorNotation === 'rgb' ? 'srgb' : colorNotation;
- const hasNone = syntaxFlags instanceof Set && syntaxFlags.has(KEY_NONE);
- if (Number.isNaN(v1)) {
- if (hasNone) {
- v1 = NONE;
- } else {
- v1 = 0;
- }
- } else {
- v1 = roundToPrecision(v1, DEC);
- }
- if (Number.isNaN(v2)) {
- if (hasNone) {
- v2 = NONE;
- } else {
- v2 = 0;
- }
- } else {
- v2 = roundToPrecision(v2, DEC);
- }
- if (Number.isNaN(v3)) {
- if (hasNone) {
- v3 = NONE;
- } else {
- v3 = 0;
- }
- } else {
- v3 = roundToPrecision(v3, DEC);
- }
- if (alpha === 1) {
- resolvedValue = `color(${cs} ${v1} ${v2} ${v3})`;
- } else {
- resolvedValue = `color(${cs} ${v1} ${v2} ${v3} / ${alpha})`;
- }
- }
- setCache(cacheKey, resolvedValue);
- return resolvedValue;
-}
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/resolve.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/resolve.ts
deleted file mode 100644
index 6776109c..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/resolve.ts
+++ /dev/null
@@ -1,379 +0,0 @@
-/**
- * resolve
- */
-
-import {
- CacheItem,
- NullObject,
- createCacheKey,
- getCache,
- setCache
-} from './cache';
-import {
- convertRgbToHex,
- resolveColorFunc,
- resolveColorMix,
- resolveColorValue
-} from './color';
-import { isString } from './common';
-import { cssCalc } from './css-calc';
-import { resolveVar } from './css-var';
-import { resolveRelativeColor } from './relative-color';
-import {
- ComputedColorChannels,
- Options,
- SpecifiedColorChannels
-} from './typedef';
-
-/* constants */
-import {
- FN_COLOR,
- FN_MIX,
- SYN_FN_CALC,
- SYN_FN_REL,
- SYN_FN_VAR,
- VAL_COMP,
- VAL_SPEC
-} from './constant';
-const NAMESPACE = 'resolve';
-const RGB_TRANSPARENT = 'rgba(0, 0, 0, 0)';
-
-/* regexp */
-const REG_FN_CALC = new RegExp(SYN_FN_CALC);
-const REG_FN_REL = new RegExp(SYN_FN_REL);
-const REG_FN_VAR = new RegExp(SYN_FN_VAR);
-
-/**
- * resolve color
- * @param value - CSS color value
- * @param [opt] - options
- * @returns resolved color
- */
-export const resolveColor = (
- value: string,
- opt: Options = {}
-): string | NullObject => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { currentColor = '', format = VAL_COMP, nullable = false } = opt;
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'resolve',
- value
- },
- opt
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- if (cachedResult.isNull) {
- return cachedResult as NullObject;
- }
- return cachedResult.item as string;
- }
- if (REG_FN_VAR.test(value)) {
- if (format === VAL_SPEC) {
- setCache(cacheKey, value);
- return value;
- }
- const resolvedValue = resolveVar(value, opt);
- if (resolvedValue instanceof NullObject) {
- switch (format) {
- case 'hex':
- case 'hexAlpha': {
- setCache(cacheKey, resolvedValue);
- return resolvedValue;
- }
- default: {
- if (nullable) {
- setCache(cacheKey, resolvedValue);
- return resolvedValue;
- }
- const res = RGB_TRANSPARENT;
- setCache(cacheKey, res);
- return res;
- }
- }
- } else {
- value = resolvedValue;
- }
- }
- if (opt.format !== format) {
- opt.format = format;
- }
- value = value.toLowerCase();
- if (REG_FN_REL.test(value)) {
- const resolvedValue = resolveRelativeColor(value, opt);
- if (format === VAL_COMP) {
- let res;
- if (resolvedValue instanceof NullObject) {
- if (nullable) {
- res = resolvedValue;
- } else {
- res = RGB_TRANSPARENT;
- }
- } else {
- res = resolvedValue;
- }
- setCache(cacheKey, res);
- return res;
- }
- if (format === VAL_SPEC) {
- let res = '';
- if (resolvedValue instanceof NullObject) {
- res = '';
- } else {
- res = resolvedValue;
- }
- setCache(cacheKey, res);
- return res;
- }
- if (resolvedValue instanceof NullObject) {
- value = '';
- } else {
- value = resolvedValue;
- }
- }
- if (REG_FN_CALC.test(value)) {
- value = cssCalc(value, opt);
- }
- let cs = '';
- let r = NaN;
- let g = NaN;
- let b = NaN;
- let alpha = NaN;
- if (value === 'transparent') {
- switch (format) {
- case VAL_SPEC: {
- setCache(cacheKey, value);
- return value;
- }
- case 'hex': {
- setCache(cacheKey, null);
- return new NullObject();
- }
- case 'hexAlpha': {
- const res = '#00000000';
- setCache(cacheKey, res);
- return res;
- }
- case VAL_COMP:
- default: {
- const res = RGB_TRANSPARENT;
- setCache(cacheKey, res);
- return res;
- }
- }
- } else if (value === 'currentcolor') {
- if (format === VAL_SPEC) {
- setCache(cacheKey, value);
- return value;
- }
- if (currentColor) {
- let resolvedValue;
- if (currentColor.startsWith(FN_MIX)) {
- resolvedValue = resolveColorMix(currentColor, opt);
- } else if (currentColor.startsWith(FN_COLOR)) {
- resolvedValue = resolveColorFunc(currentColor, opt);
- } else {
- resolvedValue = resolveColorValue(currentColor, opt);
- }
- if (resolvedValue instanceof NullObject) {
- setCache(cacheKey, resolvedValue);
- return resolvedValue;
- }
- [cs, r, g, b, alpha] = resolvedValue as ComputedColorChannels;
- } else if (format === VAL_COMP) {
- const res = RGB_TRANSPARENT;
- setCache(cacheKey, res);
- return res;
- }
- } else if (format === VAL_SPEC) {
- if (value.startsWith(FN_MIX)) {
- const res = resolveColorMix(value, opt) as string;
- setCache(cacheKey, res);
- return res;
- } else if (value.startsWith(FN_COLOR)) {
- const [scs, rr, gg, bb, aa] = resolveColorFunc(
- value,
- opt
- ) as SpecifiedColorChannels;
- let res = '';
- if (aa === 1) {
- res = `color(${scs} ${rr} ${gg} ${bb})`;
- } else {
- res = `color(${scs} ${rr} ${gg} ${bb} / ${aa})`;
- }
- setCache(cacheKey, res);
- return res;
- } else {
- const rgb = resolveColorValue(value, opt);
- if (isString(rgb)) {
- setCache(cacheKey, rgb);
- return rgb;
- }
- const [scs, rr, gg, bb, aa] = rgb as SpecifiedColorChannels;
- let res = '';
- if (scs === 'rgb') {
- if (aa === 1) {
- res = `${scs}(${rr}, ${gg}, ${bb})`;
- } else {
- res = `${scs}a(${rr}, ${gg}, ${bb}, ${aa})`;
- }
- } else if (aa === 1) {
- res = `${scs}(${rr} ${gg} ${bb})`;
- } else {
- res = `${scs}(${rr} ${gg} ${bb} / ${aa})`;
- }
- setCache(cacheKey, res);
- return res;
- }
- } else if (value.startsWith(FN_MIX)) {
- if (/currentcolor/.test(value)) {
- if (currentColor) {
- value = value.replace(/currentcolor/g, currentColor);
- }
- }
- if (/transparent/.test(value)) {
- value = value.replace(/transparent/g, RGB_TRANSPARENT);
- }
- const resolvedValue = resolveColorMix(value, opt);
- if (resolvedValue instanceof NullObject) {
- setCache(cacheKey, resolvedValue);
- return resolvedValue;
- }
- [cs, r, g, b, alpha] = resolvedValue as ComputedColorChannels;
- } else if (value.startsWith(FN_COLOR)) {
- const resolvedValue = resolveColorFunc(value, opt);
- if (resolvedValue instanceof NullObject) {
- setCache(cacheKey, resolvedValue);
- return resolvedValue;
- }
- [cs, r, g, b, alpha] = resolvedValue as ComputedColorChannels;
- } else if (value) {
- const resolvedValue = resolveColorValue(value, opt);
- if (resolvedValue instanceof NullObject) {
- setCache(cacheKey, resolvedValue);
- return resolvedValue;
- }
- [cs, r, g, b, alpha] = resolvedValue as ComputedColorChannels;
- }
- let res = '';
- switch (format) {
- case 'hex': {
- if (
- Number.isNaN(r) ||
- Number.isNaN(g) ||
- Number.isNaN(b) ||
- Number.isNaN(alpha) ||
- alpha === 0
- ) {
- setCache(cacheKey, null);
- return new NullObject();
- }
- res = convertRgbToHex([r, g, b, 1]);
- break;
- }
- case 'hexAlpha': {
- if (
- Number.isNaN(r) ||
- Number.isNaN(g) ||
- Number.isNaN(b) ||
- Number.isNaN(alpha)
- ) {
- setCache(cacheKey, null);
- return new NullObject();
- }
- res = convertRgbToHex([r, g, b, alpha]);
- break;
- }
- case VAL_COMP:
- default: {
- switch (cs) {
- case 'rgb': {
- if (alpha === 1) {
- res = `${cs}(${r}, ${g}, ${b})`;
- } else {
- res = `${cs}a(${r}, ${g}, ${b}, ${alpha})`;
- }
- break;
- }
- case 'lab':
- case 'lch':
- case 'oklab':
- case 'oklch': {
- if (alpha === 1) {
- res = `${cs}(${r} ${g} ${b})`;
- } else {
- res = `${cs}(${r} ${g} ${b} / ${alpha})`;
- }
- break;
- }
- // color()
- default: {
- if (alpha === 1) {
- res = `color(${cs} ${r} ${g} ${b})`;
- } else {
- res = `color(${cs} ${r} ${g} ${b} / ${alpha})`;
- }
- }
- }
- }
- }
- setCache(cacheKey, res);
- return res;
-};
-
-/**
- * resolve CSS color
- * @param value
- * - CSS color value
- * - system colors are not supported
- * @param [opt] - options
- * @param [opt.currentColor]
- * - color to use for `currentcolor` keyword
- * - if omitted, it will be treated as a missing color
- * i.e. `rgb(none none none / none)`
- * @param [opt.customProperty]
- * - custom properties
- * - pair of `--` prefixed property name and value,
- * e.g. `customProperty: { '--some-color': '#0000ff' }`
- * - and/or `callback` function to get the value of the custom property,
- * e.g. `customProperty: { callback: someDeclaration.getPropertyValue }`
- * @param [opt.dimension]
- * - dimension, convert relative length to pixels
- * - pair of unit and it's value as a number in pixels,
- * e.g. `dimension: { em: 12, rem: 16, vw: 10.26 }`
- * - and/or `callback` function to get the value as a number in pixels,
- * e.g. `dimension: { callback: convertUnitToPixel }`
- * @param [opt.format]
- * - output format, one of below
- * - `computedValue` (default), [computed value][139] of the color
- * - `specifiedValue`, [specified value][140] of the color
- * - `hex`, hex color notation, i.e. `rrggbb`
- * - `hexAlpha`, hex color notation with alpha channel, i.e. `#rrggbbaa`
- * @returns
- * - one of rgba?(), #rrggbb(aa)?, color-name, '(empty-string)',
- * color(color-space r g b / alpha), color(color-space x y z / alpha),
- * lab(l a b / alpha), lch(l c h / alpha), oklab(l a b / alpha),
- * oklch(l c h / alpha), null
- * - in `computedValue`, values are numbers, however `rgb()` values are
- * integers
- * - in `specifiedValue`, returns `empty string` for unknown and/or invalid
- * color
- * - in `hex`, returns `null` for `transparent`, and also returns `null` if
- * any of `r`, `g`, `b`, `alpha` is not a number
- * - in `hexAlpha`, returns `#00000000` for `transparent`,
- * however returns `null` if any of `r`, `g`, `b`, `alpha` is not a number
- */
-export const resolve = (value: string, opt: Options = {}): string | null => {
- opt.nullable = false;
- const resolvedValue = resolveColor(value, opt);
- if (resolvedValue instanceof NullObject) {
- return null;
- }
- return resolvedValue as string;
-};
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/typedef.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/typedef.ts
deleted file mode 100644
index 873badf5..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/typedef.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * typedef
- */
-
-/* type definitions */
-/**
- * @typedef Options - options
- * @property [alpha] - enable alpha
- * @property [colorSpace] - color space
- * @property [currentColor] - color for currentcolor
- * @property [customPropeerty] - custom properties
- * @property [d50] - white point in d50
- * @property [dimension] - dimension
- * @property [format] - output format
- * @property [key] - key
- */
-export interface Options {
- alpha?: boolean;
- colorSpace?: string;
- currentColor?: string;
- customProperty?: Record string)>;
- d50?: boolean;
- delimiter?: string | string[];
- dimension?: Record number)>;
- format?: string;
- nullable?: boolean;
- preserveComment?: boolean;
-}
-
-/**
- * @type ColorChannels - color channels
- */
-export type ColorChannels = [x: number, y: number, z: number, alpha: number];
-
-/**
- * @type StringColorChannels - color channels
- */
-export type StringColorChannels = [
- x: string,
- y: string,
- z: string,
- alpha: string | undefined
-];
-
-/**
- * @type StringColorSpacedChannels - specified value
- */
-export type StringColorSpacedChannels = [
- cs: string,
- x: string,
- y: string,
- z: string,
- alpha: string | undefined
-];
-
-/**
- * @type ComputedColorChannels - computed value
- */
-export type ComputedColorChannels = [
- cs: string,
- x: number,
- y: number,
- z: number,
- alpha: number
-];
-
-/**
- * @type SpecifiedColorChannels - specified value
- */
-export type SpecifiedColorChannels = [
- cs: string,
- x: number | string,
- y: number | string,
- z: number | string,
- alpha: number | string
-];
-
-/**
- * @type MatchedRegExp - matched regexp array
- */
-export type MatchedRegExp = [
- match: string,
- gr1: string,
- gr2: string,
- gr3: string,
- gr4: string
-];
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/util.ts b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/util.ts
deleted file mode 100644
index c8e1b702..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/css-color/src/js/util.ts
+++ /dev/null
@@ -1,336 +0,0 @@
-/**
- * util
- */
-
-import { TokenType, tokenize } from '@csstools/css-tokenizer';
-import { CacheItem, createCacheKey, getCache, setCache } from './cache';
-import { isString } from './common';
-import { resolveColor } from './resolve';
-import { Options } from './typedef';
-
-/* constants */
-import { NAMED_COLORS } from './color';
-import { SYN_COLOR_TYPE, SYN_MIX, VAL_SPEC } from './constant';
-const {
- CloseParen: PAREN_CLOSE,
- Comma: COMMA,
- Comment: COMMENT,
- Delim: DELIM,
- EOF,
- Function: FUNC,
- Ident: IDENT,
- OpenParen: PAREN_OPEN,
- Whitespace: W_SPACE
-} = TokenType;
-const NAMESPACE = 'util';
-
-/* numeric constants */
-const DEC = 10;
-const HEX = 16;
-const DEG = 360;
-const DEG_HALF = 180;
-
-/* regexp */
-const REG_COLOR = new RegExp(`^(?:${SYN_COLOR_TYPE})$`);
-const REG_FN_COLOR =
- /^(?:(?:ok)?l(?:ab|ch)|color(?:-mix)?|hsla?|hwb|rgba?|var)\(/;
-const REG_MIX = new RegExp(SYN_MIX);
-
-/**
- * split value
- * NOTE: comments are stripped, it can be preserved if, in the options param,
- * `delimiter` is either ',' or '/' and with `preserveComment` set to `true`
- * @param value - CSS value
- * @param [opt] - options
- * @returns array of values
- */
-export const splitValue = (value: string, opt: Options = {}): string[] => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const { delimiter = ' ', preserveComment = false } = opt;
- const cacheKey: string = createCacheKey(
- {
- namespace: NAMESPACE,
- name: 'splitValue',
- value
- },
- {
- delimiter,
- preserveComment
- }
- );
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- return cachedResult.item as string[];
- }
- let regDelimiter;
- if (delimiter === ',') {
- regDelimiter = /^,$/;
- } else if (delimiter === '/') {
- regDelimiter = /^\/$/;
- } else {
- regDelimiter = /^\s+$/;
- }
- const tokens = tokenize({ css: value });
- let nest = 0;
- let str = '';
- const res: string[] = [];
- while (tokens.length) {
- const [type, value] = tokens.shift() as [TokenType, string];
- switch (type) {
- case COMMA: {
- if (regDelimiter.test(value)) {
- if (nest === 0) {
- res.push(str.trim());
- str = '';
- } else {
- str += value;
- }
- } else {
- str += value;
- }
- break;
- }
- case DELIM: {
- if (regDelimiter.test(value)) {
- if (nest === 0) {
- res.push(str.trim());
- str = '';
- } else {
- str += value;
- }
- } else {
- str += value;
- }
- break;
- }
- case COMMENT: {
- if (preserveComment && (delimiter === ',' || delimiter === '/')) {
- str += value;
- }
- break;
- }
- case FUNC:
- case PAREN_OPEN: {
- str += value;
- nest++;
- break;
- }
- case PAREN_CLOSE: {
- str += value;
- nest--;
- break;
- }
- case W_SPACE: {
- if (regDelimiter.test(value)) {
- if (nest === 0) {
- if (str) {
- res.push(str.trim());
- str = '';
- }
- } else {
- str += ' ';
- }
- } else if (!str.endsWith(' ')) {
- str += ' ';
- }
- break;
- }
- default: {
- if (type === EOF) {
- res.push(str.trim());
- str = '';
- } else {
- str += value;
- }
- }
- }
- }
- setCache(cacheKey, res);
- return res;
-};
-
-/**
- * extract dashed-ident tokens
- * @param value - CSS value
- * @returns array of dashed-ident tokens
- */
-export const extractDashedIdent = (value: string): string[] => {
- if (isString(value)) {
- value = value.trim();
- } else {
- throw new TypeError(`${value} is not a string.`);
- }
- const cacheKey: string = createCacheKey({
- namespace: NAMESPACE,
- name: 'extractDashedIdent',
- value
- });
- const cachedResult = getCache(cacheKey);
- if (cachedResult instanceof CacheItem) {
- return cachedResult.item as string[];
- }
- const tokens = tokenize({ css: value });
- const items = new Set();
- while (tokens.length) {
- const [type, value] = tokens.shift() as [TokenType, string];
- if (type === IDENT && value.startsWith('--')) {
- items.add(value);
- }
- }
- const res = [...items] as string[];
- setCache(cacheKey, res);
- return res;
-};
-
-/**
- * is color
- * @param value - CSS value
- * @param [opt] - options
- * @returns result
- */
-export const isColor = (value: unknown, opt: Options = {}): boolean => {
- if (isString(value)) {
- value = value.toLowerCase().trim();
- if (value && isString(value)) {
- if (/^[a-z]+$/.test(value)) {
- if (
- /^(?:currentcolor|transparent)$/.test(value) ||
- Object.prototype.hasOwnProperty.call(NAMED_COLORS, value)
- ) {
- return true;
- }
- } else if (REG_COLOR.test(value) || REG_MIX.test(value)) {
- return true;
- } else if (REG_FN_COLOR.test(value)) {
- opt.nullable = true;
- if (!opt.format) {
- opt.format = VAL_SPEC;
- }
- const resolvedValue = resolveColor(value, opt);
- if (resolvedValue) {
- return true;
- }
- }
- }
- }
- return false;
-};
-
-/**
- * value to JSON string
- * @param value - CSS value
- * @param [func] - stringify function
- * @returns stringified value in JSON notation
- */
-export const valueToJsonString = (
- value: unknown,
- func: boolean = false
-): string => {
- if (typeof value === 'undefined') {
- return '';
- }
- const res = JSON.stringify(value, (_key, val) => {
- let replacedValue;
- if (typeof val === 'undefined') {
- replacedValue = null;
- } else if (typeof val === 'function') {
- if (func) {
- replacedValue = val.toString().replace(/\s/g, '').substring(0, HEX);
- } else {
- replacedValue = val.name;
- }
- } else if (val instanceof Map || val instanceof Set) {
- replacedValue = [...val];
- } else if (typeof val === 'bigint') {
- replacedValue = val.toString();
- } else {
- replacedValue = val;
- }
- return replacedValue;
- });
- return res;
-};
-
-/**
- * round to specified precision
- * @param value - numeric value
- * @param bit - minimum bits
- * @returns rounded value
- */
-export const roundToPrecision = (value: number, bit: number = 0): number => {
- if (!Number.isFinite(value)) {
- throw new TypeError(`${value} is not a finite number.`);
- }
- if (!Number.isFinite(bit)) {
- throw new TypeError(`${bit} is not a finite number.`);
- } else if (bit < 0 || bit > HEX) {
- throw new RangeError(`${bit} is not between 0 and ${HEX}.`);
- }
- if (bit === 0) {
- return Math.round(value);
- }
- let val;
- if (bit === HEX) {
- val = value.toPrecision(6);
- } else if (bit < DEC) {
- val = value.toPrecision(4);
- } else {
- val = value.toPrecision(5);
- }
- return parseFloat(val);
-};
-
-/**
- * interpolate hue
- * @param hueA - hue value
- * @param hueB - hue value
- * @param arc - shorter | longer | increasing | decreasing
- * @returns result - [hueA, hueB]
- */
-export const interpolateHue = (
- hueA: number,
- hueB: number,
- arc: string = 'shorter'
-): [number, number] => {
- if (!Number.isFinite(hueA)) {
- throw new TypeError(`${hueA} is not a finite number.`);
- }
- if (!Number.isFinite(hueB)) {
- throw new TypeError(`${hueB} is not a finite number.`);
- }
- switch (arc) {
- case 'decreasing': {
- if (hueB > hueA) {
- hueA += DEG;
- }
- break;
- }
- case 'increasing': {
- if (hueB < hueA) {
- hueB += DEG;
- }
- break;
- }
- case 'longer': {
- if (hueB > hueA && hueB < hueA + DEG_HALF) {
- hueA += DEG;
- } else if (hueB > hueA + DEG_HALF * -1 && hueB <= hueA) {
- hueB += DEG;
- }
- break;
- }
- case 'shorter':
- default: {
- if (hueB > hueA + DEG_HALF) {
- hueA += DEG;
- } else if (hueB < hueA + DEG_HALF * -1) {
- hueB += DEG;
- }
- }
- }
- return [hueA, hueB];
-};
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/dom-selector/LICENSE b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/dom-selector/LICENSE
deleted file mode 100644
index 9022b96a..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/dom-selector/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2023 asamuzaK (Kazz)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/dom-selector/README.md b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/dom-selector/README.md
deleted file mode 100644
index dc8fd44a..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/dom-selector/README.md
+++ /dev/null
@@ -1,200 +0,0 @@
-# DOM Selector
-
-[](https://github.com/asamuzaK/domSelector/actions/workflows/node.js.yml)
-[](https://github.com/asamuzaK/domSelector/actions/workflows/codeql.yml)
-[](https://www.npmjs.com/package/@asamuzakjp/dom-selector)
-
-A CSS selector engine.
-Used in jsdom since [jsdom v23.2.0](https://github.com/jsdom/jsdom/releases/tag/23.2.0).
-
-## Install
-
-```console
-npm i @asamuzakjp/dom-selector
-```
-
-## Usage
-
-```javascript
-import {
- matches, closest, querySelector, querySelectorAll
-} from '@asamuzakjp/dom-selector';
-```
-
-
-
-### matches(selector, node, opt)
-
-matches - same functionality as [Element.matches()][64]
-
-#### Parameters
-
-- `selector` **[string][59]** CSS selector
-- `node` **[object][60]** Element node
-- `opt` **[object][60]?** options
- - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
-
-Returns **[boolean][61]** `true` if matched, `false` otherwise
-
-
-### closest(selector, node, opt)
-
-closest - same functionality as [Element.closest()][65]
-
-#### Parameters
-
-- `selector` **[string][59]** CSS selector
-- `node` **[object][60]** Element node
-- `opt` **[object][60]?** options
- - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
-
-Returns **[object][60]?** matched node
-
-
-### querySelector(selector, node, opt)
-
-querySelector - same functionality as [Document.querySelector()][66], [DocumentFragment.querySelector()][67], [Element.querySelector()][68]
-
-#### Parameters
-
-- `selector` **[string][59]** CSS selector
-- `node` **[object][60]** Document, DocumentFragment or Element node
-- `opt` **[object][60]?** options
- - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
-
-Returns **[object][60]?** matched node
-
-
-### querySelectorAll(selector, node, opt)
-
-querySelectorAll - same functionality as [Document.querySelectorAll()][69], [DocumentFragment.querySelectorAll()][70], [Element.querySelectorAll()][71]
-**NOTE**: returns Array, not NodeList
-
-#### Parameters
-
-- `selector` **[string][59]** CSS selector
-- `node` **[object][60]** Document, DocumentFragment or Element node
-- `opt` **[object][60]?** options
- - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
-
-Returns **[Array][62]<([object][60] \| [undefined][63])>** array of matched nodes
-
-
-## Supported CSS selectors
-
-|Pattern|Supported|Note|
-|:--------|:-------:|:--------|
-|\*|✓| |
-|ns\|E|✓| |
-|\*\|E|✓| |
-|\|E|✓| |
-|E|✓| |
-|E:not(s1, s2, …)|✓| |
-|E:is(s1, s2, …)|✓| |
-|E:where(s1, s2, …)|✓| |
-|E:has(rs1, rs2, …)|✓| |
-|E.warning|✓| |
-|E#myid|✓| |
-|E\[foo\]|✓| |
-|E\[foo="bar"\]|✓| |
-|E\[foo="bar" i\]|✓| |
-|E\[foo="bar" s\]|✓| |
-|E\[foo~="bar"\]|✓| |
-|E\[foo^="bar"\]|✓| |
-|E\[foo$="bar"\]|✓| |
-|E\[foo*="bar"\]|✓| |
-|E\[foo\|="en"\]|✓| |
-|E:defined|Unsupported| |
-|E:dir(ltr)|✓| |
-|E:lang(en)|Partially supported|Comma-separated list of language codes, e.g. `:lang(en, fr)`, is not yet supported.|
-|E:any‑link|✓| |
-|E:link|✓| |
-|E:visited|✓|Returns `false` or `null` to prevent fingerprinting.|
-|E:local‑link|✓| |
-|E:target|✓| |
-|E:target‑within|✓| |
-|E:scope|✓| |
-|E:current|Unsupported| |
-|E:current(s)|Unsupported| |
-|E:past|Unsupported| |
-|E:future|Unsupported| |
-|E:active|Unsupported| |
-|E:hover|Unsupported| |
-|E:focus|✓| |
-|E:focus‑within|✓| |
-|E:focus‑visible|Unsupported| |
-|E:enabled
E:disabled|✓| |
-|E:read‑write
E:read‑only|✓| |
-|E:placeholder‑shown|✓| |
-|E:default|✓| |
-|E:checked|✓| |
-|E:indeterminate|✓| |
-|E:valid
E:invalid|✓| |
-|E:required
E:optional|✓| |
-|E:blank|Unsupported| |
-|E:user‑invalid|Unsupported| |
-|E:root|✓| |
-|E:empty|✓| |
-|E:nth‑child(n [of S]?)|✓| |
-|E:nth‑last‑child(n [of S]?)|✓| |
-|E:first‑child|✓| |
-|E:last‑child|✓| |
-|E:only‑child|✓| |
-|E:nth‑of‑type(n)|✓| |
-|E:nth‑last‑of‑type(n)|✓| |
-|E:first‑of‑type|✓| |
-|E:last‑of‑type|✓| |
-|E:only‑of‑type|✓| |
-|E F|✓| |
-|E > F|✓| |
-|E + F|✓| |
-|E ~ F|✓| |
-|F \|\| E|Unsupported| |
-|E:nth‑col(n)|Unsupported| |
-|E:nth‑last‑col(n)|Unsupported| |
-|:host|✓| |
-|:host(s)|✓| |
-|:host‑context(s)|✓| |
-
-
-
-
-
-## Acknowledgments
-
-The following resources have been of great help in the development of the DOM Selector.
-
-- [CSSTree](https://github.com/csstree/csstree)
-- [selery](https://github.com/danburzo/selery)
-- [jsdom](https://github.com/jsdom/jsdom)
-
-
----
-Copyright (c) 2023 [asamuzaK (Kazz)](https://github.com/asamuzaK/)
-
-
-[1]: #matches
-[2]: #parameters
-[3]: #closest
-[4]: #parameters-1
-[5]: #queryselector
-[6]: #parameters-2
-[7]: #queryselectorall
-[8]: #parameters-3
-[59]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
-[60]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
-[61]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
-[62]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
-[63]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined
-[64]: https://developer.mozilla.org/docs/Web/API/Element/matches
-[65]: https://developer.mozilla.org/docs/Web/API/Element/closest
-[66]: https://developer.mozilla.org/docs/Web/API/Document/querySelector
-[67]: https://developer.mozilla.org/docs/Web/API/DocumentFragment/querySelector
-[68]: https://developer.mozilla.org/docs/Web/API/Element/querySelector
-[69]: https://developer.mozilla.org/docs/Web/API/Document/querySelectorAll
-[70]: https://developer.mozilla.org/docs/Web/API/DocumentFragment/querySelectorAll
-[71]: https://developer.mozilla.org/docs/Web/API/Element/querySelectorAll
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/dom-selector/package.json b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/dom-selector/package.json
deleted file mode 100644
index ddad86b2..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/dom-selector/package.json
+++ /dev/null
@@ -1,62 +0,0 @@
-{
- "name": "@asamuzakjp/dom-selector",
- "description": "A CSS selector engine.",
- "author": "asamuzaK",
- "license": "MIT",
- "homepage": "https://github.com/asamuzaK/domSelector#readme",
- "bugs": {
- "url": "https://github.com/asamuzaK/domSelector/issues"
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/asamuzaK/domSelector.git"
- },
- "files": [
- "dist",
- "src",
- "types"
- ],
- "type": "module",
- "exports": {
- "import": "./src/index.js",
- "require": "./dist/cjs/index.js"
- },
- "types": "types/index.d.ts",
- "dependencies": {
- "bidi-js": "^1.0.3",
- "css-tree": "^2.3.1",
- "is-potential-custom-element-name": "^1.0.1"
- },
- "devDependencies": {
- "@types/css-tree": "^2.3.4",
- "benchmark": "^2.1.4",
- "c8": "^9.0.0",
- "chai": "^5.0.0",
- "commander": "^11.1.0",
- "esbuild": "^0.19.11",
- "eslint": "^8.56.0",
- "eslint-config-standard": "^17.1.0",
- "eslint-plugin-import": "^2.29.1",
- "eslint-plugin-jsdoc": "^48.0.2",
- "eslint-plugin-regexp": "^2.1.2",
- "eslint-plugin-unicorn": "^50.0.1",
- "happy-dom": "^12.10.3",
- "jsdom": "^23.1.0",
- "linkedom": "^0.16.6",
- "mocha": "^10.2.0",
- "sinon": "^17.0.1",
- "typescript": "^5.3.3",
- "wpt-runner": "^5.0.0"
- },
- "scripts": {
- "bench": "node benchmark/bench.js",
- "build": "npm run tsc && npm run lint && npm test && npm run compat",
- "compat": "esbuild --format=cjs --platform=node --outdir=dist/cjs/ --minify --sourcemap src/**/*.js",
- "lint": "eslint --fix .",
- "test": "c8 --reporter=text mocha --exit test/**/*.test.js",
- "test-wpt": "npm run update-wpt && node test/wpt/wpt-runner.js",
- "tsc": "npx tsc",
- "update-wpt": "git submodule update --init --recursive --remote"
- },
- "version": "2.0.2"
-}
diff --git a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/dom-selector/src/index.js b/capabilities/testdrive-jsui/node_modules/@asamuzakjp/dom-selector/src/index.js
deleted file mode 100644
index 791a74c8..00000000
--- a/capabilities/testdrive-jsui/node_modules/@asamuzakjp/dom-selector/src/index.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*!
- * DOM Selector - A CSS selector engine.
- * @license MIT
- * @copyright asamuzaK (Kazz)
- * @see {@link https://github.com/asamuzaK/domSelector/blob/main/LICENSE}
- */
-
-/* import */
-import { Matcher } from './js/matcher.js';
-
-/**
- * matches
- * @param {string} selector - CSS selector
- * @param {object} node - Element node
- * @param {object} [opt] - options
- * @param {boolean} [opt.warn] - console warn e.g. unsupported pseudo-class
- * @returns {boolean} - `true` if matched, `false` otherwise
- */
-export const matches = (selector, node, opt) =>
- new Matcher(selector, node, opt).matches();
-
-/**
- * closest
- * @param {string} selector - CSS selector
- * @param {object} node - Element node
- * @param {object} [opt] - options
- * @param {boolean} [opt.warn] - console warn e.g. unsupported pseudo-class
- * @returns {?object} - matched node
- */
-export const closest = (selector, node, opt) =>
- new Matcher(selector, node, opt).closest();
-
-/**
- * querySelector
- * @param {string} selector - CSS selector
- * @param {object} node - Document, DocumentFragment or Element node
- * @param {object} [opt] - options
- * @param {boolean} [opt.warn] - console warn e.g. unsupported pseudo-class
- * @returns {?object} - matched node
- */
-export const querySelector = (selector, node, opt) =>
- new Matcher(selector, node, opt).querySelector();
-
-/**
- * querySelectorAll
- * NOTE: returns Array, not NodeList
- * @param {string} selector - CSS selector
- * @param {object} node - Document, DocumentFragment or Element node
- * @param {object} [opt] - options
- * @param {boolean} [opt.warn] - console warn e.g. unsupported pseudo-class
- * @returns {Array.