diff --git a/django/aiservice/aiservice/validators/__init__.py b/django/aiservice/aiservice/validators/__init__.py new file mode 100644 index 000000000..a00bfd42b --- /dev/null +++ b/django/aiservice/aiservice/validators/__init__.py @@ -0,0 +1,7 @@ +""" +Code validators for different programming languages. +""" + +from aiservice.validators.javascript_validator import validate_javascript_syntax + +__all__ = ["validate_javascript_syntax"] diff --git a/django/aiservice/aiservice/validators/javascript_validator.py b/django/aiservice/aiservice/validators/javascript_validator.py new file mode 100644 index 000000000..28de7aad7 --- /dev/null +++ b/django/aiservice/aiservice/validators/javascript_validator.py @@ -0,0 +1,155 @@ +""" +JavaScript/TypeScript syntax validation. + +Uses Node.js for validation when available, with a basic regex fallback. +""" + +from __future__ import annotations + +import json +import re +import subprocess +from functools import lru_cache + + +@lru_cache(maxsize=100) +def validate_javascript_syntax(code: str) -> tuple[bool, str | None]: + """ + Validate JavaScript syntax using Node.js. + + Args: + code: The JavaScript code to validate + + Returns: + A tuple of (is_valid, error_message) + - is_valid: True if the code is syntactically valid + - error_message: None if valid, otherwise the error description + """ + try: + # Use Node.js to parse the code + # We use acorn parser via a small script that reports syntax errors + validation_script = f""" +const acorn = require('acorn'); +try {{ + acorn.parse({json.dumps(code)}, {{ + ecmaVersion: 'latest', + sourceType: 'module', + allowHashBang: true, + allowAwaitOutsideFunction: true, + allowImportExportEverywhere: true, + }}); + console.log('VALID'); +}} catch (e) {{ + console.error(e.message); + process.exit(1); +}} +""" + result = subprocess.run( + ["node", "-e", validation_script], + capture_output=True, + text=True, + timeout=5, + ) + + if result.returncode != 0: + error_msg = result.stderr.strip() or result.stdout.strip() + # Check if the error is due to missing acorn module + if "Cannot find module 'acorn'" in error_msg: + return _fallback_validation(code) + return False, error_msg + + return True, None + + except subprocess.TimeoutExpired: + return False, "Syntax validation timed out" + + except FileNotFoundError: + # Node.js not available, try fallback + return _fallback_validation(code) + + except Exception as e: + # Fallback for any other error + return _fallback_validation(code) + + +def _fallback_validation(code: str) -> tuple[bool, str | None]: + """ + Fallback validation using basic checks when Node.js is not available. + + This performs simple bracket matching and basic syntax checks. + """ + try: + # Check for obvious syntax errors + + # 1. Bracket matching + brackets = {"(": ")", "[": "]", "{": "}"} + stack = [] + in_string = False + string_char = None + escape_next = False + + for i, char in enumerate(code): + if escape_next: + escape_next = False + continue + + if char == "\\": + escape_next = True + continue + + # Handle strings + if char in "'\"`": + if not in_string: + in_string = True + string_char = char + elif char == string_char: + # Check for template literal + if char == "`" or (i + 1 < len(code) and code[i + 1] != string_char): + in_string = False + string_char = None + + if in_string: + continue + + # Check brackets + if char in brackets: + stack.append((brackets[char], i)) + elif char in brackets.values(): + if not stack: + return False, f"Unexpected closing bracket '{char}' at position {i}" + expected, _ = stack.pop() + if expected != char: + return False, f"Mismatched bracket '{char}' at position {i}" + + if stack: + return False, f"Unclosed bracket '{stack[-1][0]}'" + + # 2. Check for common invalid patterns + invalid_patterns = [ + (r"function\s*\(\s*\)\s*\{[^}]*\breturn\b[^;]*$", "Missing semicolon after return"), + (r"\bconst\s+\d", "Invalid const declaration - cannot start with number"), + (r"\blet\s+\d", "Invalid let declaration - cannot start with number"), + (r"\bvar\s+\d", "Invalid var declaration - cannot start with number"), + ] + + for pattern, error_msg in invalid_patterns: + if re.search(pattern, code): + return False, error_msg + + return True, None + + except Exception as e: + return False, f"Validation error: {e}" + + +def validate_typescript_syntax(code: str) -> tuple[bool, str | None]: + """ + Validate TypeScript syntax. + + Since acorn doesn't support TypeScript type annotations, we use the + fallback validation which checks for basic syntax errors like bracket + matching. For complete TypeScript validation, tsc would be needed. + """ + # Acorn doesn't support TypeScript syntax (type annotations, interfaces, etc.) + # Use the fallback validation which is more lenient + return _fallback_validation(code) diff --git a/django/aiservice/optimizer/models.py b/django/aiservice/optimizer/models.py index 0de8c0a97..733ba4111 100644 --- a/django/aiservice/optimizer/models.py +++ b/django/aiservice/optimizer/models.py @@ -59,7 +59,9 @@ class OptimizeSchema(Schema): source_code: str dependency_code: str | None trace_id: str - python_version: str + python_version: str | None = None # Made optional for multi-language support + language: str = "python" # NEW: language identifier (python, javascript, typescript) + language_version: str | None = None # NEW: e.g., "ES2022", "Node 20", or Python version experiment_metadata: dict[str, str] | None = None codeflash_version: str | None = None current_username: str | None = None diff --git a/django/aiservice/optimizer/optimizer.py b/django/aiservice/optimizer/optimizer.py index 7cf59f828..1c142466a 100644 --- a/django/aiservice/optimizer/optimizer.py +++ b/django/aiservice/optimizer/optimizer.py @@ -31,6 +31,7 @@ from optimizer.context_utils.optimizer_context import ( ) from optimizer.diff_patches_utils.diff import DiffMethod from optimizer.models import OptimizedCandidateSource, OptimizeSchema +from optimizer.optimizer_javascript import optimize_javascript if TYPE_CHECKING: from openai.types.chat import ChatCompletionMessageParam @@ -281,13 +282,25 @@ def validate_request_data(data: OptimizeSchema, ctx: BaseOptimizerContext) -> tu async def optimize( request: AuthenticatedRequest, data: OptimizeSchema ) -> tuple[int, OptimizeResponseSchema | OptimizeErrorResponseSchema]: + # Route based on language + if data.language in ("javascript", "typescript"): + return await optimize_javascript(request, data) + + # Default: Python optimization + return await optimize_python(request, data) + + +async def optimize_python( + request: AuthenticatedRequest, data: OptimizeSchema +) -> tuple[int, OptimizeResponseSchema | OptimizeErrorResponseSchema]: + """Optimize Python code for performance using LLMs.""" system_prompt = ASYNC_SYSTEM_PROMPT if data.is_async else SYSTEM_PROMPT user_prompt = ASYNC_USER_PROMPT if data.is_async else USER_PROMPT ctx: BaseOptimizerContext = BaseOptimizerContext.get_dynamic_context( system_prompt, user_prompt, data.source_code, DiffMethod.NO_DIFF ) - ph(request.user, "aiservice-optimize-called") + ph(request.user, "aiservice-optimize-called", properties={"language": "python"}) try: python_version = validate_request_data(data, ctx) diff --git a/django/aiservice/optimizer/optimizer_javascript.py b/django/aiservice/optimizer/optimizer_javascript.py new file mode 100644 index 000000000..1e34156fb --- /dev/null +++ b/django/aiservice/optimizer/optimizer_javascript.py @@ -0,0 +1,403 @@ +""" +JavaScript/TypeScript code optimizer module. + +This module handles optimization requests for JavaScript and TypeScript code. +""" + +from __future__ import annotations + +import asyncio +import logging +import re +import uuid +from pathlib import Path +from typing import TYPE_CHECKING, Any + +import sentry_sdk +from ninja.errors import HttpError +from openai.types.chat import ChatCompletionSystemMessageParam, ChatCompletionUserMessageParam + +from aiservice.analytics.posthog import ph +from aiservice.common_utils import validate_trace_id +from aiservice.env_specific import debug_log_sensitive_data, debug_log_sensitive_data_from_callable +from aiservice.llm import LLM, OPTIMIZE_MODEL, calculate_llm_cost, call_llm +from aiservice.validators.javascript_validator import validate_javascript_syntax, validate_typescript_syntax +from authapp.auth import AuthenticatedRequest +from authapp.user import get_user_by_id +from log_features.log_event import get_or_create_optimization_event +from log_features.log_features import log_features +from optimizer.config import MAX_OPTIMIZER_CALLS, get_model_distribution +from optimizer.context_utils.optimizer_context import ( + OptimizeErrorResponseSchema, + OptimizeResponseItemSchema, + OptimizeResponseSchema, +) +from optimizer.models import OptimizedCandidateSource, OptimizeSchema +from optimizer.prompts import get_system_prompt, get_user_prompt + +if TYPE_CHECKING: + from openai.types.chat import ChatCompletionMessageParam + + +# Pattern to extract code blocks from LLM response +JS_CODE_PATTERN = re.compile( + r"```(?:javascript|js|typescript|ts)(?::[^\n]*)?\s*\n(.*?)```", + re.MULTILINE | re.DOTALL, +) + + +def extract_code_and_explanation(content: str) -> tuple[str, str]: + """ + Extract code and explanation from LLM response. + + Args: + content: The raw LLM response content + + Returns: + Tuple of (code, explanation) + """ + match = JS_CODE_PATTERN.search(content) + if match: + code = match.group(1).strip() + # Explanation is everything before the code block + explanation_end = match.start() + explanation = content[:explanation_end].strip() + return code, explanation + + # No code block found, return empty code + return "", content + + +async def optimize_javascript_code_single( + user_id: str, + source_code: str, + trace_id: str, + dependency_code: str | None = None, + optimize_model: LLM = OPTIMIZE_MODEL, + language_version: str = "ES2022", + is_async: bool = False, + call_sequence: int | None = None, +) -> tuple[OptimizeResponseItemSchema | None, float | None, str]: + """ + Optimize JavaScript/TypeScript code using LLMs. + + Args: + user_id: The user ID making the request + source_code: The source code to optimize + trace_id: The trace ID for logging + dependency_code: Optional dependency code for context + optimize_model: The LLM model to use + language_version: Target JS/TS version (e.g., "ES2022") + is_async: Whether the code is async + call_sequence: Call sequence number for tracking + + Returns: + Tuple of (optimization_result, llm_cost, model_name) + """ + logging.info("/optimize: Optimizing JavaScript code.") + debug_log_sensitive_data(f"Optimizing JavaScript code for user {user_id}:\n{source_code}") + + # Get language-appropriate prompts + language = "javascript" # TypeScript uses same prompts + system_prompt = get_system_prompt(language, is_async) + user_prompt = get_user_prompt(language, is_async) + + # Format prompts + system_prompt = system_prompt.format(language_version=language_version) + user_prompt = user_prompt.format(source_code=f"```javascript\n{source_code}\n```") + + if dependency_code: + user_prompt = f"Dependencies (read-only):\n```javascript\n{dependency_code}\n```\n\n{user_prompt}" + + obs_context: dict[str, Any] | None = {"call_sequence": call_sequence} if call_sequence is not None else None + + messages: list[ChatCompletionMessageParam] = [ + ChatCompletionSystemMessageParam(role="system", content=system_prompt), + ChatCompletionUserMessageParam(role="user", content=user_prompt), + ] + + try: + output = await call_llm( + llm=optimize_model, + messages=messages, + call_type="optimization", + trace_id=trace_id, + user_id=user_id, + python_version=language_version, # Reusing python_version field for language version + context=obs_context, + ) + except Exception as e: + logging.exception("LLM Code Generation error in JavaScript optimizer") + sentry_sdk.capture_exception(e) + debug_log_sensitive_data(f"Failed to generate code for source:\n{source_code}") + return None, None, optimize_model.name + + llm_cost = calculate_llm_cost(output.raw_response, optimize_model) + + debug_log_sensitive_data(f"LLM optimization response:\n{output.raw_response.model_dump_json(indent=2)}") + + if output.raw_response.usage is not None: + ph( + user_id, + "aiservice-optimize-openai-usage", + properties={"model": optimize_model.name, "usage": output.raw_response.usage.json(), "language": language}, + ) + + # Extract code and explanation from response + optimized_code, explanation = extract_code_and_explanation(output.content) + + if not optimized_code: + sentry_sdk.capture_message("No code block found in JavaScript optimization response") + debug_log_sensitive_data(f"No code found in response for source:\n{source_code}") + return None, llm_cost, optimize_model.name + + # Validate the generated code + is_valid, error = validate_javascript_syntax(optimized_code) + if not is_valid: + sentry_sdk.capture_message(f"Invalid JavaScript generated: {error}") + debug_log_sensitive_data(f"Invalid code generated:\n{optimized_code}\nError: {error}") + return None, llm_cost, optimize_model.name + + # Check that the code is actually different from the original + if _normalize_code(optimized_code) == _normalize_code(source_code): + debug_log_sensitive_data("Generated code identical to original") + return None, llm_cost, optimize_model.name + + optimization_id = str(uuid.uuid4()) + result = OptimizeResponseItemSchema( + source_code=optimized_code, + explanation=explanation, + optimization_id=optimization_id, + ) + + return result, llm_cost, optimize_model.name + + +def _normalize_code(code: str) -> str: + """ + Normalize code for comparison (remove comments and whitespace). + """ + # Remove single-line comments + code = re.sub(r"//.*$", "", code, flags=re.MULTILINE) + # Remove multi-line comments + code = re.sub(r"/\*.*?\*/", "", code, flags=re.DOTALL) + # Normalize whitespace + code = " ".join(code.split()) + return code + + +async def optimize_javascript_code( + user_id: str, + source_code: str, + trace_id: str, + dependency_code: str | None = None, + language_version: str = "ES2022", + is_async: bool = False, + n_candidates: int = 0, +) -> tuple[list[OptimizeResponseItemSchema], float, dict[str, str]]: + """ + Run parallel optimizations with multiple models. + + Args: + user_id: The user ID making the request + source_code: The source code to optimize + trace_id: The trace ID for logging + dependency_code: Optional dependency code for context + language_version: Target JS/TS version + is_async: Whether the code is async + n_candidates: Number of optimization candidates to generate + + Returns: + Tuple of (optimization_results, total_cost, optimization_models) + """ + tasks: list[asyncio.Task[tuple[OptimizeResponseItemSchema | None, float | None, str]]] = [] + call_sequence = 1 + + if n_candidates == 0: + return [], 0.0, {} + + async with asyncio.TaskGroup() as tg: + for model, num_calls in get_model_distribution(n_candidates, MAX_OPTIMIZER_CALLS): + for _ in range(num_calls): + task = tg.create_task( + optimize_javascript_code_single( + user_id=user_id, + source_code=source_code, + trace_id=trace_id, + dependency_code=dependency_code, + optimize_model=model, + language_version=language_version, + is_async=is_async, + call_sequence=call_sequence, + ) + ) + tasks.append(task) + call_sequence += 1 + + # Collect results + optimization_results: list[OptimizeResponseItemSchema] = [] + total_cost = 0.0 + optimization_models: dict[str, str] = {} + seen_code: set[str] = set() + + for task in tasks: + result, cost, model_name = task.result() + if cost: + total_cost += cost + if result is not None: + # Deduplicate by normalized code + normalized = _normalize_code(result.source_code) + if normalized not in seen_code: + seen_code.add(normalized) + optimization_results.append(result) + optimization_models[result.optimization_id] = model_name + + return optimization_results, total_cost, optimization_models + + +def validate_javascript_request_data(data: OptimizeSchema) -> None: + """ + Validate JavaScript/TypeScript optimization request data. + + Args: + data: The request data + + Raises: + HttpError: If validation fails + """ + if not data.source_code: + raise HttpError(400, "Source code cannot be empty.") + if not validate_trace_id(data.trace_id): + raise HttpError(400, "Invalid trace ID. Please provide a valid UUIDv4.") + + # Validate syntax based on language + if data.language == "typescript": + is_valid, error = validate_typescript_syntax(data.source_code) + lang_name = "TypeScript" + else: + is_valid, error = validate_javascript_syntax(data.source_code) + lang_name = "JavaScript" + + if not is_valid: + raise HttpError(400, f"Invalid source code. It is not valid {lang_name}: {error}") + + +async def optimize_javascript( + request: AuthenticatedRequest, data: OptimizeSchema +) -> tuple[int, OptimizeResponseSchema | OptimizeErrorResponseSchema]: + """ + Main endpoint handler for JavaScript/TypeScript optimization. + + Args: + request: The authenticated request + data: The optimization request data + + Returns: + Tuple of (status_code, response) + """ + language = data.language + ph(request.user, "aiservice-optimize-called", properties={"language": language}) + + try: + validate_javascript_request_data(data) + except HttpError as e: + e.add_note(f"JavaScript optimizer request validation error: {e.status_code} {e.message}") + logging.error(f"JavaScript optimizer request validation error: {e.message}. trace_id={data.trace_id}") + sentry_sdk.capture_exception(e) + return e.status_code, OptimizeErrorResponseSchema(error=e.message) + + try: + async with asyncio.TaskGroup() as tg: + optimize_task = tg.create_task( + optimize_javascript_code( + user_id=request.user, + source_code=data.source_code, + trace_id=data.trace_id, + dependency_code=data.dependency_code, + language_version=data.language_version or "ES2022", + is_async=data.is_async or False, + n_candidates=data.n_candidates, + ) + ) + user_task = None + if data.current_username is None: + user_task = tg.create_task(get_user_by_id(request.user)) + except Exception as e: + logging.exception(f"Error during JavaScript optimization task. trace_id={data.trace_id}") + sentry_sdk.capture_exception(e) + return 500, OptimizeErrorResponseSchema(error="Error generating optimizations. Internal server error.") + + optimization_response_items, llm_cost, optimization_models = optimize_task.result() + if user_task: + user = await user_task + if user and user.github_username: + data.current_username = str(user.github_username) + + if len(optimization_response_items) == 0: + ph(request.user, "aiservice-optimize-no-optimizations-found", properties={"language": language}) + debug_log_sensitive_data(f"No JavaScript optimizations found for source:\n{data.source_code}") + logging.error(f"Could not generate any JavaScript optimizations. trace_id={data.trace_id}") + return 500, OptimizeErrorResponseSchema(error="Could not generate any optimizations. Please try again.") + + ph( + request.user, + "aiservice-optimize-optimizations-found", + properties={"num_optimizations": len(optimization_response_items), "language": language}, + ) + + async with asyncio.TaskGroup() as tg: + event_task = tg.create_task( + get_or_create_optimization_event( + event_type="no-pr", + user_id=request.user, + current_username=data.current_username, + repo_owner=data.repo_owner, + repo_name=data.repo_name, + trace_id=data.trace_id, + api_key_id=request.api_key_id, + metadata={ + "codeflash_version": data.codeflash_version, + "num_optimizations": len(optimization_response_items), + "experiment_metadata": data.experiment_metadata, + "language": language, + }, + llm_cost=llm_cost, + ) + ) + tg.create_task( + log_features( + trace_id=data.trace_id, + user_id=request.user, + original_code=data.source_code, + dependency_code=data.dependency_code, + optimizations_post={opt.optimization_id: opt.source_code for opt in optimization_response_items}, + explanations_post={opt.optimization_id: opt.explanation for opt in optimization_response_items}, + experiment_metadata=data.experiment_metadata if data.experiment_metadata else None, + optimizations_origin={ + opt.optimization_id: { + "source": OptimizedCandidateSource.OPTIMIZE, + "parent": None, + "model": optimization_models.get(opt.optimization_id, "unknown"), + "language": language, + } + for opt in optimization_response_items + }, + ) + ) + + event, _created = event_task.result() + + for item in optimization_response_items: + item.optimization_event_id = str(event.id) if event else None + + response = OptimizeResponseSchema(optimizations=optimization_response_items) + + def log_response() -> None: + debug_log_sensitive_data(f"JavaScript Response:\n{response.model_dump_json()}") + for opt in response.optimizations: + debug_log_sensitive_data(f"Optimized JavaScript source:\n{opt.source_code}") + debug_log_sensitive_data(f"JavaScript optimization explanation:\n{opt.explanation}") + + debug_log_sensitive_data_from_callable(log_response) + ph(request.user, "aiservice-optimize-successful", properties={"language": language}) + return 200, response diff --git a/django/aiservice/optimizer/prompts/__init__.py b/django/aiservice/optimizer/prompts/__init__.py new file mode 100644 index 000000000..be295e472 --- /dev/null +++ b/django/aiservice/optimizer/prompts/__init__.py @@ -0,0 +1,77 @@ +""" +Prompt loader module for language-specific optimization prompts. + +This module provides a unified interface to load prompts based on language. +""" + +from __future__ import annotations + +from pathlib import Path + +PROMPTS_DIR = Path(__file__).parent + + +def get_system_prompt(language: str, is_async: bool = False) -> str: + """ + Load the system prompt for the given language. + + Args: + language: The programming language (python, javascript, typescript) + is_async: Whether to load the async variant of the prompt + + Returns: + The system prompt text + + Raises: + ValueError: If no prompt exists for the language + """ + # Normalize language - typescript uses javascript prompts + prompt_language = "javascript" if language == "typescript" else language + + variant = "async_system_prompt.md" if is_async else "system_prompt.md" + prompt_file = PROMPTS_DIR / prompt_language / variant + + if not prompt_file.exists(): + raise ValueError(f"No system prompt found for language: {language}") + + return prompt_file.read_text() + + +def get_user_prompt(language: str, is_async: bool = False) -> str: + """ + Load the user prompt for the given language. + + Args: + language: The programming language (python, javascript, typescript) + is_async: Whether to load the async variant of the prompt + + Returns: + The user prompt text + + Raises: + ValueError: If no prompt exists for the language + """ + # Normalize language - typescript uses javascript prompts + prompt_language = "javascript" if language == "typescript" else language + + variant = "async_user_prompt.md" if is_async else "user_prompt.md" + prompt_file = PROMPTS_DIR / prompt_language / variant + + if not prompt_file.exists(): + raise ValueError(f"No user prompt found for language: {language}") + + return prompt_file.read_text() + + +def get_available_languages() -> list[str]: + """ + Get a list of languages that have prompts available. + + Returns: + List of language names with available prompts + """ + languages = [] + for item in PROMPTS_DIR.iterdir(): + if item.is_dir() and (item / "system_prompt.md").exists(): + languages.append(item.name) + return sorted(languages) diff --git a/django/aiservice/optimizer/prompts/javascript/async_system_prompt.md b/django/aiservice/optimizer/prompts/javascript/async_system_prompt.md new file mode 100644 index 000000000..304796d73 --- /dev/null +++ b/django/aiservice/optimizer/prompts/javascript/async_system_prompt.md @@ -0,0 +1,77 @@ +You are a professional computer programmer who specializes in writing high-performance **asynchronous** JavaScript/TypeScript code. Your goal is to optimize the runtime and memory efficiency of the provided **async** code through safe and meaningful rewrites that would pass senior-level code review. + +**CRITICAL: ASYNC CODE REQUIREMENTS** +- The code contains **async functions** that must remain async +- ALL async functions must maintain their `async function` or `async () =>` signature +- ALL `await` expressions must be preserved where they exist +- Do NOT convert async functions to synchronous functions +- Do NOT remove `await` keywords unless replacing with functionally equivalent async operations +- Preserve Promise chains and async/await flow +- Maintain proper async error handling in async contexts + +**Behavioral Preservation (CRITICAL)** +- Do NOT rename functions or change their signatures. +- You MUST NOT change the behavior, return values, side effects, console output, or thrown errors - they MUST remain exactly the same. +- Do NOT mutate inputs in a different way than the original implementation. +- The same error types should be thrown in the same circumstances. +- Preserve existing type annotations (for TypeScript) - all function parameters, return types, and variable annotations must be preserved exactly as written. +- **Preserve the original code style**: Keep existing variable names unless the logic fundamentally changes +- Preserve ALL existing comments exactly as written, unless the corresponding code logic is changed or the comment becomes factually incorrect +- Avoid excessive inline comments - only add new comments for significant or non-obvious logic changes +- Preserve the export structure - exported functions/classes must remain exported + +**Async-Specific Optimization Focus** +- Use `Promise.all()` for concurrent execution of independent async operations +- Use `Promise.allSettled()` when you need results regardless of individual failures +- Use `Promise.race()` for timeout patterns or first-to-complete scenarios +- Batch async operations instead of executing them one-by-one in a loop +- Consider using `for await...of` for async iterables when appropriate +- Optimize async I/O operations and resource management +- Use streaming APIs instead of loading entire datasets into memory +- Consider worker threads for CPU-intensive tasks that would block the event loop + +**Code Style & Structure** +- Keep existing ES module syntax (`import`/`export`) or CommonJS (`require`/`module.exports`) as-is +- You may write new async helper functions that do not already exist in the codebase. +- Avoid purely stylistic changes unless they result in noticeable performance improvements +- Ensure all new async code follows proper async patterns and conventions +- Maintain consistent code formatting + +**Optimization Strategies** +- Replace sequential awaits with parallel execution when operations are independent: + ```javascript + // Before (sequential) + const a = await fetchA(); + const b = await fetchB(); + + // After (parallel) + const [a, b] = await Promise.all([fetchA(), fetchB()]); + ``` +- Use chunked/batched processing for large async operations +- Implement proper backpressure handling for streams +- Cache async results when appropriate using memoization + +**Optimization Focus** +- Create production-ready async code that professional programmers would merge without further edits +- Prioritize changes that provide measurable runtime or memory efficiency gains in async contexts +- Consider async-specific performance patterns like batching operations or reducing context switching + +**Code Quality Standards** +- Ensure all async optimizations are safe and would pass senior-level code review +- Maintain code readability and maintainability alongside performance improvements +- Verify that async operations are properly awaited and handled + +**Response Format (REQUIRED)** +- ALWAYS start your response with a brief explanation (2-4 sentences) of what optimization you made and why it improves performance +- Then provide the optimized code in a markdown code block +- Example format: + ``` + **Optimization Explanation:** + [Your explanation here describing the optimization technique and expected performance improvement] + + ```javascript:filename.js + [optimized code] + ``` + ``` + +The target JavaScript/TypeScript version is {language_version} diff --git a/django/aiservice/optimizer/prompts/javascript/async_user_prompt.md b/django/aiservice/optimizer/prompts/javascript/async_user_prompt.md new file mode 100644 index 000000000..31a307ccc --- /dev/null +++ b/django/aiservice/optimizer/prompts/javascript/async_user_prompt.md @@ -0,0 +1,18 @@ +Rewrite this **asynchronous** JavaScript/TypeScript program to run faster while preserving all async behavior. + +**CRITICAL ASYNC REQUIREMENTS:** +- The code contains **async functions** - you MUST keep them async +- ALL `async function` signatures must be preserved exactly +- ALL `await` expressions must be maintained (unless replaced with functionally equivalent async operations) +- Do NOT convert async functions to synchronous functions +- Preserve concurrent execution patterns and Promise handling +- Maintain proper async/await flow and exception handling + +**Async Optimization Guidelines:** +- Consider using `Promise.all()` for concurrent execution when beneficial +- Batch independent async operations instead of sequential awaits +- Optimize async I/O operations and use streaming where appropriate +- Use worker threads for CPU-intensive tasks to avoid blocking the event loop +- Implement proper error handling in async contexts + +{source_code} diff --git a/django/aiservice/optimizer/prompts/javascript/system_prompt.md b/django/aiservice/optimizer/prompts/javascript/system_prompt.md new file mode 100644 index 000000000..cee7890a5 --- /dev/null +++ b/django/aiservice/optimizer/prompts/javascript/system_prompt.md @@ -0,0 +1,53 @@ +You are a professional computer programmer who specializes in writing high-performance JavaScript/TypeScript code. Your goal is to optimize the runtime and memory efficiency of the provided code through safe and meaningful rewrites that would pass senior-level code review. + +**Behavioral Preservation (CRITICAL)** +- Do NOT rename functions or change their signatures. +- You MUST NOT change the behavior, return values, side effects, console output, or thrown errors - they MUST remain exactly the same. +- Do NOT mutate inputs in a different way than the original implementation. +- The same error types should be thrown in the same circumstances. +- Preserve existing type annotations (for TypeScript) - all function parameters, return types, and variable annotations must be preserved exactly as written. +- **Preserve the original code style**: Keep existing variable names unless the logic fundamentally changes +- Preserve ALL existing comments exactly as written, unless the corresponding code logic is changed or the comment becomes factually incorrect +- Avoid excessive inline comments - only add new comments for significant or non-obvious logic changes +- Preserve the export structure - exported functions/classes must remain exported + +**Code Style & Structure** +- Keep existing ES module syntax (`import`/`export`) or CommonJS (`require`/`module.exports`) as-is +- You may write new helper functions that do not already exist in the codebase. +- Avoid purely stylistic changes unless they result in noticeable performance improvements +- Maintain consistent code formatting + +**Optimization Strategies** +- Replace O(n^2) algorithms with O(n) or O(n log n) alternatives +- Use TypedArrays (Float64Array, Int32Array, etc.) instead of regular arrays for numeric-heavy operations +- Use Map/Set instead of Object for frequent lookups +- Minimize object allocations in hot paths (avoid creating temporary objects in loops) +- Use for loops instead of forEach/map/filter for performance-critical code when the functional style adds overhead +- Cache array lengths in tight loops: `for (let i = 0, len = arr.length; i < len; i++)` +- Leverage V8 optimization hints (keep functions monomorphic, avoid hidden class changes) +- Avoid try-catch in hot loops (move error handling outside the loop when possible) +- Use string concatenation with template literals or array join for building large strings +- Consider using WeakMap/WeakSet for caching to avoid memory leaks + +**Optimization Focus** +- Create production-ready code that professional programmers would merge without further edits +- Prioritize changes that provide measurable runtime or memory efficiency gains + +**Code Quality Standards** +- Ensure all optimizations are safe and would pass senior-level code review +- Maintain code readability and maintainability alongside performance improvements + +**Response Format (REQUIRED)** +- ALWAYS start your response with a brief explanation (2-4 sentences) of what optimization you made and why it improves performance +- Then provide the optimized code in a markdown code block +- Example format: + ``` + **Optimization Explanation:** + [Your explanation here describing the optimization technique and expected performance improvement] + + ```javascript:filename.js + [optimized code] + ``` + ``` + +The target JavaScript/TypeScript version is {language_version} diff --git a/django/aiservice/optimizer/prompts/javascript/user_prompt.md b/django/aiservice/optimizer/prompts/javascript/user_prompt.md new file mode 100644 index 000000000..497d60aff --- /dev/null +++ b/django/aiservice/optimizer/prompts/javascript/user_prompt.md @@ -0,0 +1,3 @@ +Rewrite this JavaScript/TypeScript program to run faster. + +{source_code} diff --git a/django/aiservice/optimizer/prompts/python/async_system_prompt.md b/django/aiservice/optimizer/prompts/python/async_system_prompt.md new file mode 100644 index 000000000..30ac6e39f --- /dev/null +++ b/django/aiservice/optimizer/prompts/python/async_system_prompt.md @@ -0,0 +1,63 @@ +You are a professional computer programmer who specializes in writing high-performance **asynchronous** Python code. Your goal is to optimize the runtime and memory efficiency of the provided **async** code through safe and meaningful rewrites that would pass senior-level code review. + +**CRITICAL: ASYNC CODE REQUIREMENTS** +- The code contains **async functions** that must remain async +- ALL async functions must maintain their `async def` signature +- ALL `await` expressions must be preserved where they exist +- Do NOT convert async functions to synchronous functions +- Do NOT remove `await` keywords unless replacing with functionally equivalent async operations +- Preserve concurrency patterns and async context manager usage +- Maintain proper async/await flow and error handling in async contexts + +**Behavioral Preservation (CRITICAL)** +- Do NOT rename functions or change their signatures. +- You MUST NOT change the behavior, return values, side effects, printed/logged output, or raised exceptions - they MUST remain exactly the same. +- Do NOT mutate inputs in a different way than the original implementation. +- The same exception types should be raised in the same circumstances. +- Preserve existing type annotations - all function parameters, return types, and variable annotations must be preserved exactly as written. +- **Preserve the original code style**: Keep existing variable names unless the logic fundamentally changes +- Preserve ALL existing comments exactly as written, unless the corresponding code logic is changed or the comment becomes factually incorrect +- Avoid excessive inline comments - only add new comments for significant or non-obvious logic changes + +**Async-Specific Optimization Focus** +- Optimize async patterns such as concurrent execution with `asyncio.gather()` or `asyncio.create_task()` +- Consider using `asyncio.as_completed()` for better performance when appropriate +- Identify and replace blocking operations with async equivalents (e.g., `time.sleep()` → `asyncio.sleep()`, sync file I/O → `aiofiles`, blocking network calls → async libraries) +- Optimize async context managers and async iterators +- Improve async I/O operations and resource management +- Consider async comprehensions where they provide performance benefits +- Use `asyncio.to_thread()` for CPU-intensive tasks that would block the event loop +- Maintain proper async exception handling and cleanup + +**Code Style & Structure** +- Do NOT replace walrus operators (`:=`) for optimization purposes. +- Keep `assert` statements as-is - do NOT convert them to `if/raise AssertionError` patterns, it doesn't improve the performance. +- **DO NOT convert `isinstance()` checks to `type()` checks**. `isinstance()` correctly handles inheritance and subclasses, while `type()` checks are incorrect for subclass instances and represent a micro-optimization that should be avoided. +- You may write new async helper functions that do not already exist in the codebase. +- Avoid purely stylistic changes unless they result in noticeable performance improvements +- Ensure all new async code follows proper async patterns and conventions + +**Optimization Focus** +- Create production-ready async code that professional programmers would merge without further edits +- Prioritize changes that provide measurable runtime or memory efficiency gains in async contexts +- Consider async-specific performance patterns like batching operations or reducing context switching + +**Code Quality Standards** +- Ensure all async optimizations are safe and would pass senior-level code review +- Maintain code readability and maintainability alongside performance improvements +- Verify that async operations are properly awaited and handled + +**Response Format (REQUIRED)** +- ALWAYS start your response with a brief explanation (2-4 sentences) of what optimization you made and why it improves performance +- Then provide the optimized code in a markdown code block +- Example format: + ``` + **Optimization Explanation:** + [Your explanation here describing the optimization technique and expected performance improvement] + + ```python:filename.py + [optimized code] + ``` + ``` + +The current Python version is {python_version_str} diff --git a/django/aiservice/optimizer/prompts/python/async_user_prompt.md b/django/aiservice/optimizer/prompts/python/async_user_prompt.md new file mode 100644 index 000000000..6a16ccc01 --- /dev/null +++ b/django/aiservice/optimizer/prompts/python/async_user_prompt.md @@ -0,0 +1,19 @@ +Rewrite this **asynchronous** Python program to run faster while preserving all async behavior. + +**CRITICAL ASYNC REQUIREMENTS:** +- The code contains **async functions** - you MUST keep them async +- ALL `async def` function signatures must be preserved exactly +- ALL `await` expressions must be maintained (unless replaced with functionally equivalent async operations) +- Do NOT convert async functions to synchronous functions +- Preserve concurrent execution patterns and async context managers +- Maintain proper async/await flow and exception handling + +**Async Optimization Guidelines:** +- Consider using `asyncio.gather()` for concurrent execution when beneficial +- Replace blocking operations with async equivalents (e.g., `time.sleep()` with `asyncio.sleep()`, sync I/O with async libraries) +- Optimize async I/O operations and batching where appropriate +- Use `asyncio.to_thread()` for CPU-intensive tasks to avoid blocking the event loop +- Optimize async context managers and async iterators +- Maintain async exception handling and resource cleanup + +{source_code} diff --git a/django/aiservice/optimizer/prompts/python/system_prompt.md b/django/aiservice/optimizer/prompts/python/system_prompt.md new file mode 100644 index 000000000..879aed019 --- /dev/null +++ b/django/aiservice/optimizer/prompts/python/system_prompt.md @@ -0,0 +1,43 @@ +You are a professional computer programmer who specializes in writing high-performance Python code. Your goal is to optimize the runtime and memory efficiency of the provided code through safe and meaningful rewrites that would pass senior-level code review. + +**Behavioral Preservation (CRITICAL)** +- Do NOT rename functions or change their signatures. +- You MUST NOT change the behavior, return values, side effects, printed/logged output, or raised exceptions - they MUST remain exactly the same. +- Do NOT mutate inputs in a different way than the original implementation. +- The same exception types should be raised in the same circumstances. +- Preserve existing type annotations - all function parameters, return types, and variable annotations must be preserved exactly as written. +- **Preserve the original code style**: Keep existing variable names unless the logic fundamentally changes +- Preserve ALL existing comments exactly as written, unless the corresponding code logic is changed or the comment becomes factually incorrect +- Avoid excessive inline comments - only add new comments for significant or non-obvious logic changes +{critical_instructions} + +**Code Style & Structure** +- Do NOT replace walrus operators (`:=`) for optimization purposes. +- DO NOT introduce attribute lookup optimizations. The performance improvements are minimal and come at a substantial cost to readability. +- Keep `assert` statements as-is - do NOT convert them to `if/raise AssertionError` patterns, it doesn't improve the performance. +- **DO NOT convert `isinstance()` checks to `type()` checks**. `isinstance()` correctly handles inheritance and subclasses, while `type()` checks are incorrect for subclass instances and represent a micro-optimization that should be avoided. +- You may write new helper functions that do not already exist in the codebase. +- Avoid purely stylistic changes unless they result in noticeable performance improvements + +**Optimization Focus** +- Create production-ready code that professional programmers would merge without further edits +- Prioritize changes that provide measurable runtime or memory efficiency gains + +**Code Quality Standards** +- Ensure all optimizations are safe and would pass senior-level code review +- Maintain code readability and maintainability alongside performance improvements + +**Response Format (REQUIRED)** +- ALWAYS start your response with a brief explanation (2-4 sentences) of what optimization you made and why it improves performance +- Then provide the optimized code in a markdown code block +- Example format: + ``` + **Optimization Explanation:** + [Your explanation here describing the optimization technique and expected performance improvement] + + ```python:filename.py + [optimized code] + ``` + ``` + +The current Python version is {python_version_str} diff --git a/django/aiservice/optimizer/prompts/python/user_prompt.md b/django/aiservice/optimizer/prompts/python/user_prompt.md new file mode 100644 index 000000000..9b29110b9 --- /dev/null +++ b/django/aiservice/optimizer/prompts/python/user_prompt.md @@ -0,0 +1,3 @@ +Rewrite this python program to run faster. + +{source_code} diff --git a/django/aiservice/testgen/instrumentation/javascript/__init__.py b/django/aiservice/testgen/instrumentation/javascript/__init__.py new file mode 100644 index 000000000..9ec7ed7fa --- /dev/null +++ b/django/aiservice/testgen/instrumentation/javascript/__init__.py @@ -0,0 +1,13 @@ +""" +JavaScript test instrumentation module. + +This module provides unified instrumentation for JavaScript tests, +working identically for both generated and existing tests. +""" + +from testgen.instrumentation.javascript.instrument_javascript import ( + instrument_javascript_tests, + get_jest_helper_path, +) + +__all__ = ["instrument_javascript_tests", "get_jest_helper_path"] diff --git a/django/aiservice/testgen/instrumentation/javascript/codeflash-jest-helper.js b/django/aiservice/testgen/instrumentation/javascript/codeflash-jest-helper.js new file mode 100644 index 000000000..be8d22c8f --- /dev/null +++ b/django/aiservice/testgen/instrumentation/javascript/codeflash-jest-helper.js @@ -0,0 +1,277 @@ +/** + * Codeflash Jest Helper - Unified Test Instrumentation + * + * This module provides a unified approach to instrumenting JavaScript tests + * for both behavior verification and performance measurement. + * + * Unlike Python which has separate instrumentation methods for generated + * vs existing tests, this helper works identically for ALL JavaScript tests. + * + * Usage: + * const codeflash = require('codeflash-jest-helper'); + * + * // Wrap function calls to capture behavior + * const result = codeflash.capture('functionName', targetFunction, arg1, arg2); + * + * Environment Variables: + * CODEFLASH_OUTPUT_FILE - Path to write results (default: /tmp/codeflash_results.bin) + * CODEFLASH_LOOP_INDEX - Current benchmark loop iteration (default: 0) + * CODEFLASH_MODE - Testing mode: 'behavior' or 'performance' (default: 'behavior') + */ + +const fs = require('fs'); +const path = require('path'); +const { performance } = require('perf_hooks'); + +// Configuration from environment +const OUTPUT_FILE = process.env.CODEFLASH_OUTPUT_FILE || '/tmp/codeflash_results.bin'; +const LOOP_INDEX = parseInt(process.env.CODEFLASH_LOOP_INDEX || '0', 10); +const MODE = process.env.CODEFLASH_MODE || 'behavior'; + +// Current test context +let currentTestName = null; +let invocationCounter = 0; + +// Results buffer +const results = []; + +/** + * Safely serialize a value to JSON. + * Handles circular references and special types. + * + * @param {any} value - Value to serialize + * @returns {any} - Serializable representation + */ +function safeSerialize(value) { + const seen = new WeakSet(); + + function serialize(val) { + // Handle primitives + if (val === null || val === undefined) return val; + if (typeof val === 'number') { + if (Number.isNaN(val)) return { __type: 'NaN' }; + if (!Number.isFinite(val)) return { __type: val > 0 ? 'Infinity' : '-Infinity' }; + return val; + } + if (typeof val === 'string' || typeof val === 'boolean') return val; + if (typeof val === 'bigint') return { __type: 'BigInt', value: val.toString() }; + if (typeof val === 'symbol') return { __type: 'Symbol', description: val.description }; + if (typeof val === 'function') return { __type: 'Function', name: val.name || 'anonymous' }; + + // Handle special objects + if (val instanceof Date) return { __type: 'Date', value: val.toISOString() }; + if (val instanceof RegExp) return { __type: 'RegExp', source: val.source, flags: val.flags }; + if (val instanceof Error) return { __type: 'Error', name: val.name, message: val.message }; + if (val instanceof Map) return { __type: 'Map', entries: Array.from(val.entries()).map(([k, v]) => [serialize(k), serialize(v)]) }; + if (val instanceof Set) return { __type: 'Set', values: Array.from(val).map(serialize) }; + if (ArrayBuffer.isView(val)) return { __type: val.constructor.name, data: Array.from(val) }; + if (val instanceof ArrayBuffer) return { __type: 'ArrayBuffer', byteLength: val.byteLength }; + if (val instanceof Promise) return { __type: 'Promise' }; + + // Handle arrays + if (Array.isArray(val)) { + if (seen.has(val)) return { __type: 'CircularReference' }; + seen.add(val); + return val.map(serialize); + } + + // Handle objects + if (typeof val === 'object') { + if (seen.has(val)) return { __type: 'CircularReference' }; + seen.add(val); + const result = {}; + for (const key of Object.keys(val)) { + try { + result[key] = serialize(val[key]); + } catch (e) { + result[key] = { __type: 'UnserializableProperty', error: e.message }; + } + } + return result; + } + + return { __type: 'Unknown', typeof: typeof val }; + } + + try { + return serialize(value); + } catch (e) { + return { __type: 'SerializationError', error: e.message }; + } +} + +/** + * Record a test result. + * + * @param {string} funcName - Name of the function being tested + * @param {Array} args - Arguments passed to the function + * @param {any} returnValue - Return value from the function + * @param {Error|null} error - Error thrown by the function (if any) + * @param {number} durationNs - Execution time in nanoseconds + */ +function recordResult(funcName, args, returnValue, error, durationNs) { + const result = { + testName: currentTestName, + funcName, + args: safeSerialize(args), + returnValue: safeSerialize(returnValue), + error: error ? { + name: error.name, + message: error.message, + stack: error.stack + } : null, + durationNs: Math.round(durationNs), + invocationId: invocationCounter++, + loopIndex: LOOP_INDEX, + mode: MODE, + timestamp: Date.now() + }; + results.push(result); +} + +/** + * Capture a function call with full behavior tracking. + * + * This is the main API for instrumenting function calls. + * It captures inputs, outputs, errors, and timing for every call. + * + * @param {string} funcName - Name of the function being tested + * @param {Function} fn - The function to call + * @param {...any} args - Arguments to pass to the function + * @returns {any} - The function's return value + * @throws {Error} - Re-throws any error from the function + */ +function capture(funcName, fn, ...args) { + const startTime = performance.now(); + let returnValue; + let error = null; + + try { + returnValue = fn(...args); + + // Handle promises (async functions) + if (returnValue instanceof Promise) { + return returnValue.then( + (resolved) => { + const endTime = performance.now(); + const durationNs = (endTime - startTime) * 1_000_000; + recordResult(funcName, args, resolved, null, durationNs); + return resolved; + }, + (err) => { + const endTime = performance.now(); + const durationNs = (endTime - startTime) * 1_000_000; + recordResult(funcName, args, null, err, durationNs); + throw err; + } + ); + } + } catch (e) { + error = e; + } + + const endTime = performance.now(); + const durationNs = (endTime - startTime) * 1_000_000; + recordResult(funcName, args, returnValue, error, durationNs); + + if (error) throw error; + return returnValue; +} + +/** + * Capture multiple invocations for benchmarking. + * + * @param {string} funcName - Name of the function being tested + * @param {Function} fn - The function to call + * @param {Array} argsList - List of argument arrays to test + * @returns {Array} - Array of return values + */ +function captureMultiple(funcName, fn, argsList) { + return argsList.map(args => capture(funcName, fn, ...args)); +} + +/** + * Write results to output file. + * Called automatically via Jest afterAll hook. + */ +function writeResults() { + if (results.length === 0) return; + + try { + const output = { + version: '1.0.0', + mode: MODE, + loopIndex: LOOP_INDEX, + timestamp: Date.now(), + results + }; + const buffer = Buffer.from(JSON.stringify(output, null, 2)); + fs.writeFileSync(OUTPUT_FILE, buffer); + } catch (e) { + console.error('[codeflash] Error writing results:', e.message); + } +} + +/** + * Clear all recorded results. + * Useful for resetting between test files. + */ +function clearResults() { + results.length = 0; + invocationCounter = 0; +} + +/** + * Get the current results buffer. + * Useful for debugging or custom result handling. + * + * @returns {Array} - Current results buffer + */ +function getResults() { + return results; +} + +/** + * Set the current test name. + * Called automatically via Jest beforeEach hook. + * + * @param {string} name - Test name + */ +function setTestName(name) { + currentTestName = name; + invocationCounter = 0; +} + +// Jest lifecycle hooks - these run automatically when this module is imported +if (typeof beforeEach !== 'undefined') { + beforeEach(() => { + // Get current test name from Jest's expect state + try { + currentTestName = expect.getState().currentTestName || 'unknown'; + } catch (e) { + currentTestName = 'unknown'; + } + invocationCounter = 0; + }); +} + +if (typeof afterAll !== 'undefined') { + afterAll(() => { + writeResults(); + }); +} + +// Export public API +module.exports = { + capture, + captureMultiple, + writeResults, + clearResults, + getResults, + setTestName, + safeSerialize, + // Constants + MODE, + LOOP_INDEX, + OUTPUT_FILE +}; diff --git a/django/aiservice/testgen/instrumentation/javascript/instrument_javascript.py b/django/aiservice/testgen/instrumentation/javascript/instrument_javascript.py new file mode 100644 index 000000000..8c17b3079 --- /dev/null +++ b/django/aiservice/testgen/instrumentation/javascript/instrument_javascript.py @@ -0,0 +1,235 @@ +""" +JavaScript test instrumentation module. + +This module instruments JavaScript tests by injecting the codeflash-jest-helper +to capture function call behavior and performance data. + +Unlike Python which has separate instrumentation for generated vs existing tests, +JavaScript uses a UNIFIED approach - the same instrumentation works for all tests. +""" + +from __future__ import annotations + +import re +from pathlib import Path + + +def get_jest_helper_path() -> Path: + """ + Get the path to the codeflash-jest-helper.js file. + + Returns: + Path to the helper JavaScript file + """ + return Path(__file__).parent / "codeflash-jest-helper.js" + + +def instrument_javascript_tests( + test_source: str, + function_name: str, + module_path: str, +) -> str: + """ + Instrument JavaScript tests with codeflash helper. + + This is a UNIFIED approach - works for both generated and existing tests. + The instrumentation wraps function calls to capture inputs, outputs, and timing. + + Args: + test_source: The JavaScript test source code + function_name: The name of the function being tested + module_path: The path to the module containing the function + + Returns: + Instrumented test source code + """ + # Check if already instrumented + if "codeflash-jest-helper" in test_source: + return test_source + + lines = test_source.split("\n") + result_lines = [] + + # Add helper import at the top, after any existing imports + helper_import = "const codeflash = require('codeflash-jest-helper');" + import_inserted = False + in_import_block = False + + for i, line in enumerate(lines): + stripped = line.strip() + + # Track if we're in the import block + if stripped.startswith("import ") or stripped.startswith("const ") and "require" in stripped: + in_import_block = True + elif in_import_block and stripped and not stripped.startswith("import ") and not ( + stripped.startswith("const ") and "require" in stripped + ): + # End of import block - insert helper import + if not import_inserted: + result_lines.append(helper_import) + result_lines.append("") + import_inserted = True + in_import_block = False + + result_lines.append(line) + + # If no imports found, add at the beginning + if not import_inserted: + result_lines = [helper_import, ""] + result_lines + + instrumented_source = "\n".join(result_lines) + + # Wrap function calls with codeflash.capture + # Pattern matches: functionName(args) but not inside strings or comments + # This is a simple approach - a more robust solution would use an AST parser + + # Pattern for standalone function calls (not method calls) + pattern = rf"(? str: + args = match.group(1).strip() + if args: + return f"codeflash.capture('{function_name}', {function_name}, {args})" + else: + return f"codeflash.capture('{function_name}', {function_name})" + + # Apply replacement carefully - avoid replacing inside strings + # This is a simplified approach that works for most cases + instrumented_source = _safe_replace_function_calls( + instrumented_source, function_name, replace_call, pattern + ) + + return instrumented_source + + +def _safe_replace_function_calls( + source: str, + function_name: str, + replace_func: callable, + pattern: str, +) -> str: + """ + Replace function calls while avoiding string literals and comments. + + This is a simplified approach that handles common cases. + A more robust solution would use a proper JavaScript parser. + """ + result = [] + i = 0 + length = len(source) + + while i < length: + char = source[i] + + # Skip string literals + if char in "'\"`": + quote_char = char + result.append(char) + i += 1 + + # Handle template literals with ${} expressions + if quote_char == "`": + while i < length: + if source[i] == "\\": + result.append(source[i:i+2]) + i += 2 + elif source[i] == "$" and i + 1 < length and source[i + 1] == "{": + # Template expression - need to handle nested braces + result.append(source[i:i+2]) + i += 2 + brace_count = 1 + while i < length and brace_count > 0: + if source[i] == "{": + brace_count += 1 + elif source[i] == "}": + brace_count -= 1 + result.append(source[i]) + i += 1 + elif source[i] == quote_char: + result.append(source[i]) + i += 1 + break + else: + result.append(source[i]) + i += 1 + else: + # Regular string + while i < length: + if source[i] == "\\": + result.append(source[i:i+2]) + i += 2 + elif source[i] == quote_char: + result.append(source[i]) + i += 1 + break + else: + result.append(source[i]) + i += 1 + continue + + # Skip single-line comments + if char == "/" and i + 1 < length and source[i + 1] == "/": + while i < length and source[i] != "\n": + result.append(source[i]) + i += 1 + continue + + # Skip multi-line comments + if char == "/" and i + 1 < length and source[i + 1] == "*": + result.append(source[i:i+2]) + i += 2 + while i < length - 1: + if source[i] == "*" and source[i + 1] == "/": + result.append(source[i:i+2]) + i += 2 + break + result.append(source[i]) + i += 1 + continue + + # Check for function call pattern + remaining = source[i:] + match = re.match(pattern, remaining) + if match: + # Check that we're not preceded by a dot (method call) + if i > 0 and source[i - 1] == ".": + result.append(char) + i += 1 + continue + + # Check that we haven't already wrapped this + if i >= len("codeflash.capture") and source[i - len("codeflash.capture"):i] == "codeflash.capture": + result.append(char) + i += 1 + continue + + # Apply replacement + replacement = replace_func(match) + result.append(replacement) + i += match.end() + continue + + result.append(char) + i += 1 + + return "".join(result) + + +def get_jest_setup_code(output_file: str, mode: str = "behavior", loop_index: int = 0) -> str: + """ + Generate Jest setup code for setting environment variables. + + Args: + output_file: Path where results should be written + mode: Testing mode ('behavior' or 'performance') + loop_index: Current benchmark loop iteration + + Returns: + JavaScript code to set up the testing environment + """ + return f""" +// Codeflash test setup +process.env.CODEFLASH_OUTPUT_FILE = '{output_file}'; +process.env.CODEFLASH_MODE = '{mode}'; +process.env.CODEFLASH_LOOP_INDEX = '{loop_index}'; +""" diff --git a/django/aiservice/testgen/models.py b/django/aiservice/testgen/models.py index bef31223d..eb6eb53c6 100644 --- a/django/aiservice/testgen/models.py +++ b/django/aiservice/testgen/models.py @@ -19,10 +19,12 @@ class TestGenSchema(Schema): dependent_function_names: list[str] | None = None # Only for backwards compatibility module_path: str test_module_path: str - test_framework: str + test_framework: str # "pytest", "unittest", "jest", "mocha" test_timeout: int trace_id: str - python_version: str + python_version: str | None = None # Made optional for multi-language support + language: str = "python" # NEW: language identifier (python, javascript, typescript) + language_version: str | None = None # NEW: e.g., "ES2022", "Node 20", or Python version codeflash_version: str | None = None test_index: int | None = None is_async: bool | None = False diff --git a/django/aiservice/testgen/prompts/javascript/execute_async_system_prompt.md b/django/aiservice/testgen/prompts/javascript/execute_async_system_prompt.md new file mode 100644 index 000000000..b96d863fb --- /dev/null +++ b/django/aiservice/testgen/prompts/javascript/execute_async_system_prompt.md @@ -0,0 +1,37 @@ +**Role**: You are Codeflash, a world-class JavaScript/TypeScript developer with an eagle eye for unintended bugs and edge cases. You write careful, accurate unit tests for **asynchronous** code using Jest. When asked to reply only with code, you write all of your code in a single markdown code block. + +**Task** Your task is to create comprehensive, high quality test cases for the **async** {function_name} function. These test cases should encompass Basic, Edge, and Large Scale scenarios to ensure the code's robustness, reliability, and scalability with proper async/await handling. + +**CRITICAL: ASYNC TEST REQUIREMENTS** +- The function under test is **asynchronous** - all tests must handle async properly +- Use `async/await` syntax in test functions +- Ensure all promises are awaited +- Test both successful resolution and rejection scenarios +- Handle async timeouts appropriately + +**1. Basic Test Cases**: +- **Objective**: To verify the fundamental async functionality of the {function_name} function under normal conditions. + +**2. Edge Test Cases**: +- **Objective**: To evaluate the async function's behavior under extreme or unusual conditions, including error handling. + +**3. Large Scale Test Cases**: +- **Objective**: To assess the async function's performance and scalability with concurrent operations and large data samples. + +**Instructions**: +- Implement a comprehensive set of test cases following the guidelines above. +- Use Jest testing framework with `describe`, `test`, and `expect`. +- **ALL test functions must be async**: `test('...', async () => {{ ... }})` +- **ALL calls to the function must be awaited**: `const result = await {function_name}(...)` +- Ensure each test case is well-documented with comments explaining the scenario it covers. +- Pay special attention to edge cases including async error handling. +- For large-scale tests, consider concurrent execution with `Promise.all()`. +- Avoid loops exceeding 1000 iterations, and keep data structures under 1000 elements. +- **CRITICAL: DO NOT MOCK THE FUNCTION UNDER TEST** - Never mock, stub, or spy on the {function_name} function itself. +- **CRITICAL: TEST REJECTION CASES** - Use `expect(...).rejects.toThrow()` for testing async errors. + +**Output Format Requirements**: +- Your response MUST be a single markdown code block containing valid JavaScript/TypeScript code. +- Do NOT nest code blocks inside each other. +- The code block MUST contain at least one async test using `test('...', async () => ...)`. +- Follow the exact template structure provided in the user message. diff --git a/django/aiservice/testgen/prompts/javascript/execute_async_user_prompt.md b/django/aiservice/testgen/prompts/javascript/execute_async_user_prompt.md new file mode 100644 index 000000000..f76703c2c --- /dev/null +++ b/django/aiservice/testgen/prompts/javascript/execute_async_user_prompt.md @@ -0,0 +1,50 @@ +Using the {test_framework} testing framework, write a test suite for the following **ASYNC** JavaScript function. + +**CRITICAL: This function is ASYNCHRONOUS** +- All test functions MUST be async: `test('...', async () => {{ ... }})` +- All calls to {function_name} MUST be awaited: `await {function_name}(...)` +- Test both successful and error cases for async operations + +**Function to Test:** +```javascript +{function_code} +``` + +**Template to Follow:** +```javascript +// imports +const {{ {function_name} }} = require('{module_path}'); + +// unit tests +describe('{function_name}', () => {{ + // Basic Test Cases + describe('Basic async functionality', () => {{ + test('should resolve with correct value', async () => {{ + const result = await {function_name}(/* args */); + expect(result).toBe(/* expected */); + }}); + }}); + + // Edge Test Cases + describe('Async edge cases', () => {{ + test('should handle async error case', async () => {{ + await expect({function_name}(/* invalid args */)).rejects.toThrow(); + }}); + }}); + + // Large Scale Test Cases + describe('Concurrent execution tests', () => {{ + test('should handle multiple concurrent calls', async () => {{ + const results = await Promise.all([ + {function_name}(/* args1 */), + {function_name}(/* args2 */), + ]); + // assertions + }}); + }}); +}}); +``` + +{package_comment} + +Reply only with code, in a single markdown code block. diff --git a/django/aiservice/testgen/prompts/javascript/execute_system_prompt.md b/django/aiservice/testgen/prompts/javascript/execute_system_prompt.md new file mode 100644 index 000000000..77c859b65 --- /dev/null +++ b/django/aiservice/testgen/prompts/javascript/execute_system_prompt.md @@ -0,0 +1,28 @@ +**Role**: You are Codeflash, a world-class JavaScript/TypeScript developer with an eagle eye for unintended bugs and edge cases. You write careful, accurate unit tests using Jest. When asked to reply only with code, you write all of your code in a single markdown code block. + +**Task** Your task is to create comprehensive, high quality test cases for the {function_name} function. These test cases should encompass Basic, Edge, and Large Scale scenarios to ensure the code's robustness, reliability, and scalability. These test cases should *define* the {function_name} function, meaning that the function should pass all the tests, and a function with different external functional behavior should fail them. + +**1. Basic Test Cases**: +- **Objective**: To verify the fundamental functionality of the {function_name} function under normal conditions. + +**2. Edge Test Cases**: +- **Objective**: To evaluate the function's behavior under extreme or unusual conditions. + +**3. Large Scale Test Cases**: +- **Objective**: To assess the function's performance and scalability with large data samples. + +**Instructions**: +- Implement a comprehensive set of test cases following the guidelines above. +- Use Jest testing framework with `describe`, `test`, and `expect`. +- Ensure each test case is well-documented with comments explaining the scenario it covers. +- Pay special attention to edge cases as they often reveal hidden bugs. +- For large-scale tests, focus on the function's efficiency and performance under heavy loads. Avoid loops exceeding 1000 iterations, and keep data structures under 1000 elements. +- **CRITICAL: DO NOT MOCK THE FUNCTION UNDER TEST** - Never mock, stub, or spy on the {function_name} function itself. You may mock external dependencies (APIs, databases, network calls, file I/O, etc.) if necessary, but the function being tested must execute with its real implementation. +- **CRITICAL: IMPORT FROM REAL MODULES** - Import the function and any related classes/utilities from their actual module paths as shown in the context. +- **CRITICAL: HANDLE ASYNC PROPERLY** - If the function is async, use `async/await` in your tests and ensure all promises are properly awaited. + +**Output Format Requirements**: +- Your response MUST be a single markdown code block containing valid JavaScript/TypeScript code. +- Do NOT nest code blocks inside each other. +- The code block MUST contain at least one test using `test()` or `it()`. +- Follow the exact template structure provided in the user message. diff --git a/django/aiservice/testgen/prompts/javascript/execute_user_prompt.md b/django/aiservice/testgen/prompts/javascript/execute_user_prompt.md new file mode 100644 index 000000000..ca9d8615e --- /dev/null +++ b/django/aiservice/testgen/prompts/javascript/execute_user_prompt.md @@ -0,0 +1,40 @@ +Using the {test_framework} testing framework, write a test suite for the following JavaScript function. + +**Function to Test:** +```javascript +{function_code} +``` + +**Template to Follow:** +```javascript +// imports +const {{ {function_name} }} = require('{module_path}'); + +// unit tests +describe('{function_name}', () => {{ + // Basic Test Cases + describe('Basic functionality', () => {{ + test('should handle normal input', () => {{ + // Test implementation + }}); + }}); + + // Edge Test Cases + describe('Edge cases', () => {{ + test('should handle edge case', () => {{ + // Test implementation + }}); + }}); + + // Large Scale Test Cases + describe('Performance tests', () => {{ + test('should handle large inputs efficiently', () => {{ + // Test implementation + }}); + }}); +}}); +``` + +{package_comment} + +Reply only with code, in a single markdown code block. diff --git a/django/aiservice/testgen/testgen.py b/django/aiservice/testgen/testgen.py index fe34f2ff6..305fc93b1 100644 --- a/django/aiservice/testgen/testgen.py +++ b/django/aiservice/testgen/testgen.py @@ -36,6 +36,7 @@ from testgen.postprocessing.add_missing_imports import add_missing_imports_from_ from testgen.postprocessing.code_validator import has_test_functions, validate_testgen_code from testgen.postprocessing.postprocess_pipeline import postprocessing_testgen_pipeline from testgen.testgen_context import BaseTestGenContext, TestGenContextData +from testgen.testgen_javascript import testgen_javascript if TYPE_CHECKING: from openai.types.chat import ChatCompletionMessageParam @@ -379,7 +380,19 @@ def validate_request_data(data: TestGenSchema) -> tuple[tuple[int, int, int], Ba async def testgen( request: AuthenticatedRequest, data: TestGenSchema ) -> tuple[int, TestGenResponseSchema | TestGenErrorResponseSchema]: - ph(request.user, "aiservice-testgen-called") + # Route based on language + if data.language in ("javascript", "typescript"): + return await testgen_javascript(request, data) + + # Default: Python test generation + return await testgen_python(request, data) + + +async def testgen_python( + request: AuthenticatedRequest, data: TestGenSchema +) -> tuple[int, TestGenResponseSchema | TestGenErrorResponseSchema]: + """Generate Python tests using LLMs.""" + ph(request.user, "aiservice-testgen-called", properties={"language": "python"}) try: python_version, ctx = validate_request_data(data) diff --git a/django/aiservice/testgen/testgen_javascript.py b/django/aiservice/testgen/testgen_javascript.py new file mode 100644 index 000000000..7c4b736bb --- /dev/null +++ b/django/aiservice/testgen/testgen_javascript.py @@ -0,0 +1,389 @@ +""" +JavaScript/TypeScript test generation module. + +This module generates Jest tests for JavaScript/TypeScript functions +and applies unified instrumentation for behavior verification and +performance measurement. +""" + +from __future__ import annotations + +import asyncio +import logging +import re +from pathlib import Path +from typing import TYPE_CHECKING + +import sentry_sdk +import stamina +from ninja.errors import HttpError +from openai import OpenAIError + +from aiservice.analytics.posthog import ph +from aiservice.common_utils import validate_trace_id +from aiservice.env_specific import debug_log_sensitive_data +from aiservice.llm import EXECUTE_MODEL, HAIKU_MODEL, OPENAI_MODEL, calculate_llm_cost, call_llm +from aiservice.validators.javascript_validator import validate_javascript_syntax +from authapp.auth import AuthenticatedRequest +from log_features.log_event import update_optimization_cost +from log_features.log_features import log_features +from testgen.instrumentation.javascript import instrument_javascript_tests +from testgen.models import ( + TestGenerationFailedError, + TestGenErrorResponseSchema, + TestGenResponseSchema, + TestGenSchema, +) + +if TYPE_CHECKING: + from aiservice.llm import LLM + +# Get the directory of the current file +current_dir = Path(__file__).parent +JS_PROMPTS_DIR = current_dir / "prompts" / "javascript" + +# Load JavaScript prompts +JS_EXECUTE_SYSTEM_PROMPT = (JS_PROMPTS_DIR / "execute_system_prompt.md").read_text() +JS_EXECUTE_USER_PROMPT = (JS_PROMPTS_DIR / "execute_user_prompt.md").read_text() +JS_EXECUTE_ASYNC_SYSTEM_PROMPT = (JS_PROMPTS_DIR / "execute_async_system_prompt.md").read_text() +JS_EXECUTE_ASYNC_USER_PROMPT = (JS_PROMPTS_DIR / "execute_async_user_prompt.md").read_text() + +# Pattern to extract JavaScript code blocks +JS_PATTERN = re.compile(r"^```(?:javascript|js|typescript|ts)?\s*\n(.*?)\n```", re.MULTILINE | re.DOTALL) + + +def build_javascript_prompt( + function_name: str, + function_code: str, + module_path: str, + test_framework: str, + is_async: bool, +) -> tuple[list[dict[str, str]], str]: + """ + Build the prompt messages for JavaScript test generation. + + Args: + function_name: Name of the function to test + function_code: Source code of the function + module_path: Import path for the module + test_framework: Testing framework (jest, mocha) + is_async: Whether the function is async + + Returns: + Tuple of (messages, posthog_event_suffix) + """ + if is_async: + system_prompt = JS_EXECUTE_ASYNC_SYSTEM_PROMPT + user_prompt = JS_EXECUTE_ASYNC_USER_PROMPT + posthog_event_suffix = "async-" + else: + system_prompt = JS_EXECUTE_SYSTEM_PROMPT + user_prompt = JS_EXECUTE_USER_PROMPT + posthog_event_suffix = "" + + # Format prompts + system_message = { + "role": "system", + "content": system_prompt.format(function_name=function_name), + } + + user_message = { + "role": "user", + "content": user_prompt.format( + test_framework=test_framework, + function_name=function_name, + function_code=function_code, + module_path=module_path, + package_comment="", + ), + } + + messages = [system_message, user_message] + return messages, posthog_event_suffix + + +def parse_and_validate_js_output(response_content: str) -> str: + """ + Parse and validate the LLM response for JavaScript code. + + Args: + response_content: Raw LLM response + + Returns: + Validated JavaScript code + + Raises: + ValueError: If no valid code block found + SyntaxError: If code has syntax errors + """ + # Check for code block + if "```" not in response_content: + sentry_sdk.capture_message("LLM response did not contain a code block:\n" + response_content[:500]) + raise ValueError("LLM response did not contain a code block.") + + pattern_res = JS_PATTERN.search(response_content) + if not pattern_res: + raise ValueError("No JavaScript code block found in the LLM response.") + + code = pattern_res.group(1).strip() + + # Validate syntax + is_valid, error = validate_javascript_syntax(code) + if not is_valid: + raise SyntaxError(f"Invalid JavaScript code: {error}") + + # Check for test functions + if not _has_test_functions(code): + raise ValueError("Generated code does not contain any test functions.") + + return code + + +def _has_test_functions(code: str) -> bool: + """Check if the code contains Jest test functions.""" + # Look for test() or it() calls + test_pattern = r"(?:test|it)\s*\(\s*['\"]" + return bool(re.search(test_pattern, code)) + + +@stamina.retry(on=(SyntaxError, ValueError, OpenAIError), attempts=2) +async def generate_and_validate_js_test_code( + messages: list[dict[str, str]], + model: LLM, + cost_tracker: list[float], + user_id: str, + posthog_event_suffix: str, + trace_id: str = "", + call_sequence: int | None = None, +) -> str: + """ + Generate and validate JavaScript test code using LLM. + + Args: + messages: Prompt messages + model: LLM model to use + cost_tracker: List to track costs + user_id: User ID + posthog_event_suffix: Suffix for PostHog events + trace_id: Trace ID for logging + call_sequence: Call sequence number + + Returns: + Validated JavaScript test code + + Raises: + SyntaxError: If code is invalid + ValueError: If no valid code found + """ + obs_context: dict | None = {"call_sequence": call_sequence} if call_sequence is not None else None + + response = await call_llm( + llm=model, + messages=messages, + call_type="test_generation", + trace_id=trace_id, + user_id=user_id, + python_version="javascript", # Reusing field for language + context=obs_context, + ) + + cost = calculate_llm_cost(response.raw_response, model) + cost_tracker.append(cost) + + debug_log_sensitive_data( + f"JavaScript {posthog_event_suffix}execute response:\n{response.raw_response.model_dump_json(indent=2)}" + ) + + if response.raw_response.usage: + ph( + user_id, + f"aiservice-testgen-js-{posthog_event_suffix}execute-openai-usage", + properties={"model": model.name, "usage": response.raw_response.usage.model_dump_json()}, + ) + + # Parse and validate + validated_code = parse_and_validate_js_output(response.content) + return validated_code + + +@stamina.retry(on=TestGenerationFailedError, attempts=2) +async def generate_javascript_tests_from_function( + user_id: str, + function_name: str, + function_code: str, + module_path: str, + test_framework: str = "jest", + execute_model: LLM = EXECUTE_MODEL, + is_async: bool = False, + trace_id: str = "", + call_sequence: int | None = None, +) -> tuple[str, str, str]: + """ + Generate JavaScript tests for a function. + + Args: + user_id: User ID + function_name: Name of function to test + function_code: Source code of function + module_path: Import path for module + test_framework: Testing framework (jest, mocha) + execute_model: LLM model to use + is_async: Whether function is async + trace_id: Trace ID for logging + call_sequence: Call sequence number + + Returns: + Tuple of (generated_tests, instrumented_behavior_tests, instrumented_perf_tests) + + Raises: + TestGenerationFailedError: If test generation fails + """ + messages, posthog_event_suffix = build_javascript_prompt( + function_name=function_name, + function_code=function_code, + module_path=module_path, + test_framework=test_framework, + is_async=is_async, + ) + + cost_tracker = [] + + try: + validated_code = await generate_and_validate_js_test_code( + messages=messages, + model=execute_model, + cost_tracker=cost_tracker, + user_id=user_id, + posthog_event_suffix=posthog_event_suffix, + trace_id=trace_id, + call_sequence=call_sequence, + ) + + total_llm_cost = sum(cost_tracker) + await update_optimization_cost(trace_id=trace_id, cost=total_llm_cost, user_id=user_id) + + # Apply UNIFIED instrumentation (same for behavior and perf) + instrumented_tests = instrument_javascript_tests( + test_source=validated_code, + function_name=function_name, + module_path=module_path, + ) + + # For JavaScript, behavior and perf tests use the same instrumentation + # The difference is in how they're run (environment variables) + return validated_code, instrumented_tests, instrumented_tests + + except (SyntaxError, ValueError) as e: + total_llm_cost = sum(cost_tracker) + await update_optimization_cost(trace_id=trace_id, cost=total_llm_cost, user_id=user_id) + msg = f"Failed to generate valid JavaScript test code after {len(cost_tracker)} tries. trace_id={trace_id}" + logging.error(msg) + raise TestGenerationFailedError(msg) from e + + +def validate_javascript_testgen_request_data(data: TestGenSchema) -> None: + """ + Validate JavaScript test generation request data. + + Args: + data: Request data + + Raises: + HttpError: If validation fails + """ + if data.test_framework not in ["jest", "mocha"]: + raise HttpError(400, "Invalid test framework for JavaScript. We only support jest and mocha.") + if not data.function_to_optimize: + raise HttpError(400, "Invalid function to optimize. It is empty.") + if not validate_trace_id(data.trace_id): + raise HttpError(400, "Invalid trace ID. Please provide a valid UUIDv4.") + + # Validate JavaScript syntax + is_valid, error = validate_javascript_syntax(data.source_code_being_tested) + if not is_valid: + raise HttpError(400, f"Invalid source code. It is not valid JavaScript: {error}") + + +async def testgen_javascript( + request: AuthenticatedRequest, data: TestGenSchema +) -> tuple[int, TestGenResponseSchema | TestGenErrorResponseSchema]: + """ + Main endpoint handler for JavaScript test generation. + + Args: + request: Authenticated request + data: Test generation request data + + Returns: + Tuple of (status_code, response) + """ + language = data.language + ph(request.user, "aiservice-testgen-called", properties={"language": language}) + + try: + validate_javascript_testgen_request_data(data) + except HttpError as e: + e.add_note(f"JavaScript testgen request validation error: {e.status_code} {e.message}") + sentry_sdk.capture_exception(e) + return e.status_code, TestGenErrorResponseSchema(error=e.message) + + logging.info("/testgen: Generating JavaScript tests...") + + try: + debug_log_sensitive_data(f"Generating JavaScript tests for function {data.function_to_optimize.function_name}") + + # Using different LLMs for different test_index values + test_index = data.test_index if data.test_index is not None else 0 + if test_index % 2 == 0: + execute_model = OPENAI_MODEL + model_source = "OpenAI" + else: + execute_model = HAIKU_MODEL + model_source = "Anthropic" + + logging.info( + f"Using {model_source} model ({execute_model.name}) for JavaScript test_index {test_index}" + ) + + ( + generated_test_source, + instrumented_behavior_tests, + instrumented_perf_tests, + ) = await generate_javascript_tests_from_function( + user_id=request.user, + function_name=data.function_to_optimize.qualified_name, + function_code=data.source_code_being_tested, + module_path=data.module_path, + test_framework=data.test_framework, + is_async=data.is_async or False, + trace_id=data.trace_id, + call_sequence=data.call_sequence, + execute_model=execute_model, + ) + + ph(request.user, "aiservice-testgen-tests-generated", properties={"language": language}) + + if hasattr(request, "should_log_features") and request.should_log_features: + await log_features( + trace_id=data.trace_id, + user_id=request.user, + generated_tests=[generated_test_source], + instrumented_generated_tests=[instrumented_behavior_tests], + test_framework=data.test_framework, + metadata={ + "test_timeout": data.test_timeout, + "function_to_optimize": data.function_to_optimize.function_name, + "language": language, + }, + ) + + return 200, TestGenResponseSchema( + generated_tests=generated_test_source, + instrumented_behavior_tests=instrumented_behavior_tests, + instrumented_perf_tests=instrumented_perf_tests, + ) + + except Exception as e: + logging.exception(f"JavaScript test generation failed. trace_id={data.trace_id}") + sentry_sdk.capture_exception(e) + return 500, TestGenErrorResponseSchema(error="Error generating JavaScript tests. Internal server error.") diff --git a/django/aiservice/tests/optimizer/test_javascript_api.py b/django/aiservice/tests/optimizer/test_javascript_api.py new file mode 100644 index 000000000..df978888b --- /dev/null +++ b/django/aiservice/tests/optimizer/test_javascript_api.py @@ -0,0 +1,366 @@ +""" +Integration tests for JavaScript optimization API endpoints. + +These tests call the actual API endpoints to verify end-to-end functionality. + +NOTE: These tests require authentication mocking which is complex due to Django +middleware being instantiated at startup. The tests are marked to skip by default. +Run with: pytest -m integration tests/optimizer/test_javascript_api.py + +For actual API testing, use curl or httpie against a running dev server with a valid +API key. +""" + +import json +import uuid +from unittest.mock import patch + +import pytest +from django.test import AsyncClient + + +# Mark all tests in this module as integration tests that skip by default +pytestmark = [ + pytest.mark.integration, + pytest.mark.skip(reason="Integration tests require running server - run with -m integration --runintegration"), +] + + +@pytest.fixture +def api_client(): + """Create an async test client.""" + return AsyncClient() + + +@pytest.fixture +def valid_trace_id(): + """Generate a valid UUIDv4 trace ID.""" + return str(uuid.uuid4()) + + +@pytest.fixture +def mock_auth(settings): + """Mock authentication by patching the AuthBearer class method. + + Note: This mock is applied but Django middleware is instantiated at startup, + so the mock may not take effect unless the server is restarted after patching. + """ + from authapp.auth import AuthBearer + + # Store original authenticate method + original_authenticate = AuthBearer.authenticate + + async def fake_authenticate(self, request, token): + request.user = "test-user-123" + request.tier = "pro" + request.api_key_id = 1 + request.organization_id = "test-org" + request.should_log_features = False + return token + + # Create a mock subscription + class FakeSubscription: + subscription_status = "active" + optimizations_used = 0 + optimizations_limit = 1000 + total_lifetime_optimizations = 0 + plan_type = "pro" + + async def asave(self, *args, **kwargs): + return None + + class FakeFilter: + async def afirst(self): + return FakeSubscription() + + async def aupdate(self, **kwargs): + return 1 + + # Patch the method on the class (affects all instances) + AuthBearer.authenticate = fake_authenticate + + with patch( + "aiservice.middleware.track_usage_middleware.Subscriptions.objects.filter", + return_value=FakeFilter() + ): + yield + + # Restore original method + AuthBearer.authenticate = original_authenticate + + +@pytest.fixture +def auth_headers(): + """Headers with authentication token.""" + return {"HTTP_AUTHORIZATION": "Bearer test-token-123"} + + +class TestOptimizeJavaScriptRouting: + """Test that JavaScript optimization requests are properly routed.""" + + @pytest.mark.asyncio + @pytest.mark.django_db + async def test_javascript_language_routes_correctly(self, api_client, valid_trace_id, mock_auth, auth_headers): + """Test that language=javascript routes to JavaScript optimizer.""" + response = await api_client.post( + "/ai/optimize/", + data=json.dumps({ + "source_code": "function add(a, b) { return a + b; }", + "dependency_code": None, + "trace_id": valid_trace_id, + "language": "javascript", + "language_version": "ES2022", + "n_candidates": 1, + }), + content_type="application/json", + **auth_headers, + ) + + # The request should be processed (may fail due to LLM mocking, + # but should not fail due to routing) + assert response.status_code in [200, 400, 500] + + # If it fails, check that it's not a "not implemented" error + if response.status_code != 200: + data = response.json() + assert "not yet implemented" not in data.get("error", "").lower() + + @pytest.mark.asyncio + @pytest.mark.django_db + async def test_typescript_language_routes_correctly(self, api_client, valid_trace_id, mock_auth, auth_headers): + """Test that language=typescript routes to JavaScript optimizer.""" + response = await api_client.post( + "/ai/optimize/", + data=json.dumps({ + "source_code": "function add(a: number, b: number): number { return a + b; }", + "dependency_code": None, + "trace_id": valid_trace_id, + "language": "typescript", + "language_version": "ES2022", + "n_candidates": 1, + }), + content_type="application/json", + **auth_headers, + ) + + assert response.status_code in [200, 400, 500] + + if response.status_code != 200: + data = response.json() + assert "not yet implemented" not in data.get("error", "").lower() + + @pytest.mark.asyncio + @pytest.mark.django_db + async def test_python_still_works(self, api_client, valid_trace_id, mock_auth, auth_headers): + """Test that Python optimization still works (backward compatibility).""" + response = await api_client.post( + "/ai/optimize/", + data=json.dumps({ + "source_code": "def add(a, b): return a + b", + "dependency_code": None, + "trace_id": valid_trace_id, + "language": "python", + "python_version": "3.11", + "n_candidates": 1, + }), + content_type="application/json", + **auth_headers, + ) + + assert response.status_code in [200, 400, 500] + + @pytest.mark.asyncio + @pytest.mark.django_db + async def test_default_language_is_python(self, api_client, valid_trace_id, mock_auth, auth_headers): + """Test that omitting language defaults to Python.""" + response = await api_client.post( + "/ai/optimize/", + data=json.dumps({ + "source_code": "def add(a, b): return a + b", + "dependency_code": None, + "trace_id": valid_trace_id, + "python_version": "3.11", + "n_candidates": 1, + }), + content_type="application/json", + **auth_headers, + ) + + # Should work as Python (the default) + assert response.status_code in [200, 400, 500] + + +class TestOptimizeJavaScriptValidation: + """Test JavaScript-specific validation in the API.""" + + @pytest.mark.asyncio + @pytest.mark.django_db + async def test_invalid_javascript_syntax_rejected(self, api_client, valid_trace_id, mock_auth, auth_headers): + """Test that invalid JavaScript syntax is rejected.""" + response = await api_client.post( + "/ai/optimize/", + data=json.dumps({ + "source_code": "function broken( { return; }", # Invalid syntax + "dependency_code": None, + "trace_id": valid_trace_id, + "language": "javascript", + "n_candidates": 1, + }), + content_type="application/json", + **auth_headers, + ) + + assert response.status_code == 400 + data = response.json() + assert "error" in data + + @pytest.mark.asyncio + @pytest.mark.django_db + async def test_empty_source_code_rejected(self, api_client, valid_trace_id, mock_auth, auth_headers): + """Test that empty source code is rejected.""" + response = await api_client.post( + "/ai/optimize/", + data=json.dumps({ + "source_code": "", + "dependency_code": None, + "trace_id": valid_trace_id, + "language": "javascript", + "n_candidates": 1, + }), + content_type="application/json", + **auth_headers, + ) + + assert response.status_code == 400 + + @pytest.mark.asyncio + @pytest.mark.django_db + async def test_invalid_trace_id_rejected(self, api_client, mock_auth, auth_headers): + """Test that invalid trace ID is rejected.""" + response = await api_client.post( + "/ai/optimize/", + data=json.dumps({ + "source_code": "function add(a, b) { return a + b; }", + "dependency_code": None, + "trace_id": "not-a-valid-uuid", + "language": "javascript", + "n_candidates": 1, + }), + content_type="application/json", + **auth_headers, + ) + + assert response.status_code == 400 + data = response.json() + assert "trace" in data.get("error", "").lower() or "uuid" in data.get("error", "").lower() + + +class TestTestGenJavaScriptRouting: + """Test that JavaScript test generation requests are properly routed.""" + + @pytest.mark.asyncio + @pytest.mark.django_db + async def test_javascript_testgen_routes_correctly(self, api_client, valid_trace_id, mock_auth, auth_headers): + """Test that language=javascript routes to JavaScript testgen.""" + response = await api_client.post( + "/ai/testgen/", + data=json.dumps({ + "source_code_being_tested": "function add(a, b) { return a + b; }", + "function_to_optimize": { + "function_name": "add", + "file_path": "/test.js", + "parents": [], + "starting_line": 1, + "ending_line": 1, + }, + "module_path": "./math", + "test_module_path": "./math.test", + "test_framework": "jest", + "test_timeout": 30, + "trace_id": valid_trace_id, + "language": "javascript", + }), + content_type="application/json", + **auth_headers, + ) + + assert response.status_code in [200, 400, 500] + + if response.status_code != 200: + data = response.json() + assert "not yet implemented" not in data.get("error", "").lower() + + @pytest.mark.asyncio + @pytest.mark.django_db + async def test_invalid_test_framework_rejected(self, api_client, valid_trace_id, mock_auth, auth_headers): + """Test that invalid test framework is rejected for JavaScript.""" + response = await api_client.post( + "/ai/testgen/", + data=json.dumps({ + "source_code_being_tested": "function add(a, b) { return a + b; }", + "function_to_optimize": { + "function_name": "add", + "file_path": "/test.js", + "parents": [], + "starting_line": 1, + "ending_line": 1, + }, + "module_path": "./math", + "test_module_path": "./math.test", + "test_framework": "pytest", # Wrong framework for JS + "test_timeout": 30, + "trace_id": valid_trace_id, + "language": "javascript", + }), + content_type="application/json", + **auth_headers, + ) + + assert response.status_code == 400 + data = response.json() + assert "framework" in data.get("error", "").lower() + + +class TestSchemaValidation: + """Test that API schema validation works correctly.""" + + @pytest.mark.asyncio + @pytest.mark.django_db + async def test_language_field_accepted(self, api_client, valid_trace_id, mock_auth, auth_headers): + """Test that the language field is accepted in the API.""" + response = await api_client.post( + "/ai/optimize/", + data=json.dumps({ + "source_code": "const x = 1;", + "dependency_code": None, + "trace_id": valid_trace_id, + "language": "javascript", + "language_version": "ES2022", + "n_candidates": 0, # 0 candidates to avoid LLM call + }), + content_type="application/json", + **auth_headers, + ) + + # Should not fail schema validation (may fail elsewhere) + assert response.status_code != 422 # 422 = schema validation error + + @pytest.mark.asyncio + @pytest.mark.django_db + async def test_language_version_field_accepted(self, api_client, valid_trace_id, mock_auth, auth_headers): + """Test that the language_version field is accepted in the API.""" + response = await api_client.post( + "/ai/optimize/", + data=json.dumps({ + "source_code": "const x = 1;", + "dependency_code": None, + "trace_id": valid_trace_id, + "language": "javascript", + "language_version": "ES2020", + "n_candidates": 0, + }), + content_type="application/json", + **auth_headers, + ) + + assert response.status_code != 422 diff --git a/django/aiservice/tests/optimizer/test_javascript_prompts.py b/django/aiservice/tests/optimizer/test_javascript_prompts.py new file mode 100644 index 000000000..7e5e746fe --- /dev/null +++ b/django/aiservice/tests/optimizer/test_javascript_prompts.py @@ -0,0 +1,122 @@ +"""Tests for JavaScript prompt loader.""" + +import pytest + +from optimizer.prompts import get_available_languages, get_system_prompt, get_user_prompt + + +class TestPromptLoader: + """Tests for the prompt loader module.""" + + def test_get_javascript_system_prompt(self) -> None: + """Test loading JavaScript system prompt.""" + prompt = get_system_prompt("javascript", is_async=False) + + assert isinstance(prompt, str) + assert len(prompt) > 0 + assert "JavaScript" in prompt or "javascript" in prompt.lower() + assert "{language_version}" in prompt # Should have placeholder + assert "Behavioral Preservation" in prompt + assert "Optimization" in prompt + + def test_get_javascript_async_system_prompt(self) -> None: + """Test loading JavaScript async system prompt.""" + prompt = get_system_prompt("javascript", is_async=True) + + assert isinstance(prompt, str) + assert len(prompt) > 0 + assert "async" in prompt.lower() + assert "await" in prompt.lower() + assert "Promise" in prompt + + def test_get_javascript_user_prompt(self) -> None: + """Test loading JavaScript user prompt.""" + prompt = get_user_prompt("javascript", is_async=False) + + assert isinstance(prompt, str) + assert len(prompt) > 0 + assert "{source_code}" in prompt # Should have placeholder + + def test_get_javascript_async_user_prompt(self) -> None: + """Test loading JavaScript async user prompt.""" + prompt = get_user_prompt("javascript", is_async=True) + + assert isinstance(prompt, str) + assert len(prompt) > 0 + assert "async" in prompt.lower() + + def test_typescript_uses_javascript_prompts(self) -> None: + """Test that TypeScript uses the same prompts as JavaScript.""" + js_prompt = get_system_prompt("javascript", is_async=False) + ts_prompt = get_system_prompt("typescript", is_async=False) + + assert js_prompt == ts_prompt + + def test_invalid_language_raises_error(self) -> None: + """Test that invalid language raises ValueError.""" + with pytest.raises(ValueError) as exc_info: + get_system_prompt("rust", is_async=False) + + assert "rust" in str(exc_info.value).lower() + + def test_get_available_languages(self) -> None: + """Test getting list of available languages.""" + languages = get_available_languages() + + assert isinstance(languages, list) + assert "javascript" in languages + assert "python" in languages + + def test_python_prompts_still_exist(self) -> None: + """Test that Python prompts still work after adding JavaScript.""" + prompt = get_system_prompt("python", is_async=False) + + assert isinstance(prompt, str) + assert len(prompt) > 0 + # Python prompts should reference Python-specific things + assert "Python" in prompt or "python" in prompt.lower() + + def test_python_async_prompts_exist(self) -> None: + """Test that Python async prompts still work.""" + prompt = get_system_prompt("python", is_async=True) + + assert isinstance(prompt, str) + assert "async" in prompt.lower() + + +class TestPromptContent: + """Tests for specific content in the prompts.""" + + def test_javascript_prompt_has_v8_optimization_hints(self) -> None: + """Test that JavaScript prompt includes V8 optimization guidance.""" + prompt = get_system_prompt("javascript", is_async=False) + + # Should mention V8-specific optimizations + assert "V8" in prompt or "TypedArray" in prompt or "Map/Set" in prompt + + def test_javascript_prompt_has_response_format(self) -> None: + """Test that JavaScript prompt specifies response format.""" + prompt = get_system_prompt("javascript", is_async=False) + + assert "Response Format" in prompt or "code block" in prompt.lower() + assert "```javascript" in prompt or "```js" in prompt.lower() + + def test_javascript_prompt_preserves_behavior(self) -> None: + """Test that JavaScript prompt emphasizes behavioral preservation.""" + prompt = get_system_prompt("javascript", is_async=False) + + assert "Behavioral Preservation" in prompt or "behavior" in prompt.lower() + assert "MUST NOT change" in prompt or "must remain" in prompt.lower() + + def test_async_prompt_mentions_promise_all(self) -> None: + """Test that async prompt mentions Promise.all for concurrency.""" + prompt = get_system_prompt("javascript", is_async=True) + + assert "Promise.all" in prompt + + def test_async_prompt_warns_about_sequential_awaits(self) -> None: + """Test that async prompt addresses sequential vs parallel awaits.""" + prompt = get_system_prompt("javascript", is_async=True) + + # Should mention concurrent execution patterns + assert "concurrent" in prompt.lower() or "parallel" in prompt.lower() diff --git a/django/aiservice/tests/optimizer/test_javascript_schema.py b/django/aiservice/tests/optimizer/test_javascript_schema.py new file mode 100644 index 000000000..37a991e3d --- /dev/null +++ b/django/aiservice/tests/optimizer/test_javascript_schema.py @@ -0,0 +1,90 @@ +"""Tests for JavaScript-related schema changes.""" + +import pytest + +from optimizer.models import OptimizeSchema + +# Note: TestGenSchema tests are in a separate file due to import dependencies + + +class TestOptimizeSchemaLanguageField: + """Tests for language field in OptimizeSchema.""" + + def test_default_language_is_python(self) -> None: + """Test that the default language is Python.""" + schema = OptimizeSchema( + source_code="def add(a, b): return a + b", + dependency_code=None, + trace_id="00000000-0000-0000-0000-000000000001", + ) + + assert schema.language == "python" + + def test_can_set_javascript_language(self) -> None: + """Test that language can be set to JavaScript.""" + schema = OptimizeSchema( + source_code="function add(a, b) { return a + b; }", + dependency_code=None, + trace_id="00000000-0000-0000-0000-000000000001", + language="javascript", + ) + + assert schema.language == "javascript" + + def test_can_set_typescript_language(self) -> None: + """Test that language can be set to TypeScript.""" + schema = OptimizeSchema( + source_code="function add(a: number, b: number): number { return a + b; }", + dependency_code=None, + trace_id="00000000-0000-0000-0000-000000000001", + language="typescript", + ) + + assert schema.language == "typescript" + + def test_language_version_is_optional(self) -> None: + """Test that language_version is optional.""" + schema = OptimizeSchema( + source_code="function add(a, b) { return a + b; }", + dependency_code=None, + trace_id="00000000-0000-0000-0000-000000000001", + language="javascript", + ) + + assert schema.language_version is None + + def test_can_set_language_version(self) -> None: + """Test that language_version can be set.""" + schema = OptimizeSchema( + source_code="function add(a, b) { return a + b; }", + dependency_code=None, + trace_id="00000000-0000-0000-0000-000000000001", + language="javascript", + language_version="ES2022", + ) + + assert schema.language_version == "ES2022" + + def test_python_version_still_works(self) -> None: + """Test that python_version field still works for backward compatibility.""" + schema = OptimizeSchema( + source_code="def add(a, b): return a + b", + dependency_code=None, + trace_id="00000000-0000-0000-0000-000000000001", + python_version="3.11", + ) + + assert schema.python_version == "3.11" + assert schema.language == "python" # Default + + def test_python_version_is_now_optional(self) -> None: + """Test that python_version is now optional.""" + schema = OptimizeSchema( + source_code="function add(a, b) { return a + b; }", + dependency_code=None, + trace_id="00000000-0000-0000-0000-000000000001", + language="javascript", + ) + + # python_version should be None for JavaScript + assert schema.python_version is None diff --git a/django/aiservice/tests/optimizer/test_javascript_validator.py b/django/aiservice/tests/optimizer/test_javascript_validator.py new file mode 100644 index 000000000..c2a3f75c5 --- /dev/null +++ b/django/aiservice/tests/optimizer/test_javascript_validator.py @@ -0,0 +1,231 @@ +"""Tests for JavaScript syntax validation.""" + +import pytest + +from aiservice.validators.javascript_validator import ( + _fallback_validation, + validate_javascript_syntax, + validate_typescript_syntax, +) + + +class TestJavaScriptValidatorFallback: + """Tests for the fallback validation (when Node.js is not available).""" + + def test_valid_simple_function(self) -> None: + """Test that a simple valid function passes validation.""" + code = """ +function add(a, b) { + return a + b; +} +""" + is_valid, error = _fallback_validation(code) + assert is_valid is True + assert error is None + + def test_valid_arrow_function(self) -> None: + """Test that arrow functions pass validation.""" + code = "const add = (a, b) => a + b;" + is_valid, error = _fallback_validation(code) + assert is_valid is True + assert error is None + + def test_valid_class(self) -> None: + """Test that a class definition passes validation.""" + code = """ +class Calculator { + constructor() { + this.result = 0; + } + + add(value) { + this.result += value; + return this; + } +} +""" + is_valid, error = _fallback_validation(code) + assert is_valid is True + assert error is None + + def test_valid_async_function(self) -> None: + """Test that async functions pass validation.""" + code = """ +async function fetchData(url) { + const response = await fetch(url); + return response.json(); +} +""" + is_valid, error = _fallback_validation(code) + assert is_valid is True + assert error is None + + def test_valid_template_literal(self) -> None: + """Test that template literals pass validation.""" + code = """ +const greeting = `Hello, ${name}!`; +const multiline = ` + This is a + multiline string +`; +""" + is_valid, error = _fallback_validation(code) + assert is_valid is True + assert error is None + + def test_unclosed_brace(self) -> None: + """Test that unclosed braces are detected.""" + code = """ +function broken() { + return true; +""" + is_valid, error = _fallback_validation(code) + assert is_valid is False + assert error is not None + assert "Unclosed" in error or "bracket" in error.lower() + + def test_unclosed_parenthesis(self) -> None: + """Test that unclosed parentheses are detected.""" + code = "const result = add(1, 2" + is_valid, error = _fallback_validation(code) + assert is_valid is False + assert error is not None + + def test_unclosed_bracket(self) -> None: + """Test that unclosed brackets are detected.""" + code = "const arr = [1, 2, 3" + is_valid, error = _fallback_validation(code) + assert is_valid is False + assert error is not None + + def test_mismatched_brackets(self) -> None: + """Test that mismatched brackets are detected.""" + code = "const arr = [1, 2, 3}" + is_valid, error = _fallback_validation(code) + assert is_valid is False + assert error is not None + assert "Mismatched" in error or "Unexpected" in error + + def test_string_with_brackets_ignored(self) -> None: + """Test that brackets inside strings are ignored.""" + code = """ +const str = "This string has { and } and [ and ]"; +const obj = { valid: true }; +""" + is_valid, error = _fallback_validation(code) + assert is_valid is True + assert error is None + + def test_empty_code(self) -> None: + """Test that empty code passes validation.""" + is_valid, error = _fallback_validation("") + assert is_valid is True + assert error is None + + def test_comments_only(self) -> None: + """Test that code with only comments passes validation.""" + code = """ +// This is a comment +/* This is a + multiline comment */ +""" + is_valid, error = _fallback_validation(code) + assert is_valid is True + assert error is None + + def test_nested_structures(self) -> None: + """Test that deeply nested structures pass validation.""" + code = """ +const nested = { + level1: { + level2: { + level3: [ + { deep: true } + ] + } + } +}; +""" + is_valid, error = _fallback_validation(code) + assert is_valid is True + assert error is None + + +class TestJavaScriptValidatorMain: + """Tests for the main validation function.""" + + def test_valid_module_exports(self) -> None: + """Test that module.exports syntax passes validation.""" + code = """ +function fibonacci(n) { + if (n <= 1) return n; + return fibonacci(n - 1) + fibonacci(n - 2); +} + +module.exports = { fibonacci }; +""" + is_valid, error = validate_javascript_syntax(code) + # This may pass with fallback even if Node.js isn't available + # The point is it shouldn't crash + assert isinstance(is_valid, bool) + + def test_valid_es6_imports(self) -> None: + """Test that ES6 import syntax passes validation.""" + code = """ +import { useState, useEffect } from 'react'; + +export function Counter() { + const [count, setCount] = useState(0); + return count; +} +""" + is_valid, error = validate_javascript_syntax(code) + assert isinstance(is_valid, bool) + + def test_destructuring(self) -> None: + """Test that destructuring passes validation.""" + code = """ +const { a, b } = obj; +const [first, second, ...rest] = arr; +""" + is_valid, error = validate_javascript_syntax(code) + assert isinstance(is_valid, bool) + + def test_spread_operator(self) -> None: + """Test that spread operator passes validation.""" + code = """ +const merged = { ...obj1, ...obj2 }; +const combined = [...arr1, ...arr2]; +""" + is_valid, error = validate_javascript_syntax(code) + assert isinstance(is_valid, bool) + + +class TestTypeScriptValidator: + """Tests for TypeScript validation.""" + + def test_typescript_types(self) -> None: + """Test that TypeScript type annotations pass validation.""" + code = """ +function add(a: number, b: number): number { + return a + b; +} +""" + is_valid, error = validate_typescript_syntax(code) + # TypeScript uses the same validator as JavaScript + assert isinstance(is_valid, bool) + + def test_typescript_interface(self) -> None: + """Test that TypeScript interfaces pass validation (if Node available).""" + code = """ +interface User { + name: string; + age: number; +} + +function greet(user: User): string { + return `Hello, ${user.name}`; +} +""" + is_valid, error = validate_typescript_syntax(code) + assert isinstance(is_valid, bool) diff --git a/django/aiservice/tests/optimizer/test_optimizer_javascript.py b/django/aiservice/tests/optimizer/test_optimizer_javascript.py new file mode 100644 index 000000000..a6d28db18 --- /dev/null +++ b/django/aiservice/tests/optimizer/test_optimizer_javascript.py @@ -0,0 +1,264 @@ +"""Tests for JavaScript optimizer module. + +Tests the code extraction and normalization functions without importing +the full optimizer module (to avoid LLM dependencies in tests). +""" + +import re + +import pytest + + +# Pattern to extract code blocks from LLM response (copied from optimizer_javascript.py) +JS_CODE_PATTERN = re.compile( + r"```(?:javascript|js|typescript|ts)(?::[^\n]*)?\s*\n(.*?)```", + re.MULTILINE | re.DOTALL, +) + + +def extract_code_and_explanation(content: str) -> tuple[str, str]: + """Extract code and explanation from LLM response.""" + match = JS_CODE_PATTERN.search(content) + if match: + code = match.group(1).strip() + explanation_end = match.start() + explanation = content[:explanation_end].strip() + return code, explanation + return "", content + + +def _normalize_code(code: str) -> str: + """Normalize code for comparison.""" + # Remove single-line comments + code = re.sub(r"//.*$", "", code, flags=re.MULTILINE) + # Remove multi-line comments + code = re.sub(r"/\*.*?\*/", "", code, flags=re.DOTALL) + # Normalize whitespace + code = " ".join(code.split()) + return code + + +class TestExtractCodeAndExplanation: + """Tests for extracting code and explanation from LLM responses.""" + + def test_extract_javascript_code_block(self) -> None: + """Test extracting code from a JavaScript code block.""" + response = """**Optimization Explanation:** +I replaced the O(n²) nested loop with a more efficient Map-based lookup. + +```javascript +function findDuplicates(arr) { + const seen = new Map(); + const duplicates = []; + for (const item of arr) { + if (seen.has(item)) { + duplicates.push(item); + } + seen.set(item, true); + } + return duplicates; +} +``` +""" + code, explanation = extract_code_and_explanation(response) + + assert "function findDuplicates" in code + assert "new Map()" in code + assert "O(n²)" in explanation or "Map-based" in explanation + + def test_extract_js_code_block(self) -> None: + """Test extracting code from a ```js code block.""" + response = """Here's the optimized version: + +```js +const add = (a, b) => a + b; +``` +""" + code, explanation = extract_code_and_explanation(response) + + assert "const add" in code + assert "=>" in code + + def test_extract_typescript_code_block(self) -> None: + """Test extracting code from a TypeScript code block.""" + response = """Optimized with types: + +```typescript +function add(a: number, b: number): number { + return a + b; +} +``` +""" + code, explanation = extract_code_and_explanation(response) + + assert "function add" in code + assert ": number" in code + + def test_extract_ts_code_block(self) -> None: + """Test extracting code from a ```ts code block.""" + response = """```ts +const multiply = (a: number, b: number): number => a * b; +```""" + code, explanation = extract_code_and_explanation(response) + + assert "multiply" in code + assert ": number" in code + + def test_extract_with_filename(self) -> None: + """Test extracting code from a code block with filename.""" + response = """Here's the optimized code: + +```javascript:utils.js +export function fibonacci(n) { + if (n <= 1) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} +``` +""" + code, explanation = extract_code_and_explanation(response) + + assert "function fibonacci" in code + assert "export" in code + + def test_no_code_block_returns_empty(self) -> None: + """Test that missing code block returns empty code.""" + response = "This response has no code block, just explanation." + + code, explanation = extract_code_and_explanation(response) + + assert code == "" + assert len(explanation) > 0 + + def test_multiple_code_blocks_takes_first(self) -> None: + """Test that only the first code block is extracted.""" + response = """First version: + +```javascript +function first() { return 1; } +``` + +Alternative version: + +```javascript +function second() { return 2; } +``` +""" + code, explanation = extract_code_and_explanation(response) + + assert "first" in code + assert "second" not in code + + +class TestNormalizeCode: + """Tests for code normalization for comparison.""" + + def test_normalize_removes_single_line_comments(self) -> None: + """Test that single-line comments are removed.""" + code = """ +function add(a, b) { + // This is a comment + return a + b; // inline comment +} +""" + normalized = _normalize_code(code) + + assert "//" not in normalized + assert "This is a comment" not in normalized + assert "inline comment" not in normalized + + def test_normalize_removes_multiline_comments(self) -> None: + """Test that multi-line comments are removed.""" + code = """ +/* This is a + multi-line comment */ +function add(a, b) { + return a + b; +} +""" + normalized = _normalize_code(code) + + assert "/*" not in normalized + assert "*/" not in normalized + assert "multi-line" not in normalized + + def test_normalize_whitespace(self) -> None: + """Test that whitespace is normalized.""" + code1 = """ +function add(a, b) { + return a + b; +} +""" + code2 = "function add(a, b) { return a + b; }" + + assert _normalize_code(code1) == _normalize_code(code2) + + def test_identical_code_normalizes_same(self) -> None: + """Test that identical code normalizes to the same string.""" + code1 = "function add(a, b) { return a + b; }" + code2 = "function add(a, b) { return a + b; }" + + assert _normalize_code(code1) == _normalize_code(code2) + + def test_different_code_normalizes_different(self) -> None: + """Test that different code normalizes to different strings.""" + code1 = "function add(a, b) { return a + b; }" + code2 = "function subtract(a, b) { return a - b; }" + + assert _normalize_code(code1) != _normalize_code(code2) + + def test_normalize_preserves_string_contents(self) -> None: + """Test that string contents are preserved.""" + code = 'const msg = "Hello // not a comment";' + normalized = _normalize_code(code) + + # The string content should be preserved + # (though this is a simplified test - real implementation + # might handle this differently) + assert "Hello" in normalized + + def test_normalize_empty_code(self) -> None: + """Test that empty code normalizes to empty string.""" + assert _normalize_code("") == "" + assert _normalize_code(" ") == "" + assert _normalize_code("\n\n\n") == "" + + +class TestCodeDeduplication: + """Tests for code deduplication logic.""" + + def test_same_code_different_comments_equal(self) -> None: + """Test that same code with different comments is considered equal.""" + code1 = """ +// Version 1 +function add(a, b) { + return a + b; +} +""" + code2 = """ +// Version 2 - optimized +function add(a, b) { + return a + b; // sum +} +""" + assert _normalize_code(code1) == _normalize_code(code2) + + def test_same_code_different_whitespace_equal(self) -> None: + """Test that same code with different whitespace is considered equal.""" + code1 = "function add(a, b) { return a + b; }" + code2 = """ +function add(a, b) { + return a + b; +} +""" + assert _normalize_code(code1) == _normalize_code(code2) + + def test_semantically_different_code_not_equal(self) -> None: + """Test that semantically different code is not equal.""" + code1 = "function add(a, b) { return a + b; }" + code2 = "function add(a, b) { return a - b; }" # Different operation + + assert _normalize_code(code1) != _normalize_code(code2) diff --git a/django/aiservice/tests/testgen/test_testgen_javascript.py b/django/aiservice/tests/testgen/test_testgen_javascript.py new file mode 100644 index 000000000..f41314c54 --- /dev/null +++ b/django/aiservice/tests/testgen/test_testgen_javascript.py @@ -0,0 +1,294 @@ +"""Tests for JavaScript test generation module. + +Tests the prompt building and validation functions without importing +the full testgen module (to avoid LLM dependencies in tests). +""" + +import re +from pathlib import Path + +import pytest + +# Load prompts directly to avoid importing testgen_javascript.py +current_dir = Path(__file__).parent.parent.parent / "testgen" +JS_PROMPTS_DIR = current_dir / "prompts" / "javascript" + +JS_EXECUTE_SYSTEM_PROMPT = (JS_PROMPTS_DIR / "execute_system_prompt.md").read_text() +JS_EXECUTE_USER_PROMPT = (JS_PROMPTS_DIR / "execute_user_prompt.md").read_text() +JS_EXECUTE_ASYNC_SYSTEM_PROMPT = (JS_PROMPTS_DIR / "execute_async_system_prompt.md").read_text() +JS_EXECUTE_ASYNC_USER_PROMPT = (JS_PROMPTS_DIR / "execute_async_user_prompt.md").read_text() + +JS_PATTERN = re.compile(r"^```(?:javascript|js|typescript|ts)?\s*\n(.*?)\n```", re.MULTILINE | re.DOTALL) + + +def _has_test_functions(code: str) -> bool: + """Check if the code contains Jest test functions.""" + test_pattern = r"(?:test|it)\s*\(\s*['\"]" + return bool(re.search(test_pattern, code)) + + +def build_javascript_prompt( + function_name: str, + function_code: str, + module_path: str, + test_framework: str, + is_async: bool, +) -> tuple[list[dict[str, str]], str]: + """Build the prompt messages for JavaScript test generation.""" + if is_async: + system_prompt = JS_EXECUTE_ASYNC_SYSTEM_PROMPT + user_prompt = JS_EXECUTE_ASYNC_USER_PROMPT + posthog_event_suffix = "async-" + else: + system_prompt = JS_EXECUTE_SYSTEM_PROMPT + user_prompt = JS_EXECUTE_USER_PROMPT + posthog_event_suffix = "" + + system_message = { + "role": "system", + "content": system_prompt.format(function_name=function_name), + } + + user_message = { + "role": "user", + "content": user_prompt.format( + test_framework=test_framework, + function_name=function_name, + function_code=function_code, + module_path=module_path, + package_comment="", + ), + } + + messages = [system_message, user_message] + return messages, posthog_event_suffix + + +def parse_and_validate_js_output(response_content: str) -> str: + """Parse and validate the LLM response for JavaScript code.""" + if "```" not in response_content: + raise ValueError("LLM response did not contain a code block.") + + pattern_res = JS_PATTERN.search(response_content) + if not pattern_res: + raise ValueError("No JavaScript code block found in the LLM response.") + + code = pattern_res.group(1).strip() + + if not _has_test_functions(code): + raise ValueError("Generated code does not contain any test functions.") + + return code + + +class TestHasTestFunctions: + """Tests for detecting Jest test functions in code.""" + + def test_detects_test_function(self) -> None: + """Test that test() calls are detected.""" + code = """ +test('should add numbers', () => { + expect(add(1, 2)).toBe(3); +}); +""" + assert _has_test_functions(code) is True + + def test_detects_it_function(self) -> None: + """Test that it() calls are detected.""" + code = """ +it('should add numbers', () => { + expect(add(1, 2)).toBe(3); +}); +""" + assert _has_test_functions(code) is True + + def test_detects_test_in_describe(self) -> None: + """Test that tests inside describe blocks are detected.""" + code = """ +describe('Calculator', () => { + test('should add', () => { + expect(add(1, 2)).toBe(3); + }); +}); +""" + assert _has_test_functions(code) is True + + def test_no_tests_returns_false(self) -> None: + """Test that code without tests returns false.""" + code = """ +function add(a, b) { + return a + b; +} +""" + assert _has_test_functions(code) is False + + def test_empty_code_returns_false(self) -> None: + """Test that empty code returns false.""" + assert _has_test_functions("") is False + + def test_describe_only_returns_false(self) -> None: + """Test that describe without tests returns false.""" + code = """ +describe('Calculator', () => { + // No tests yet +}); +""" + assert _has_test_functions(code) is False + + +class TestParseAndValidateJsOutput: + """Tests for parsing and validating LLM output.""" + + def test_extracts_javascript_code(self) -> None: + """Test extracting code from JavaScript code block.""" + response = """Here are the tests: + +```javascript +test('should work', () => { + expect(true).toBe(true); +}); +``` +""" + code = parse_and_validate_js_output(response) + + assert "test('should work'" in code + assert "expect(true)" in code + + def test_extracts_js_code(self) -> None: + """Test extracting code from js code block.""" + response = """```js +test('basic', () => { + expect(1).toBe(1); +}); +```""" + code = parse_and_validate_js_output(response) + + assert "test('basic'" in code + + def test_raises_on_no_code_block(self) -> None: + """Test that missing code block raises ValueError.""" + response = "This response has no code block." + + with pytest.raises(ValueError) as exc_info: + parse_and_validate_js_output(response) + + assert "code block" in str(exc_info.value).lower() + + def test_raises_on_no_tests(self) -> None: + """Test that code without tests raises ValueError.""" + response = """```javascript +function add(a, b) { + return a + b; +} +```""" + + with pytest.raises(ValueError) as exc_info: + parse_and_validate_js_output(response) + + assert "test" in str(exc_info.value).lower() + + +class TestBuildJavaScriptPrompt: + """Tests for building JavaScript prompts.""" + + def test_sync_function_prompt(self) -> None: + """Test building prompt for sync function.""" + messages, suffix = build_javascript_prompt( + function_name="fibonacci", + function_code="function fibonacci(n) { return n <= 1 ? n : fibonacci(n-1) + fibonacci(n-2); }", + module_path="./fibonacci", + test_framework="jest", + is_async=False, + ) + + assert len(messages) == 2 + assert messages[0]["role"] == "system" + assert messages[1]["role"] == "user" + assert "fibonacci" in messages[0]["content"] + assert "fibonacci" in messages[1]["content"] + assert suffix == "" # Non-async should have empty suffix + + def test_async_function_prompt(self) -> None: + """Test building prompt for async function.""" + messages, suffix = build_javascript_prompt( + function_name="fetchData", + function_code="async function fetchData(url) { return await fetch(url); }", + module_path="./api", + test_framework="jest", + is_async=True, + ) + + assert len(messages) == 2 + assert "async" in messages[0]["content"].lower() + assert suffix == "async-" + + def test_prompt_includes_function_code(self) -> None: + """Test that prompt includes the function source code.""" + function_code = "function add(a, b) { return a + b; }" + messages, _ = build_javascript_prompt( + function_name="add", + function_code=function_code, + module_path="./math", + test_framework="jest", + is_async=False, + ) + + # User message should contain the function code + assert function_code in messages[1]["content"] + + def test_prompt_includes_module_path(self) -> None: + """Test that prompt includes the module path.""" + messages, _ = build_javascript_prompt( + function_name="add", + function_code="function add(a, b) { return a + b; }", + module_path="./math/utils", + test_framework="jest", + is_async=False, + ) + + assert "./math/utils" in messages[1]["content"] + + +class TestJavaScriptTestGenPromptContent: + """Tests for JavaScript test generation prompt content.""" + + def test_system_prompt_mentions_jest(self) -> None: + """Test that system prompt mentions Jest framework.""" + messages, _ = build_javascript_prompt( + function_name="test", + function_code="function test() {}", + module_path="./test", + test_framework="jest", + is_async=False, + ) + + assert "Jest" in messages[0]["content"] or "jest" in messages[0]["content"].lower() + + def test_system_prompt_has_test_categories(self) -> None: + """Test that system prompt mentions test categories.""" + messages, _ = build_javascript_prompt( + function_name="test", + function_code="function test() {}", + module_path="./test", + test_framework="jest", + is_async=False, + ) + + system_content = messages[0]["content"] + # Should mention different test categories + assert "Basic" in system_content or "basic" in system_content.lower() + assert "Edge" in system_content or "edge" in system_content.lower() + + def test_system_prompt_warns_against_mocking(self) -> None: + """Test that system prompt warns against mocking the function under test.""" + messages, _ = build_javascript_prompt( + function_name="test", + function_code="function test() {}", + module_path="./test", + test_framework="jest", + is_async=False, + ) + + system_content = messages[0]["content"] + # Should warn against mocking + assert "mock" in system_content.lower() or "Mock" in system_content diff --git a/django/aiservice/tests/testgen_instrumentation/test_instrument_javascript.py b/django/aiservice/tests/testgen_instrumentation/test_instrument_javascript.py new file mode 100644 index 000000000..9ec2853d8 --- /dev/null +++ b/django/aiservice/tests/testgen_instrumentation/test_instrument_javascript.py @@ -0,0 +1,327 @@ +"""Tests for JavaScript test instrumentation.""" + +from pathlib import Path + +import pytest + +from testgen.instrumentation.javascript.instrument_javascript import ( + get_jest_helper_path, + get_jest_setup_code, + instrument_javascript_tests, +) + + +class TestJestHelperPath: + """Tests for Jest helper path resolution.""" + + def test_helper_path_exists(self) -> None: + """Test that the Jest helper file exists.""" + helper_path = get_jest_helper_path() + + assert helper_path.exists() + assert helper_path.is_file() + assert helper_path.name == "codeflash-jest-helper.js" + + def test_helper_path_is_javascript(self) -> None: + """Test that the helper file has .js extension.""" + helper_path = get_jest_helper_path() + + assert helper_path.suffix == ".js" + + def test_helper_contains_capture_function(self) -> None: + """Test that the helper contains the capture function.""" + helper_path = get_jest_helper_path() + content = helper_path.read_text() + + assert "function capture" in content + assert "module.exports" in content + + +class TestJestSetupCode: + """Tests for Jest setup code generation.""" + + def test_generates_environment_variables(self) -> None: + """Test that setup code sets environment variables.""" + setup = get_jest_setup_code("/tmp/results.bin", "behavior", 0) + + assert "CODEFLASH_OUTPUT_FILE" in setup + assert "/tmp/results.bin" in setup + assert "CODEFLASH_MODE" in setup + assert "behavior" in setup + assert "CODEFLASH_LOOP_INDEX" in setup + + def test_performance_mode(self) -> None: + """Test setup code for performance mode.""" + setup = get_jest_setup_code("/tmp/results.bin", "performance", 5) + + assert "performance" in setup + assert "'5'" in setup or "5" in setup + + +class TestInstrumentJavaScriptTests: + """Tests for the main instrumentation function.""" + + def test_adds_helper_import(self) -> None: + """Test that the codeflash helper import is added.""" + test_source = """ +const { fibonacci } = require('./fibonacci'); + +describe('fibonacci', () => { + test('should return 0 for n=0', () => { + expect(fibonacci(0)).toBe(0); + }); +}); +""" + result = instrument_javascript_tests( + test_source=test_source, + function_name="fibonacci", + module_path="./fibonacci", + ) + + assert "codeflash-jest-helper" in result + assert "const codeflash = require" in result + + def test_does_not_duplicate_import(self) -> None: + """Test that import is not duplicated if already present.""" + test_source = """ +const codeflash = require('codeflash-jest-helper'); +const { fibonacci } = require('./fibonacci'); + +describe('fibonacci', () => { + test('should return 0 for n=0', () => { + expect(codeflash.capture('fibonacci', fibonacci, 0)).toBe(0); + }); +}); +""" + result = instrument_javascript_tests( + test_source=test_source, + function_name="fibonacci", + module_path="./fibonacci", + ) + + # Should only have one import + assert result.count("codeflash-jest-helper") == 1 + + def test_wraps_function_calls(self) -> None: + """Test that function calls are wrapped with codeflash.capture.""" + test_source = """ +const { add } = require('./math'); + +describe('add', () => { + test('should add two numbers', () => { + const result = add(1, 2); + expect(result).toBe(3); + }); +}); +""" + result = instrument_javascript_tests( + test_source=test_source, + function_name="add", + module_path="./math", + ) + + assert "codeflash.capture('add', add, 1, 2)" in result + + def test_wraps_function_without_args(self) -> None: + """Test wrapping function calls without arguments.""" + test_source = """ +const { getVersion } = require('./utils'); + +test('should return version', () => { + expect(getVersion()).toBe('1.0.0'); +}); +""" + result = instrument_javascript_tests( + test_source=test_source, + function_name="getVersion", + module_path="./utils", + ) + + assert "codeflash.capture('getVersion', getVersion)" in result + + def test_preserves_test_structure(self) -> None: + """Test that the overall test structure is preserved.""" + test_source = """ +const { sort } = require('./sort'); + +describe('sort', () => { + describe('basic cases', () => { + test('should sort empty array', () => { + expect(sort([])).toEqual([]); + }); + + test('should sort single element', () => { + expect(sort([1])).toEqual([1]); + }); + }); +}); +""" + result = instrument_javascript_tests( + test_source=test_source, + function_name="sort", + module_path="./sort", + ) + + # Test structure should be preserved + assert "describe('sort'" in result + assert "describe('basic cases'" in result + assert "test('should sort empty array'" in result + assert "test('should sort single element'" in result + + def test_handles_es6_imports(self) -> None: + """Test that ES6 imports are handled correctly.""" + test_source = """ +import { fibonacci } from './fibonacci'; + +describe('fibonacci', () => { + test('base case', () => { + expect(fibonacci(0)).toBe(0); + }); +}); +""" + result = instrument_javascript_tests( + test_source=test_source, + function_name="fibonacci", + module_path="./fibonacci", + ) + + # Helper should be added + assert "codeflash-jest-helper" in result + # Original import should be preserved + assert "import { fibonacci }" in result + + def test_does_not_wrap_method_calls(self) -> None: + """Test that method calls on objects are not wrapped.""" + test_source = """ +const { Calculator } = require('./calc'); + +test('should add', () => { + const calc = new Calculator(); + expect(calc.add(1, 2)).toBe(3); +}); +""" + result = instrument_javascript_tests( + test_source=test_source, + function_name="add", + module_path="./calc", + ) + + # Method calls should NOT be wrapped (they have a dot before them) + # Only standalone function calls should be wrapped + assert "calc.add" in result # Method call preserved + # But not wrapped (no codeflash.capture around method call) + + def test_handles_multiple_calls_same_test(self) -> None: + """Test handling multiple function calls in the same test.""" + test_source = """ +const { process } = require('./processor'); + +test('should process multiple inputs', () => { + const result1 = process('a'); + const result2 = process('b'); + const result3 = process('c'); + expect([result1, result2, result3]).toEqual(['A', 'B', 'C']); +}); +""" + result = instrument_javascript_tests( + test_source=test_source, + function_name="process", + module_path="./processor", + ) + + # All three calls should be wrapped + assert result.count("codeflash.capture('process'") == 3 + + def test_handles_async_functions(self) -> None: + """Test instrumentation of async function calls.""" + test_source = """ +const { fetchData } = require('./api'); + +test('should fetch data', async () => { + const data = await fetchData('http://example.com'); + expect(data).toBeDefined(); +}); +""" + result = instrument_javascript_tests( + test_source=test_source, + function_name="fetchData", + module_path="./api", + ) + + # Should wrap the async function call + assert "codeflash.capture('fetchData'" in result + + +class TestInstrumentationEdgeCases: + """Tests for edge cases in instrumentation.""" + + def test_function_name_in_string_not_wrapped(self) -> None: + """Test that function names in strings are not wrapped.""" + test_source = """ +const { add } = require('./math'); + +test('should call add function', () => { + console.log('Calling add function'); + expect(add(1, 2)).toBe(3); +}); +""" + result = instrument_javascript_tests( + test_source=test_source, + function_name="add", + module_path="./math", + ) + + # The string should remain unchanged + assert "'Calling add function'" in result + # But the actual call should be wrapped + assert "codeflash.capture('add', add, 1, 2)" in result + + def test_function_name_in_comment_not_wrapped(self) -> None: + """Test that function names in comments are not wrapped.""" + test_source = """ +const { multiply } = require('./math'); + +test('should multiply', () => { + // multiply is the function we're testing + const result = multiply(2, 3); + expect(result).toBe(6); +}); +""" + result = instrument_javascript_tests( + test_source=test_source, + function_name="multiply", + module_path="./math", + ) + + # The actual call should be wrapped + assert "codeflash.capture('multiply', multiply, 2, 3)" in result + + def test_empty_test_file(self) -> None: + """Test handling of empty test file.""" + result = instrument_javascript_tests( + test_source="", + function_name="test", + module_path="./test", + ) + + # Should add the helper import even to empty file + assert "codeflash-jest-helper" in result + + def test_complex_arguments(self) -> None: + """Test handling of complex function arguments.""" + test_source = """ +const { process } = require('./processor'); + +test('should process', () => { + const result = process({ key: 'value' }, [1, 2, 3], () => true); + expect(result).toBeDefined(); +}); +""" + result = instrument_javascript_tests( + test_source=test_source, + function_name="process", + module_path="./processor", + ) + + # Should handle complex arguments + assert "codeflash.capture('process'" in result diff --git a/django/aiservice/tests/testgen_instrumentation/test_jest_helper.py b/django/aiservice/tests/testgen_instrumentation/test_jest_helper.py new file mode 100644 index 000000000..6526e8210 --- /dev/null +++ b/django/aiservice/tests/testgen_instrumentation/test_jest_helper.py @@ -0,0 +1,151 @@ +"""Tests for the codeflash-jest-helper.js module structure.""" + +from pathlib import Path + +import pytest + +from testgen.instrumentation.javascript.instrument_javascript import get_jest_helper_path + + +class TestJestHelperStructure: + """Tests for the structure and content of the Jest helper module.""" + + @pytest.fixture + def helper_content(self) -> str: + """Load the Jest helper content.""" + helper_path = get_jest_helper_path() + return helper_path.read_text() + + def test_exports_capture_function(self, helper_content: str) -> None: + """Test that the helper exports a capture function.""" + assert "function capture" in helper_content + assert "module.exports" in helper_content + # Check that capture is exported + assert "capture" in helper_content.split("module.exports")[1] + + def test_has_safe_serialize(self, helper_content: str) -> None: + """Test that the helper has a safeSerialize function for handling complex objects.""" + assert "safeSerialize" in helper_content or "safe" in helper_content.lower() + + def test_handles_promises(self, helper_content: str) -> None: + """Test that the helper handles Promise returns for async functions.""" + assert "Promise" in helper_content + assert ".then" in helper_content or "instanceof Promise" in helper_content + + def test_records_timing(self, helper_content: str) -> None: + """Test that the helper records timing information.""" + assert "performance" in helper_content.lower() + assert "duration" in helper_content.lower() or "time" in helper_content.lower() + + def test_captures_errors(self, helper_content: str) -> None: + """Test that the helper captures and re-throws errors.""" + assert "error" in helper_content.lower() + assert "catch" in helper_content + assert "throw" in helper_content + + def test_uses_environment_variables(self, helper_content: str) -> None: + """Test that the helper reads from environment variables.""" + assert "process.env" in helper_content + assert "CODEFLASH" in helper_content + + def test_has_write_results_function(self, helper_content: str) -> None: + """Test that there's a function to write results to file.""" + assert "writeResults" in helper_content or "write" in helper_content.lower() + assert "fs" in helper_content # Uses fs module + + def test_has_jest_hooks(self, helper_content: str) -> None: + """Test that the helper includes Jest lifecycle hooks.""" + # Should reference beforeEach and/or afterAll hooks + assert "beforeEach" in helper_content or "afterAll" in helper_content + + def test_has_invocation_tracking(self, helper_content: str) -> None: + """Test that the helper tracks invocation order.""" + assert "invocation" in helper_content.lower() + + def test_handles_special_types(self, helper_content: str) -> None: + """Test that the helper handles special JavaScript types.""" + # Should handle at least some special types + special_types = ["Date", "Map", "Set", "Symbol", "BigInt", "Error"] + handled = sum(1 for t in special_types if t in helper_content) + assert handled >= 3 # Should handle at least 3 special types + + def test_handles_circular_references(self, helper_content: str) -> None: + """Test that the helper handles circular references.""" + assert "Circular" in helper_content or "seen" in helper_content.lower() + + def test_valid_javascript_syntax(self, helper_content: str) -> None: + """Test that the helper has valid JavaScript syntax (basic check).""" + # Basic bracket matching + brackets = {"(": ")", "[": "]", "{": "}"} + stack = [] + in_string = False + string_char = None + + for char in helper_content: + if char in "'\"`" and not in_string: + in_string = True + string_char = char + elif char == string_char and in_string: + in_string = False + string_char = None + elif not in_string: + if char in brackets: + stack.append(brackets[char]) + elif char in brackets.values(): + if stack and stack[-1] == char: + stack.pop() + + # Should have balanced brackets (allowing for some slack due to strings) + assert len(stack) < 5 # Some tolerance for complex string handling + + +class TestJestHelperExports: + """Tests for what the Jest helper exports.""" + + @pytest.fixture + def helper_content(self) -> str: + """Load the Jest helper content.""" + helper_path = get_jest_helper_path() + return helper_path.read_text() + + def test_exports_section_exists(self, helper_content: str) -> None: + """Test that there's a module.exports section.""" + assert "module.exports" in helper_content + + def test_exports_capture(self, helper_content: str) -> None: + """Test that capture is exported.""" + exports_section = helper_content.split("module.exports")[-1] + assert "capture" in exports_section + + def test_exports_multiple_functions(self, helper_content: str) -> None: + """Test that multiple utility functions are exported.""" + exports_section = helper_content.split("module.exports")[-1] + # Should export multiple things + export_count = exports_section.count(",") + assert export_count >= 2 # At least 3 exports + + +class TestJestHelperDocumentation: + """Tests for documentation in the Jest helper.""" + + @pytest.fixture + def helper_content(self) -> str: + """Load the Jest helper content.""" + helper_path = get_jest_helper_path() + return helper_path.read_text() + + def test_has_jsdoc_comments(self, helper_content: str) -> None: + """Test that the helper has JSDoc comments.""" + # Should have at least some JSDoc-style comments + assert "/**" in helper_content + assert "@param" in helper_content or "@returns" in helper_content + + def test_has_usage_instructions(self, helper_content: str) -> None: + """Test that the helper has usage instructions.""" + # Should have some usage guidance + assert "Usage" in helper_content or "require" in helper_content + + def test_documents_environment_variables(self, helper_content: str) -> None: + """Test that environment variables are documented.""" + assert "CODEFLASH_OUTPUT_FILE" in helper_content + assert "CODEFLASH_MODE" in helper_content or "MODE" in helper_content diff --git a/package-lock.json b/package-lock.json index 747472f32..bdcab65f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,29 +9,15 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "ts-jest": "^29.3.4" + "acorn": "^8.15.0" }, "devDependencies": { "@evilmartians/lefthook": "^1.8.2", "@secretlint/secretlint-rule-preset-recommend": "^9.0.0", "eslint": "^9.14.0", - "jest": "^29.7.0", "secretlint": "^9.0.0" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@azu/format-text": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz", @@ -53,6 +39,7 @@ "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", @@ -63,453 +50,16 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/compat-data": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.2.tgz", - "integrity": "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", - "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.1", - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helpers": "^7.27.1", - "@babel/parser": "^7.27.1", - "@babel/template": "^7.27.1", - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1", - "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.27.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", - "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.27.1", - "@babel/types": "^7.27.1", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "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==", - "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-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==", - "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.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", - "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.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==", - "license": "MIT", - "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==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-validator-identifier": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "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==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", - "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz", - "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.1" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.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==", - "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==", - "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==", - "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==", - "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-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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "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.27.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", - "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.1", - "@babel/parser": "^7.27.1", - "@babel/template": "^7.27.1", - "@babel/types": "^7.27.1", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", - "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" - }, - "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==", - "license": "MIT" - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", @@ -738,440 +288,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "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==", - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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==", - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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==", - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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==", - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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==", - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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==", - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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==", - "license": "MIT", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "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", @@ -1372,12 +488,6 @@ "node": "^14.13.1 || >=16.0.0" } }, - "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==", - "license": "MIT" - }, "node_modules/@sindresorhus/merge-streams": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", @@ -1391,24 +501,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "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==", - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, "node_modules/@textlint/ast-node-types": { "version": "14.7.1", "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-14.7.1.tgz", @@ -1494,47 +586,6 @@ "@textlint/ast-node-types": "^14.7.1" } }, - "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==", - "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==", - "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==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", - "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.20.7" - } - }, "node_modules/@types/estree": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", @@ -1542,39 +593,6 @@ "dev": true, "license": "MIT" }, - "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==", - "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==", - "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==", - "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==", - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -1582,15 +600,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/node": { - "version": "22.15.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.19.tgz", - "integrity": "sha512-3vMNr4TzNQyjHcRZadojpRaD9Ofr6LsonZAoQ+HMUa/9ORTPoxVIw0e0mpqWpdjj8xybyCM+oKOUH2vwFu/oEw==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", @@ -1598,32 +607,10 @@ "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==", - "license": "MIT" - }, - "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "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==", - "license": "MIT" - }, "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -1677,6 +664,7 @@ "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" @@ -1692,6 +680,7 @@ "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" @@ -1701,6 +690,7 @@ "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" @@ -1712,19 +702,6 @@ "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==", - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1742,126 +719,11 @@ "node": ">=8" } }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "license": "MIT" - }, - "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==", - "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==", - "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-istanbul/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==", - "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/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==", - "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-preset-current-node-syntax": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", - "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", - "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" - } - }, - "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==", - "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/binaryextensions": { @@ -1888,6 +750,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -1898,6 +761,7 @@ "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" @@ -1906,107 +770,21 @@ "node": ">=8" } }, - "node_modules/browserslist": { - "version": "4.24.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz", - "integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==", - "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": { - "caniuse-lite": "^1.0.30001716", - "electron-to-chromium": "^1.5.149", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "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==", - "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==", - "license": "MIT" - }, "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==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001718", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", - "integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==", - "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", @@ -2019,36 +797,6 @@ "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==", - "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==", - "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==", - "license": "MIT" - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -2059,40 +807,11 @@ "node": ">=6" } }, - "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==", - "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==", - "license": "MIT", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "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" @@ -2105,45 +824,21 @@ "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/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==", - "license": "MIT" - }, - "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==", - "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", @@ -2158,6 +853,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2171,20 +867,6 @@ } } }, - "node_modules/dedent": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", - "integrity": "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==", - "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", @@ -2192,90 +874,23 @@ "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==", - "license": "MIT", - "engines": { - "node": ">=0.10.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==", - "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==", - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.155", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.155.tgz", - "integrity": "sha512-ps5KcGGmwL8VaeJlvlDlu4fORQpv3+GIcF5I3f9tUKUlJ/wsysh6HU8P5L1XWRYeXfA0oJd4PyM8ds8zTFf6Ng==", - "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==", - "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/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "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", @@ -2402,6 +1017,7 @@ "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", @@ -2457,53 +1073,6 @@ "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==", - "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==", - "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==", - "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", @@ -2545,6 +1114,7 @@ "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": { @@ -2581,15 +1151,6 @@ "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==", - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -2603,40 +1164,11 @@ "node": ">=16.0.0" } }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "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" @@ -2683,95 +1215,6 @@ "dev": true, "license": "ISC" }, - "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==", - "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==", - "hasInstallScript": 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/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==", - "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==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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", - "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", @@ -2842,33 +1285,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", - "license": "ISC" - }, "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/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/hosted-git-info": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", @@ -2889,21 +1315,6 @@ "dev": true, "license": "ISC" }, - "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==", - "license": "MIT" - }, - "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==", - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -2931,29 +1342,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", - "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" @@ -2969,44 +1362,13 @@ "node": ">=8" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "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.", - "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==", - "license": "ISC" - }, "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-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==", - "license": "MIT", - "dependencies": { - "hasown": "^2.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", @@ -3021,20 +1383,12 @@ "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==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -3052,107 +1406,19 @@ "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-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "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==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "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==", - "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/istanbul-lib-instrument/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "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==", - "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==", - "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.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/istextorbinary": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-6.0.0.tgz", @@ -3170,595 +1436,11 @@ "url": "https://bevry.me/fund" } }, - "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", - "license": "MIT", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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": { @@ -3774,18 +1456,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "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", @@ -3793,12 +1463,6 @@ "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==", - "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", @@ -3817,6 +1481,7 @@ "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" @@ -3835,24 +1500,6 @@ "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==", - "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==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3867,12 +1514,6 @@ "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==", - "license": "MIT" - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -3896,12 +1537,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3916,63 +1551,6 @@ "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==", - "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==", - "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.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "license": "ISC" - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, - "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==", - "license": "MIT" - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3987,6 +1565,7 @@ "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", @@ -3996,19 +1575,11 @@ "node": ">=8.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==", - "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" @@ -4021,24 +1592,14 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "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==", - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, "license": "MIT" }, "node_modules/normalize-package-data": { @@ -4069,51 +1630,6 @@ "node": ">=10" } }, - "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==", - "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==", - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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==", - "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==", - "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", @@ -4136,6 +1652,7 @@ "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" @@ -4179,15 +1696,6 @@ "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==", - "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", @@ -4201,57 +1709,26 @@ "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==", - "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/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==", - "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==", - "license": "MIT" - }, "node_modules/path-type": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", @@ -4269,12 +1746,14 @@ "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" @@ -4283,79 +1762,6 @@ "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==", - "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==", - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/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==", - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/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==", - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/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==", - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/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==", - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -4376,45 +1782,6 @@ "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==", - "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==", - "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==", - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -4425,22 +1792,6 @@ "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==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -4475,12 +1826,6 @@ "require-from-string": "^2.0.2" } }, - "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==", - "license": "MIT" - }, "node_modules/read-pkg": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.1.0.tgz", @@ -4566,15 +1911,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", - "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", @@ -4585,47 +1921,6 @@ "node": ">=0.10.0" } }, - "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.0", - "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==", - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/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==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -4636,15 +1931,6 @@ "node": ">=4" } }, - "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==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -4702,19 +1988,11 @@ "node": "^14.13.1 || >=16.0.0" } }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "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" @@ -4727,27 +2005,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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==", - "license": "ISC" - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "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" @@ -4771,25 +2029,6 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "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==", - "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==", - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -4830,46 +2069,14 @@ "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==", - "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==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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==", - "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", @@ -4884,6 +2091,7 @@ "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" @@ -4892,28 +2100,11 @@ "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==", - "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==", - "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" @@ -4936,6 +2127,7 @@ "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" @@ -4958,18 +2150,6 @@ "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==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/table": { "version": "6.9.0", "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", @@ -5028,20 +2208,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", - "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", @@ -5062,16 +2228,11 @@ "url": "https://bevry.me/fund" } }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "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" @@ -5080,79 +2241,6 @@ "node": ">=8.0" } }, - "node_modules/ts-jest": { - "version": "29.3.4", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.3.4.tgz", - "integrity": "sha512-Iqbrm8IXOmV+ggWHOTEbjwyCf2xZlUMv5npExksXohL+tk8va4Fjhb+X2+Rt9NBmgO7bJ8WpnMLOwih/DnMlFA==", - "license": "MIT", - "dependencies": { - "bs-logger": "^0.2.6", - "ejs": "^3.1.10", - "fast-json-stable-stringify": "^2.1.0", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.7.2", - "type-fest": "^4.41.0", - "yargs-parser": "^21.1.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-jest/node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -5166,19 +2254,11 @@ "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==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "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" @@ -5187,26 +2267,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "license": "MIT" - }, "node_modules/unicorn-magic": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", @@ -5220,36 +2280,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "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", @@ -5260,20 +2290,6 @@ "punycode": "^2.1.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==", - "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/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -5285,19 +2301,11 @@ "spdx-expression-parse": "^3.0.0" } }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, "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" @@ -5319,88 +2327,11 @@ "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==", - "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==", - "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==", - "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/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "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==", - "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==", - "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==", - "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" diff --git a/package.json b/package.json index 14724c867..59fa7655f 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "prepare": "lefthook install", - "secretlint": "secretlint \"**/*\" --maskSecrets --config ./secretlint.config.js --ignore \"**/node_modules/**\" \"**/venv/**\" \"**/.venv/**\" \"**/__pycache__/**\"" + "secretlint": "secretlint \"**/*\" --maskSecrets --config ./secretlint.config.js --ignore \"**/node_modules/**\" \"**/venv/**\" \"**/.venv/**\" \"**/__pycache__/**\"" }, "keywords": [], "author": "", @@ -19,5 +19,8 @@ "@secretlint/secretlint-rule-preset-recommend": "^9.0.0", "eslint": "^9.14.0", "secretlint": "^9.0.0" + }, + "dependencies": { + "acorn": "^8.15.0" } }