From d5c30f7d99d308f839dfc31add23a3d95e6378f7 Mon Sep 17 00:00:00 2001 From: Arthur Fiorette Date: Fri, 16 Jan 2026 18:18:18 -0300 Subject: [PATCH 01/22] code --- .serena/.gitignore | 1 + .serena/memories/architecture_and_patterns.md | 223 +++++++++++ .../memories/code_style_and_conventions.md | 83 ++++ .serena/memories/darwin_system_commands.md | 202 ++++++++++ .serena/memories/project_overview.md | 54 +++ .serena/memories/suggested_commands.md | 136 +++++++ .serena/memories/task_completion_checklist.md | 92 +++++ .serena/project.yml | 87 ++++ .vscode/settings.json | 5 +- benchmarks/honojsx/package.json | 9 +- benchmarks/jsxte/package.json | 9 +- benchmarks/kitajs/package.json | 7 +- benchmarks/preact/package.json | 11 +- benchmarks/react/package.json | 13 +- benchmarks/reactjsx/package.json | 13 +- benchmarks/runner/package.json | 4 +- benchmarks/templates/package.json | 9 +- benchmarks/typed-html/package.json | 7 +- benchmarks/vhtml/package.json | 7 +- package.json | 16 +- packages/fastify-html-plugin/package.json | 14 +- packages/html/package.json | 21 +- packages/ts-html-plugin/package.json | 15 +- pnpm-lock.yaml | 370 +++++++++++------- pnpm-workspace.yaml | 25 ++ 25 files changed, 1211 insertions(+), 222 deletions(-) create mode 100644 .serena/.gitignore create mode 100644 .serena/memories/architecture_and_patterns.md create mode 100644 .serena/memories/code_style_and_conventions.md create mode 100644 .serena/memories/darwin_system_commands.md create mode 100644 .serena/memories/project_overview.md create mode 100644 .serena/memories/suggested_commands.md create mode 100644 .serena/memories/task_completion_checklist.md create mode 100644 .serena/project.yml diff --git a/.serena/.gitignore b/.serena/.gitignore new file mode 100644 index 000000000..14d86ad62 --- /dev/null +++ b/.serena/.gitignore @@ -0,0 +1 @@ +/cache diff --git a/.serena/memories/architecture_and_patterns.md b/.serena/memories/architecture_and_patterns.md new file mode 100644 index 000000000..18e097ae2 --- /dev/null +++ b/.serena/memories/architecture_and_patterns.md @@ -0,0 +1,223 @@ +# Architecture and Design Patterns + +## Core Architecture + +### JSX Runtime Model + +The library transforms JSX into function calls that generate HTML strings: + +```tsx +
{content}
; +// Transpiles to: +jsx('div', { class: 'foo', children: content }); +// Returns: '
content
' +``` + +Key architectural points: + +- JSX elements are **always strings or Promises** (never React-like objects) +- No virtual DOM - direct string generation +- Async components propagate up the tree (if child is async, parent becomes async) + +### Monorepo Structure + +- **Workspace-based**: Uses pnpm workspaces with shared catalog for dependencies +- **Independent versioning**: Each package has its own version via changesets +- **Shared configuration**: Root-level TypeScript and Prettier configs + +## Key Design Patterns + +### 1. String Building Pattern + +Core pattern: Efficient string concatenation without intermediate objects + +```javascript +// From index.js +function createElement(tag, attrs, ...children) { + return `<${tag}${attributesToString(attrs)}>${contentsToString(children)}`; +} +``` + +### 2. Async/Await Pattern + +Async components are seamlessly integrated: + +- Sync components return `string` +- Async components return `Promise` +- Type system tracks async propagation via `JSX.Element` type + +### 3. Security by Default Pattern + +- **Attributes**: Auto-escaped by default +- **Children**: Must explicitly use `safe` attribute or `Html.escapeHtml()` +- **TypeScript Plugin**: Catches XSS at compile time + +### 4. Suspense Pattern + +Streaming HTML with fallback content: + +```tsx +} catch={(err) => }> + + +``` + +Uses request IDs (rid) for concurrent request safety. + +### 5. Error Boundary Pattern + +Catch errors in async component trees: + +```tsx + }> + + +``` + +## Module System + +### Exports Pattern + +Each package uses explicit exports in package.json: + +```json +{ + "exports": { + ".": "./index.js", + "./jsx-runtime": "./jsx-runtime.js", + "./suspense": "./suspense.js" + // etc. + } +} +``` + +### CommonJS with ESM Compatibility + +- Main output: CommonJS +- `esModuleInterop` enabled for compatibility +- No ESM build currently (could be added) + +## Type System Patterns + +### 1. Namespace-based Types + +Uses `JSX` namespace for type definitions: + +```typescript +declare namespace JSX { + interface IntrinsicElements { + div: HtmlTag & { + /* div-specific */ + }; + } +} +``` + +### 2. Type Extensions + +Users can extend types globally: + +```typescript +declare global { + namespace JSX { + interface HtmlTag { + 'hx-get'?: string; // HTMX support + } + } +} +``` + +### 3. Conditional Types + +`JSX.Element` is conditionally `string | Promise` based on usage. + +## Testing Patterns + +### 1. Node Native Test Runner + +Uses Node.js built-in test runner (not Jest/Mocha): + +```javascript +import { test } from 'node:test'; +import assert from 'node:assert'; +``` + +### 2. JSDOM for DOM Testing + +When DOM testing is needed: + +```javascript +import { JSDOM } from 'jsdom'; +const dom = new JSDOM(htmlString); +``` + +### 3. TSD for Type Testing + +For TypeScript type definitions: + +```typescript +// test-d.ts files +import { expectType } from 'tsd'; +expectType(
foo
); +``` + +## Performance Patterns + +### 1. Minimal Allocations + +- Avoid creating intermediate objects +- Direct string concatenation where possible +- Avoid regex when string methods suffice + +### 2. Void Element Optimization + +Special handling for self-closing tags: + +```javascript +if (isVoidElement(tag)) { + return `<${tag}${attributesToString(attrs)}>`; +} +``` + +### 3. Attribute String Building + +Efficient attribute serialization with kebab-case conversion: + +```javascript +function attributesToString(attrs) { + // Optimized string building +} +``` + +## Guidelines and Best Practices + +### Do's: + +- Use `safe` attribute for all user input +- Prefer composition over prop drilling +- Keep components pure when possible +- Use TypeScript strict mode +- Write tests for new features +- Consider performance for core HTML generation + +### Don'ts: + +- Don't use React-specific patterns (hooks, context, etc.) +- Don't create circular dependencies between packages +- Don't bypass XSS safety features +- Don't use `any` type without strong justification +- Don't mix CommonJS and ESM syntax + +### Async Component Guidelines: + +- Use request IDs (rid) for Suspense components +- Error boundaries for async error handling +- Avoid AsyncLocalStorage (performance penalty) +- Document when a component is async + +### Security Guidelines: + +- **ALWAYS** escape user input +- Use `@kitajs/ts-html-plugin` to catch XSS issues +- Review all changes to escaping logic carefully +- Test with malicious input samples diff --git a/.serena/memories/code_style_and_conventions.md b/.serena/memories/code_style_and_conventions.md new file mode 100644 index 000000000..3650527e9 --- /dev/null +++ b/.serena/memories/code_style_and_conventions.md @@ -0,0 +1,83 @@ +# Code Style and Conventions + +## TypeScript Configuration + +The project uses **strict TypeScript settings** with the following key configurations: + +### JSX Settings + +- `jsx`: "react-jsx" +- `jsxImportSource`: "@kitajs/html" +- `plugins`: [{ "name": "@kitajs/ts-html-plugin" }] + +### Module Settings + +- `module`: "CommonJS" +- `moduleResolution`: "node" +- `target`: "ESNext" +- `esModuleInterop`: true + +### Strict Mode Settings (all enabled) + +- `strict`: true +- `noImplicitAny`: true +- `strictNullChecks`: true +- `strictFunctionTypes`: true +- `strictBindCallApply`: true +- `strictPropertyInitialization`: true +- `noImplicitThis`: true +- `useUnknownInCatchVariables`: true +- `alwaysStrict`: true +- `noUnusedLocals`: true +- `noUnusedParameters`: true +- `noImplicitReturns`: true +- `noFallthroughCasesInSwitch`: true +- `noUncheckedIndexedAccess`: true +- `noImplicitOverride`: true + +### Build Settings + +- Source maps and declaration maps enabled +- Output directory: `dist` +- Incremental compilation enabled + +## Formatting + +- **Tool**: Prettier +- **Configuration**: Uses @arthurfiorette/prettier-config +- **Plugins**: + - prettier-plugin-jsdoc + - prettier-plugin-organize-imports + - prettier-plugin-packagejson +- **Pre-commit hook**: Automatically formats staged files before commit + +## Naming Conventions + +Based on the codebase: + +- Functions: camelCase (e.g., `createElement`, `attributesToString`) +- Constants: UPPER_SNAKE_CASE (e.g., `CAMEL_REGEX`, `ESCAPED_REGEX`) +- Variables: camelCase (e.g., `escapeHtml`) +- Files: kebab-case for test files (e.g., `simple-html.test.tsx`) +- Packages: scoped with @kitajs/ prefix + +## JSX Usage + +- No need to import React or Html namespace when using react-jsx transform +- Components can be sync (return string) or async (return Promise) +- Always use `safe` attribute or `Html.escapeHtml()` for user input to prevent XSS +- Attributes are automatically escaped by default +- Children content is NOT escaped by default (requires `safe` attribute) + +## File Organization + +- Source files in package root or src/ +- Tests in `test/` directory with `.test.tsx` or `.test.ts` extension +- Type definitions alongside implementation files (.d.ts files) +- Build output in `dist/` directory + +## Documentation + +- Use JSDoc comments for public APIs +- TypeScript types serve as primary documentation +- README.md in each package with comprehensive examples diff --git a/.serena/memories/darwin_system_commands.md b/.serena/memories/darwin_system_commands.md new file mode 100644 index 000000000..a2ee726ef --- /dev/null +++ b/.serena/memories/darwin_system_commands.md @@ -0,0 +1,202 @@ +# macOS (Darwin) System Commands + +The project is running on macOS (Darwin 25.2.0). Here are important system-specific +considerations: + +## Standard Unix Commands Available + +Most standard Unix commands work on macOS: + +- `ls`, `cd`, `pwd`, `mkdir`, `rm`, `cp`, `mv` +- `cat`, `less`, `head`, `tail` +- `grep`, `find`, `sed`, `awk` +- `chmod`, `chown` +- `ps`, `kill`, `top` + +## macOS-Specific Considerations + +### Package Management + +This project uses **pnpm** for Node.js packages, enforced by preinstall hook. + +### File System + +- **Case-insensitive** by default (but case-preserving) +- Be careful with file naming to avoid cross-platform issues +- Use forward slashes (/) in paths, not backslashes + +### Command Differences from Linux + +Some commands have different options or behavior: + +- `sed -i` requires an extension argument: `sed -i '' 's/foo/bar/g'` +- `readlink` doesn't have `-f` flag (use `greadlink` from coreutils if needed) +- `stat` has different syntax than GNU stat +- `xargs` may have different default behavior + +### Git + +Standard git commands work as expected: + +```bash +git status +git add . +git commit -m "message" +git push +git pull +git branch +git checkout +git diff +``` + +### Node.js & pnpm + +```bash +# Node version +node --version # Should be >= 20.13 + +# pnpm commands +pnpm install +pnpm test +pnpm build +pnpm format +``` + +### Common Development Tasks + +#### File Search + +```bash +# Find files by name +find . -name "*.tsx" + +# Find files excluding node_modules +find . -name "*.tsx" -not -path "*/node_modules/*" + +# Using grep for content search +grep -r "searchTerm" packages/ +``` + +#### Process Management + +```bash +# List processes +ps aux | grep node + +# Kill process by PID +kill + +# Kill process by name +pkill -f "process-name" +``` + +#### File Operations + +```bash +# View file contents +cat file.txt +less file.txt + +# View end of log file +tail -f logfile.txt + +# Count lines +wc -l file.txt + +# Find and replace (macOS-specific) +sed -i '' 's/old/new/g' file.txt +``` + +#### Permissions + +```bash +# Make script executable +chmod +x script.sh + +# Fix permission issues +chmod 644 file.txt # rw-r--r-- +chmod 755 file.sh # rwxr-xr-x +``` + +### Environment + +#### Shell + +Default shell on macOS is zsh (as of Catalina+): + +- Shell scripts should use `#!/usr/bin/env bash` or `#!/bin/sh` +- Environment variables work standard way: `export VAR=value` + +#### Paths + +- Home directory: `~` or `$HOME` +- Current directory: `.` +- Parent directory: `..` +- Absolute paths start with `/` + +### Performance Monitoring + +```bash +# CPU and memory usage +top + +# Better alternative (if installed) +htop + +# Disk usage +du -sh * + +# Disk free space +df -h +``` + +### Networking (if needed) + +```bash +# Check port usage +lsof -i :3000 + +# Check network connections +netstat -an | grep LISTEN +``` + +## Project-Specific Commands + +### Most Used Git Operations + +```bash +# Check status +git status + +# View changes +git diff + +# Add all changes +git add . + +# Commit (pre-commit hook will run Prettier automatically) +git commit -m "feat: add new feature" + +# Push +git push + +# Pull with rebase +git pull --rebase +``` + +### Testing Individual Files + +```bash +# Run specific test file (after building) +node --test dist/test/specific-test.test.js +``` + +### Debugging + +```bash +# Run with inspector +node --inspect dist/test/test-file.js + +# Run with more verbose output +NODE_OPTIONS="--trace-warnings" pnpm test +``` diff --git a/.serena/memories/project_overview.md b/.serena/memories/project_overview.md new file mode 100644 index 000000000..e6809f9cb --- /dev/null +++ b/.serena/memories/project_overview.md @@ -0,0 +1,54 @@ +# KitaJS HTML - Project Overview + +## Purpose + +KitaJS HTML is a monorepo containing a super fast JSX runtime library that generates HTML +strings. It's designed to work with any Node.js framework (Express, Fastify, Hono, +AdonisJS, Bun, etc.) and integrates well with HTMX, Alpine.js, and Hotwire Turbo. + +Key features: + +- JSX-based HTML generation that outputs strings +- Type-safe HTML templates using TypeScript +- Built-in XSS protection with TypeScript plugin +- Support for async components with Suspense +- Error boundaries for async error handling +- Performance-focused (benchmarks show 7-41x faster than alternatives) + +## Repository Structure + +This is a pnpm monorepo with the following structure: + +### Main Packages (packages/) + +- **@kitajs/html** - Core JSX runtime for HTML generation +- **@kitajs/ts-html-plugin** - TypeScript LSP plugin for XSS detection and validation +- **@kitajs/fastify-html-plugin** - Fastify integration plugin + +### Additional Directories + +- **benchmarks/** - Performance benchmarks comparing with React, Typed Html, etc. +- **examples/** - Example code demonstrating usage +- **.husky/** - Git hooks configuration +- **.github/** - GitHub workflows and CI/CD +- **.changeset/** - Changesets for version management + +## Tech Stack + +- **Language**: TypeScript 5.9.2+ +- **Runtime**: Node.js >= 20.13 +- **Package Manager**: pnpm >= 9 (required via preinstall hook) +- **JSX Transform**: react-jsx with jsxImportSource: @kitajs/html +- **Module System**: CommonJS +- **Testing**: Node.js native test runner with c8 for coverage +- **Formatting**: Prettier with @arthurfiorette/prettier-config +- **Git Hooks**: Husky +- **Versioning**: Changesets with GitHub changelog integration + +## Key Dependencies + +- csstype (for CSS types) +- fastify-plugin (for Fastify integration) +- TypeScript, tslib, @swc-node/register (build tools) +- JSDOM (for testing) +- c8 (code coverage) diff --git a/.serena/memories/suggested_commands.md b/.serena/memories/suggested_commands.md new file mode 100644 index 000000000..4e5cd2784 --- /dev/null +++ b/.serena/memories/suggested_commands.md @@ -0,0 +1,136 @@ +# Suggested Development Commands + +## Package Manager + +**Always use pnpm** - The project enforces this via preinstall hook. + +## Main Development Commands + +### Building + +```bash +# Build all packages +pnpm build + +# Build with watch mode (rebuilds on changes) +pnpm watch + +# Build specific package (from root) +pnpm --filter "@kitajs/html" build +``` + +### Testing + +```bash +# Run all tests in all packages +pnpm test + +# Run tests in a specific package (from package directory) +cd packages/html +pnpm test + +# For packages/html specifically: +# - Compiles TypeScript +# - Runs tests with c8 coverage +# - Uses Node.js native test runner +# - Test files: dist/test/**/*.test.js (compiled from test/*.test.tsx) + +# Run only tests marked with .only +pnpm test:only + +# Watch mode (for fastify-html-plugin) +pnpm --filter "@kitajs/fastify-html-plugin" test:watch +``` + +### Formatting + +```bash +# Format all files +pnpm format + +# Format specific files (Prettier) +prettier --write +``` + +### Benchmarking + +```bash +# Run performance benchmarks +pnpm bench + +# This builds benchmark packages and runs the benchmark runner +``` + +### Versioning & Publishing + +```bash +# Create a changeset (for version bumps) +pnpm change + +# Version packages (CI command) +pnpm ci-version + +# Publish packages (CI command) +pnpm ci-publish +``` + +### Git Hooks + +Git hooks are managed by Husky: + +- **pre-commit**: Automatically formats staged files with Prettier +- Setup: `pnpm prepare` (runs `husky` command) + +## Per-Package Commands + +### @kitajs/html + +```bash +cd packages/html +pnpm test # Run tests with coverage +pnpm test:only # Run only .only tests +pnpm bench # Run benchmarks +``` + +### @kitajs/fastify-html-plugin + +```bash +cd packages/fastify-html-plugin +pnpm test # Run tests with tsd and c8 +pnpm test:watch # Watch mode for tests +``` + +## Common Workflows + +### After making changes: + +1. Format code: `pnpm format` (or let pre-commit hook handle it) +2. Run tests: `pnpm test` +3. Build: `pnpm build` + +### Before committing: + +- Pre-commit hook automatically runs Prettier on staged files +- No manual action needed + +### Testing a single package: + +```bash +pnpm --filter "@kitajs/html" test +``` + +### Working with workspace: + +```bash +# Install dependencies +pnpm install + +# Run command in all packages +pnpm -r + +# Run command in specific package +pnpm --filter "" + +# Run commands in parallel +pnpm -r --parallel +``` diff --git a/.serena/memories/task_completion_checklist.md b/.serena/memories/task_completion_checklist.md new file mode 100644 index 000000000..5794a53ca --- /dev/null +++ b/.serena/memories/task_completion_checklist.md @@ -0,0 +1,92 @@ +# Task Completion Checklist + +When completing a coding task in this project, follow these steps: + +## 1. Code Quality + +- [ ] TypeScript compiles without errors (`tsc`) +- [ ] Code follows strict TypeScript settings (no `any`, proper null checks) +- [ ] No unused variables or parameters +- [ ] All functions have proper return types + +## 2. Formatting + +- [ ] Code is formatted with Prettier + - Run: `pnpm format` + - Or let pre-commit hook handle it automatically + +## 3. XSS Safety (Critical for this project!) + +- [ ] All user input uses `safe` attribute or `Html.escapeHtml()` +- [ ] No raw string concatenation with user input +- [ ] TypeScript plugin catches potential XSS vulnerabilities +- [ ] Consider running `xss-scan` if modifying JSX/HTML generation code + +## 4. Testing + +- [ ] Run tests: `pnpm test` (from root or package directory) +- [ ] All tests pass with no failures +- [ ] Code coverage is maintained or improved (c8 reports) +- [ ] For new features: Add appropriate tests in `test/` directory + +## 5. Build + +- [ ] Build succeeds: `pnpm build` +- [ ] No build warnings or errors +- [ ] Type definitions (.d.ts) are correctly generated + +## 6. Documentation + +- [ ] Update README.md if adding new features or changing APIs +- [ ] Add JSDoc comments for public APIs +- [ ] Update type definitions if needed +- [ ] Consider updating examples if relevant + +## 7. Performance (if applicable) + +- [ ] Consider running benchmarks if changes affect core HTML generation + - Run: `pnpm bench` +- [ ] No performance regressions + +## 8. Version Management (if releasing) + +- [ ] Create changeset if making user-facing changes + - Run: `pnpm change` +- [ ] Follow semantic versioning + +## 9. Git + +- [ ] Commit messages are clear and descriptive +- [ ] Pre-commit hook has run (Prettier formatting) +- [ ] No unnecessary files committed +- [ ] Changes are focused and atomic + +## Quick Check Before Committing + +From the root directory: + +```bash +pnpm format # Format code +pnpm build # Build all packages +pnpm test # Run all tests +``` + +If all three succeed, the code is ready to commit! + +## Special Considerations + +### For Core HTML Package (@kitajs/html) + +- XSS safety is CRITICAL - always verify proper escaping +- Performance matters - avoid unnecessary allocations +- Type safety - ensure JSX types are correct + +### For TypeScript Plugin (@kitajs/ts-html-plugin) + +- Test with real TypeScript projects +- Ensure error messages are clear and helpful + +### For Fastify Plugin (@kitajs/fastify-html-plugin) + +- Test integration with Fastify +- Ensure type definitions work correctly (tsd tests) diff --git a/.serena/project.yml b/.serena/project.yml new file mode 100644 index 000000000..5f1bc809e --- /dev/null +++ b/.serena/project.yml @@ -0,0 +1,87 @@ +# list of languages for which language servers are started; choose from: +# al bash clojure cpp csharp csharp_omnisharp +# dart elixir elm erlang fortran fsharp +# go groovy haskell java julia kotlin +# lua markdown nix pascal perl php +# powershell python python_jedi r rego ruby +# ruby_solargraph rust scala swift terraform toml +# typescript typescript_vts yaml zig +# Note: +# - For C, use cpp +# - For JavaScript, use typescript +# - For Free Pascal / Lazarus, use pascal +# Special requirements: +# - csharp: Requires the presence of a .sln file in the project folder. +# - pascal: Requires Free Pascal Compiler (fpc) and optionally Lazarus. +# When using multiple languages, the first language server that supports a given file will be used for that file. +# The first language is the default language and the respective language server will be used as a fallback. +# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. +languages: + - typescript + +# the encoding used by text files in the project +# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings +encoding: 'utf-8' + +# whether to use the project's gitignore file to ignore files +# Added on 2025-04-07 +ignore_all_files_in_gitignore: true + +# list of additional paths to ignore +# same syntax as gitignore, so you can use * and ** +# Was previously called `ignored_dirs`, please update your config if you are using that. +# Added (renamed) on 2025-04-07 +ignored_paths: [] + +# whether the project is in read-only mode +# If set to true, all editing tools will be disabled and attempts to use them will result in an error +# Added on 2025-04-18 +read_only: false + +# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details. +# Below is the complete list of tools for convenience. +# To make sure you have the latest list of tools, and to view their descriptions, +# execute `uv run scripts/print_tool_overview.py`. +# +# * `activate_project`: Activates a project by name. +# * `check_onboarding_performed`: Checks whether project onboarding was already performed. +# * `create_text_file`: Creates/overwrites a file in the project directory. +# * `delete_lines`: Deletes a range of lines within a file. +# * `delete_memory`: Deletes a memory from Serena's project-specific memory store. +# * `execute_shell_command`: Executes a shell command. +# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced. +# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type). +# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type). +# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes. +# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file. +# * `initial_instructions`: Gets the initial instructions for the current project. +# Should only be used in settings where the system prompt cannot be set, +# e.g. in clients you have no control over, like Claude Desktop. +# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol. +# * `insert_at_line`: Inserts content at a given line in a file. +# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol. +# * `list_dir`: Lists files and directories in the given directory (optionally with recursion). +# * `list_memories`: Lists memories in Serena's project-specific memory store. +# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building). +# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context). +# * `read_file`: Reads a file within the project directory. +# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store. +# * `remove_project`: Removes a project from the Serena configuration. +# * `replace_lines`: Replaces a range of lines within a file with new content. +# * `replace_symbol_body`: Replaces the full definition of a symbol. +# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen. +# * `search_for_pattern`: Performs a search for a pattern in the project. +# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase. +# * `switch_modes`: Activates modes by providing a list of their names +# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information. +# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task. +# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed. +# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store. +excluded_tools: [] + +# initial prompt for the project. It will always be given to the LLM upon activating the project +# (contrary to the memories, which are loaded on demand). +initial_prompt: '' + +project_name: 'html' +included_optional_tools: [] diff --git a/.vscode/settings.json b/.vscode/settings.json index edc22acec..f9ff80aab 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { - "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, - "cSpell.words": ["KITA"] + "typescript.experimental.useTsgo": true, + "typescript.tsdk": "node_modules/typescript/lib", + "typescript.tsserver.maxTsServerMemory": 4096 } diff --git a/benchmarks/honojsx/package.json b/benchmarks/honojsx/package.json index 7b3cf1194..37a13cabe 100644 --- a/benchmarks/honojsx/package.json +++ b/benchmarks/honojsx/package.json @@ -4,14 +4,15 @@ "private": true, "main": "dist/index.js", "scripts": { - "build": "tsc" + "build": "tsgo" }, "dependencies": { + "@typescript/native-preview": "catalog:", "hono": "^4.8.2", - "tslib": "^2.8.1", - "typescript": "^5.9.2" + "tslib": "catalog:", + "typescript": "catalog:" }, "devDependencies": { - "@types/node": "^22.13.13" + "@types/node": "catalog:" } } diff --git a/benchmarks/jsxte/package.json b/benchmarks/jsxte/package.json index d36c9a7a2..6c0c9a397 100644 --- a/benchmarks/jsxte/package.json +++ b/benchmarks/jsxte/package.json @@ -4,14 +4,15 @@ "private": true, "main": "dist/index.js", "scripts": { - "build": "tsc" + "build": "tsgo" }, "dependencies": { + "@typescript/native-preview": "catalog:", "jsxte": "^3.3.1", - "tslib": "^2.8.1", - "typescript": "^5.9.2" + "tslib": "catalog:", + "typescript": "catalog:" }, "devDependencies": { - "@types/node": "^22.13.13" + "@types/node": "catalog:" } } diff --git a/benchmarks/kitajs/package.json b/benchmarks/kitajs/package.json index a7aa9e8c4..a150965d1 100644 --- a/benchmarks/kitajs/package.json +++ b/benchmarks/kitajs/package.json @@ -4,11 +4,12 @@ "private": true, "main": "dist/index.js", "scripts": { - "build": "tsc" + "build": "tsgo" }, "dependencies": { "@kitajs/html": "workspace:*", - "tslib": "^2.8.1", - "typescript": "^5.9.2" + "@typescript/native-preview": "catalog:", + "tslib": "catalog:", + "typescript": "catalog:" } } diff --git a/benchmarks/preact/package.json b/benchmarks/preact/package.json index 8633db121..3c83029ac 100644 --- a/benchmarks/preact/package.json +++ b/benchmarks/preact/package.json @@ -4,15 +4,16 @@ "private": true, "main": "dist/index.js", "scripts": { - "build": "tsc" + "build": "tsgo" }, "dependencies": { + "@typescript/native-preview": "catalog:", "preact": "^10.27.3", - "tslib": "^2.8.1", - "typescript": "^5.9.2" + "tslib": "catalog:", + "typescript": "catalog:" }, "devDependencies": { - "@types/node": "^22.13.13", - "@types/react": "^18.3.12" + "@types/node": "catalog:", + "@types/react": "catalog:" } } diff --git a/benchmarks/react/package.json b/benchmarks/react/package.json index 7a2e362fb..f8f4e56ed 100644 --- a/benchmarks/react/package.json +++ b/benchmarks/react/package.json @@ -4,15 +4,16 @@ "private": true, "main": "dist/index.js", "scripts": { - "build": "tsc" + "build": "tsgo" }, "dependencies": { - "react": "^18.3.1", - "tslib": "^2.8.1", - "typescript": "^5.9.2" + "@typescript/native-preview": "catalog:", + "react": "catalog:", + "tslib": "catalog:", + "typescript": "catalog:" }, "devDependencies": { - "@types/node": "^22.13.13", - "@types/react": "^18.3.12" + "@types/node": "catalog:", + "@types/react": "catalog:" } } diff --git a/benchmarks/reactjsx/package.json b/benchmarks/reactjsx/package.json index 9b07ea7a6..75b2368ce 100644 --- a/benchmarks/reactjsx/package.json +++ b/benchmarks/reactjsx/package.json @@ -4,15 +4,16 @@ "private": true, "main": "dist/index.js", "scripts": { - "build": "tsc" + "build": "tsgo" }, "dependencies": { - "react": "^18.3.1", - "tslib": "^2.8.1", - "typescript": "^5.9.2" + "@typescript/native-preview": "catalog:", + "react": "catalog:", + "tslib": "catalog:", + "typescript": "catalog:" }, "devDependencies": { - "@types/node": "^22.13.13", - "@types/react": "^18.3.12" + "@types/node": "catalog:", + "@types/react": "catalog:" } } diff --git a/benchmarks/runner/package.json b/benchmarks/runner/package.json index 2a9e83fe4..04b3d9ca7 100644 --- a/benchmarks/runner/package.json +++ b/benchmarks/runner/package.json @@ -27,7 +27,7 @@ "mitata": "1.0.34", "nano-jsx": "0.1.0", "preact-render-to-string": "6.5.13", - "react": "18.3.1", - "react-dom": "18.3.1" + "react": "catalog:", + "react-dom": "catalog:" } } diff --git a/benchmarks/templates/package.json b/benchmarks/templates/package.json index c401e2eb4..469381237 100644 --- a/benchmarks/templates/package.json +++ b/benchmarks/templates/package.json @@ -4,13 +4,14 @@ "private": true, "main": "dist/index.js", "scripts": { - "build": "tsc" + "build": "tsgo" }, "dependencies": { - "tslib": "^2.8.1", - "typescript": "^5.9.2" + "@typescript/native-preview": "catalog:", + "tslib": "catalog:", + "typescript": "catalog:" }, "devDependencies": { - "@types/node": "^22.13.13" + "@types/node": "catalog:" } } diff --git a/benchmarks/typed-html/package.json b/benchmarks/typed-html/package.json index 464ea7742..422beab42 100644 --- a/benchmarks/typed-html/package.json +++ b/benchmarks/typed-html/package.json @@ -4,11 +4,12 @@ "private": true, "main": "dist/index.js", "scripts": { - "build": "tsc" + "build": "tsgo" }, "dependencies": { - "tslib": "^2.8.1", + "@typescript/native-preview": "catalog:", + "tslib": "catalog:", "typed-html": "^3.0.1", - "typescript": "^5.9.2" + "typescript": "catalog:" } } diff --git a/benchmarks/vhtml/package.json b/benchmarks/vhtml/package.json index 2dfeeb219..07372a6a3 100644 --- a/benchmarks/vhtml/package.json +++ b/benchmarks/vhtml/package.json @@ -4,11 +4,12 @@ "private": true, "main": "dist/index.js", "scripts": { - "build": "tsc" + "build": "tsgo" }, "dependencies": { - "tslib": "^2.8.1", - "typescript": "^5.9.2", + "@typescript/native-preview": "catalog:", + "tslib": "catalog:", + "typescript": "catalog:", "vhtml": "^2.2.0" } } diff --git a/package.json b/package.json index 7a64400f7..0b833048e 100644 --- a/package.json +++ b/package.json @@ -26,19 +26,19 @@ }, "devDependencies": { "@arthurfiorette/prettier-config": "^1.0.12", - "@changesets/changelog-github": "^0.5.1", - "@changesets/cli": "^2.29.7", + "@changesets/changelog-github": "^0.5.2", + "@changesets/cli": "^2.29.8", "@kitajs/html": "workspace:*", "husky": "^9.1.7", - "prettier": "^3.6.2", - "prettier-plugin-jsdoc": "^1.3.3", + "prettier": "^3.8.0", + "prettier-plugin-jsdoc": "^1.8.0", "prettier-plugin-organize-imports": "^4.2.0", - "prettier-plugin-packagejson": "^2.5.19", - "typescript": "^5.9.2" + "prettier-plugin-packagejson": "^2.5.21", + "typescript": "catalog:" }, - "packageManager": "pnpm@10.15.1", + "packageManager": "pnpm@10.28.0", "engines": { "node": ">=20.13", - "pnpm": ">=9" + "pnpm": ">=10" } } diff --git a/packages/fastify-html-plugin/package.json b/packages/fastify-html-plugin/package.json index c97105388..49586229f 100644 --- a/packages/fastify-html-plugin/package.json +++ b/packages/fastify-html-plugin/package.json @@ -24,15 +24,15 @@ }, "devDependencies": { "@fastify/formbody": "^8.0.2", - "@swc-node/register": "^1.11.1", - "@swc/helpers": "^0.5.17", - "@types/jsdom": "^21.1.7", - "@types/node": "^24.5.0", - "c8": "^10.1.3", + "@swc-node/register": "catalog:", + "@swc/helpers": "catalog:", + "@types/jsdom": "catalog:", + "@types/node": "catalog:", + "c8": "catalog:", "fastify": "^5.6.0", - "jsdom": "^27.0.0", + "jsdom": "catalog:", "tsd": "^0.33.0", - "tslib": "^2.8.1" + "tslib": "catalog:" }, "peerDependencies": { "@kitajs/html": "workspace:^4.2.10", diff --git a/packages/html/package.json b/packages/html/package.json index a1b09a65c..012a78d04 100644 --- a/packages/html/package.json +++ b/packages/html/package.json @@ -31,20 +31,21 @@ "types": "index.d.ts", "scripts": { "bench": "pnpm --filter \"benchmark-*\" build && pnpm --filter \"benchmark-runner\" start", - "test": "tsc; c8 --reporter lcov --reporter text node --no-deprecation --enable-source-maps --test dist/test", - "test:only": "tsc; node --no-deprecation --test-only --test dist/test" + "test": "tsgo; c8 --reporter lcov --reporter text node --no-deprecation --enable-source-maps --test dist/test", + "test:only": "tsgo; node --no-deprecation --test-only --test dist/test" }, "dependencies": { - "csstype": "^3.1.3" + "csstype": "^3.2.3" }, "devDependencies": { - "@types/jsdom": "^21.1.7", - "@types/node": "^24.5.0", - "c8": "^10.1.3", - "jsdom": "^27.0.0", - "react": "^19.1.1", - "react-dom": "^19.1.1", - "typescript": "^5.9.2" + "@types/jsdom": "catalog:", + "@types/node": "catalog:", + "@typescript/native-preview": "catalog:", + "c8": "catalog:", + "jsdom": "catalog:", + "react": "catalog:", + "react-dom": "catalog:", + "typescript": "catalog:" }, "engines": { "node": ">=12" diff --git a/packages/ts-html-plugin/package.json b/packages/ts-html-plugin/package.json index a407683da..f611a07f2 100644 --- a/packages/ts-html-plugin/package.json +++ b/packages/ts-html-plugin/package.json @@ -20,22 +20,23 @@ "xss-scan": "dist/cli.js" }, "scripts": { - "build": "tsc -p tsconfig.build.json", - "dev": "tsc -p tsconfig.build.json --watch", + "build": "tsgo -p tsconfig.build.json", + "dev": "tsgo -p tsconfig.build.json --watch", "prepack": "npm run build", "test": "pnpm build && pnpm install && pnpm test-exec", "test-exec": "node --require @swc-node/register --test test/**/*.test.ts" }, "dependencies": { "chalk": "^5.6.2", - "tslib": "^2.8.1", + "tslib": "catalog:", "yargs": "^18.0.0" }, "devDependencies": { - "@swc-node/register": "^1.11.1", - "@swc/helpers": "^0.5.17", - "@types/node": "^24.5.0", - "@types/yargs": "^17.0.33", + "@swc-node/register": "catalog:", + "@swc/helpers": "catalog:", + "@types/node": "catalog:", + "@types/yargs": "^17.0.35", + "@typescript/native-preview": "catalog:", "fast-defer": "^1.1.9", "self": "file:" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c3561cd43..715a5a276 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,13 +4,52 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +catalogs: + default: + '@swc-node/register': + specifier: ^1.11.1 + version: 1.11.1 + '@swc/helpers': + specifier: ^0.5.17 + version: 0.5.17 + '@types/jsdom': + specifier: ^21.1.7 + version: 21.1.7 + '@types/node': + specifier: ^24.5.0 + version: 24.5.0 + '@types/react': + specifier: ^18.3.12 + version: 18.3.24 + '@typescript/native-preview': + specifier: latest + version: 7.0.0-dev.20260116.1 + c8: + specifier: ^10.1.3 + version: 10.1.3 + jsdom: + specifier: ^27.0.0 + version: 27.0.0 + react: + specifier: ^19.1.1 + version: 19.1.1 + react-dom: + specifier: ^19.1.1 + version: 19.1.1 + tslib: + specifier: ^2.8.1 + version: 2.8.1 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + importers: .: devDependencies: '@arthurfiorette/prettier-config': specifier: ^1.0.12 - version: 1.0.12(prettier@3.6.2)(typescript@5.9.2) + version: 1.0.12(prettier@3.6.2)(typescript@5.9.3) '@changesets/changelog-github': specifier: ^0.5.1 version: 0.5.1 @@ -31,113 +70,131 @@ importers: version: 1.3.3(prettier@3.6.2) prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.2.0(prettier@3.6.2)(typescript@5.9.2) + version: 4.2.0(prettier@3.6.2)(typescript@5.9.3) prettier-plugin-packagejson: specifier: ^2.5.19 version: 2.5.19(prettier@3.6.2) typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: 'catalog:' + version: 5.9.3 benchmarks/honojsx: dependencies: + '@typescript/native-preview': + specifier: 'catalog:' + version: 7.0.0-dev.20260116.1 hono: specifier: ^4.8.2 version: 4.8.2 tslib: - specifier: ^2.8.1 + specifier: 'catalog:' version: 2.8.1 typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: 'catalog:' + version: 5.9.3 devDependencies: '@types/node': - specifier: ^22.13.13 - version: 22.18.4 + specifier: 'catalog:' + version: 24.5.0 benchmarks/jsxte: dependencies: + '@typescript/native-preview': + specifier: 'catalog:' + version: 7.0.0-dev.20260116.1 jsxte: specifier: ^3.3.1 version: 3.3.1 tslib: - specifier: ^2.8.1 + specifier: 'catalog:' version: 2.8.1 typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: 'catalog:' + version: 5.9.3 devDependencies: '@types/node': - specifier: ^22.13.13 - version: 22.18.4 + specifier: 'catalog:' + version: 24.5.0 benchmarks/kitajs: dependencies: '@kitajs/html': specifier: workspace:* version: link:../../packages/html + '@typescript/native-preview': + specifier: 'catalog:' + version: 7.0.0-dev.20260116.1 tslib: - specifier: ^2.8.1 + specifier: 'catalog:' version: 2.8.1 typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: 'catalog:' + version: 5.9.3 benchmarks/preact: dependencies: + '@typescript/native-preview': + specifier: 'catalog:' + version: 7.0.0-dev.20260116.1 preact: specifier: ^10.27.3 version: 10.27.3 tslib: - specifier: ^2.8.1 + specifier: 'catalog:' version: 2.8.1 typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: 'catalog:' + version: 5.9.3 devDependencies: '@types/node': - specifier: ^22.13.13 - version: 22.18.4 + specifier: 'catalog:' + version: 24.5.0 '@types/react': - specifier: ^18.3.12 + specifier: 'catalog:' version: 18.3.24 benchmarks/react: dependencies: + '@typescript/native-preview': + specifier: 'catalog:' + version: 7.0.0-dev.20260116.1 react: - specifier: ^18.3.1 - version: 18.3.1 + specifier: 'catalog:' + version: 19.1.1 tslib: - specifier: ^2.8.1 + specifier: 'catalog:' version: 2.8.1 typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: 'catalog:' + version: 5.9.3 devDependencies: '@types/node': - specifier: ^22.13.13 - version: 22.18.4 + specifier: 'catalog:' + version: 24.5.0 '@types/react': - specifier: ^18.3.12 + specifier: 'catalog:' version: 18.3.24 benchmarks/reactjsx: dependencies: + '@typescript/native-preview': + specifier: 'catalog:' + version: 7.0.0-dev.20260116.1 react: - specifier: ^18.3.1 - version: 18.3.1 + specifier: 'catalog:' + version: 19.1.1 tslib: - specifier: ^2.8.1 + specifier: 'catalog:' version: 2.8.1 typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: 'catalog:' + version: 5.9.3 devDependencies: '@types/node': - specifier: ^22.13.13 - version: 22.18.4 + specifier: 'catalog:' + version: 24.5.0 '@types/react': - specifier: ^18.3.12 + specifier: 'catalog:' version: 18.3.24 benchmarks/runner: @@ -194,45 +251,54 @@ importers: specifier: 6.5.13 version: 6.5.13(preact@10.27.3) react: - specifier: 18.3.1 - version: 18.3.1 + specifier: 'catalog:' + version: 19.1.1 react-dom: - specifier: 18.3.1 - version: 18.3.1(react@18.3.1) + specifier: 'catalog:' + version: 19.1.1(react@19.1.1) benchmarks/templates: dependencies: + '@typescript/native-preview': + specifier: 'catalog:' + version: 7.0.0-dev.20260116.1 tslib: - specifier: ^2.8.1 + specifier: 'catalog:' version: 2.8.1 typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: 'catalog:' + version: 5.9.3 devDependencies: '@types/node': - specifier: ^22.13.13 - version: 22.18.4 + specifier: 'catalog:' + version: 24.5.0 benchmarks/typed-html: dependencies: + '@typescript/native-preview': + specifier: 'catalog:' + version: 7.0.0-dev.20260116.1 tslib: - specifier: ^2.8.1 + specifier: 'catalog:' version: 2.8.1 typed-html: specifier: ^3.0.1 version: 3.0.1 typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: 'catalog:' + version: 5.9.3 benchmarks/vhtml: dependencies: + '@typescript/native-preview': + specifier: 'catalog:' + version: 7.0.0-dev.20260116.1 tslib: - specifier: ^2.8.1 + specifier: 'catalog:' version: 2.8.1 typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: 'catalog:' + version: 5.9.3 vhtml: specifier: ^2.2.0 version: 2.2.0 @@ -253,31 +319,31 @@ importers: specifier: ^8.0.2 version: 8.0.2 '@swc-node/register': - specifier: ^1.11.1 + specifier: 'catalog:' version: 1.11.1(@swc/core@1.7.26(@swc/helpers@0.5.17))(@swc/types@0.1.12)(typescript@5.9.3) '@swc/helpers': - specifier: ^0.5.17 + specifier: 'catalog:' version: 0.5.17 '@types/jsdom': - specifier: ^21.1.7 + specifier: 'catalog:' version: 21.1.7 '@types/node': - specifier: ^24.5.0 + specifier: 'catalog:' version: 24.5.0 c8: - specifier: ^10.1.3 + specifier: 'catalog:' version: 10.1.3 fastify: specifier: ^5.6.0 version: 5.6.0 jsdom: - specifier: ^27.0.0 + specifier: 'catalog:' version: 27.0.0(postcss@8.5.6) tsd: specifier: ^0.33.0 version: 0.33.0 tslib: - specifier: ^2.8.1 + specifier: 'catalog:' version: 2.8.1 packages/html: @@ -287,26 +353,29 @@ importers: version: 3.1.3 devDependencies: '@types/jsdom': - specifier: ^21.1.7 + specifier: 'catalog:' version: 21.1.7 '@types/node': - specifier: ^24.5.0 + specifier: 'catalog:' version: 24.5.0 + '@typescript/native-preview': + specifier: 'catalog:' + version: 7.0.0-dev.20260116.1 c8: - specifier: ^10.1.3 + specifier: 'catalog:' version: 10.1.3 jsdom: - specifier: ^27.0.0 + specifier: 'catalog:' version: 27.0.0(postcss@8.5.6) react: - specifier: ^19.1.1 + specifier: 'catalog:' version: 19.1.1 react-dom: - specifier: ^19.1.1 + specifier: 'catalog:' version: 19.1.1(react@19.1.1) typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: 'catalog:' + version: 5.9.3 packages/ts-html-plugin: dependencies: @@ -321,14 +390,14 @@ importers: version: 2.8.1 typescript: specifier: ^5.6.2 - version: 5.9.2 + version: 5.9.3 yargs: specifier: ^18.0.0 version: 18.0.0 devDependencies: '@swc-node/register': specifier: ^1.11.1 - version: 1.11.1(@swc/core@1.7.26(@swc/helpers@0.5.17))(@swc/types@0.1.12)(typescript@5.9.2) + version: 1.11.1(@swc/core@1.7.26(@swc/helpers@0.5.17))(@swc/types@0.1.12)(typescript@5.9.3) '@swc/helpers': specifier: ^0.5.17 version: 0.5.17 @@ -338,12 +407,15 @@ importers: '@types/yargs': specifier: ^17.0.33 version: 17.0.33 + '@typescript/native-preview': + specifier: latest + version: 7.0.0-dev.20260116.1 fast-defer: specifier: ^1.1.9 version: 1.1.9 self: specifier: 'file:' - version: '@kitajs/ts-html-plugin@file:packages/ts-html-plugin(@kitajs/html@packages+html)(typescript@5.9.2)' + version: '@kitajs/ts-html-plugin@file:packages/ts-html-plugin(@kitajs/html@packages+html)(typescript@5.9.3)' packages: @@ -799,9 +871,6 @@ packages: '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@22.18.4': - resolution: {integrity: sha512-UJdblFqXymSBhmZf96BnbisoFIr8ooiiBRMolQgg77Ea+VM37jXw76C2LQr9n8wm9+i/OvlUlW6xSvqwzwqznw==} - '@types/node@24.5.0': resolution: {integrity: sha512-y1dMvuvJspJiPSDZUQ+WMBvF7dpnEqN4x9DDC9ie5Fs/HUZJA3wFp7EhHoVaKX/iI0cRoECV8X2jL8zi0xrHCg==} @@ -826,6 +895,45 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260116.1': + resolution: {integrity: sha512-+HoFBoTy6GrdqpN2sBCmvNNVqKXndVqgKPojaTpc1OfiH2YAa1p2zXsHuw2+PtXcsGDBvIX4Fce4i8urHlF6mQ==} + cpu: [arm64] + os: [darwin] + + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260116.1': + resolution: {integrity: sha512-cKSm37T0rrCskKKjwr/i97+k9fIQydsOfYO8oUzOFWEHKYl83vQib0JdSyelbLGEfT5Xpt6Wm12ul6MS42e+xw==} + cpu: [x64] + os: [darwin] + + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260116.1': + resolution: {integrity: sha512-mF+y2V95kYJx6ELk3BaXd0lDRGq3ce8fCDxx3MRgCEuexm/SYXC9OnQfkdyEPqU366sYwYw98TFIYjf6ruhZ7Q==} + cpu: [arm64] + os: [linux] + + '@typescript/native-preview-linux-arm@7.0.0-dev.20260116.1': + resolution: {integrity: sha512-fCgBsrrbURMutyBdnYXa13OVDOGtlu1AWMCqq21jQFDv2hglUR2l7BOZmqobLgWY76DGHQS7zK+hXcEcOqR7hA==} + cpu: [arm] + os: [linux] + + '@typescript/native-preview-linux-x64@7.0.0-dev.20260116.1': + resolution: {integrity: sha512-7lxKOVF0ph2+92ySc8HSUxKnBHkfoj7bm43QE482fb0z1YhNuUc/3R79NJGKywgmDP5IXEb1PY8piQbwoPYHwg==} + cpu: [x64] + os: [linux] + + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260116.1': + resolution: {integrity: sha512-VzS2LDsXqmC+6v+DEdjHxhadKzN5l/yMMQp3pVvq/ZM52NkUWzUtBpAU3nxB8n02L9Xr6625jEMduyZba0TVVg==} + cpu: [arm64] + os: [win32] + + '@typescript/native-preview-win32-x64@7.0.0-dev.20260116.1': + resolution: {integrity: sha512-OUmQLOIoknUmwaNz2iA0tkClIbbuzjHLrnFZNF4rlw1LlelNExGQlrMmx0szMRjTz9CFOh9qhYT23/3jOoOsqA==} + cpu: [x64] + os: [win32] + + '@typescript/native-preview@7.0.0-dev.20260116.1': + resolution: {integrity: sha512-9N2Sa3Ap8E5+V4K+eTs5y8//dW77qFKzo+OfmYpL4f/Vb6WEoo6SDhjaSB2eNtgeiCKkNQySLO3pz3/QEpuVXg==} + hasBin: true + abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} @@ -1424,10 +1532,6 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - lower-case@1.1.4: resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==} @@ -1789,11 +1893,6 @@ packages: resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} engines: {node: '>=8'} - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} - peerDependencies: - react: ^18.3.1 - react-dom@19.1.1: resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} peerDependencies: @@ -1802,10 +1901,6 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} - engines: {node: '>=0.10.0'} - react@19.1.1: resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} engines: {node: '>=0.10.0'} @@ -1882,9 +1977,6 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - scheduler@0.26.0: resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} @@ -2083,11 +2175,6 @@ packages: resolution: {integrity: sha512-JKCM9zTfPDuPqQqdGZBWSEiItShliKkBFg5c6yOR8zth43v763XkAzTWaOlVqc0Y6p9ee8AaAbipGfUnCsYZUA==} engines: {node: '>=12'} - typescript@5.9.2: - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} - engines: {node: '>=14.17'} - hasBin: true - typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -2098,9 +2185,6 @@ packages: engines: {node: '>=0.8.0'} hasBin: true - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.12.0: resolution: {integrity: sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==} @@ -2220,11 +2304,11 @@ packages: snapshots: - '@arthurfiorette/prettier-config@1.0.12(prettier@3.6.2)(typescript@5.9.2)': + '@arthurfiorette/prettier-config@1.0.12(prettier@3.6.2)(typescript@5.9.3)': dependencies: prettier: 3.6.2 prettier-plugin-jsdoc: 1.3.3(prettier@3.6.2) - prettier-plugin-organize-imports: 3.2.4(prettier@3.6.2)(typescript@5.9.2) + prettier-plugin-organize-imports: 3.2.4(prettier@3.6.2)(typescript@5.9.3) prettier-plugin-packagejson: 2.5.19(prettier@3.6.2) transitivePeerDependencies: - '@volar/vue-language-plugin-pug' @@ -2519,12 +2603,12 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@kitajs/ts-html-plugin@file:packages/ts-html-plugin(@kitajs/html@packages+html)(typescript@5.9.2)': + '@kitajs/ts-html-plugin@file:packages/ts-html-plugin(@kitajs/html@packages+html)(typescript@5.9.3)': dependencies: '@kitajs/html': link:packages/html chalk: 5.6.2 tslib: 2.8.1 - typescript: 5.9.2 + typescript: 5.9.3 yargs: 18.0.0 '@manypkg/find-root@1.1.0': @@ -2633,21 +2717,6 @@ snapshots: '@swc/core': 1.7.26(@swc/helpers@0.5.17) '@swc/types': 0.1.12 - '@swc-node/register@1.11.1(@swc/core@1.7.26(@swc/helpers@0.5.17))(@swc/types@0.1.12)(typescript@5.9.2)': - dependencies: - '@swc-node/core': 1.14.1(@swc/core@1.7.26(@swc/helpers@0.5.17))(@swc/types@0.1.12) - '@swc-node/sourcemap-support': 0.6.1 - '@swc/core': 1.7.26(@swc/helpers@0.5.17) - colorette: 2.0.20 - debug: 4.4.3 - oxc-resolver: 11.8.0 - pirates: 4.0.7 - tslib: 2.8.1 - typescript: 5.9.2 - transitivePeerDependencies: - - '@swc/types' - - supports-color - '@swc-node/register@1.11.1(@swc/core@1.7.26(@swc/helpers@0.5.17))(@swc/types@0.1.12)(typescript@5.9.3)': dependencies: '@swc-node/core': 1.14.1(@swc/core@1.7.26(@swc/helpers@0.5.17))(@swc/types@0.1.12) @@ -2763,10 +2832,6 @@ snapshots: '@types/node@12.20.55': {} - '@types/node@22.18.4': - dependencies: - undici-types: 6.21.0 - '@types/node@24.5.0': dependencies: undici-types: 7.12.0 @@ -2790,6 +2855,37 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260116.1': + optional: true + + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260116.1': + optional: true + + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260116.1': + optional: true + + '@typescript/native-preview-linux-arm@7.0.0-dev.20260116.1': + optional: true + + '@typescript/native-preview-linux-x64@7.0.0-dev.20260116.1': + optional: true + + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260116.1': + optional: true + + '@typescript/native-preview-win32-x64@7.0.0-dev.20260116.1': + optional: true + + '@typescript/native-preview@7.0.0-dev.20260116.1': + optionalDependencies: + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260116.1 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260116.1 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20260116.1 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260116.1 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20260116.1 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260116.1 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20260116.1 + abstract-logging@2.0.1: {} agent-base@7.1.4: {} @@ -3371,10 +3467,6 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 - lower-case@1.1.4: {} lru-cache@10.4.3: {} @@ -3760,15 +3852,15 @@ snapshots: transitivePeerDependencies: - supports-color - prettier-plugin-organize-imports@3.2.4(prettier@3.6.2)(typescript@5.9.2): + prettier-plugin-organize-imports@3.2.4(prettier@3.6.2)(typescript@5.9.3): dependencies: prettier: 3.6.2 - typescript: 5.9.2 + typescript: 5.9.3 - prettier-plugin-organize-imports@4.2.0(prettier@3.6.2)(typescript@5.9.2): + prettier-plugin-organize-imports@4.2.0(prettier@3.6.2)(typescript@5.9.3): dependencies: prettier: 3.6.2 - typescript: 5.9.2 + typescript: 5.9.3 prettier-plugin-packagejson@2.5.19(prettier@3.6.2): dependencies: @@ -3801,12 +3893,6 @@ snapshots: quick-lru@4.0.1: {} - react-dom@18.3.1(react@18.3.1): - dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 - react-dom@19.1.1(react@19.1.1): dependencies: react: 19.1.1 @@ -3814,10 +3900,6 @@ snapshots: react-is@18.3.1: {} - react@18.3.1: - dependencies: - loose-envify: 1.4.0 - react@19.1.1: {} read-pkg-up@7.0.1: @@ -3885,10 +3967,6 @@ snapshots: dependencies: xmlchars: 2.2.0 - scheduler@0.23.2: - dependencies: - loose-envify: 1.4.0 - scheduler@0.26.0: {} secure-json-parse@4.0.0: {} @@ -4069,14 +4147,10 @@ snapshots: typed-html@3.0.1: {} - typescript@5.9.2: {} - typescript@5.9.3: {} uglify-js@3.19.3: {} - undici-types@6.21.0: {} - undici-types@7.12.0: {} unist-util-stringify-position@4.0.0: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 94c9de2fd..b1c183148 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,28 @@ packages: - 'packages/*' - 'benchmarks/*' + +catalog: + # TypeScript and tooling + typescript: ^5.9.2 + tslib: ^2.8.1 + '@typescript/native-preview': latest + + # Node types + '@types/node': ^24.10.9 + + # SWC tooling + '@swc-node/register': ^1.11.1 + '@swc/helpers': ^0.5.18 + + # Testing and coverage + c8: ^10.1.3 + + # JSDOM for testing + '@types/jsdom': ^27.0.0 + jsdom: ^27.4.0 + + # React + '@types/react': ^19.2.8 + react: ^19.2.3 + react-dom: ^19.2.3 From a65c61c8eca682313476f9889d667f8a7b640151 Mon Sep 17 00:00:00 2001 From: Arthur Fiorette Date: Thu, 22 Jan 2026 01:44:40 +0700 Subject: [PATCH 02/22] code --- .changeset/warm-seas-kiss.md | 5 + .gitignore | 1 + package.json | 6 +- packages/fastify-html-plugin/index.js | 2 +- packages/html/.npmignore | 9 - packages/html/all-types.js | 1 - packages/html/alpine.js | 7 - packages/html/error-boundary.js | 42 - packages/html/hotwire-turbo.js | 7 - packages/html/htmx.js | 7 - packages/html/index.d.ts | 174 -- packages/html/jsx-dev-runtime.d.ts | 37 - packages/html/jsx-dev-runtime.js | 10 - packages/html/jsx-runtime.d.ts | 37 - packages/html/jsx-runtime.js | 78 - packages/html/jsx.d.ts | 996 ----------- packages/html/jsx.js | 7 - packages/html/package.json | 36 +- packages/html/register.d.ts | 12 - packages/html/register.js | 19 - .../error-boundary.ts} | 50 +- packages/html/{index.js => src/index.ts} | 247 ++- packages/html/src/jsx-dev-runtime.ts | 21 + packages/html/src/jsx-runtime.ts | 97 + packages/html/src/jsx.ts | 997 +++++++++++ .../html/{suspense.js => src/suspense.ts} | 182 +- packages/html/suspense.d.ts | 158 -- packages/html/test/async.test.tsx | 19 +- packages/html/test/attributes.test.tsx | 139 +- packages/html/test/components.test.tsx | 20 +- packages/html/test/encoding.test.tsx | 48 +- packages/html/test/error-boundary.test.tsx | 25 +- .../html/test/escape-tagged-func.test.tsx | 149 +- packages/html/test/escape.test.tsx | 159 +- packages/html/test/hotwire-turbo.test.tsx | 42 +- packages/html/test/html-standards.test.tsx | 8 +- packages/html/test/misc.test.tsx | 146 +- packages/html/test/react.test.tsx | 66 +- packages/html/test/register.test.tsx | 29 - packages/html/test/runtime.test.tsx | 83 +- packages/html/test/simple-html.test.tsx | 46 +- packages/html/test/style.test.tsx | 30 +- packages/html/test/suspense.test.tsx | 195 +- packages/html/test/tags.test.tsx | 70 +- packages/html/test/util.test.ts | 41 +- packages/html/tsconfig.build.json | 10 + packages/html/tsconfig.json | 37 +- packages/ts-html-plugin/package.json | 15 +- packages/ts-html-plugin/src/index.ts | 2 +- packages/ts-html-plugin/test/arrays.test.ts | 7 +- packages/ts-html-plugin/test/children.test.ts | 15 +- .../ts-html-plugin/test/component-xss.test.ts | 7 +- .../ts-html-plugin/test/double-escape.test.ts | 5 +- .../ts-html-plugin/test/operators.test.ts | 5 +- packages/ts-html-plugin/test/readme.test.ts | 5 +- packages/ts-html-plugin/test/safe.test.ts | 5 +- .../ts-html-plugin/test/unsafe-tags.test.ts | 5 +- .../ts-html-plugin/test/util/lang-server.ts | 7 +- packages/ts-html-plugin/test/warn.test.ts | 5 +- packages/ts-html-plugin/tsconfig.json | 5 +- pnpm-lock.yaml | 1576 +++++++++++++---- pnpm-workspace.yaml | 29 +- tsconfig.json | 65 +- 63 files changed, 3473 insertions(+), 2892 deletions(-) create mode 100644 .changeset/warm-seas-kiss.md delete mode 100644 packages/html/.npmignore delete mode 100644 packages/html/all-types.js delete mode 100644 packages/html/alpine.js delete mode 100644 packages/html/error-boundary.js delete mode 100644 packages/html/hotwire-turbo.js delete mode 100644 packages/html/htmx.js delete mode 100644 packages/html/index.d.ts delete mode 100644 packages/html/jsx-dev-runtime.d.ts delete mode 100644 packages/html/jsx-dev-runtime.js delete mode 100644 packages/html/jsx-runtime.d.ts delete mode 100644 packages/html/jsx-runtime.js delete mode 100644 packages/html/jsx.d.ts delete mode 100644 packages/html/jsx.js delete mode 100644 packages/html/register.d.ts delete mode 100644 packages/html/register.js rename packages/html/{error-boundary.d.ts => src/error-boundary.ts} (56%) rename packages/html/{index.js => src/index.ts} (63%) create mode 100644 packages/html/src/jsx-dev-runtime.ts create mode 100644 packages/html/src/jsx-runtime.ts create mode 100644 packages/html/src/jsx.ts rename packages/html/{suspense.js => src/suspense.ts} (58%) delete mode 100644 packages/html/suspense.d.ts delete mode 100644 packages/html/test/register.test.tsx create mode 100644 packages/html/tsconfig.build.json diff --git a/.changeset/warm-seas-kiss.md b/.changeset/warm-seas-kiss.md new file mode 100644 index 000000000..cedb85b33 --- /dev/null +++ b/.changeset/warm-seas-kiss.md @@ -0,0 +1,5 @@ +--- +'@kitajs/html': major +--- + +Major overhaul diff --git a/.gitignore b/.gitignore index 0310715b3..f6200f0cc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ dist coverage *.log +*.tsbuildinfo benchmarks/runner/profile.cpuprofile \ No newline at end of file diff --git a/package.json b/package.json index 0b833048e..901f03791 100644 --- a/package.json +++ b/package.json @@ -32,11 +32,11 @@ "husky": "^9.1.7", "prettier": "^3.8.0", "prettier-plugin-jsdoc": "^1.8.0", - "prettier-plugin-organize-imports": "^4.2.0", - "prettier-plugin-packagejson": "^2.5.21", + "prettier-plugin-organize-imports": "^4.3.0", + "prettier-plugin-packagejson": "^3.0.0", "typescript": "catalog:" }, - "packageManager": "pnpm@10.28.0", + "packageManager": "pnpm@10.28.1", "engines": { "node": ">=20.13", "pnpm": ">=10" diff --git a/packages/fastify-html-plugin/index.js b/packages/fastify-html-plugin/index.js index a2ac21d42..5188bc05e 100644 --- a/packages/fastify-html-plugin/index.js +++ b/packages/fastify-html-plugin/index.js @@ -9,8 +9,8 @@ const kAutoDoctype = Symbol.for('fastify-kita-html.autoDoctype'); /** * Returns true if the string starts with ` -/// -/// - -/** - * Returns true if the character at the given index is an uppercase character. - * - * @param input The string to check. - * @param index The index of the character to check. - * @returns If the character at the given index is an uppercase character. - */ -export function isUpper(this: void, input: string, index: number): boolean; - -/** - * Tag function that escapes the given string pieces and interpolates the given values. - * Internally it uses {@linkcode escapeHtml} to escape the values. - * - * @param strings Template string. - * @param values Values to interpolate. - * @returns The escaped string. - */ -export function escape( - this: void, - strings: TemplateStringsArray, - ...values: any[] -): string; - -/** - * Escapes a string for safe use as HTML text content. If the value is not a string, it is - * coerced to one with its own `toString()` method. - * - * If the {@linkcode Bun} runtime is available, this function will be swapped out to - * {@linkcode Bun.escapeHTML}. - * - * @param value The value to escape. - * @returns The escaped string. - */ -export function escapeHtml(this: void, value: any): string; - -/** - * Returns true if the element is a html void element. - * - * @param tag The name of the element to check. - * @returns If the element is a html void element. - */ -export function isVoidElement(this: void, tag: string): boolean; - -/** - * Transforms an object of style attributes into a html style string. - * - * @param style A record of literal values to use as style attributes or a string. - * @returns The generated html style string. - */ -export function styleToString(this: void, style: object | string): string; - -/** - * Transforms an object of attributes into a html attributes string. - * - * **This function does not support Date objects.** - * - * @example `a b="c" d="1"` - * - * @param attributes A record of literal values to use as attributes. - * @returns The generated html attributes string. - */ -export function attributesToString(this: void, attributes: object): string; - -/** - * Converts a camel cased string to a kebab cased string. - * - * @param camel The camel cased string to convert. - */ -export function toKebabCase(this: void, camel: string): string; - -/** - * Generates a html string from the given contents. - * - * @param name The name of the element to create or a function that creates the element. - * @param [attributes] A record of literal values to use as attributes. A property named - * `children` will be used as the children of the element. - * @param contents The inner contents of the element. - * @returns The generated html string. - */ -export function createElement( - this: void, - name: string | Function, - attributes: PropsWithChildren | null, - ...contents: Children[] -): JSX.Element; - -/** - * Joins raw string html elements into a single html string. - * - * A raw html fragment is just an array of strings, this method concatenates . - * - * @param contents An maybe nested array of strings to concatenate. - * @param escape If it should escape the contents before concatenating them. Default is - * `false` - * @returns The concatenated and escaped string of contents. - */ -export function contentsToString( - this: void, - contents: Children[], - escape?: boolean -): JSX.Element; - -/** - * Transforms a single content into a string. - * - * @param content The content to transform. - * @param escape If it should escape the content before transforming it. Default is - * `false` - * @returns The transformed and escaped string of content. - */ -export function contentToString( - this: void, - content: Children, - escape?: boolean -): JSX.Element; - -/** Here for interop with `preact` and many build systems. */ -export const h: typeof createElement; - -/** - * Alias of {@linkcode escape} to reduce verbosity. - * - * @example - * - * ```tsx - * import { e } from '@kitajs/html' - * - *
{e`My name is ${user.name}!`}
; - * ``` - */ -export const e: typeof escape; - -/** - * A JSX Fragment is used to return multiple elements from a component. - * - * @example - * - * ```tsx - * // renders
1
and
2
without needing a wrapper element - * const html = <>
1
2
- * - * // Html.Fragment is the same as <>... - * const html =
1
2
- * ``` - */ -export function Fragment(props: PropsWithChildren): JSX.Element; - -export type Children = - | number - | string - | boolean - | null - | undefined - | bigint - | Promise - | Children[]; - -export type PropsWithChildren = { children?: Children } & T; - -export type Component = (this: void, props: PropsWithChildren) => JSX.Element; - -/** - * Fast and type safe HTML templates using JSX syntax. - * - * @module Html - * @license Apache License Version 2.0 - * @link https://github.com/kitajs/html - * @link https://www.npmjs.com/package/@kitajs/html - */ -export const Html: Omit; diff --git a/packages/html/jsx-dev-runtime.d.ts b/packages/html/jsx-dev-runtime.d.ts deleted file mode 100644 index 6a83fcb0a..000000000 --- a/packages/html/jsx-dev-runtime.d.ts +++ /dev/null @@ -1,37 +0,0 @@ -/// -/// -/// - -import type { Children } from './index'; - -/** - * Generates a html string from an attribute name of component and it's props. - * - * This function is meant to be used by the jsx runtime and should not be called directly. - * - * @param name The name of the element to create or another component function - * @param attributes The props to apply to the component - * @retuns The generated html string or a promise that resolves to the generated html string - */ -export function jsxDEV( - this: void, - name: string | Function, - attributes: { children?: Children; [k: string]: any } -): JSX.Element; - -/** - * Generates a html string from an attribute name of component and it's props. - * - * This function is meant to be used by the jsx runtime and should not be called directly. - * - * @param name The name of the element to create or another component function - * @param attributes The props to apply to the component - * @retuns The generated html string or a promise that resolves to the generated html string - */ -export function jsxs( - this: void, - name: string | Function, - attributes: { children: Children[]; [k: string]: any } -): JSX.Element; - -export { Fragment } from './index'; diff --git a/packages/html/jsx-dev-runtime.js b/packages/html/jsx-dev-runtime.js deleted file mode 100644 index 014acd53f..000000000 --- a/packages/html/jsx-dev-runtime.js +++ /dev/null @@ -1,10 +0,0 @@ -/// -/// -/// - -const { Fragment, jsx, jsxs } = require('./jsx-runtime'); - -exports.jsx = jsx; -exports.jsxs = jsxs; -exports.jsxDEV = jsx; -exports.Fragment = Fragment; diff --git a/packages/html/jsx-runtime.d.ts b/packages/html/jsx-runtime.d.ts deleted file mode 100644 index aa0c6dae8..000000000 --- a/packages/html/jsx-runtime.d.ts +++ /dev/null @@ -1,37 +0,0 @@ -/// -/// -/// - -import type { Children } from './index'; - -/** - * Generates a html string from an attribute name of component and it's props. - * - * This function is meant to be used by the jsx runtime and should not be called directly. - * - * @param name The name of the element to create or another component function - * @param attributes The props to apply to the component - * @retuns The generated html string or a promise that resolves to the generated html string - */ -export function jsx( - this: void, - name: string | Function, - attributes: { children?: Children; [k: string]: any } -): JSX.Element; - -/** - * Generates a html string from an attribute name of component and it's props. - * - * This function is meant to be used by the jsx runtime and should not be called directly. - * - * @param name The name of the element to create or another component function - * @param attributes The props to apply to the component - * @retuns The generated html string or a promise that resolves to the generated html string - */ -export function jsxs( - this: void, - name: string | Function, - attributes: { children: Children[]; [k: string]: any } -): JSX.Element; - -export { Fragment } from './index'; diff --git a/packages/html/jsx-runtime.js b/packages/html/jsx-runtime.js deleted file mode 100644 index 6d26e462a..000000000 --- a/packages/html/jsx-runtime.js +++ /dev/null @@ -1,78 +0,0 @@ -/// -/// -/// - -const { - Fragment, - attributesToString, - isVoidElement, - contentsToString, - contentToString -} = require('./index'); - -/** @type {import('./jsx-runtime').jsx} */ -function jsx(name, attrs) { - // Calls the element creator function if the name is a function - if (typeof name === 'function') { - return name(attrs); - } - - // Switches the tag name when this custom `tag` is present. - if (name === 'tag') { - name = /** @type {string} */ (attrs.of); - } - - const attributes = attributesToString(attrs); - - if (attrs.children === undefined) { - return isVoidElement(name) - ? '<' + name + attributes + '/>' - : '<' + name + attributes + '>'; - } - - const contents = contentToString(attrs.children, attrs.safe); - - if (contents instanceof Promise) { - return contents.then(function resolveContents(child) { - return '<' + name + attributes + '>' + child + ''; - }); - } - - return '<' + name + attributes + '>' + contents + ''; -} - -/** @type {import('./jsx-runtime').jsxs} */ -function jsxs(name, attrs) { - // Calls the element creator function if the name is a function - if (typeof name === 'function') { - return name(attrs); - } - - // Switches the tag name when this custom `tag` is present. - if (name === 'tag') { - name = /** @type {string} */ (attrs.of); - } - - const attributes = attributesToString(attrs); - - if (attrs.children.length === 0) { - return isVoidElement(name) - ? '<' + name + attributes + '/>' - : '<' + name + attributes + '>'; - } - - const contents = contentsToString(attrs.children, attrs.safe); - - if (contents instanceof Promise) { - return contents.then(function resolveContents(child) { - return '<' + name + attributes + '>' + child + ''; - }); - } - - return '<' + name + attributes + '>' + contents + ''; -} - -exports.jsx = jsx; -exports.jsxs = jsxs; -// According to the jsx-runtime spec we must export the fragment element also -exports.Fragment = Fragment; diff --git a/packages/html/jsx.d.ts b/packages/html/jsx.d.ts deleted file mode 100644 index bd75b6e2a..000000000 --- a/packages/html/jsx.d.ts +++ /dev/null @@ -1,996 +0,0 @@ -// This file is a result from many sources, including: RFCs, typescript dom lib, w3schools, and others. -// Possibly there are many tags/attributes missing, but it is a good start. -// Missing something? Please submit a issue report or a PR: -// https://github.com/kitajs/html - -/** Same as a string type but allows autocompletion of literal values */ -type AnyString = string & {}; - -declare namespace JSX { - /** - * A {@linkcode JSX.Element} will always be a string, unless one of its children is a - * promise, in which case all of its subsequent children will also be promises. - * - * Direct calls of `Html.createElement` uses correct return type based on its children. - * However, when using JSX syntax, typescript does not support this yet. - * - * @see https://github.com/microsoft/TypeScript/issues/14729 - */ - type Element = string | Promise; - - /** - * The index signature was removed to enable closed typing for style using CSSType. - * You're able to use type assertion or module augmentation to add properties or an - * index signature of your own. - * - * For examples and more information, visit: - * https://github.com/frenic/csstype#what-should-i-do-when-i-get-type-errors - */ - type CSSProperties = import('csstype').Properties; - - interface HtmlTag extends ElementChildrenAttribute, IntrinsicAttributes { - accesskey?: undefined | string; - autocapitalize?: - | undefined - | 'off' - | 'none' - | 'on' - | 'sentences' - | 'words' - | 'characters' - | AnyString; - autocorrect?: undefined | 'on' | 'off' | AnyString; - contenteditable?: undefined | string; - enterkeyhint?: - | undefined - | 'enter' - | 'done' - | 'go' - | 'next' - | 'previous' - | 'search' - | 'send' - | AnyString; - inert?: undefined | boolean; - inputmode?: - | undefined - | 'none' - | 'text' - | 'decimal' - | 'numeric' - | 'tel' - | 'search' - | 'email' - | 'url' - | AnyString; - dir?: undefined | string; - hidden?: undefined | string | boolean; - id?: undefined | number | string; - nonce?: undefined | string; - part?: undefined | string; - popover?: undefined | boolean | 'auto' | 'manual'; - role?: undefined | AriaRole; - lang?: undefined | string; - slot?: undefined | string; - draggable?: undefined | string | boolean; - spellcheck?: undefined | string | boolean; - tabindex?: undefined | number | string; - title?: undefined | string; - translate?: undefined | string | boolean; - virtualkeyboardpolicy?: undefined | 'auto' | 'manual' | AnyString; - writingsuggestions?: undefined | 'true' | 'false' | AnyString; - - /** A css style attribute which also supports a `csstype` object. */ - style?: undefined | string | CSSProperties; - - /** - * When set to true, all inner content (html or not) of this tag will be escaped when - * evaluated. - * - * **Warning: This will escape even inner jsx tags. You should only use this in the - * most inner tag of the html tree.** - * - * @example - * - * ```tsx - *
{''; const safeTag = Html.escape`${unsafeTag}`; describe('HTML Escaping', () => { test('e is the same as escape', () => { - assert.equal(Html.e, Html.escape); + expect(Html.e).toBe(Html.escape); }); test('escapes content', () => { - assert.equal(<>{unsafeTag}, <>{unsafeTag}); + expect(<>{unsafeTag}).toBe(<>{unsafeTag}); }); test('with children', () => { - assert.equal( + expect( <>
{unsafeTag}
- , + + ).toBe( <>
{unsafeTag}
@@ -26,10 +26,11 @@ describe('HTML Escaping', () => { }); test('escapes children', () => { - assert.equal( + expect( <>
{unsafeTag}
- , + + ).toBe( <>
{safeTag}
@@ -37,12 +38,13 @@ describe('HTML Escaping', () => { }); test('escapes deep children', () => { - assert.equal( + expect( <>
{unsafeTag}
- , + + ).toBe( <>
{Html.escape`${(
{unsafeTag}
)}`}
@@ -50,34 +52,31 @@ describe('HTML Escaping', () => { }); test('always escapes attributes', () => { - assert.equal( + expect( <>
\''}>
\'' }}>
\''}>
'">
-
-
-
+ ).toMatchInlineSnapshot( + `"
"` ); - assert.equal( + expect( <>
'`}>
'` }}>
'`}>
- , - `
` + + ).toMatchInlineSnapshot( + `"
"` ); }); test('handles unknown values', () => { - assert.equal(Html.escape``, ''); - assert.equal(Html.escape`${{ a: 1 }}`, '[object Object]'); + expect(Html.escape``).toBe(''); + expect(Html.escape`${{ a: 1 }}`).toBe('[object Object]'); }); // The matrix of cases we need to test for: @@ -90,111 +89,93 @@ describe('HTML Escaping', () => { // 7. Works when the text to escape is in the end // 8. Returns the same string when there's no need to escape test('always escape', () => { - assert.equal( - Html.escape`absolutely nothing to do here`, + expect(Html.escape`absolutely nothing to do here`).toBe( 'absolutely nothing to do here' ); - assert.equal( - Html.escape``, + expect(Html.escape``).toBe( '<script>alert(1)</script>' ); - assert.equal(Html.escape`<`, '<'); - assert.equal(Html.escape`>`, '>'); - assert.equal(Html.escape`&`, '&'); - assert.equal(Html.escape`'`, '''); - assert.equal(Html.escape`"`, '"'); - assert.equal(Html.escape`\u00A0`, '\u00A0'); - assert.equal(Html.escape`lalala`, + expect(Html.escape`<`).toBe('<'); + expect(Html.escape`>`).toBe('>'); + expect(Html.escape`&`).toBe('&'); + expect(Html.escape`'`).toBe('''); + expect(Html.escape`"`).toBe('"'); + expect(Html.escape`\u00A0`).toBe('\u00A0'); + expect(Html.escape`lalala`).toBe( 'lalala<script>alert(1)</script>lalala' ); - assert.equal( - Html.escape`lalala`, + expect(Html.escape`lalala`).toBe( '<script>alert(1)</script>lalala' ); - assert.equal( - Html.escape`lalala`, + expect(Html.escape`lalala`).toBe( 'lalala' + '<script>alert(1)</script>' ); - assert.equal(Html.escape`What does 😊 mean?`, 'What does 😊 mean?'); - assert.equal(Html.escape`What does 😊 mean in text?`, + expect(Html.escape`What does 😊 mean?`).toBe('What does 😊 mean?'); + expect(Html.escape`What does 😊 mean in text?`).toBe( '<div>What does 😊 mean in text?' ); - assert.equal( - Html.escape`${('lalala' + '' + 'lalala').repeat(900)}`, - 'lalala<script>alert(1)</script>lalala'.repeat(900) - ); - assert.equal( - Html.escape`${('' + 'lalala').repeat(900)}`, + expect( + Html.escape`${('lalala' + '' + 'lalala').repeat(900)}` + ).toBe('lalala<script>alert(1)</script>lalala'.repeat(900)); + expect(Html.escape`${('' + 'lalala').repeat(900)}`).toBe( '<script>alert(1)</script>lalala'.repeat(900) ); - assert.equal( - Html.escape`${('lalala' + '').repeat(900)}`, + expect(Html.escape`${('lalala' + '').repeat(900)}`).toBe( ('lalala' + '<script>alert(1)</script>').repeat(900) ); // the positions of the unicode codepoint are important // our simd code for U16 is at 8 bytes, so we need to especially check the boundaries - assert.equal( - Html.escape`😊lalalalalala`, + expect(Html.escape`😊lalalalalala`).toBe( '😊lalala<script>alert(1)</script>lalala' ); - assert.equal( - Html.escape`${'' + 'lalala'}`, + expect(Html.escape`${'' + 'lalala'}`).toBe( '<script>😊alert(1)</script>lalala' ); - assert.equal( - Html.escape`lalala`, + expect(Html.escape`lalala`).toBe( '<script>alert(1)😊</script>lalala' ); - assert.equal( - Html.escape`😊lalala`, + expect(Html.escape`😊lalala`).toBe( '<script>alert(1)</script>😊lalala' ); - assert.equal( - Html.escape`lal😊ala`, + expect(Html.escape`lal😊ala`).toBe( '<script>alert(1)</script>lal😊ala' ); - assert.equal( - Html.escape`${'' + 'lal😊ala'.repeat(10)}`, + expect(Html.escape`${'' + 'lal😊ala'.repeat(10)}`).toBe( '<script>alert(1)</script>' + 'lal😊ala'.repeat(10) ); for (let i = 1; i < 10; i++) - assert.equal( - Html.escape`${'' + 'la😊'.repeat(i)}`, + expect(Html.escape`${'' + 'la😊'.repeat(i)}`).toBe( '<script>alert(1)</script>' + 'la😊'.repeat(i) ); - assert.equal( - Html.escape`${'la😊' + ''}`, + expect(Html.escape`${'la😊' + ''}`).toBe( 'la😊' + '<script>alert(1)</script>' ); - assert.equal( - Html.escape`${('lalala' + '😊').repeat(1)}`, + expect(Html.escape`${('lalala' + '😊').repeat(1)}`).toBe( ('lalala' + '<script>alert(1)</script>😊').repeat(1) ); - assert.equal(Html.escape`${'😊'.repeat(100)}`, '😊'.repeat(100)); - assert.equal(Html.escape`${'😊<'.repeat(100)}`, '😊<'.repeat(100)); - assert.equal(Html.escape`${'<😊>'.repeat(100)}`, '<😊>'.repeat(100)); - assert.equal(Html.escape`😊`, '😊'); - assert.equal(Html.escape`😊😊`, '😊😊'); - assert.equal(Html.escape`😊lo`, '😊lo'); - assert.equal(Html.escape`lo😊`, 'lo😊'); + expect(Html.escape`${'😊'.repeat(100)}`).toBe('😊'.repeat(100)); + expect(Html.escape`${'😊<'.repeat(100)}`).toBe('😊<'.repeat(100)); + expect(Html.escape`${'<😊>'.repeat(100)}`).toBe('<😊>'.repeat(100)); + expect(Html.escape`😊`).toBe('😊'); + expect(Html.escape`😊😊`).toBe('😊😊'); + expect(Html.escape`😊lo`).toBe('😊lo'); + expect(Html.escape`lo😊`).toBe('lo😊'); - assert.equal(Html.escape`${' '.repeat(32) + '😊'}`, ' '.repeat(32) + '😊'); - assert.equal(Html.escape`${' '.repeat(32) + '😊😊'}`, ' '.repeat(32) + '😊😊'); - assert.equal(Html.escape`${' '.repeat(32) + '😊lo'}`, ' '.repeat(32) + '😊lo'); - assert.equal(Html.escape`${' '.repeat(32) + 'lo😊'}`, ' '.repeat(32) + 'lo😊'); + expect(Html.escape`${' '.repeat(32) + '😊'}`).toBe(' '.repeat(32) + '😊'); + expect(Html.escape`${' '.repeat(32) + '😊😊'}`).toBe(' '.repeat(32) + '😊😊'); + expect(Html.escape`${' '.repeat(32) + '😊lo'}`).toBe(' '.repeat(32) + '😊lo'); + expect(Html.escape`${' '.repeat(32) + 'lo😊'}`).toBe(' '.repeat(32) + 'lo😊'); }); }); diff --git a/packages/html/test/escape.test.tsx b/packages/html/test/escape.test.tsx index 9e6b0cc2e..9a5d75fa6 100644 --- a/packages/html/test/escape.test.tsx +++ b/packages/html/test/escape.test.tsx @@ -1,20 +1,20 @@ -import assert from 'node:assert'; -import test, { describe } from 'node:test'; -import Html from '../index'; +import { describe, expect, test } from 'vitest'; +import * as Html from '../src/index.js'; const unsafeTag = ''; const safeTag = Html.escapeHtml(unsafeTag); describe('HTML Escaping', () => { test('escapes content', () => { - assert.equal(<>{unsafeTag}, <>{unsafeTag}); + expect(<>{unsafeTag}).toBe(<>{unsafeTag}); }); test('with children', () => { - assert.equal( + expect( <>
{unsafeTag}
- , + + ).toBe( <>
{unsafeTag}
@@ -22,10 +22,11 @@ describe('HTML Escaping', () => { }); test('escapes children', () => { - assert.equal( + expect( <>
{unsafeTag}
- , + + ).toBe( <>
{safeTag}
@@ -33,12 +34,13 @@ describe('HTML Escaping', () => { }); test('escapes deep children', () => { - assert.equal( + expect( <>
{unsafeTag}
- , + + ).toBe( <>
{Html.escapeHtml(
{unsafeTag}
)}
@@ -46,34 +48,31 @@ describe('HTML Escaping', () => { }); test('always escapes attributes', () => { - assert.equal( + expect( <>
\''}>
\'' }}>
\''}>
'">
-
-
-
+ ).toMatchInlineSnapshot( + `"
"` ); - assert.equal( + expect( <>
'`}>
'` }}>
'`}>
- , - `
` + + ).toMatchInlineSnapshot( + `"
"` ); }); test('handles unknown values', () => { - assert.equal(Html.escapeHtml(''), ''); - assert.equal(Html.escapeHtml({ a: 1 }), '[object Object]'); + expect(Html.escapeHtml('')).toBe(''); + expect(Html.escapeHtml({ a: 1 })).toBe('[object Object]'); }); // The matrix of cases we need to test for: @@ -86,118 +85,100 @@ describe('HTML Escaping', () => { // 7. Works when the text to escape is in the end // 8. Returns the same string when there's no need to escape test('always escapeHtml', () => { - assert.equal( - Html.escapeHtml('absolutely nothing to do here'), + expect(Html.escapeHtml('absolutely nothing to do here')).toBe( 'absolutely nothing to do here' ); - assert.equal( - Html.escapeHtml(''), + expect(Html.escapeHtml('')).toBe( '<script>alert(1)</script>' ); - assert.equal(Html.escapeHtml('<'), '<'); - assert.equal(Html.escapeHtml('>'), '>'); - assert.equal(Html.escapeHtml('&'), '&'); - assert.equal(Html.escapeHtml("'"), '''); - assert.equal(Html.escapeHtml('"'), '"'); - assert.equal(Html.escapeHtml('\n'), '\n'); - assert.equal(Html.escapeHtml('\r'), '\r'); - assert.equal(Html.escapeHtml('\t'), '\t'); - assert.equal(Html.escapeHtml('\f'), '\f'); - assert.equal(Html.escapeHtml('\v'), '\v'); - assert.equal(Html.escapeHtml('\b'), '\b'); - assert.equal(Html.escapeHtml('\u00A0'), '\u00A0'); - assert.equal(Html.escapeHtml('' + 'lalala'), + expect(Html.escapeHtml('<')).toBe('<'); + expect(Html.escapeHtml('>')).toBe('>'); + expect(Html.escapeHtml('&')).toBe('&'); + expect(Html.escapeHtml("'")).toBe('''); + expect(Html.escapeHtml('"')).toBe('"'); + expect(Html.escapeHtml('\n')).toBe('\n'); + expect(Html.escapeHtml('\r')).toBe('\r'); + expect(Html.escapeHtml('\t')).toBe('\t'); + expect(Html.escapeHtml('\f')).toBe('\f'); + expect(Html.escapeHtml('\v')).toBe('\v'); + expect(Html.escapeHtml('\b')).toBe('\b'); + expect(Html.escapeHtml('\u00A0')).toBe('\u00A0'); + expect(Html.escapeHtml('' + 'lalala')).toBe( 'lalala<script>alert(1)</script>lalala' ); - assert.equal( - Html.escapeHtml('' + 'lalala'), + expect(Html.escapeHtml('' + 'lalala')).toBe( '<script>alert(1)</script>lalala' ); - assert.equal( - Html.escapeHtml('lalala' + ''), + expect(Html.escapeHtml('lalala' + '')).toBe( 'lalala' + '<script>alert(1)</script>' ); - assert.equal(Html.escapeHtml('What does 😊 mean?'), 'What does 😊 mean?'); + expect(Html.escapeHtml('What does 😊 mean?')).toBe('What does 😊 mean?'); - assert.equal(Html.escapeHtml('What does 😊 mean in text?'), + expect(Html.escapeHtml('What does 😊 mean in text?')).toBe( '<div>What does 😊 mean in text?' ); - assert.equal( - Html.escapeHtml(('lalala' + '' + 'lalala').repeat(900)), - 'lalala<script>alert(1)</script>lalala'.repeat(900) - ); - assert.equal( - Html.escapeHtml(('' + 'lalala').repeat(900)), + expect( + Html.escapeHtml(('lalala' + '' + 'lalala').repeat(900)) + ).toBe('lalala<script>alert(1)</script>lalala'.repeat(900)); + expect(Html.escapeHtml(('' + 'lalala').repeat(900))).toBe( '<script>alert(1)</script>lalala'.repeat(900) ); - assert.equal( - Html.escapeHtml(('lalala' + '').repeat(900)), + expect(Html.escapeHtml(('lalala' + '').repeat(900))).toBe( ('lalala' + '<script>alert(1)</script>').repeat(900) ); // the positions of the unicode codepoint are important // our simd code for U16 is at 8 bytes, so we need to especially check the boundaries - assert.equal( - Html.escapeHtml('😊lalala' + '' + 'lalala'), + expect(Html.escapeHtml('😊lalala' + '' + 'lalala')).toBe( '😊lalala<script>alert(1)</script>lalala' ); - assert.equal( - Html.escapeHtml('' + 'lalala'), + expect(Html.escapeHtml('' + 'lalala')).toBe( '<script>😊alert(1)</script>lalala' ); - assert.equal( - Html.escapeHtml('' + 'lalala'), + expect(Html.escapeHtml('' + 'lalala')).toBe( '<script>alert(1)😊</script>lalala' ); - assert.equal( - Html.escapeHtml('' + '😊lalala'), + expect(Html.escapeHtml('' + '😊lalala')).toBe( '<script>alert(1)</script>😊lalala' ); - assert.equal( - Html.escapeHtml('' + 'lal😊ala'), + expect(Html.escapeHtml('' + 'lal😊ala')).toBe( '<script>alert(1)</script>lal😊ala' ); - assert.equal( - Html.escapeHtml('' + 'lal😊ala'.repeat(10)), + expect(Html.escapeHtml('' + 'lal😊ala'.repeat(10))).toBe( '<script>alert(1)</script>' + 'lal😊ala'.repeat(10) ); for (let i = 1; i < 10; i++) - assert.equal( - Html.escapeHtml('' + 'la😊'.repeat(i)), + expect(Html.escapeHtml('' + 'la😊'.repeat(i))).toBe( '<script>alert(1)</script>' + 'la😊'.repeat(i) ); - assert.equal( - Html.escapeHtml('la😊' + ''), + expect(Html.escapeHtml('la😊' + '')).toBe( 'la😊' + '<script>alert(1)</script>' ); - assert.equal( - Html.escapeHtml(('lalala' + '😊').repeat(1)), + expect(Html.escapeHtml(('lalala' + '😊').repeat(1))).toBe( ('lalala' + '<script>alert(1)</script>😊').repeat(1) ); - assert.equal(Html.escapeHtml('😊'.repeat(100)), '😊'.repeat(100)); - assert.equal(Html.escapeHtml('😊<'.repeat(100)), '😊<'.repeat(100)); - assert.equal(Html.escapeHtml('<😊>'.repeat(100)), '<😊>'.repeat(100)); - assert.equal(Html.escapeHtml('😊'), '😊'); - assert.equal(Html.escapeHtml('😊😊'), '😊😊'); - assert.equal(Html.escapeHtml('😊lo'), '😊lo'); - assert.equal(Html.escapeHtml('lo😊'), 'lo😊'); + expect(Html.escapeHtml('😊'.repeat(100))).toBe('😊'.repeat(100)); + expect(Html.escapeHtml('😊<'.repeat(100))).toBe('😊<'.repeat(100)); + expect(Html.escapeHtml('<😊>'.repeat(100))).toBe('<😊>'.repeat(100)); + expect(Html.escapeHtml('😊')).toBe('😊'); + expect(Html.escapeHtml('😊😊')).toBe('😊😊'); + expect(Html.escapeHtml('😊lo')).toBe('😊lo'); + expect(Html.escapeHtml('lo😊')).toBe('lo😊'); - assert.equal(Html.escapeHtml(' '.repeat(32) + '😊'), ' '.repeat(32) + '😊'); - assert.equal(Html.escapeHtml(' '.repeat(32) + '😊😊'), ' '.repeat(32) + '😊😊'); - assert.equal(Html.escapeHtml(' '.repeat(32) + '😊lo'), ' '.repeat(32) + '😊lo'); - assert.equal(Html.escapeHtml(' '.repeat(32) + 'lo😊'), ' '.repeat(32) + 'lo😊'); + expect(Html.escapeHtml(' '.repeat(32) + '😊')).toBe(' '.repeat(32) + '😊'); + expect(Html.escapeHtml(' '.repeat(32) + '😊😊')).toBe(' '.repeat(32) + '😊😊'); + expect(Html.escapeHtml(' '.repeat(32) + '😊lo')).toBe(' '.repeat(32) + '😊lo'); + expect(Html.escapeHtml(' '.repeat(32) + 'lo😊')).toBe(' '.repeat(32) + 'lo😊'); }); }); diff --git a/packages/html/test/hotwire-turbo.test.tsx b/packages/html/test/hotwire-turbo.test.tsx index 63b0b4f7a..ef545e317 100644 --- a/packages/html/test/hotwire-turbo.test.tsx +++ b/packages/html/test/hotwire-turbo.test.tsx @@ -1,63 +1,67 @@ -/// -// -import assert from 'node:assert'; -import { describe, it } from 'node:test'; +/// + +import { describe, expect, it } from 'vitest'; describe('Turbo', () => { it('should return turbo frames correctly', async () => { - assert.equal( - '', - + expect().toMatchInlineSnapshot( + `""` ); - assert.equal( - 'Show all expanded messages in this frame.
Show response from this form within this frame.
', + expect( Show all expanded messages in this frame.
Show response from this form within this frame.
+ ).toMatchInlineSnapshot( + `"Show all expanded messages in this frame.
Show response from this form within this frame.
"` ); - assert.equal( - 'Following link will replace just this frame.', + expect( Following link will replace just this frame. + ).toMatchInlineSnapshot( + `"Following link will replace just this frame."` ); - assert.equal( - 'Replace history with next page', + expect( Replace history with next page + ).toMatchInlineSnapshot( + `"Replace history with next page"` ); }); it('should render turbo streams correctly', async () => { - assert.equal( - '', + expect( + ).toMatchInlineSnapshot( + `""` ); - assert.equal( - '', + expect( + ).toMatchInlineSnapshot( + `""` ); - assert.equal( - '', + expect( + ).toMatchInlineSnapshot( + `""` ); }); }); diff --git a/packages/html/test/html-standards.test.tsx b/packages/html/test/html-standards.test.tsx index 0fd9c02ed..055b90a6a 100644 --- a/packages/html/test/html-standards.test.tsx +++ b/packages/html/test/html-standards.test.tsx @@ -1,14 +1,14 @@ -import assert from 'node:assert'; -import test, { describe } from 'node:test'; +import { describe, expect, test } from 'vitest'; describe('Expose correct html standards types', () => { test('Select', () => { - assert.equal( - '', + expect( + ).toMatchInlineSnapshot( + `""` ); }); }); diff --git a/packages/html/test/misc.test.tsx b/packages/html/test/misc.test.tsx index 34bdff82d..529c7444d 100644 --- a/packages/html/test/misc.test.tsx +++ b/packages/html/test/misc.test.tsx @@ -1,144 +1,126 @@ -/// - -import assert from 'node:assert'; -import test, { describe } from 'node:test'; +import { describe, expect, test } from 'vitest'; describe('Miscellaneous', () => { test('Htmx properties', () => { - assert.equal( - //@ts-expect-error - should warn about invalid property -
, - '
' + expect(
).toMatchInlineSnapshot( + `"
"` ); - assert.equal(
, '
'); - assert.equal(
, '
'); + expect(
).toMatchInlineSnapshot(`"
"`); + expect(
).toMatchInlineSnapshot( + `"
"` + ); }); test('Primitive values renders exactly like React', () => { - assert.equal(
{false}
,
); - assert.equal(
{null}
,
); - assert.equal(
{undefined}
,
); - assert.equal(
{0}
,
0
); - assert.equal(
{432}
,
432
); - assert.equal(
{NaN}
,
NaN
); - assert.equal(
{true}
,
); - assert.equal(
{Infinity}
,
Infinity
); - assert.equal(
{-Infinity}
,
-Infinity
); - assert.equal(
{[1, 2, 3]}
,
123
); + expect(
{false}
).toMatchInlineSnapshot(`"
"`); + expect(
{null}
).toMatchInlineSnapshot(`"
"`); + expect(
{undefined}
).toMatchInlineSnapshot(`"
"`); + expect(
{0}
).toMatchInlineSnapshot(`"
0
"`); + expect(
{432}
).toMatchInlineSnapshot(`"
432
"`); + expect(
{NaN}
).toMatchInlineSnapshot(`"
NaN
"`); + expect(
{true}
).toMatchInlineSnapshot(`"
"`); + expect(
{Infinity}
).toMatchInlineSnapshot(`"
Infinity
"`); + expect(
{-Infinity}
).toMatchInlineSnapshot(`"
-Infinity
"`); + expect(
{[1, 2, 3]}
).toMatchInlineSnapshot(`"
123
"`); - assert.equal( + expect(
{false} {false} -
, -
- ); - assert.equal( +
+ ).toMatchInlineSnapshot(`"
"`); + expect(
{null} {null} -
, -
- ); - assert.equal( + + ).toMatchInlineSnapshot(`"
"`); + expect(
{undefined} {undefined} -
, -
- ); - assert.equal( + + ).toMatchInlineSnapshot(`"
"`); + expect(
{0} {0} -
, -
00
- ); - assert.equal( + + ).toMatchInlineSnapshot(`"
00
"`); + expect(
{432} {432} -
, -
432432
- ); - assert.equal( + + ).toMatchInlineSnapshot(`"
432432
"`); + expect(
{NaN} {NaN} -
, -
NaNNaN
- ); - assert.equal( + + ).toMatchInlineSnapshot(`"
NaNNaN
"`); + expect(
{true} {true} -
, -
- ); - assert.equal( + + ).toMatchInlineSnapshot(`"
"`); + expect(
{Infinity} {Infinity} -
, -
InfinityInfinity
- ); - assert.equal( + + ).toMatchInlineSnapshot(`"
InfinityInfinity
"`); + expect(
{-Infinity} {-Infinity} -
, -
-Infinity-Infinity
- ); - assert.equal( + + ).toMatchInlineSnapshot(`"
-Infinity-Infinity
"`); + expect(
{[1, 2, 3]} {[1, 2, 3]} -
, -
123123
- ); + + ).toMatchInlineSnapshot(`"
123123
"`); // Bigint is the only case where it differs from React. // where React renders a empty string and we render the whole number. - assert.equal(
{123456789123456789n}
,
123456789123456789
); - assert.equal(<>{123456789123456789n}, <>123456789123456789); + expect(
{123456789123456789n}
).toMatchInlineSnapshot( + `"
123456789123456789
"` + ); + expect(<>{123456789123456789n}).toMatchInlineSnapshot(`"123456789123456789"`); }); test('Rendering objects throws', () => { - assert.throws( + expect( //@ts-expect-error - should warn about invalid child - () =>
{{}}
, - /Objects are not valid as a KitaJSX child/ - ); + () =>
{{}}
+ ).toThrow(/Objects are not valid as a KitaJSX child/); - assert.throws( + expect( //prettier-ignore //@ts-expect-error - should warn about invalid child - () => (
{{}} {{}}
), - /Objects are not valid as a KitaJSX child/ - ); + () => (
{{}} {{}}
) + ).toThrow(/Objects are not valid as a KitaJSX child/); }); test('Events', () => { - assert.equal( - '
', + expect(
+ ).toMatchInlineSnapshot( + `"
"` ); - assert.equal( - '
', + expect(
- ); + ).toMatchInlineSnapshot(`"
"`); - assert.equal( - '', - + expect().toMatchInlineSnapshot( + `""` ); }); }); diff --git a/packages/html/test/react.test.tsx b/packages/html/test/react.test.tsx index 541a0abb6..17af05260 100644 --- a/packages/html/test/react.test.tsx +++ b/packages/html/test/react.test.tsx @@ -1,6 +1,5 @@ -import assert from 'node:assert'; -import test, { describe } from 'node:test'; -import Html from '../index'; +import { describe, expect, test } from 'vitest'; +import * as Html from '../src/index.js'; const Header: Html.Component = ({ children, ...attributes }) => (

{children}

@@ -14,42 +13,43 @@ function Button({ children, ...attributes }: Html.PropsWithChildren) { ); } -function AssertChildren({ children, expect }: Html.PropsWithChildren<{ expect: any }>) { - assert.deepEqual(children, expect); +function AssertChildren({ + children, + expect: expectedChildren +}: Html.PropsWithChildren<{ expect: any }>) { + expect(children).toEqual(expectedChildren); return
{children}
; } describe('React integration', () => { test('react children', () => { - assert.equal( - '

Header Text', + expect( <>
Header Text + ).toMatchInlineSnapshot( + `"

Header Text"` ); }); test('React-style children', () => { - assert.equal( - '

Header Text

', + expect(
Header Text
- ); + ).toMatchInlineSnapshot(`"

Header Text

"`); - assert.equal( - '', - "` ); - assert.equal( - '', - + expect().toMatchInlineSnapshot( + `""` ); - assert.equal( + expect( <> @@ -65,28 +65,27 @@ describe('React integration', () => { , '1',
]}>
1
- , - '
' + - '
' + - '
' + - '
1
' + - '
1 2
' + - '
' + - '
1
' + + ).toMatchInlineSnapshot( + `"
1
1 2
1
"` ); }); test('React-style className', () => { - assert.equal(
, '
'); - assert.equal(
, '
'); - assert.equal(
, '
'); - assert.equal(
, '
'); + expect(
).toMatchInlineSnapshot(`"
"`); + expect(
).toMatchInlineSnapshot(`"
"`); + expect(
).toMatchInlineSnapshot( + `"
"` + ); + expect(
).toMatchInlineSnapshot( + `"
"` + ); }); test('Reserved `key` attribute', () => { function Test({ key }: { key: number }) { // ensure the below component call does not passed key - assert.equal(key, undefined); + expect(key).toBe(undefined); return (
{ ); } - assert.equal( + expect( , - '
' - ); + /> + ).toMatchInlineSnapshot(`"
"`); }); }); diff --git a/packages/html/test/register.test.tsx b/packages/html/test/register.test.tsx deleted file mode 100644 index 7f07c294c..000000000 --- a/packages/html/test/register.test.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import assert from 'node:assert'; -import test, { describe } from 'node:test'; -import HtmlModule from '../index'; - -describe('Global instance', () => { - test('registers Html to the global namespace', async () => { - // This should not be defined yet - assert.equal(typeof Html, 'undefined'); - - // Avoids printing warnings - const previous = process.env.NODE_NO_WARNINGS; - process.env.NODE_NO_WARNINGS = '1'; - - // Adds Html to the global namespace - await import('../register'); - - process.env.NODE_NO_WARNINGS = previous; - - // Literally the same object - assert.equal(typeof Html, 'object'); - assert.deepStrictEqual(Html, HtmlModule.Html); - - // @ts-expect-error - Delete globalThis to test that it is added - delete globalThis.Html; - - // Should be the same as the start of this test - assert.equal(typeof Html, 'undefined'); - }); -}); diff --git a/packages/html/test/runtime.test.tsx b/packages/html/test/runtime.test.tsx index f99d16b5d..32b8ac877 100644 --- a/packages/html/test/runtime.test.tsx +++ b/packages/html/test/runtime.test.tsx @@ -1,8 +1,6 @@ -import test, { describe } from 'node:test'; - -import assert from 'node:assert'; -import { createElement, h } from '../'; -import { jsx, jsxs } from '../jsx-runtime'; +import { describe, expect, test } from 'vitest'; +import { createElement, h } from '../src/index.js'; +import { jsx, jsxs } from '../src/jsx-runtime.js'; describe('Runtime behavior of JSX', () => { test('createElement', () => { @@ -14,94 +12,95 @@ describe('Runtime behavior of JSX', () => { return Promise.resolve('
1
'); } - assert.strictEqual(createElement, h); + expect(createElement).toBe(h); // children - assert.equal( - createElement('div', { id: 'test' }, 'Hello'), - '
Hello
' + expect(createElement('div', { id: 'test' }, 'Hello')).toMatchInlineSnapshot( + `"
Hello
"` ); // no children - assert.equal(createElement('div', { id: 'test' }), '
'); + expect(createElement('div', { id: 'test' })).toMatchInlineSnapshot( + `"
"` + ); // no attributes - assert.equal(createElement('div', null), '
'); + expect(createElement('div', null)).toMatchInlineSnapshot(`"
"`); // render Component - assert.equal(createElement(Component, null), '
'); - assert.equal(createElement(Component, {}, 'child'), '
child
'); - assert.equal( - createElement(Component, null, 'child ', 'child2'), - '
child child2
' + expect(createElement(Component, null)).toMatchInlineSnapshot(`"
"`); + expect(createElement(Component, {}, 'child')).toMatchInlineSnapshot( + `"
child
"` + ); + expect(createElement(Component, null, 'child ', 'child2')).toMatchInlineSnapshot( + `"
child child2
"` ); - assert.equal( - createElement(Component, {}, 'child ', 'child2'), - '
child child2
' + expect(createElement(Component, {}, 'child ', 'child2')).toMatchInlineSnapshot( + `"
child child2
"` ); // render tag - assert.equal( - createElement('tag', { of: 'custom-html-tag' }), - '' + expect(createElement('tag', { of: 'custom-html-tag' })).toMatchInlineSnapshot( + `""` ); // render async Component - assert.ok( + expect( createElement('div', null, createElement(AsyncComponent, null)) instanceof Promise - ); + ).toBeTruthy(); // void element - assert.equal(createElement('meta', null), ''); + expect(createElement('meta', null)).toMatchInlineSnapshot(`""`); }); test('jsx', () => { function Component(attrs: any) { - assert.deepStrictEqual(attrs.children, 'Hello'); + expect(attrs.children).toEqual('Hello'); return 'Hello'; } // child - assert.equal( - jsx('div', { id: 'test', children: 'Hello' }), - '
Hello
' + expect(jsx('div', { id: 'test', children: 'Hello' })).toMatchInlineSnapshot( + `"
Hello
"` ); // no child - assert.equal(jsx('div', { id: 'test' }), '
'); + expect(jsx('div', { id: 'test' })).toMatchInlineSnapshot(`"
"`); // no attributes - assert.equal(jsx('div', {}), '
'); + expect(jsx('div', {})).toMatchInlineSnapshot(`"
"`); // render tag - assert.equal( - jsx('tag', { of: 'custom-html-tag' }), - '' + expect(jsx('tag', { of: 'custom-html-tag' })).toMatchInlineSnapshot( + `""` ); // Single child - assert.equal(jsx(Component, { id: 'test', children: 'Hello' }), 'Hello'); + expect(jsx(Component, { id: 'test', children: 'Hello' })).toBe('Hello'); }); test('jsxs', () => { function Component(attrs: any) { - assert.deepStrictEqual(attrs.children, ['Hello']); + expect(attrs.children).toEqual(['Hello']); return 'Hello'; } // child - assert.equal( - jsxs('div', { id: 'test', children: ['Hello'] }), - '
Hello
' + expect(jsxs('div', { id: 'test', children: ['Hello'] })).toMatchInlineSnapshot( + `"
Hello
"` ); // epmty childrens - assert.equal(jsxs('div', { id: 'test', children: [] }), '
'); + expect(jsxs('div', { id: 'test', children: [] })).toMatchInlineSnapshot( + `"
"` + ); // void element - assert.equal(jsxs('meta', { children: [] }), ''); + expect(jsxs('meta', { children: [] })).toMatchInlineSnapshot(`""`); // Array children - assert.equal(jsxs(Component, { id: 'test', children: ['Hello'] }), ['Hello']); + expect(jsxs(Component, { id: 'test', children: ['Hello'] })).toMatchInlineSnapshot( + `"Hello"` + ); }); }); diff --git a/packages/html/test/simple-html.test.tsx b/packages/html/test/simple-html.test.tsx index 05ad4535c..9de414095 100644 --- a/packages/html/test/simple-html.test.tsx +++ b/packages/html/test/simple-html.test.tsx @@ -1,52 +1,58 @@ -import assert from 'node:assert'; -import test, { describe } from 'node:test'; +import { describe, expect, test } from 'vitest'; describe('Html structures', () => { test('simple html structures', () => { - assert.equal(a link, 'a link'); + expect(a link).toMatchInlineSnapshot( + `"a link"` + ); - assert.equal( - `
  • 1
  • 2
`, + expect(
    {[1, 2].map((li) => (
  • {li}
  • ))}
- ); + ).toMatchInlineSnapshot(`"
  • 1
  • 2
"`); - assert.equal( - '', - + expect().toMatchInlineSnapshot( + `""` ); - assert.equal('
',
); + expect(
).toMatchInlineSnapshot( + `"
"` + ); - assert.equal( - '', + expect( + ).toMatchInlineSnapshot( + `""` ); }); test('untyped & unknown attributes', () => { - assert.equal(, ''); - assert.equal(, ''); - assert.equal(, ''); - assert.equal(, ''); + expect().toMatchInlineSnapshot(`""`); + //@ts-expect-error - should allow unknown attributes + expect().toMatchInlineSnapshot(`""`); + //@ts-expect-error - should allow unknown attributes + expect().toMatchInlineSnapshot(`""`); + //@ts-expect-error - should allow unknown attributes + expect().toMatchInlineSnapshot(`""`); function D() { return
; } // @ts-expect-error - should complain about unknown tag on component and not render it - assert.equal(, '
'); + expect().toMatchInlineSnapshot(`"
"`); }); test('simple svg structure', () => { - assert.equal( + expect( - , - '' + + ).toMatchInlineSnapshot( + `""` ); }); }); diff --git a/packages/html/test/style.test.tsx b/packages/html/test/style.test.tsx index 4b3843e1a..98abb0e3f 100644 --- a/packages/html/test/style.test.tsx +++ b/packages/html/test/style.test.tsx @@ -1,27 +1,26 @@ -import assert from 'node:assert'; -import test, { describe } from 'node:test'; -import { styleToString } from '../index'; +import { describe, expect, test } from 'vitest'; +import { styleToString } from '../src/index.js'; describe('Style', () => { test('camel case property', () => { - assert.equal( + expect( <>
- , - '
' + + ).toMatchInlineSnapshot( + `"
"` ); }); test('accepts undefined', () => { - assert.equal( -
, - '
' + expect(
).toMatchInlineSnapshot( + `"
"` ); - assert.equal(
, '
'); + expect(
).toMatchInlineSnapshot(`"
"`); }); test('CSSProperties', () => { @@ -31,19 +30,20 @@ describe('Style', () => { not: 'defined' }; - assert.equal(
, '
'); + expect(
).toMatchInlineSnapshot( + `"
"` + ); }); test('Weird values', () => { - assert.equal( + expect( styleToString({ a: 0, b: undefined, c: 1, d: '2', e: { f: 3 } - }), - 'a:0;c:1;d:2;e:[object Object];' - ); + }) + ).toBe('a:0;c:1;d:2;e:[object Object];'); }); }); diff --git a/packages/html/test/suspense.test.tsx b/packages/html/test/suspense.test.tsx index 8a1c4e593..4a34a884f 100644 --- a/packages/html/test/suspense.test.tsx +++ b/packages/html/test/suspense.test.tsx @@ -1,10 +1,9 @@ import { JSDOM } from 'jsdom'; -import assert from 'node:assert'; import { text } from 'node:stream/consumers'; -import { afterEach, describe, it, mock, test } from 'node:test'; import { setImmediate, setTimeout } from 'node:timers/promises'; -import Html, { type PropsWithChildren } from '../index'; -import { Suspense, SuspenseScript, renderToStream } from '../suspense'; +import { afterEach, describe, expect, it, test, vi } from 'vitest'; +import { Html, type PropsWithChildren } from '../src/index.js'; +import { Suspense, SuspenseScript, renderToStream } from '../src/suspense.js'; async function SleepForMs({ ms, children }: PropsWithChildren<{ ms: number }>) { await setTimeout(ms * 50); @@ -17,7 +16,7 @@ function Throw(): string { // Detect leaks of pending promises afterEach(() => { - assert.equal(SUSPENSE_ROOT.requests.size, 0, 'Suspense root left pending requests'); + expect(SUSPENSE_ROOT.requests.size).toBe(0); // Reset suspense root SUSPENSE_ROOT.autoScript = true; @@ -27,33 +26,33 @@ afterEach(() => { describe('Suspense', () => { test('Sync without suspense', async () => { - assert.equal(await text(renderToStream(() =>
)),
); + expect(await text(renderToStream(() =>
))).toBe(
); - assert.equal(await text(renderToStream(async () =>
)),
); + expect(await text(renderToStream(async () =>
))).toBe(
); }); test('Suspense sync children', async () => { - assert.equal( + expect( await text( renderToStream((r) => ( 1
}>
2
)) - ), -
2
- ); + ) + ).toBe(
2
); }); test('Suspense async children', async () => { - assert.equal( + expect( await text( renderToStream((r) => ( 1
}> )) - ), + ) + ).toBe( <>
1
@@ -72,14 +71,15 @@ describe('Suspense', () => { }); test('Suspense async children & fallback', async () => { - assert.equal( + expect( await text( renderToStream((r) => ( 1
)}> )) - ), + ) + ).toBe( <>
1
@@ -98,14 +98,15 @@ describe('Suspense', () => { }); test('Suspense async fallback sync children', async () => { - assert.equal( + expect( await text( renderToStream((r) => ( 1
)}>
2
)) - ), + ) + ).toBe( <>
2
@@ -124,8 +125,7 @@ describe('Suspense', () => { ); }) ).then((res) => { - assert.equal( - res, + expect(res).toBe( <>
1
@@ -148,14 +148,15 @@ describe('Suspense', () => { test('Multiple sync renders cleanup', async () => { for (let i = 0; i < 10; i++) { - assert.equal( + expect( await text( renderToStream((r) => ( 1
)}> )) - ), + ) + ).toBe( <>
1
@@ -175,7 +176,7 @@ describe('Suspense', () => { }); test('Multiple children', async () => { - assert.equal( + expect( await text( renderToStream((r) => (
@@ -192,7 +193,8 @@ describe('Suspense', () => {
)) - ), + ) + ).toBe( <>
@@ -260,8 +262,7 @@ describe('Suspense', () => { //@ts-expect-error - testing invalid promises const seconds = +promises[index]!.seconds; - assert.strictEqual( - result, + expect(result).toBe( <>
{Array.from({ length: seconds }, (_, i) => ( @@ -290,26 +291,26 @@ describe('Suspense', () => { it('ensures autoScript works', async () => { // Sync does not needs autoScript - assert.equal( + expect( await text( renderToStream((r) => ( 1
}>
2
)) - ), -
2
- ); + ) + ).toBe(
2
); // Async renders SuspenseScript - assert.equal( + expect( await text( renderToStream((r) => ( 1
}> {Promise.resolve(
2
)} )) - ), + ) + ).toBe( <>
1
@@ -330,14 +331,15 @@ describe('Suspense', () => { SUSPENSE_ROOT.autoScript = false; // Async renders SuspenseScript - assert.equal( + expect( await text( renderToStream((r) => ( 1
}> {Promise.resolve(
2
)} )) - ), + ) + ).toBe( <>
1
@@ -361,10 +363,10 @@ describe('Suspense', () => {
)); - assert(stream.readable); + expect(stream.readable).toBeTruthy(); // emits end event - const fn = mock.fn(); + const fn = vi.fn(); stream.on('end', fn); const chunks = []; @@ -373,11 +375,10 @@ describe('Suspense', () => { chunks.push(chunk); } - assert.equal(fn.mock.calls.length, 1); - assert.equal(chunks.length, 2); + expect(fn.mock.calls.length).toBe(1); + expect(chunks.length).toBe(2); - assert.equal( - chunks[0].toString(), + expect(chunks[0].toString()).toBe(
2
@@ -385,8 +386,7 @@ describe('Suspense', () => {
); - assert.equal( - chunks[1].toString(), + expect(chunks[1].toString()).toBe( <> {SuspenseScript} @@ -403,39 +403,38 @@ describe('Suspense', () => { test('renderToStream without suspense', async () => { const stream = renderToStream(() => '
not suspense
', 1227); - assert.ok(stream.readable); + expect(stream.readable).toBeTruthy(); const data = stream.read(); - assert.equal(data.toString(), '
not suspense
'); + expect(data.toString()).toBe('
not suspense
'); - assert.equal(await text(stream), ''); + expect(await text(stream)).toBe(''); - assert.ok(stream.closed); + expect(stream.closed).toBeTruthy(); }); it('tests suspense without children', async () => { - assert.equal( + expect( await text( renderToStream((r) => ( //@ts-expect-error - testing invalid children 1
}> )) - ), - '' - ); + ) + ).toBe(''); }); it('works with async error handlers', async () => { - assert.equal( + expect( await text( renderToStream((r) => ( 1
} catch={Promise.resolve(
2
)}> {Promise.reject(
3
)} )) - ), - + ) + ).toBe( <>
1
@@ -454,7 +453,7 @@ describe('Suspense', () => { }); it('works with deep suspense calls', async () => { - assert.equal( + expect( await text( renderToStream((rid) => { return ( @@ -478,7 +477,8 @@ describe('Suspense', () => {
); }) - ), + ) + ).toBe( <>
@@ -513,7 +513,7 @@ describe('Suspense', () => { }); it('works with deep suspense calls resolving first', async () => { - assert.equal( + expect( await text( renderToStream((rid) => { return ( @@ -537,7 +537,8 @@ describe('Suspense', () => {
); }) - ), + ) + ).toBe( <>
@@ -594,8 +595,7 @@ describe('Suspense', () => { )) ); - assert.equal( - html, + expect(html).toBe( <>
@@ -705,8 +705,9 @@ describe('Suspense', () => { ); // tests with final html result - assert.equal( - new JSDOM(html, { runScripts: 'dangerously' }).window.document.body.innerHTML, + expect( + new JSDOM(html, { runScripts: 'dangerously' }).window.document.body.innerHTML + ).toBe( <>
Outer 0!
@@ -753,8 +754,7 @@ describe('Suspense', () => { )) ); - assert.equal( - html, + expect(html).toBe( <>
@@ -799,9 +799,9 @@ describe('Suspense', () => { )) ); - assert.fail('should throw'); + throw new Error('should throw'); } catch (error) { - assert.equal(error, 'Fallback!'); + expect(error).toBe('Fallback!'); } }); }); @@ -815,8 +815,7 @@ describe('Suspense errors', () => { ); - assert.equal( - outside, + expect(outside).toBe(
1
@@ -824,10 +823,10 @@ describe('Suspense errors', () => { const requestData = SUSPENSE_ROOT.requests.get(1); - assert.equal(requestData?.running, 1); - assert.equal(requestData?.sent, false); + expect(requestData?.running).toBe(1); + expect(requestData?.sent).toBe(false); } finally { - assert.ok(SUSPENSE_ROOT.requests.has(1)); + expect(SUSPENSE_ROOT.requests.has(1)).toBeTruthy(); // cleans up SUSPENSE_ROOT.requests.delete(1); @@ -835,16 +834,15 @@ describe('Suspense errors', () => { }); it('tests sync errors are thrown', async () => { - await assert.rejects( + await expect( text( renderToStream((r) => ( fallback
}> )) - ), - /test/ - ); + ) + ).rejects.toThrow(/test/); }); it('test sync errors after suspense', async () => { @@ -866,9 +864,9 @@ describe('Suspense errors', () => { )) ); - assert.fail('should throw'); + throw new Error('should throw'); } catch (error: any) { - assert.equal(error.message, 'test'); + expect(error.message).toBe('test'); } }); @@ -884,9 +882,9 @@ describe('Suspense errors', () => { )) ); - assert.fail('should throw'); + throw new Error('should throw'); } catch (error) { - assert.equal(error, err); + expect(error).toBe(err); } }); @@ -902,17 +900,16 @@ describe('Suspense errors', () => { try { for await (const data of stream) { // Second stream would be the suspense result, which errors out - assert.equal( - data.toString(), + expect(data.toString()).toBe(
1
); } - assert.fail('should throw'); + throw new Error('should throw'); } catch (error) { - assert.equal(error, err); + expect(error).toBe(err); } }); @@ -920,14 +917,14 @@ describe('Suspense errors', () => { const err = new Error('component failed'); // Sync does not needs autoScript - assert.equal( + expect( await text( renderToStream((r) => ( 1
} catch={(err2) => { - assert.equal(err2, err); + expect(err2).toBe(err); return
3
; }} @@ -935,7 +932,8 @@ describe('Suspense errors', () => { {Promise.reject(err)} )) - ), + ) + ).toBe( <>
1
@@ -953,29 +951,29 @@ describe('Suspense errors', () => { }); it('throws when rid is not provided', async () => { - await assert.rejects( + await expect( text( renderToStream(() => ( //@ts-expect-error 1
}>{Promise.resolve('123')} )) - ), - /Error: Suspense requires a `rid` to be specified./ - ); + ) + ).rejects.toThrow(/Suspense requires a `rid` to be specified./); }); it('tests suspense with error boundary', async () => { const err = new Error('component failed'); // Sync does not needs autoScript - assert.equal( + expect( await text( renderToStream((r) => ( 1
} catch={
3
}> {Promise.reject(err)} )) - ), + ) + ).toBe( <>
1
@@ -1015,8 +1013,7 @@ describe('Suspense errors', () => { await new Promise((res) => rendered.once('close', res)); - assert.equal( - firstChunk.toString(), + expect(firstChunk.toString()).toBe(
1
@@ -1026,7 +1023,7 @@ describe('Suspense errors', () => { // The error below would be thrown: // Error [ERR_STREAM_PUSH_AFTER_EOF]: stream.push() after EOF - assert.equal(await text(rendered), ''); + expect(await text(rendered)).toBe(''); }); it('does not allows to use the same rid', async () => { @@ -1042,15 +1039,13 @@ describe('Suspense errors', () => { const stream = renderToStream(render, 1); - await assert.rejects( - text(renderToStream(render, 1)), - /Error: The provided Request Id is already in use: 1./ + await expect(text(renderToStream(render, 1))).rejects.toThrow( + /The provided Request Id is already in use: 1./ ); const html = await text(stream); - assert.equal( - html, + expect(html).toBe( <>
1
@@ -1076,9 +1071,9 @@ describe('Suspense errors', () => { try { await text(stream); - assert.fail('should throw'); + throw new Error('should throw'); } catch (error: any) { - assert.equal(error.message, 'Factory error'); + expect(error.message).toBe('Factory error'); } }); }); diff --git a/packages/html/test/tags.test.tsx b/packages/html/test/tags.test.tsx index 75c0d4323..aa1f06292 100644 --- a/packages/html/test/tags.test.tsx +++ b/packages/html/test/tags.test.tsx @@ -1,69 +1,71 @@ -import assert from 'node:assert'; -import test, { describe } from 'node:test'; +import { describe, expect, test } from 'vitest'; describe('Tags', () => { test('Self-closing html tags', () => { - assert.equal('', ); + expect().toMatchInlineSnapshot(`""`); - assert.equal('
',
); + expect(
).toMatchInlineSnapshot(`"
"`); - assert.equal('
content',
content); + expect(
content).toMatchInlineSnapshot(`"
content"`); - assert.equal('', ); + expect().toMatchInlineSnapshot( + `""` + ); - assert.equal('', ); + expect().toMatchInlineSnapshot(`""`); //@ts-expect-error - invalid type - assert.equal('', ); + expect().toMatchInlineSnapshot( + `""` + ); //@ts-expect-error - invalid type - assert.equal('', ); + expect().toMatchInlineSnapshot( + `""` + ); }); test('custom tag', () => { - assert.equal(, '
'); + expect().toMatchInlineSnapshot(`"
"`); - assert.equal(, '
'); - assert.equal( + expect().toMatchInlineSnapshot(`"
"`); + expect(
-
, - '
' - ); +
+ ).toMatchInlineSnapshot(`"
"`); - assert.equal( + expect( 1 - , - '
1
' - ); +
+ ).toMatchInlineSnapshot(`"
1
"`); - assert.equal( + expect( {' '} - , - '
' - ); + + ).toMatchInlineSnapshot(`"
"`); }); test('custom void tag', () => { - assert.equal(, ''); + expect().toMatchInlineSnapshot(`""`); - assert.equal(, ''); + expect().toMatchInlineSnapshot(`""`); - assert.equal( + expect( 1 - , - '1' - ); + + ).toMatchInlineSnapshot(`"1"`); - assert.equal( + expect( {' '} - , - ' ' - ); + + ).toMatchInlineSnapshot(`" "`); - assert.equal(, ''); + expect().toMatchInlineSnapshot( + `""` + ); }); }); diff --git a/packages/html/test/util.test.ts b/packages/html/test/util.test.ts index 9c668147d..cd31d12c7 100644 --- a/packages/html/test/util.test.ts +++ b/packages/html/test/util.test.ts @@ -1,10 +1,9 @@ -import assert from 'node:assert'; -import { describe, test } from 'node:test'; -import Html from '../index'; +import { describe, expect, test } from 'vitest'; +import { Html } from '../src/index.js'; describe('Util', () => { test('Undefined contents', async () => { - assert.equal( + expect( await Html.contentsToString([ undefined, Promise.resolve(undefined), @@ -13,9 +12,8 @@ describe('Util', () => { Promise.resolve(null), [null, Promise.resolve(null)], [[[[[[[]]]]]]] - ]), - '' - ); + ]) + ).toBe(''); for (const i of [ undefined, @@ -26,19 +24,18 @@ describe('Util', () => { [null, Promise.resolve(null)], [[[[[[[]]]]]]] ]) { - assert.equal(await Html.contentToString(i), ''); + expect(await Html.contentToString(i)).toBe(''); } - assert.equal(await Html.contentsToString([]), ''); + expect(await Html.contentsToString([])).toBe(''); }); test('Deep scaping', async () => { - assert.equal( - await Html.contentsToString(['<>', Promise.resolve('<>')], true), + expect(await Html.contentsToString(['<>', Promise.resolve('<>')], true)).toBe( '<><>' ); - assert.equal( + expect( await Html.contentsToString( [ undefined, @@ -50,24 +47,22 @@ describe('Util', () => { [[[[[[['<>']]]]]]] ], true - ), - '<>' - ); + ) + ).toBe('<>'); }); test('String contents', async () => { - assert.equal( + expect( await Html.contentsToString([ 'a', Promise.resolve('b'), ['c', Promise.resolve('d')] - ]), - 'abcd' - ); + ]) + ).toBe('abcd'); }); test('Only string contents', async () => { - assert.equal(await Html.contentsToString(['a', 'b', ['c', 'd']]), 'abcd'); + expect(await Html.contentsToString(['a', 'b', ['c', 'd']])).toBe('abcd'); }); test('Promises', async () => { @@ -77,11 +72,11 @@ describe('Util', () => { Promise.resolve(['c', Promise.resolve('d')]) ]); - assert.ok(result instanceof Promise); - assert.equal(await result, 'abcd'); + expect(result instanceof Promise).toBeTruthy(); + expect(await result).toBe('abcd'); }); test('h() function', async () => { - assert.equal(Html.h, Html.createElement); + expect(Html.h).toBe(Html.createElement); }); }); diff --git a/packages/html/tsconfig.build.json b/packages/html/tsconfig.build.json new file mode 100644 index 000000000..ed84364ea --- /dev/null +++ b/packages/html/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "noEmit": false, + "outDir": "./dist", + "rootDir": "./src", + "tsBuildInfoFile": "dist/.tsbuildinfo" + }, + "include": ["src"] +} diff --git a/packages/html/tsconfig.json b/packages/html/tsconfig.json index 3833b5846..cbe7f4e7d 100644 --- a/packages/html/tsconfig.json +++ b/packages/html/tsconfig.json @@ -1,38 +1,9 @@ { + "extends": "../../tsconfig.json", "compilerOptions": { - "target": "ESNext", "jsx": "react-jsx", - "jsxImportSource": "..", - "plugins": [{ "name": "@kitajs/ts-html-plugin" }], - "module": "CommonJS", - "moduleResolution": "node", - "incremental": true, - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitAny": true, - "strictNullChecks": true, - "declaration": true, - "importHelpers": true, - "declarationMap": true, - "sourceMap": true, - "strictFunctionTypes": true, - "strictBindCallApply": true, - "strictPropertyInitialization": true, - "noImplicitThis": true, - "useUnknownInCatchVariables": true, - "alwaysStrict": true, - "outDir": "dist", - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedIndexedAccess": true, - "noImplicitOverride": true, - "skipDefaultLibCheck": true + "jsxImportSource": "self", + "outDir": "./dist" }, - "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.d.ts", "node_modules/csstype"], - "exclude": ["node_modules", "dist", "coverage", "benchmarks"] + "include": ["src", "test"] } diff --git a/packages/ts-html-plugin/package.json b/packages/ts-html-plugin/package.json index f611a07f2..8705731b4 100644 --- a/packages/ts-html-plugin/package.json +++ b/packages/ts-html-plugin/package.json @@ -21,10 +21,9 @@ }, "scripts": { "build": "tsgo -p tsconfig.build.json", - "dev": "tsgo -p tsconfig.build.json --watch", "prepack": "npm run build", - "test": "pnpm build && pnpm install && pnpm test-exec", - "test-exec": "node --require @swc-node/register --test test/**/*.test.ts" + "pretest": "npm run build", + "test": "vitest --coverage --typecheck --run" }, "dependencies": { "chalk": "^5.6.2", @@ -32,16 +31,16 @@ "yargs": "^18.0.0" }, "devDependencies": { - "@swc-node/register": "catalog:", - "@swc/helpers": "catalog:", "@types/node": "catalog:", "@types/yargs": "^17.0.35", "@typescript/native-preview": "catalog:", + "@vitest/coverage-v8": "catalog:", "fast-defer": "^1.1.9", - "self": "file:" + "self": "link:", + "vitest": "catalog:" }, "peerDependencies": { - "@kitajs/html": "workspace:^4.2.10", - "typescript": "^5.6.2" + "@kitajs/html": "workspace:^", + "typescript": "catalog:" } } diff --git a/packages/ts-html-plugin/src/index.ts b/packages/ts-html-plugin/src/index.ts index e34ea3730..f8a4ed71d 100644 --- a/packages/ts-html-plugin/src/index.ts +++ b/packages/ts-html-plugin/src/index.ts @@ -1,7 +1,7 @@ import type { default as TS, server } from 'typescript/lib/tsserverlibrary'; import { proxyObject, recursiveDiagnoseJsxElements } from './util'; -export = function initHtmlPlugin(modules: { typescript: typeof TS }) { +module.exports = function (modules: { typescript: typeof TS }) { const ts = modules.typescript; return { diff --git a/packages/ts-html-plugin/test/arrays.test.ts b/packages/ts-html-plugin/test/arrays.test.ts index 2deb8d117..99bcf9b09 100644 --- a/packages/ts-html-plugin/test/arrays.test.ts +++ b/packages/ts-html-plugin/test/arrays.test.ts @@ -1,12 +1,11 @@ -import assert from 'node:assert'; -import { it } from 'node:test'; +import { expect, it } from 'vitest'; import { TSLangServer } from './util/lang-server'; it('Lists and arrays can be used normally', async () => { await using server = new TSLangServer(__dirname); const diagnostics = await server.openWithDiagnostics /* tsx */ ` - const list: JSX.Element[] = []; + const list: JSX.Element[] = []; export default ( <> @@ -15,5 +14,5 @@ it('Lists and arrays can be used normally', async () => { ); `; - assert.deepStrictEqual(diagnostics.body, []); + expect(diagnostics.body).toEqual([]); }); diff --git a/packages/ts-html-plugin/test/children.test.ts b/packages/ts-html-plugin/test/children.test.ts index 8c36b2236..60a8750e0 100644 --- a/packages/ts-html-plugin/test/children.test.ts +++ b/packages/ts-html-plugin/test/children.test.ts @@ -1,5 +1,4 @@ -import assert from 'node:assert'; -import { it } from 'node:test'; +import { expect, it } from 'vitest'; import { TSLangServer } from './util/lang-server'; it('Ensure PropsWithChildren works as normal', async () => { @@ -9,23 +8,23 @@ it('Ensure PropsWithChildren works as normal', async () => { export interface Extension extends PropsWithChildren { user?: { name: string }; } - + export function Test({ children }: Extension) { return
{children}
; } - + export function Test2(props: Extension) { return
{props.children}
; } - + export function Test3({ children }: PropsWithChildren) { return
{children}
; } - + export function Test4(props: PropsWithChildren) { return
{props.children}
; } - + export function Test5(props?: PropsWithChildren) { return
{props?.children}
; } @@ -49,5 +48,5 @@ it('Ensure PropsWithChildren works as normal', async () => { ); `; - assert.deepStrictEqual(diagnostics.body, []); + expect(diagnostics.body).toEqual([]); }); diff --git a/packages/ts-html-plugin/test/component-xss.test.ts b/packages/ts-html-plugin/test/component-xss.test.ts index b327c3584..046eda386 100644 --- a/packages/ts-html-plugin/test/component-xss.test.ts +++ b/packages/ts-html-plugin/test/component-xss.test.ts @@ -1,5 +1,4 @@ -import assert from 'node:assert'; -import { it } from 'node:test'; +import { expect, it } from 'vitest'; import { ComponentXss } from '../src/errors'; import { TSLangServer } from './util/lang-server'; @@ -38,7 +37,7 @@ it('Ensure children are safe', async () => { ); `; - assert.deepStrictEqual(diagnostics.body, [ + expect(diagnostics.body).toEqual([ { start: { line: 39, offset: 23 }, end: { line: 39, offset: 24 }, @@ -100,7 +99,7 @@ it('Ensure children are safe using "e" tag function', async () => ); `; - assert.deepStrictEqual(diagnostics.body, [ + expect(diagnostics.body).toEqual([ { start: { line: 39, offset: 23 }, end: { line: 39, offset: 24 }, diff --git a/packages/ts-html-plugin/test/double-escape.test.ts b/packages/ts-html-plugin/test/double-escape.test.ts index 84bc75eeb..0458c7a81 100644 --- a/packages/ts-html-plugin/test/double-escape.test.ts +++ b/packages/ts-html-plugin/test/double-escape.test.ts @@ -1,5 +1,4 @@ -import assert from 'node:assert'; -import { it } from 'node:test'; +import { expect, it } from 'vitest'; import { DoubleEscape } from '../src/errors'; import { TSLangServer } from './util/lang-server'; @@ -23,7 +22,7 @@ it('Avoid escaping twice', async () => { ); `; - assert.deepStrictEqual(diagnostics.body, [ + expect(diagnostics.body).toEqual([ { start: { line: 36, offset: 14 }, end: { line: 36, offset: 18 }, diff --git a/packages/ts-html-plugin/test/operators.test.ts b/packages/ts-html-plugin/test/operators.test.ts index 803cf6634..dec8790ae 100644 --- a/packages/ts-html-plugin/test/operators.test.ts +++ b/packages/ts-html-plugin/test/operators.test.ts @@ -1,5 +1,4 @@ -import assert from 'node:assert'; -import { it } from 'node:test'; +import { expect, it } from 'vitest'; import { DoubleEscape, Xss } from '../src/errors'; import { TSLangServer } from './util/lang-server'; @@ -71,7 +70,7 @@ it('Operators are evaluated normally', async () => { ); `; - assert.deepStrictEqual(diagnostics.body, [ + expect(diagnostics.body).toEqual([ { start: { line: 40, offset: 34 }, end: { line: 40, offset: 38 }, diff --git a/packages/ts-html-plugin/test/readme.test.ts b/packages/ts-html-plugin/test/readme.test.ts index bc4e018c8..aafc7e4d3 100644 --- a/packages/ts-html-plugin/test/readme.test.ts +++ b/packages/ts-html-plugin/test/readme.test.ts @@ -1,5 +1,4 @@ -import assert from 'node:assert'; -import { it } from 'node:test'; +import { expect, it } from 'vitest'; import { Xss } from '../src/errors'; import { TSLangServer } from './util/lang-server'; @@ -14,7 +13,7 @@ it('Ensures readme checks will throw error', async () => { ); `; - assert.deepStrictEqual(diagnostics.body, [ + expect(diagnostics.body).toEqual([ { category: 'error', code: Xss.code, diff --git a/packages/ts-html-plugin/test/safe.test.ts b/packages/ts-html-plugin/test/safe.test.ts index bbe10a13e..5390b717d 100644 --- a/packages/ts-html-plugin/test/safe.test.ts +++ b/packages/ts-html-plugin/test/safe.test.ts @@ -1,5 +1,4 @@ -import assert from 'node:assert'; -import { it } from 'node:test'; +import { expect, it } from 'vitest'; import { TSLangServer } from './util/lang-server'; it('Allow correct xss usage', async () => { @@ -75,5 +74,5 @@ it('Allow correct xss usage', async () => { ); `; - assert.strictEqual(diagnostics.body.length, 0); + expect(diagnostics.body).toHaveLength(0); }); diff --git a/packages/ts-html-plugin/test/unsafe-tags.test.ts b/packages/ts-html-plugin/test/unsafe-tags.test.ts index 118e04522..5fc947d76 100644 --- a/packages/ts-html-plugin/test/unsafe-tags.test.ts +++ b/packages/ts-html-plugin/test/unsafe-tags.test.ts @@ -1,5 +1,4 @@ -import assert from 'node:assert'; -import { it } from 'node:test'; +import { expect, it } from 'vitest'; import { Xss } from '../src/errors'; import { TSLangServer } from './util/lang-server'; @@ -30,7 +29,7 @@ it('Detect xss prone usage', async () => { ); `; - assert.deepStrictEqual(diagnostics.body, [ + expect(diagnostics.body).toEqual([ { start: { line: 37, offset: 15 }, end: { line: 37, offset: 19 }, diff --git a/packages/ts-html-plugin/test/util/lang-server.ts b/packages/ts-html-plugin/test/util/lang-server.ts index 46187e176..d3d319d2d 100644 --- a/packages/ts-html-plugin/test/util/lang-server.ts +++ b/packages/ts-html-plugin/test/util/lang-server.ts @@ -64,11 +64,10 @@ export class TSLangServer { isClosed = false; server: ChildProcess; sequence = 0; + debug: boolean; - constructor( - projectPath: string, - private readonly debug = false - ) { + constructor(projectPath: string, debug = false) { + this.debug = debug; this.server = fork(require.resolve('typescript/lib/tsserver'), { cwd: projectPath, stdio: ['pipe', 'pipe', 'pipe', 'ipc'], diff --git a/packages/ts-html-plugin/test/warn.test.ts b/packages/ts-html-plugin/test/warn.test.ts index 14351d0f8..61d838ff6 100644 --- a/packages/ts-html-plugin/test/warn.test.ts +++ b/packages/ts-html-plugin/test/warn.test.ts @@ -1,5 +1,4 @@ -import assert from 'node:assert'; -import { it } from 'node:test'; +import { expect, it } from 'vitest'; import { UnusedSafe } from '../src/errors'; import { TSLangServer } from './util/lang-server'; @@ -20,7 +19,7 @@ it('Warn on unused `safe` tags', async () => { ); `; - assert.deepStrictEqual(diagnostics.body, [ + expect(diagnostics.body).toEqual([ { start: { line: 36, offset: 14 }, end: { line: 36, offset: 18 }, diff --git a/packages/ts-html-plugin/tsconfig.json b/packages/ts-html-plugin/tsconfig.json index 6e521c8a2..c5b66c772 100644 --- a/packages/ts-html-plugin/tsconfig.json +++ b/packages/ts-html-plugin/tsconfig.json @@ -1,12 +1,13 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "target": "ES2022", + "verbatimModuleSyntax": false, + "target": "esnext", "jsx": "react-jsx", "jsxImportSource": "@kitajs/html", "module": "CommonJS", "moduleResolution": "Node", - "outDir": "dist", + "outDir": "./dist", "plugins": [{ "name": "self" }] }, "include": ["src", "test"] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 715a5a276..5d494760c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,38 +10,44 @@ catalogs: specifier: ^1.11.1 version: 1.11.1 '@swc/helpers': - specifier: ^0.5.17 - version: 0.5.17 + specifier: ^0.5.18 + version: 0.5.18 '@types/jsdom': - specifier: ^21.1.7 - version: 21.1.7 + specifier: ^27.0.0 + version: 27.0.0 '@types/node': - specifier: ^24.5.0 - version: 24.5.0 + specifier: ^24.10.9 + version: 24.10.9 '@types/react': - specifier: ^18.3.12 - version: 18.3.24 + specifier: ^19.2.9 + version: 19.2.9 '@typescript/native-preview': specifier: latest - version: 7.0.0-dev.20260116.1 + version: 7.0.0-dev.20260120.1 + '@vitest/coverage-v8': + specifier: ^4.0.17 + version: 4.0.17 c8: specifier: ^10.1.3 version: 10.1.3 jsdom: - specifier: ^27.0.0 - version: 27.0.0 + specifier: ^27.4.0 + version: 27.4.0 react: - specifier: ^19.1.1 - version: 19.1.1 + specifier: ^19.2.3 + version: 19.2.3 react-dom: - specifier: ^19.1.1 - version: 19.1.1 + specifier: ^19.2.3 + version: 19.2.3 tslib: specifier: ^2.8.1 version: 2.8.1 typescript: - specifier: ^5.9.2 + specifier: ^5.9.3 version: 5.9.3 + vitest: + specifier: ^4.0.17 + version: 4.0.17 importers: @@ -49,13 +55,13 @@ importers: devDependencies: '@arthurfiorette/prettier-config': specifier: ^1.0.12 - version: 1.0.12(prettier@3.6.2)(typescript@5.9.3) + version: 1.0.12(prettier@3.8.0)(typescript@5.9.3) '@changesets/changelog-github': - specifier: ^0.5.1 - version: 0.5.1 + specifier: ^0.5.2 + version: 0.5.2 '@changesets/cli': - specifier: ^2.29.7 - version: 2.29.7(@types/node@24.5.0) + specifier: ^2.29.8 + version: 2.29.8(@types/node@24.10.9) '@kitajs/html': specifier: workspace:* version: link:packages/html @@ -63,17 +69,17 @@ importers: specifier: ^9.1.7 version: 9.1.7 prettier: - specifier: ^3.6.2 - version: 3.6.2 + specifier: ^3.8.0 + version: 3.8.0 prettier-plugin-jsdoc: - specifier: ^1.3.3 - version: 1.3.3(prettier@3.6.2) + specifier: ^1.8.0 + version: 1.8.0(prettier@3.8.0) prettier-plugin-organize-imports: - specifier: ^4.2.0 - version: 4.2.0(prettier@3.6.2)(typescript@5.9.3) + specifier: ^4.3.0 + version: 4.3.0(prettier@3.8.0)(typescript@5.9.3) prettier-plugin-packagejson: - specifier: ^2.5.19 - version: 2.5.19(prettier@3.6.2) + specifier: ^3.0.0 + version: 3.0.0(prettier@3.8.0) typescript: specifier: 'catalog:' version: 5.9.3 @@ -82,7 +88,7 @@ importers: dependencies: '@typescript/native-preview': specifier: 'catalog:' - version: 7.0.0-dev.20260116.1 + version: 7.0.0-dev.20260120.1 hono: specifier: ^4.8.2 version: 4.8.2 @@ -95,13 +101,13 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 24.5.0 + version: 24.10.9 benchmarks/jsxte: dependencies: '@typescript/native-preview': specifier: 'catalog:' - version: 7.0.0-dev.20260116.1 + version: 7.0.0-dev.20260120.1 jsxte: specifier: ^3.3.1 version: 3.3.1 @@ -114,7 +120,7 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 24.5.0 + version: 24.10.9 benchmarks/kitajs: dependencies: @@ -123,7 +129,7 @@ importers: version: link:../../packages/html '@typescript/native-preview': specifier: 'catalog:' - version: 7.0.0-dev.20260116.1 + version: 7.0.0-dev.20260120.1 tslib: specifier: 'catalog:' version: 2.8.1 @@ -135,7 +141,7 @@ importers: dependencies: '@typescript/native-preview': specifier: 'catalog:' - version: 7.0.0-dev.20260116.1 + version: 7.0.0-dev.20260120.1 preact: specifier: ^10.27.3 version: 10.27.3 @@ -148,19 +154,19 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 24.5.0 + version: 24.10.9 '@types/react': specifier: 'catalog:' - version: 18.3.24 + version: 19.2.9 benchmarks/react: dependencies: '@typescript/native-preview': specifier: 'catalog:' - version: 7.0.0-dev.20260116.1 + version: 7.0.0-dev.20260120.1 react: specifier: 'catalog:' - version: 19.1.1 + version: 19.2.3 tslib: specifier: 'catalog:' version: 2.8.1 @@ -170,19 +176,19 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 24.5.0 + version: 24.10.9 '@types/react': specifier: 'catalog:' - version: 18.3.24 + version: 19.2.9 benchmarks/reactjsx: dependencies: '@typescript/native-preview': specifier: 'catalog:' - version: 7.0.0-dev.20260116.1 + version: 7.0.0-dev.20260120.1 react: specifier: 'catalog:' - version: 19.1.1 + version: 19.2.3 tslib: specifier: 'catalog:' version: 2.8.1 @@ -192,10 +198,10 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 24.5.0 + version: 24.10.9 '@types/react': specifier: 'catalog:' - version: 18.3.24 + version: 19.2.9 benchmarks/runner: dependencies: @@ -252,16 +258,16 @@ importers: version: 6.5.13(preact@10.27.3) react: specifier: 'catalog:' - version: 19.1.1 + version: 19.2.3 react-dom: specifier: 'catalog:' - version: 19.1.1(react@19.1.1) + version: 19.2.3(react@19.2.3) benchmarks/templates: dependencies: '@typescript/native-preview': specifier: 'catalog:' - version: 7.0.0-dev.20260116.1 + version: 7.0.0-dev.20260120.1 tslib: specifier: 'catalog:' version: 2.8.1 @@ -271,13 +277,13 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 24.5.0 + version: 24.10.9 benchmarks/typed-html: dependencies: '@typescript/native-preview': specifier: 'catalog:' - version: 7.0.0-dev.20260116.1 + version: 7.0.0-dev.20260120.1 tslib: specifier: 'catalog:' version: 2.8.1 @@ -292,7 +298,7 @@ importers: dependencies: '@typescript/native-preview': specifier: 'catalog:' - version: 7.0.0-dev.20260116.1 + version: 7.0.0-dev.20260120.1 tslib: specifier: 'catalog:' version: 2.8.1 @@ -320,16 +326,16 @@ importers: version: 8.0.2 '@swc-node/register': specifier: 'catalog:' - version: 1.11.1(@swc/core@1.7.26(@swc/helpers@0.5.17))(@swc/types@0.1.12)(typescript@5.9.3) + version: 1.11.1(@swc/core@1.7.26(@swc/helpers@0.5.18))(@swc/types@0.1.12)(typescript@5.9.3) '@swc/helpers': specifier: 'catalog:' - version: 0.5.17 + version: 0.5.18 '@types/jsdom': specifier: 'catalog:' - version: 21.1.7 + version: 27.0.0 '@types/node': specifier: 'catalog:' - version: 24.5.0 + version: 24.10.9 c8: specifier: 'catalog:' version: 10.1.3 @@ -338,7 +344,7 @@ importers: version: 5.6.0 jsdom: specifier: 'catalog:' - version: 27.0.0(postcss@8.5.6) + version: 27.4.0 tsd: specifier: ^0.33.0 version: 0.33.0 @@ -349,87 +355,99 @@ importers: packages/html: dependencies: csstype: - specifier: ^3.1.3 - version: 3.1.3 + specifier: ^3.2.3 + version: 3.2.3 devDependencies: '@types/jsdom': specifier: 'catalog:' - version: 21.1.7 + version: 27.0.0 '@types/node': specifier: 'catalog:' - version: 24.5.0 + version: 24.10.9 '@typescript/native-preview': specifier: 'catalog:' - version: 7.0.0-dev.20260116.1 + version: 7.0.0-dev.20260120.1 + '@vitest/coverage-v8': + specifier: ^4.0.17 + version: 4.0.17(vitest@4.0.17(@types/node@24.10.9)(jsdom@27.4.0)) c8: specifier: 'catalog:' version: 10.1.3 jsdom: specifier: 'catalog:' - version: 27.0.0(postcss@8.5.6) + version: 27.4.0 react: specifier: 'catalog:' - version: 19.1.1 + version: 19.2.3 react-dom: specifier: 'catalog:' - version: 19.1.1(react@19.1.1) + version: 19.2.3(react@19.2.3) + self: + specifier: 'link:' + version: 'link:' typescript: specifier: 'catalog:' version: 5.9.3 + vitest: + specifier: 'catalog:' + version: 4.0.17(@types/node@24.10.9)(jsdom@27.4.0) packages/ts-html-plugin: dependencies: '@kitajs/html': - specifier: workspace:^4.2.10 + specifier: workspace:^ version: link:../html chalk: specifier: ^5.6.2 version: 5.6.2 tslib: - specifier: ^2.8.1 + specifier: 'catalog:' version: 2.8.1 typescript: - specifier: ^5.6.2 + specifier: 'catalog:' version: 5.9.3 yargs: specifier: ^18.0.0 version: 18.0.0 devDependencies: - '@swc-node/register': - specifier: ^1.11.1 - version: 1.11.1(@swc/core@1.7.26(@swc/helpers@0.5.17))(@swc/types@0.1.12)(typescript@5.9.3) - '@swc/helpers': - specifier: ^0.5.17 - version: 0.5.17 '@types/node': - specifier: ^24.5.0 - version: 24.5.0 + specifier: 'catalog:' + version: 24.10.9 '@types/yargs': - specifier: ^17.0.33 - version: 17.0.33 + specifier: ^17.0.35 + version: 17.0.35 '@typescript/native-preview': - specifier: latest - version: 7.0.0-dev.20260116.1 + specifier: 'catalog:' + version: 7.0.0-dev.20260120.1 + '@vitest/coverage-v8': + specifier: 'catalog:' + version: 4.0.17(vitest@4.0.17(@types/node@24.10.9)(jsdom@27.4.0)) fast-defer: specifier: ^1.1.9 version: 1.1.9 self: - specifier: 'file:' - version: '@kitajs/ts-html-plugin@file:packages/ts-html-plugin(@kitajs/html@packages+html)(typescript@5.9.3)' + specifier: 'link:' + version: 'link:' + vitest: + specifier: 'catalog:' + version: 4.0.17(@types/node@24.10.9)(jsdom@27.4.0) packages: + '@acemir/cssom@0.9.31': + resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} + '@arthurfiorette/prettier-config@1.0.12': resolution: {integrity: sha512-jR36bHWLVv71FuKkU9XYeBe6ry/AN98EDh0WVyfo3QwjJFbhpeElFTS4nluwxeXfu6nJ8/Hv8bJf6cYeXzfeoA==} hasBin: true peerDependencies: prettier: ^3.0.3 - '@asamuzakjp/css-color@4.0.4': - resolution: {integrity: sha512-cKjSKvWGmAziQWbCouOsFwb14mp1betm8Y7Fn+yglDMUUu3r9DCbJ9iJbeFDenLMqFbIMC0pQP8K+B8LAxX3OQ==} + '@asamuzakjp/css-color@4.1.1': + resolution: {integrity: sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==} - '@asamuzakjp/dom-selector@6.5.4': - resolution: {integrity: sha512-RNSNk1dnB8lAn+xdjlRoM4CzdVrHlmXZtSXAWs2jyl4PiBRWqTZr9ML5M710qgd9RPTBsVG6P0SLy7dwy0Foig==} + '@asamuzakjp/dom-selector@6.7.6': + resolution: {integrity: sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==} '@asamuzakjp/nwsapi@2.3.9': resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} @@ -438,20 +456,33 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} + '@babel/parser@7.28.6': + resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/runtime@7.28.4': resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} + '@babel/types@7.28.6': + resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} + engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@changesets/apply-release-plan@7.0.13': - resolution: {integrity: sha512-BIW7bofD2yAWoE8H4V40FikC+1nNFEKBisMECccS16W1rt6qqhNTBDmIw5HaqmMgtLNz9e7oiALiEUuKrQ4oHg==} + '@changesets/apply-release-plan@7.0.14': + resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==} '@changesets/assemble-release-plan@6.0.9': resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==} @@ -459,15 +490,15 @@ packages: '@changesets/changelog-git@0.2.1': resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} - '@changesets/changelog-github@0.5.1': - resolution: {integrity: sha512-BVuHtF+hrhUScSoHnJwTELB4/INQxVFc+P/Qdt20BLiBFIHFJDDUaGsZw+8fQeJTRP5hJZrzpt3oZWh0G19rAQ==} + '@changesets/changelog-github@0.5.2': + resolution: {integrity: sha512-HeGeDl8HaIGj9fQHo/tv5XKQ2SNEi9+9yl1Bss1jttPqeiASRXhfi0A2wv8yFKCp07kR1gpOI5ge6+CWNm1jPw==} - '@changesets/cli@2.29.7': - resolution: {integrity: sha512-R7RqWoaksyyKXbKXBTbT4REdy22yH81mcFK6sWtqSanxUCbUi9Uf+6aqxZtDQouIqPdem2W56CdxXgsxdq7FLQ==} + '@changesets/cli@2.29.8': + resolution: {integrity: sha512-1weuGZpP63YWUYjay/E84qqwcnt5yJMM0tep10Up7Q5cS/DGe2IZ0Uj3HNMxGhCINZuR7aO9WBMdKnPit5ZDPA==} hasBin: true - '@changesets/config@3.1.1': - resolution: {integrity: sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==} + '@changesets/config@3.1.2': + resolution: {integrity: sha512-CYiRhA4bWKemdYi/uwImjPxqWNpqGPNbEBdX1BdONALFIDK7MCUj6FPkzD+z9gJcvDFUQJn9aDVf4UG7OT6Kog==} '@changesets/errors@0.2.0': resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} @@ -475,11 +506,11 @@ packages: '@changesets/get-dependents-graph@2.1.3': resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} - '@changesets/get-github-info@0.6.0': - resolution: {integrity: sha512-v/TSnFVXI8vzX9/w3DU2Ol+UlTZcu3m0kXTjTT4KlAdwSvwutcByYwyYn9hwerPWfPkT2JfpoX0KgvCEi8Q/SA==} + '@changesets/get-github-info@0.7.0': + resolution: {integrity: sha512-+i67Bmhfj9V4KfDeS1+Tz3iF32btKZB2AAx+cYMqDSRFP7r3/ZdGbjCo+c6qkyViN9ygDuBjzageuPGJtKGe5A==} - '@changesets/get-release-plan@4.0.13': - resolution: {integrity: sha512-DWG1pus72FcNeXkM12tx+xtExyH/c9I1z+2aXlObH3i9YA7+WZEVaiHzHl03thpvAgWTRaH64MpfHxozfF7Dvg==} + '@changesets/get-release-plan@4.0.14': + resolution: {integrity: sha512-yjZMHpUHgl4Xl5gRlolVuxDkm4HgSJqT93Ri1Uz8kGrQb+5iJ8dkXJ20M2j/Y4iV5QzS2c5SeTxVSKX+2eMI0g==} '@changesets/get-version-range-type@0.4.0': resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} @@ -490,14 +521,14 @@ packages: '@changesets/logger@0.1.1': resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} - '@changesets/parse@0.4.1': - resolution: {integrity: sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==} + '@changesets/parse@0.4.2': + resolution: {integrity: sha512-Uo5MC5mfg4OM0jU3up66fmSn6/NE9INK+8/Vn/7sMVcdWg46zfbvvUSjD9EMonVqPi9fbrJH9SXHn48Tr1f2yA==} '@changesets/pre@2.0.2': resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} - '@changesets/read@0.6.5': - resolution: {integrity: sha512-UPzNGhsSjHD3Veb0xO/MwvasGe8eMyNrR/sT9gR8Q3DhOQZirgKhhXv/8hVsI0QpPjR004Z9iFxoJU6in3uGMg==} + '@changesets/read@0.6.6': + resolution: {integrity: sha512-P5QaN9hJSQQKJShzzpBT13FzOSPyHbqdoIBUd2DJdgvnECCyO6LmAOWSV+O8se2TaZJVwSXjL+v9yhb+a9JeJg==} '@changesets/should-skip-package@0.1.2': resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} @@ -535,11 +566,9 @@ packages: peerDependencies: '@csstools/css-tokenizer': ^3.0.4 - '@csstools/css-syntax-patches-for-csstree@1.0.14': - resolution: {integrity: sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==} + '@csstools/css-syntax-patches-for-csstree@1.0.25': + resolution: {integrity: sha512-g0Kw9W3vjx5BEBAF8c5Fm2NcB/Fs8jJXh85aXqwEXiL+tqtOut07TWgyaGzAAfTM+gKckrrncyeGEZPcaRgm2Q==} engines: {node: '>=18'} - peerDependencies: - postcss: ^8.4 '@csstools/css-tokenizer@3.0.4': resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} @@ -554,6 +583,171 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@esbuild/aix-ppc64@0.27.2': + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.2': + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.2': + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.2': + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.2': + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.2': + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.2': + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.2': + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.2': + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.2': + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.2': + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.2': + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.2': + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.2': + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.2': + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.2': + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.2': + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.2': + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.2': + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.2': + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.2': + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.2': + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.2': + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.2': + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.2': + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.2': + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@exodus/bytes@1.9.0': + resolution: {integrity: sha512-lagqsvnk09NKogQaN/XrtlWeUF8SRhT12odMvbTIIaVObqzwAogL6jhR4DAp0gPuKoM1AOVrKUshJpRdpMFrww==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@fastify/ajv-compiler@4.0.2': resolution: {integrity: sha512-Rkiu/8wIjpsf46Rr+Fitd3HRP+VsxUFDDeag0hs9L0ksfnwx2g7SPQQTFL0E8Qv+rfXzQOxBJnjUB9ITUDjfWQ==} @@ -606,13 +800,6 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@kitajs/ts-html-plugin@file:packages/ts-html-plugin': - resolution: {directory: packages/ts-html-plugin, type: directory} - hasBin: true - peerDependencies: - '@kitajs/html': workspace:^4.2.10 - typescript: ^5.6.2 - '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -733,13 +920,137 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@pkgr/core@0.2.9': - resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@rollup/rollup-android-arm-eabi@4.55.3': + resolution: {integrity: sha512-qyX8+93kK/7R5BEXPC2PjUt0+fS/VO2BVHjEHyIEWiYn88rcRBHmdLgoJjktBltgAf+NY7RfCGB1SoyKS/p9kg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.55.3': + resolution: {integrity: sha512-6sHrL42bjt5dHQzJ12Q4vMKfN+kUnZ0atHHnv4V0Wd9JMTk7FDzSY35+7qbz3ypQYMBPANbpGK7JpnWNnhGt8g==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.55.3': + resolution: {integrity: sha512-1ht2SpGIjEl2igJ9AbNpPIKzb1B5goXOcmtD0RFxnwNuMxqkR6AUaaErZz+4o+FKmzxcSNBOLrzsICZVNYa1Rw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.55.3': + resolution: {integrity: sha512-FYZ4iVunXxtT+CZqQoPVwPhH7549e/Gy7PIRRtq4t5f/vt54pX6eG9ebttRH6QSH7r/zxAFA4EZGlQ0h0FvXiA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.55.3': + resolution: {integrity: sha512-M/mwDCJ4wLsIgyxv2Lj7Len+UMHd4zAXu4GQ2UaCdksStglWhP61U3uowkaYBQBhVoNpwx5Hputo8eSqM7K82Q==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.55.3': + resolution: {integrity: sha512-5jZT2c7jBCrMegKYTYTpni8mg8y3uY8gzeq2ndFOANwNuC/xJbVAoGKR9LhMDA0H3nIhvaqUoBEuJoICBudFrA==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.55.3': + resolution: {integrity: sha512-YeGUhkN1oA+iSPzzhEjVPS29YbViOr8s4lSsFaZKLHswgqP911xx25fPOyE9+khmN6W4VeM0aevbDp4kkEoHiA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.55.3': + resolution: {integrity: sha512-eo0iOIOvcAlWB3Z3eh8pVM8hZ0oVkK3AjEM9nSrkSug2l15qHzF3TOwT0747omI6+CJJvl7drwZepT+re6Fy/w==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.55.3': + resolution: {integrity: sha512-DJay3ep76bKUDImmn//W5SvpjRN5LmK/ntWyeJs/dcnwiiHESd3N4uteK9FDLf0S0W8E6Y0sVRXpOCoQclQqNg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.55.3': + resolution: {integrity: sha512-BKKWQkY2WgJ5MC/ayvIJTHjy0JUGb5efaHCUiG/39sSUvAYRBaO3+/EK0AZT1RF3pSj86O24GLLik9mAYu0IJg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.55.3': + resolution: {integrity: sha512-Q9nVlWtKAG7ISW80OiZGxTr6rYtyDSkauHUtvkQI6TNOJjFvpj4gcH+KaJihqYInnAzEEUetPQubRwHef4exVg==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.55.3': + resolution: {integrity: sha512-2H5LmhzrpC4fFRNwknzmmTvvyJPHwESoJgyReXeFoYYuIDfBhP29TEXOkCJE/KxHi27mj7wDUClNq78ue3QEBQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.55.3': + resolution: {integrity: sha512-9S542V0ie9LCTznPYlvaeySwBeIEa7rDBgLHKZ5S9DBgcqdJYburabm8TqiqG6mrdTzfV5uttQRHcbKff9lWtA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.55.3': + resolution: {integrity: sha512-ukxw+YH3XXpcezLgbJeasgxyTbdpnNAkrIlFGDl7t+pgCxZ89/6n1a+MxlY7CegU+nDgrgdqDelPRNQ/47zs0g==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.55.3': + resolution: {integrity: sha512-Iauw9UsTTvlF++FhghFJjqYxyXdggXsOqGpFBylaRopVpcbfyIIsNvkf9oGwfgIcf57z3m8+/oSYTo6HutBFNw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.55.3': + resolution: {integrity: sha512-3OqKAHSEQXKdq9mQ4eajqUgNIK27VZPW3I26EP8miIzuKzCJ3aW3oEn2pzF+4/Hj/Moc0YDsOtBgT5bZ56/vcA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.55.3': + resolution: {integrity: sha512-0CM8dSVzVIaqMcXIFej8zZrSFLnGrAE8qlNbbHfTw1EEPnFTg1U1ekI0JdzjPyzSfUsHWtodilQQG/RA55berA==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.55.3': + resolution: {integrity: sha512-+fgJE12FZMIgBaKIAGd45rxf+5ftcycANJRWk8Vz0NnMTM5rADPGuRFTYar+Mqs560xuART7XsX2lSACa1iOmQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.55.3': + resolution: {integrity: sha512-tMD7NnbAolWPzQlJQJjVFh/fNH3K/KnA7K8gv2dJWCwwnaK6DFCYST1QXYWfu5V0cDwarWC8Sf/cfMHniNq21A==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.55.3': + resolution: {integrity: sha512-u5KsqxOxjEeIbn7bUK1MPM34jrnPwjeqgyin4/N6e/KzXKfpE9Mi0nCxcQjaM9lLmPcHmn/xx1yOjgTMtu1jWQ==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.55.3': + resolution: {integrity: sha512-vo54aXwjpTtsAnb3ca7Yxs9t2INZg7QdXN/7yaoG7nPGbOBXYXQY41Km+S1Ov26vzOAzLcAjmMdjyEqS1JkVhw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.55.3': + resolution: {integrity: sha512-HI+PIVZ+m+9AgpnY3pt6rinUdRYrGHvmVdsNQ4odNqQ/eRF78DVpMR7mOq7nW06QxpczibwBmeQzB68wJ+4W4A==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.55.3': + resolution: {integrity: sha512-vRByotbdMo3Wdi+8oC2nVxtc3RkkFKrGaok+a62AT8lz/YBuQjaVYAS5Zcs3tPzW43Vsf9J0wehJbUY5xRSekA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.55.3': + resolution: {integrity: sha512-POZHq7UeuzMJljC5NjKi8vKMFN6/5EOqcX1yGntNLp7rUTpBAXQ1hW8kWPFxYLv07QMcNM75xqVLGPWQq6TKFA==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.55.3': + resolution: {integrity: sha512-aPFONczE4fUFKNXszdvnd2GqKEYQdV5oEsIbKPujJmWlCI9zEsv1Otig8RKK+X9bed9gFUN6LAeN4ZcNuu4zjg==} + cpu: [x64] + os: [win32] '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@swc-node/core@1.14.1': resolution: {integrity: sha512-jrt5GUaZUU6cmMS+WTJEvGvaB6j1YNKPHPzC2PUi2BjaFbtxURHj6641Az6xN7b665hNniAIdvjxWcRml5yCnw==} engines: {node: '>= 10'} @@ -828,8 +1139,8 @@ packages: '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - '@swc/helpers@0.5.17': - resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + '@swc/helpers@0.5.18': + resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} '@swc/types@0.1.12': resolution: {integrity: sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==} @@ -841,9 +1152,15 @@ packages: '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/eslint@7.29.0': resolution: {integrity: sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==} @@ -853,8 +1170,8 @@ packages: '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - '@types/jsdom@21.1.7': - resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==} + '@types/jsdom@27.0.0': + resolution: {integrity: sha512-NZyFl/PViwKzdEkQg96gtnB8wm+1ljhdDay9ahn4hgb+SfVtPCbm3TlmDUFXTA+MGN3CijicnMhG18SI5H3rFw==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -871,17 +1188,14 @@ packages: '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@24.5.0': - resolution: {integrity: sha512-y1dMvuvJspJiPSDZUQ+WMBvF7dpnEqN4x9DDC9ie5Fs/HUZJA3wFp7EhHoVaKX/iI0cRoECV8X2jL8zi0xrHCg==} + '@types/node@24.10.9': + resolution: {integrity: sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} - '@types/prop-types@15.7.15': - resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} - - '@types/react@18.3.24': - resolution: {integrity: sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==} + '@types/react@19.2.9': + resolution: {integrity: sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA==} '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} @@ -892,48 +1206,86 @@ packages: '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - '@types/yargs@17.0.33': - resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260116.1': - resolution: {integrity: sha512-+HoFBoTy6GrdqpN2sBCmvNNVqKXndVqgKPojaTpc1OfiH2YAa1p2zXsHuw2+PtXcsGDBvIX4Fce4i8urHlF6mQ==} + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260120.1': + resolution: {integrity: sha512-r3pWFuR2H7mn6ScwpH5jJljKQqKto0npVuJSk6pRwFwexpTyxOGmJTZJ1V0AWiisaNxU2+CNAqWFJSJYIE/QTg==} cpu: [arm64] os: [darwin] - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260116.1': - resolution: {integrity: sha512-cKSm37T0rrCskKKjwr/i97+k9fIQydsOfYO8oUzOFWEHKYl83vQib0JdSyelbLGEfT5Xpt6Wm12ul6MS42e+xw==} + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260120.1': + resolution: {integrity: sha512-cuC1+wLbUP+Ip2UT94G134fqRdp5w3b3dhcCO6/FQ4yXxvRNyv/WK+upHBUFDaeSOeHgDTyO9/QFYUWwC4If1A==} cpu: [x64] os: [darwin] - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260116.1': - resolution: {integrity: sha512-mF+y2V95kYJx6ELk3BaXd0lDRGq3ce8fCDxx3MRgCEuexm/SYXC9OnQfkdyEPqU366sYwYw98TFIYjf6ruhZ7Q==} + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260120.1': + resolution: {integrity: sha512-zZGvEGY7wcHYefMZ87KNmvjN3NLIhsCMHEpHZiGCS3khKf+8z6ZsanrzCjOTodvL01VPyBzHxV1EtkSxAcLiQg==} cpu: [arm64] os: [linux] - '@typescript/native-preview-linux-arm@7.0.0-dev.20260116.1': - resolution: {integrity: sha512-fCgBsrrbURMutyBdnYXa13OVDOGtlu1AWMCqq21jQFDv2hglUR2l7BOZmqobLgWY76DGHQS7zK+hXcEcOqR7hA==} + '@typescript/native-preview-linux-arm@7.0.0-dev.20260120.1': + resolution: {integrity: sha512-vN6OYVySol/kQZjJGmAzd6L30SyVlCgmCXS8WjUYtE5clN0YrzQHop16RK29fYZHMxpkOniVBtRPxUYQANZBlQ==} cpu: [arm] os: [linux] - '@typescript/native-preview-linux-x64@7.0.0-dev.20260116.1': - resolution: {integrity: sha512-7lxKOVF0ph2+92ySc8HSUxKnBHkfoj7bm43QE482fb0z1YhNuUc/3R79NJGKywgmDP5IXEb1PY8piQbwoPYHwg==} + '@typescript/native-preview-linux-x64@7.0.0-dev.20260120.1': + resolution: {integrity: sha512-JBfNhWd/asd5MDeS3VgRvE24pGKBkmvLub6tsux6ypr+Yhy+o0WaAEzVpmlRYZUqss2ai5tvOu4dzPBXzZAtFw==} cpu: [x64] os: [linux] - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260116.1': - resolution: {integrity: sha512-VzS2LDsXqmC+6v+DEdjHxhadKzN5l/yMMQp3pVvq/ZM52NkUWzUtBpAU3nxB8n02L9Xr6625jEMduyZba0TVVg==} + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260120.1': + resolution: {integrity: sha512-tTndRtYCq2xwgE0VkTi9ACNiJaV43+PqvBqCxk8ceYi3X36Ve+CCnwlZfZJ4k9NxZthtrAwF/kUmpC9iIYbq1w==} cpu: [arm64] os: [win32] - '@typescript/native-preview-win32-x64@7.0.0-dev.20260116.1': - resolution: {integrity: sha512-OUmQLOIoknUmwaNz2iA0tkClIbbuzjHLrnFZNF4rlw1LlelNExGQlrMmx0szMRjTz9CFOh9qhYT23/3jOoOsqA==} + '@typescript/native-preview-win32-x64@7.0.0-dev.20260120.1': + resolution: {integrity: sha512-oZia7hFL6k9pVepfonuPI86Jmyz6WlJKR57tWCDwRNmpA7odxuTq1PbvcYgy1z4+wHF1nnKKJY0PMAiq6ac18w==} cpu: [x64] os: [win32] - '@typescript/native-preview@7.0.0-dev.20260116.1': - resolution: {integrity: sha512-9N2Sa3Ap8E5+V4K+eTs5y8//dW77qFKzo+OfmYpL4f/Vb6WEoo6SDhjaSB2eNtgeiCKkNQySLO3pz3/QEpuVXg==} + '@typescript/native-preview@7.0.0-dev.20260120.1': + resolution: {integrity: sha512-nnEf37C9ue7OBRnF2zmV/OCBmV5Y7T/K4mCHa+nxgiXcF/1w8sA0cgdFl+gHQ0mysqUJ+Bu5btAMeWgpLyjrgg==} hasBin: true + '@vitest/coverage-v8@4.0.17': + resolution: {integrity: sha512-/6zU2FLGg0jsd+ePZcwHRy3+WpNTBBhDY56P4JTRqUN/Dp6CvOEa9HrikcQ4KfV2b2kAHUFB4dl1SuocWXSFEw==} + peerDependencies: + '@vitest/browser': 4.0.17 + vitest: 4.0.17 + peerDependenciesMeta: + '@vitest/browser': + optional: true + + '@vitest/expect@4.0.17': + resolution: {integrity: sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ==} + + '@vitest/mocker@4.0.17': + resolution: {integrity: sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.0.17': + resolution: {integrity: sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw==} + + '@vitest/runner@4.0.17': + resolution: {integrity: sha512-JmuQyf8aMWoo/LmNFppdpkfRVHJcsgzkbCA+/Bk7VfNH7RE6Ut2qxegeyx2j3ojtJtKIbIGy3h+KxGfYfk28YQ==} + + '@vitest/snapshot@4.0.17': + resolution: {integrity: sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ==} + + '@vitest/spy@4.0.17': + resolution: {integrity: sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew==} + + '@vitest/utils@4.0.17': + resolution: {integrity: sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w==} + abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} @@ -983,6 +1335,9 @@ packages: argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -991,6 +1346,13 @@ packages: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-v8-to-istanbul@0.3.10: + resolution: {integrity: sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==} + atomic-sleep@1.0.0: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} @@ -1042,6 +1404,10 @@ packages: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -1108,12 +1474,12 @@ packages: resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - cssstyle@5.3.0: - resolution: {integrity: sha512-RveJPnk3m7aarYQ2bJ6iw+Urh55S6FzUiqtBq+TihnTDP4cI8y/TYDqGOyqgnG1J1a6BxJXZsV9JFSTulm9Z7g==} + cssstyle@5.3.7: + resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==} engines: {node: '>=20'} - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} data-urls@6.0.0: resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} @@ -1153,8 +1519,8 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} - detect-indent@7.0.1: - resolution: {integrity: sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==} + detect-indent@7.0.2: + resolution: {integrity: sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==} engines: {node: '>=12.20'} detect-newline@4.0.1: @@ -1199,6 +1565,14 @@ packages: error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -1215,6 +1589,13 @@ packages: engines: {node: '>=4'} hasBin: true + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -1290,6 +1671,11 @@ packages: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -1351,9 +1737,9 @@ packages: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} - html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -1380,10 +1766,6 @@ packages: engines: {node: '>=18'} hasBin: true - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - iconv-lite@0.7.0: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} @@ -1479,13 +1861,20 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true - jsdom@27.0.0: - resolution: {integrity: sha512-lIHeR1qlIRrIN5VMccd8tI2Sgw6ieYXSVktcSHaNe3Z5nE/tcPQYQWOq00wxMvYOsz+73eAkNenVvmPC6bba9A==} - engines: {node: '>=20'} + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsdom@27.4.0: + resolution: {integrity: sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: canvas: ^3.0.0 peerDependenciesMeta: @@ -1538,14 +1927,20 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.1: - resolution: {integrity: sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==} + lru-cache@11.2.4: + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} engines: {node: 20 || >=22} lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magicast@0.5.1: + resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==} + make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} @@ -1701,6 +2096,9 @@ packages: resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} engines: {node: '>=10'} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + on-exit-leak-free@2.1.2: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} @@ -1755,6 +2153,9 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parse5@8.0.0: + resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -1774,6 +2175,9 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1819,8 +2223,8 @@ packages: preact@10.27.3: resolution: {integrity: sha512-ZieIP3zQHiQsNF3BA+SNVS8dcuRIg/nsxlkFbCMBLS2L1Ww4Bkxd9n6Md2A1crfTZsEbQPADV0neYmh/EElgeQ==} - prettier-plugin-jsdoc@1.3.3: - resolution: {integrity: sha512-YIxejcbPYK4N58jHGiXjYvrCzBMyvV2AEMSoF5LvqqeMEI0nsmww57I6NGnpVc0AU9ncFCTEBoYHN/xuBf80YA==} + prettier-plugin-jsdoc@1.8.0: + resolution: {integrity: sha512-byW8EBZ1DSA3CPdDGBXfcdqqhh2eq0+HlIOPTGZ6rf9O2p/AwBmtS0e49ot5ZeOdcszj81FyzbyHr/VS0eYpCg==} engines: {node: '>=14.13.1 || >=16.0.0'} peerDependencies: prettier: ^3.0.0 @@ -1838,8 +2242,8 @@ packages: '@volar/vue-typescript': optional: true - prettier-plugin-organize-imports@4.2.0: - resolution: {integrity: sha512-Zdy27UhlmyvATZi67BTnLcKTo8fm6Oik59Sz6H64PgZJVs6NJpPD1mT240mmJn62c98/QaL+r3kx9Q3gRpDajg==} + prettier-plugin-organize-imports@4.3.0: + resolution: {integrity: sha512-FxFz0qFhyBsGdIsb697f/EkvHzi5SZOhWAjxcx2dLt+Q532bAlhswcXGYB1yzjZ69kW8UoadFBw7TyNwlq96Iw==} peerDependencies: prettier: '>=2.0' typescript: '>=2.9' @@ -1848,21 +2252,29 @@ packages: vue-tsc: optional: true - prettier-plugin-packagejson@2.5.19: - resolution: {integrity: sha512-Qsqp4+jsZbKMpEGZB1UP1pxeAT8sCzne2IwnKkr+QhUe665EXUo3BAvTf1kAPCqyMv9kg3ZmO0+7eOni/C6Uag==} + prettier-plugin-packagejson@2.5.22: + resolution: {integrity: sha512-G6WalmoUssKF8ZXkni0+n4324K+gG143KPysSQNW+FrR0XyNb3BdRxchGC/Q1FE/F702p7/6KU7r4mv0WSWbzA==} peerDependencies: prettier: '>= 1.16.0' peerDependenciesMeta: prettier: optional: true + prettier-plugin-packagejson@3.0.0: + resolution: {integrity: sha512-z8/QmPSqx/ANvvQMWJSkSq1+ihBXeuwDEYdjX3ZjRJ5Ty1k7vGbFQfhzk2eDe0rwS/TNyRjWK/qnjJEStAOtDw==} + peerDependencies: + prettier: ^3 + peerDependenciesMeta: + prettier: + optional: true + prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} hasBin: true - prettier@3.6.2: - resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + prettier@3.8.0: + resolution: {integrity: sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==} engines: {node: '>=14'} hasBin: true @@ -1893,16 +2305,16 @@ packages: resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} engines: {node: '>=8'} - react-dom@19.1.1: - resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} + react-dom@19.2.3: + resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} peerDependencies: - react: ^19.1.1 + react: ^19.2.3 react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react@19.1.1: - resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} + react@19.2.3: + resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} engines: {node: '>=0.10.0'} read-pkg-up@7.0.1: @@ -1957,8 +2369,10 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rrweb-cssom@0.8.0: - resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + rollup@4.55.3: + resolution: {integrity: sha512-y9yUpfQvetAjiDLtNMf1hL9NXchIJgWt6zIKeoB+tCd3npX08Eqfzg60V9DhIGVMtQ0AlMkFw5xa+AQ37zxnAA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -1977,8 +2391,8 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} - scheduler@0.26.0: - resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} secure-json-parse@4.0.0: resolution: {integrity: sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==} @@ -1987,8 +2401,8 @@ packages: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} hasBin: true @@ -2003,6 +2417,9 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -2014,11 +2431,11 @@ packages: sonic-boom@4.2.0: resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} - sort-object-keys@1.1.3: - resolution: {integrity: sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==} + sort-object-keys@2.1.0: + resolution: {integrity: sha512-SOiEnthkJKPv2L6ec6HMwhUcN0/lppkeYuN1x63PbyPRrgSPIuBJCiYxYyvWRTtjMlOi14vQUCGUJqS6PLVm8g==} - sort-package-json@3.4.0: - resolution: {integrity: sha512-97oFRRMM2/Js4oEA9LJhjyMlde+2ewpZQf53pgue27UkbEXfHJnDzHlUxQ/DWUkzqmp7DFwJp8D+wi/TYeQhpA==} + sort-package-json@3.6.0: + resolution: {integrity: sha512-fyJsPLhWvY7u2KsKPZn1PixbXp+1m7V8NWqU8CvgFRbMEX41Ffw1kD8n0CfJiGoaSfoAvbrqRRl/DcHO8omQOQ==} engines: {node: '>=20'} hasBin: true @@ -2055,6 +2472,12 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -2098,10 +2521,6 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - synckit@0.11.11: - resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} - engines: {node: ^14.18.0 || >=16.0.0} - term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} @@ -2113,10 +2532,21 @@ packages: thread-stream@3.1.0: resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + engines: {node: '>=14.0.0'} + tldts-core@7.0.14: resolution: {integrity: sha512-viZGNK6+NdluOJWwTO9olaugx0bkKhscIdriQQ+lNNhwitIKvb+SvhbYgnCz6j9p7dX3cJntt4agQAKMXLjJ5g==} @@ -2139,9 +2569,9 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - tr46@5.1.1: - resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} - engines: {node: '>=18'} + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} trim-newlines@3.0.1: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} @@ -2185,8 +2615,8 @@ packages: engines: {node: '>=0.8.0'} hasBin: true - undici-types@7.12.0: - resolution: {integrity: sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==} + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} @@ -2208,6 +2638,80 @@ packages: vhtml@2.2.0: resolution: {integrity: sha512-TPXrXrxBOslRUVnlVkiAqhoXneiertIg86bdvzionrUYhEuiROvyPZNiiP6GIIJ2Q7oPNVyEtIx8gMAZZE9lCQ==} + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.0.17: + resolution: {integrity: sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.17 + '@vitest/browser-preview': 4.0.17 + '@vitest/browser-webdriverio': 4.0.17 + '@vitest/ui': 4.0.17 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} @@ -2219,17 +2723,12 @@ packages: resolution: {integrity: sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==} engines: {node: '>=20'} - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation - whatwg-mimetype@4.0.0: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} - whatwg-url@15.0.0: - resolution: {integrity: sha512-+0q+Pc6oUhtbbeUfuZd4heMNOLDJDdagYxv756mCf9vnLF+NTj4zvv5UyYNkHJpc3CJIesMVoEIOdhi7L9RObA==} + whatwg-url@15.1.0: + resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} engines: {node: '>=20'} whatwg-url@5.0.0: @@ -2240,6 +2739,11 @@ packages: engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -2304,50 +2808,64 @@ packages: snapshots: - '@arthurfiorette/prettier-config@1.0.12(prettier@3.6.2)(typescript@5.9.3)': + '@acemir/cssom@0.9.31': {} + + '@arthurfiorette/prettier-config@1.0.12(prettier@3.8.0)(typescript@5.9.3)': dependencies: - prettier: 3.6.2 - prettier-plugin-jsdoc: 1.3.3(prettier@3.6.2) - prettier-plugin-organize-imports: 3.2.4(prettier@3.6.2)(typescript@5.9.3) - prettier-plugin-packagejson: 2.5.19(prettier@3.6.2) + prettier: 3.8.0 + prettier-plugin-jsdoc: 1.8.0(prettier@3.8.0) + prettier-plugin-organize-imports: 3.2.4(prettier@3.8.0)(typescript@5.9.3) + prettier-plugin-packagejson: 2.5.22(prettier@3.8.0) transitivePeerDependencies: - '@volar/vue-language-plugin-pug' - '@volar/vue-typescript' - supports-color - typescript - '@asamuzakjp/css-color@4.0.4': + '@asamuzakjp/css-color@4.1.1': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - lru-cache: 11.2.1 + lru-cache: 11.2.4 - '@asamuzakjp/dom-selector@6.5.4': + '@asamuzakjp/dom-selector@6.7.6': dependencies: '@asamuzakjp/nwsapi': 2.3.9 bidi-js: 1.0.3 css-tree: 3.1.0 is-potential-custom-element-name: 1.0.1 + lru-cache: 11.2.4 '@asamuzakjp/nwsapi@2.3.9': {} '@babel/code-frame@7.27.1': dependencies: - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.28.6': + dependencies: + '@babel/types': 7.28.6 '@babel/runtime@7.28.4': {} + '@babel/types@7.28.6': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@bcoe/v8-coverage@1.0.2': {} - '@changesets/apply-release-plan@7.0.13': + '@changesets/apply-release-plan@7.0.14': dependencies: - '@changesets/config': 3.1.1 + '@changesets/config': 3.1.2 '@changesets/get-version-range-type': 0.4.0 '@changesets/git': 3.0.4 '@changesets/should-skip-package': 0.1.2 @@ -2359,7 +2877,7 @@ snapshots: outdent: 0.5.0 prettier: 2.8.8 resolve-from: 5.0.0 - semver: 7.7.2 + semver: 7.7.3 '@changesets/assemble-release-plan@6.0.9': dependencies: @@ -2368,37 +2886,37 @@ snapshots: '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 - semver: 7.7.2 + semver: 7.7.3 '@changesets/changelog-git@0.2.1': dependencies: '@changesets/types': 6.1.0 - '@changesets/changelog-github@0.5.1': + '@changesets/changelog-github@0.5.2': dependencies: - '@changesets/get-github-info': 0.6.0 + '@changesets/get-github-info': 0.7.0 '@changesets/types': 6.1.0 dotenv: 8.6.0 transitivePeerDependencies: - encoding - '@changesets/cli@2.29.7(@types/node@24.5.0)': + '@changesets/cli@2.29.8(@types/node@24.10.9)': dependencies: - '@changesets/apply-release-plan': 7.0.13 + '@changesets/apply-release-plan': 7.0.14 '@changesets/assemble-release-plan': 6.0.9 '@changesets/changelog-git': 0.2.1 - '@changesets/config': 3.1.1 + '@changesets/config': 3.1.2 '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.1.3 - '@changesets/get-release-plan': 4.0.13 + '@changesets/get-release-plan': 4.0.14 '@changesets/git': 3.0.4 '@changesets/logger': 0.1.1 '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.5 + '@changesets/read': 0.6.6 '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@changesets/write': 0.4.0 - '@inquirer/external-editor': 1.0.2(@types/node@24.5.0) + '@inquirer/external-editor': 1.0.2(@types/node@24.10.9) '@manypkg/get-packages': 1.1.3 ansi-colors: 4.1.3 ci-info: 3.9.0 @@ -2409,13 +2927,13 @@ snapshots: package-manager-detector: 0.2.11 picocolors: 1.1.1 resolve-from: 5.0.0 - semver: 7.7.2 + semver: 7.7.3 spawndamnit: 3.0.1 term-size: 2.2.1 transitivePeerDependencies: - '@types/node' - '@changesets/config@3.1.1': + '@changesets/config@3.1.2': dependencies: '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.1.3 @@ -2434,21 +2952,21 @@ snapshots: '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 picocolors: 1.1.1 - semver: 7.7.2 + semver: 7.7.3 - '@changesets/get-github-info@0.6.0': + '@changesets/get-github-info@0.7.0': dependencies: dataloader: 1.4.0 node-fetch: 2.7.0 transitivePeerDependencies: - encoding - '@changesets/get-release-plan@4.0.13': + '@changesets/get-release-plan@4.0.14': dependencies: '@changesets/assemble-release-plan': 6.0.9 - '@changesets/config': 3.1.1 + '@changesets/config': 3.1.2 '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.5 + '@changesets/read': 0.6.6 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 @@ -2466,10 +2984,10 @@ snapshots: dependencies: picocolors: 1.1.1 - '@changesets/parse@0.4.1': + '@changesets/parse@0.4.2': dependencies: '@changesets/types': 6.1.0 - js-yaml: 3.14.1 + js-yaml: 4.1.1 '@changesets/pre@2.0.2': dependencies: @@ -2478,11 +2996,11 @@ snapshots: '@manypkg/get-packages': 1.1.3 fs-extra: 7.0.1 - '@changesets/read@0.6.5': + '@changesets/read@0.6.6': dependencies: '@changesets/git': 3.0.4 '@changesets/logger': 0.1.1 - '@changesets/parse': 0.4.1 + '@changesets/parse': 0.4.2 '@changesets/types': 6.1.0 fs-extra: 7.0.1 p-filter: 2.1.0 @@ -2522,9 +3040,7 @@ snapshots: dependencies: '@csstools/css-tokenizer': 3.0.4 - '@csstools/css-syntax-patches-for-csstree@1.0.14(postcss@8.5.6)': - dependencies: - postcss: 8.5.6 + '@csstools/css-syntax-patches-for-csstree@1.0.25': {} '@csstools/css-tokenizer@3.0.4': {} @@ -2544,6 +3060,86 @@ snapshots: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.27.2': + optional: true + + '@esbuild/android-arm64@0.27.2': + optional: true + + '@esbuild/android-arm@0.27.2': + optional: true + + '@esbuild/android-x64@0.27.2': + optional: true + + '@esbuild/darwin-arm64@0.27.2': + optional: true + + '@esbuild/darwin-x64@0.27.2': + optional: true + + '@esbuild/freebsd-arm64@0.27.2': + optional: true + + '@esbuild/freebsd-x64@0.27.2': + optional: true + + '@esbuild/linux-arm64@0.27.2': + optional: true + + '@esbuild/linux-arm@0.27.2': + optional: true + + '@esbuild/linux-ia32@0.27.2': + optional: true + + '@esbuild/linux-loong64@0.27.2': + optional: true + + '@esbuild/linux-mips64el@0.27.2': + optional: true + + '@esbuild/linux-ppc64@0.27.2': + optional: true + + '@esbuild/linux-riscv64@0.27.2': + optional: true + + '@esbuild/linux-s390x@0.27.2': + optional: true + + '@esbuild/linux-x64@0.27.2': + optional: true + + '@esbuild/netbsd-arm64@0.27.2': + optional: true + + '@esbuild/netbsd-x64@0.27.2': + optional: true + + '@esbuild/openbsd-arm64@0.27.2': + optional: true + + '@esbuild/openbsd-x64@0.27.2': + optional: true + + '@esbuild/openharmony-arm64@0.27.2': + optional: true + + '@esbuild/sunos-x64@0.27.2': + optional: true + + '@esbuild/win32-arm64@0.27.2': + optional: true + + '@esbuild/win32-ia32@0.27.2': + optional: true + + '@esbuild/win32-x64@0.27.2': + optional: true + + '@exodus/bytes@1.9.0': {} + '@fastify/ajv-compiler@4.0.2': dependencies: ajv: 8.17.1 @@ -2572,12 +3168,12 @@ snapshots: '@fastify/forwarded': 3.0.0 ipaddr.js: 2.2.0 - '@inquirer/external-editor@1.0.2(@types/node@24.5.0)': + '@inquirer/external-editor@1.0.2(@types/node@24.10.9)': dependencies: chardet: 2.1.0 iconv-lite: 0.7.0 optionalDependencies: - '@types/node': 24.5.0 + '@types/node': 24.10.9 '@isaacs/cliui@8.0.2': dependencies: @@ -2603,14 +3199,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@kitajs/ts-html-plugin@file:packages/ts-html-plugin(@kitajs/html@packages+html)(typescript@5.9.3)': - dependencies: - '@kitajs/html': link:packages/html - chalk: 5.6.2 - tslib: 2.8.1 - typescript: 5.9.3 - yargs: 18.0.0 - '@manypkg/find-root@1.1.0': dependencies: '@babel/runtime': 7.28.4 @@ -2708,20 +3296,95 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@pkgr/core@0.2.9': {} + '@rollup/rollup-android-arm-eabi@4.55.3': + optional: true + + '@rollup/rollup-android-arm64@4.55.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.55.3': + optional: true + + '@rollup/rollup-darwin-x64@4.55.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.55.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.55.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.55.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.55.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.55.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.55.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.55.3': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.55.3': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.55.3': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.55.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.55.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.55.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.55.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.55.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.55.3': + optional: true + + '@rollup/rollup-openbsd-x64@4.55.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.55.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.55.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.55.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.55.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.55.3': + optional: true '@sinclair/typebox@0.27.8': {} - '@swc-node/core@1.14.1(@swc/core@1.7.26(@swc/helpers@0.5.17))(@swc/types@0.1.12)': + '@standard-schema/spec@1.1.0': {} + + '@swc-node/core@1.14.1(@swc/core@1.7.26(@swc/helpers@0.5.18))(@swc/types@0.1.12)': dependencies: - '@swc/core': 1.7.26(@swc/helpers@0.5.17) + '@swc/core': 1.7.26(@swc/helpers@0.5.18) '@swc/types': 0.1.12 - '@swc-node/register@1.11.1(@swc/core@1.7.26(@swc/helpers@0.5.17))(@swc/types@0.1.12)(typescript@5.9.3)': + '@swc-node/register@1.11.1(@swc/core@1.7.26(@swc/helpers@0.5.18))(@swc/types@0.1.12)(typescript@5.9.3)': dependencies: - '@swc-node/core': 1.14.1(@swc/core@1.7.26(@swc/helpers@0.5.17))(@swc/types@0.1.12) + '@swc-node/core': 1.14.1(@swc/core@1.7.26(@swc/helpers@0.5.18))(@swc/types@0.1.12) '@swc-node/sourcemap-support': 0.6.1 - '@swc/core': 1.7.26(@swc/helpers@0.5.17) + '@swc/core': 1.7.26(@swc/helpers@0.5.18) colorette: 2.0.20 debug: 4.4.3 oxc-resolver: 11.8.0 @@ -2767,7 +3430,7 @@ snapshots: '@swc/core-win32-x64-msvc@1.7.26': optional: true - '@swc/core@1.7.26(@swc/helpers@0.5.17)': + '@swc/core@1.7.26(@swc/helpers@0.5.18)': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.12 @@ -2782,11 +3445,11 @@ snapshots: '@swc/core-win32-arm64-msvc': 1.7.26 '@swc/core-win32-ia32-msvc': 1.7.26 '@swc/core-win32-x64-msvc': 1.7.26 - '@swc/helpers': 0.5.17 + '@swc/helpers': 0.5.18 '@swc/counter@0.1.3': {} - '@swc/helpers@0.5.17': + '@swc/helpers@0.5.18': dependencies: tslib: 2.8.1 @@ -2801,10 +3464,17 @@ snapshots: tslib: 2.8.1 optional: true + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + '@types/debug@4.1.12': dependencies: '@types/ms': 2.1.0 + '@types/deep-eql@4.0.2': {} + '@types/eslint@7.29.0': dependencies: '@types/estree': 1.0.8 @@ -2814,9 +3484,9 @@ snapshots: '@types/istanbul-lib-coverage@2.0.6': {} - '@types/jsdom@21.1.7': + '@types/jsdom@27.0.0': dependencies: - '@types/node': 24.5.0 + '@types/node': 24.10.9 '@types/tough-cookie': 4.0.5 parse5: 7.3.0 @@ -2832,18 +3502,15 @@ snapshots: '@types/node@12.20.55': {} - '@types/node@24.5.0': + '@types/node@24.10.9': dependencies: - undici-types: 7.12.0 + undici-types: 7.16.0 '@types/normalize-package-data@2.4.4': {} - '@types/prop-types@15.7.15': {} - - '@types/react@18.3.24': + '@types/react@19.2.9': dependencies: - '@types/prop-types': 15.7.15 - csstype: 3.1.3 + csstype: 3.2.3 '@types/tough-cookie@4.0.5': {} @@ -2851,40 +3518,93 @@ snapshots: '@types/yargs-parser@21.0.3': {} - '@types/yargs@17.0.33': + '@types/yargs@17.0.35': dependencies: '@types/yargs-parser': 21.0.3 - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260116.1': + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260120.1': optional: true - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260116.1': + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260120.1': optional: true - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260116.1': + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260120.1': optional: true - '@typescript/native-preview-linux-arm@7.0.0-dev.20260116.1': + '@typescript/native-preview-linux-arm@7.0.0-dev.20260120.1': optional: true - '@typescript/native-preview-linux-x64@7.0.0-dev.20260116.1': + '@typescript/native-preview-linux-x64@7.0.0-dev.20260120.1': optional: true - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260116.1': + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260120.1': optional: true - '@typescript/native-preview-win32-x64@7.0.0-dev.20260116.1': + '@typescript/native-preview-win32-x64@7.0.0-dev.20260120.1': optional: true - '@typescript/native-preview@7.0.0-dev.20260116.1': + '@typescript/native-preview@7.0.0-dev.20260120.1': optionalDependencies: - '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260116.1 - '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260116.1 - '@typescript/native-preview-linux-arm': 7.0.0-dev.20260116.1 - '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260116.1 - '@typescript/native-preview-linux-x64': 7.0.0-dev.20260116.1 - '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260116.1 - '@typescript/native-preview-win32-x64': 7.0.0-dev.20260116.1 + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260120.1 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260120.1 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20260120.1 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260120.1 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20260120.1 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260120.1 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20260120.1 + + '@vitest/coverage-v8@4.0.17(vitest@4.0.17(@types/node@24.10.9)(jsdom@27.4.0))': + dependencies: + '@bcoe/v8-coverage': 1.0.2 + '@vitest/utils': 4.0.17 + ast-v8-to-istanbul: 0.3.10 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-reports: 3.2.0 + magicast: 0.5.1 + obug: 2.1.1 + std-env: 3.10.0 + tinyrainbow: 3.0.3 + vitest: 4.0.17(@types/node@24.10.9)(jsdom@27.4.0) + + '@vitest/expect@4.0.17': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.0.17 + '@vitest/utils': 4.0.17 + chai: 6.2.2 + tinyrainbow: 3.0.3 + + '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@24.10.9))': + dependencies: + '@vitest/spy': 4.0.17 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.1(@types/node@24.10.9) + + '@vitest/pretty-format@4.0.17': + dependencies: + tinyrainbow: 3.0.3 + + '@vitest/runner@4.0.17': + dependencies: + '@vitest/utils': 4.0.17 + pathe: 2.0.3 + + '@vitest/snapshot@4.0.17': + dependencies: + '@vitest/pretty-format': 4.0.17 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.0.17': {} + + '@vitest/utils@4.0.17': + dependencies: + '@vitest/pretty-format': 4.0.17 + tinyrainbow: 3.0.3 abstract-logging@2.0.1: {} @@ -2923,10 +3643,20 @@ snapshots: dependencies: sprintf-js: 1.0.3 + argparse@2.0.1: {} + array-union@2.1.0: {} arrify@1.0.1: {} + assertion-error@2.0.1: {} + + ast-v8-to-istanbul@0.3.10: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 9.0.1 + atomic-sleep@1.0.0: {} avvio@9.1.0: @@ -2983,6 +3713,8 @@ snapshots: camelcase@5.3.1: {} + chai@6.2.2: {} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -3041,20 +3773,19 @@ snapshots: mdn-data: 2.12.2 source-map-js: 1.2.1 - cssstyle@5.3.0(postcss@8.5.6): + cssstyle@5.3.7: dependencies: - '@asamuzakjp/css-color': 4.0.4 - '@csstools/css-syntax-patches-for-csstree': 1.0.14(postcss@8.5.6) + '@asamuzakjp/css-color': 4.1.1 + '@csstools/css-syntax-patches-for-csstree': 1.0.25 css-tree: 3.1.0 - transitivePeerDependencies: - - postcss + lru-cache: 11.2.4 - csstype@3.1.3: {} + csstype@3.2.3: {} data-urls@6.0.0: dependencies: whatwg-mimetype: 4.0.0 - whatwg-url: 15.0.0 + whatwg-url: 15.1.0 dataloader@1.4.0: {} @@ -3079,7 +3810,7 @@ snapshots: detect-indent@6.1.0: {} - detect-indent@7.0.1: {} + detect-indent@7.0.2: {} detect-newline@4.0.1: {} @@ -3114,6 +3845,37 @@ snapshots: dependencies: is-arrayish: 0.2.1 + es-module-lexer@1.7.0: {} + + esbuild@0.27.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 + escalade@3.2.0: {} eslint-formatter-pretty@4.1.0: @@ -3131,6 +3893,12 @@ snapshots: esprima@4.0.1: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + expect-type@1.3.0: {} + extendable-error@0.1.7: {} fast-decode-uri-component@1.0.1: {} @@ -3181,7 +3949,7 @@ snapshots: process-warning: 5.0.0 rfdc: 1.4.1 secure-json-parse: 4.0.0 - semver: 7.7.2 + semver: 7.7.3 toad-cache: 3.7.0 fastq@1.19.1: @@ -3229,6 +3997,9 @@ snapshots: jsonfile: 4.0.0 universalify: 0.1.2 + fsevents@2.3.3: + optional: true + function-bind@1.1.2: {} get-caller-file@2.0.5: {} @@ -3283,9 +4054,11 @@ snapshots: dependencies: lru-cache: 6.0.0 - html-encoding-sniffer@4.0.0: + html-encoding-sniffer@6.0.0: dependencies: - whatwg-encoding: 3.1.1 + '@exodus/bytes': 1.9.0 + transitivePeerDependencies: + - '@noble/hashes' html-escaper@2.0.2: {} @@ -3317,10 +4090,6 @@ snapshots: husky@9.1.7: {} - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - iconv-lite@0.7.0: dependencies: safer-buffer: 2.1.2 @@ -3395,36 +4164,42 @@ snapshots: js-tokens@4.0.0: {} + js-tokens@9.0.1: {} + js-yaml@3.14.1: dependencies: argparse: 1.0.10 esprima: 4.0.1 - jsdom@27.0.0(postcss@8.5.6): + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsdom@27.4.0: dependencies: - '@asamuzakjp/dom-selector': 6.5.4 - cssstyle: 5.3.0(postcss@8.5.6) + '@acemir/cssom': 0.9.31 + '@asamuzakjp/dom-selector': 6.7.6 + '@exodus/bytes': 1.9.0 + cssstyle: 5.3.7 data-urls: 6.0.0 decimal.js: 10.6.0 - html-encoding-sniffer: 4.0.0 + html-encoding-sniffer: 6.0.0 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 - parse5: 7.3.0 - rrweb-cssom: 0.8.0 + parse5: 8.0.0 saxes: 6.0.0 symbol-tree: 3.2.4 tough-cookie: 6.0.0 w3c-xmlserializer: 5.0.0 webidl-conversions: 8.0.0 - whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 - whatwg-url: 15.0.0 + whatwg-url: 15.1.0 ws: 8.18.3 xml-name-validator: 5.0.0 transitivePeerDependencies: + - '@noble/hashes' - bufferutil - - postcss - supports-color - utf-8-validate @@ -3471,15 +4246,25 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.2.1: {} + lru-cache@11.2.4: {} lru-cache@6.0.0: dependencies: yallist: 4.0.0 + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.5.1: + dependencies: + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 + source-map-js: 1.2.1 + make-dir@4.0.0: dependencies: - semver: 7.7.2 + semver: 7.7.3 map-obj@1.0.1: {} @@ -3708,9 +4493,11 @@ snapshots: dependencies: hosted-git-info: 4.1.0 is-core-module: 2.16.1 - semver: 7.7.2 + semver: 7.7.3 validate-npm-package-license: 3.0.4 + obug@2.1.1: {} + on-exit-leak-free@2.1.2: {} outdent@0.5.0: {} @@ -3784,6 +4571,10 @@ snapshots: dependencies: entities: 6.0.1 + parse5@8.0.0: + dependencies: + entities: 6.0.1 + path-exists@4.0.0: {} path-key@3.1.1: {} @@ -3797,6 +4588,8 @@ snapshots: path-type@4.0.0: {} + pathe@2.0.3: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -3843,35 +4636,40 @@ snapshots: preact@10.27.3: {} - prettier-plugin-jsdoc@1.3.3(prettier@3.6.2): + prettier-plugin-jsdoc@1.8.0(prettier@3.8.0): dependencies: binary-searching: 2.0.5 comment-parser: 1.4.1 mdast-util-from-markdown: 2.0.2 - prettier: 3.6.2 + prettier: 3.8.0 transitivePeerDependencies: - supports-color - prettier-plugin-organize-imports@3.2.4(prettier@3.6.2)(typescript@5.9.3): + prettier-plugin-organize-imports@3.2.4(prettier@3.8.0)(typescript@5.9.3): dependencies: - prettier: 3.6.2 + prettier: 3.8.0 typescript: 5.9.3 - prettier-plugin-organize-imports@4.2.0(prettier@3.6.2)(typescript@5.9.3): + prettier-plugin-organize-imports@4.3.0(prettier@3.8.0)(typescript@5.9.3): dependencies: - prettier: 3.6.2 + prettier: 3.8.0 typescript: 5.9.3 - prettier-plugin-packagejson@2.5.19(prettier@3.6.2): + prettier-plugin-packagejson@2.5.22(prettier@3.8.0): + dependencies: + sort-package-json: 3.6.0 + optionalDependencies: + prettier: 3.8.0 + + prettier-plugin-packagejson@3.0.0(prettier@3.8.0): dependencies: - sort-package-json: 3.4.0 - synckit: 0.11.11 + sort-package-json: 3.6.0 optionalDependencies: - prettier: 3.6.2 + prettier: 3.8.0 prettier@2.8.8: {} - prettier@3.6.2: {} + prettier@3.8.0: {} pretty-format@29.7.0: dependencies: @@ -3893,14 +4691,14 @@ snapshots: quick-lru@4.0.1: {} - react-dom@19.1.1(react@19.1.1): + react-dom@19.2.3(react@19.2.3): dependencies: - react: 19.1.1 - scheduler: 0.26.0 + react: 19.2.3 + scheduler: 0.27.0 react-is@18.3.1: {} - react@19.1.1: {} + react@19.2.3: {} read-pkg-up@7.0.1: dependencies: @@ -3949,7 +4747,36 @@ snapshots: rfdc@1.4.1: {} - rrweb-cssom@0.8.0: {} + rollup@4.55.3: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.55.3 + '@rollup/rollup-android-arm64': 4.55.3 + '@rollup/rollup-darwin-arm64': 4.55.3 + '@rollup/rollup-darwin-x64': 4.55.3 + '@rollup/rollup-freebsd-arm64': 4.55.3 + '@rollup/rollup-freebsd-x64': 4.55.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.55.3 + '@rollup/rollup-linux-arm-musleabihf': 4.55.3 + '@rollup/rollup-linux-arm64-gnu': 4.55.3 + '@rollup/rollup-linux-arm64-musl': 4.55.3 + '@rollup/rollup-linux-loong64-gnu': 4.55.3 + '@rollup/rollup-linux-loong64-musl': 4.55.3 + '@rollup/rollup-linux-ppc64-gnu': 4.55.3 + '@rollup/rollup-linux-ppc64-musl': 4.55.3 + '@rollup/rollup-linux-riscv64-gnu': 4.55.3 + '@rollup/rollup-linux-riscv64-musl': 4.55.3 + '@rollup/rollup-linux-s390x-gnu': 4.55.3 + '@rollup/rollup-linux-x64-gnu': 4.55.3 + '@rollup/rollup-linux-x64-musl': 4.55.3 + '@rollup/rollup-openbsd-x64': 4.55.3 + '@rollup/rollup-openharmony-arm64': 4.55.3 + '@rollup/rollup-win32-arm64-msvc': 4.55.3 + '@rollup/rollup-win32-ia32-msvc': 4.55.3 + '@rollup/rollup-win32-x64-gnu': 4.55.3 + '@rollup/rollup-win32-x64-msvc': 4.55.3 + fsevents: 2.3.3 run-parallel@1.2.0: dependencies: @@ -3967,13 +4794,13 @@ snapshots: dependencies: xmlchars: 2.2.0 - scheduler@0.26.0: {} + scheduler@0.27.0: {} secure-json-parse@4.0.0: {} semver@5.7.2: {} - semver@7.7.2: {} + semver@7.7.3: {} set-cookie-parser@2.7.1: {} @@ -3983,6 +4810,8 @@ snapshots: shebang-regex@3.0.0: {} + siginfo@2.0.0: {} + signal-exit@4.1.0: {} slash@3.0.0: {} @@ -3991,16 +4820,16 @@ snapshots: dependencies: atomic-sleep: 1.0.0 - sort-object-keys@1.1.3: {} + sort-object-keys@2.1.0: {} - sort-package-json@3.4.0: + sort-package-json@3.6.0: dependencies: - detect-indent: 7.0.1 + detect-indent: 7.0.2 detect-newline: 4.0.1 git-hooks-list: 4.1.1 is-plain-obj: 4.1.0 - semver: 7.7.2 - sort-object-keys: 1.1.3 + semver: 7.7.3 + sort-object-keys: 2.1.0 tinyglobby: 0.2.15 source-map-js@1.2.1: {} @@ -4035,6 +4864,10 @@ snapshots: sprintf-js@1.0.3: {} + stackback@0.0.2: {} + + std-env@3.10.0: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -4080,10 +4913,6 @@ snapshots: symbol-tree@3.2.4: {} - synckit@0.11.11: - dependencies: - '@pkgr/core': 0.2.9 - term-size@2.2.1: {} test-exclude@7.0.1: @@ -4096,11 +4925,17 @@ snapshots: dependencies: real-require: 0.2.0 + tinybench@2.9.0: {} + + tinyexec@1.0.2: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + tinyrainbow@3.0.3: {} + tldts-core@7.0.14: {} tldts@7.0.14: @@ -4119,7 +4954,7 @@ snapshots: tr46@0.0.3: {} - tr46@5.1.1: + tr46@6.0.0: dependencies: punycode: 2.3.1 @@ -4151,7 +4986,7 @@ snapshots: uglify-js@3.19.3: {} - undici-types@7.12.0: {} + undici-types@7.16.0: {} unist-util-stringify-position@4.0.0: dependencies: @@ -4174,6 +5009,56 @@ snapshots: vhtml@2.2.0: {} + vite@7.3.1(@types/node@24.10.9): + dependencies: + esbuild: 0.27.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.55.3 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 24.10.9 + fsevents: 2.3.3 + + vitest@4.0.17(@types/node@24.10.9)(jsdom@27.4.0): + dependencies: + '@vitest/expect': 4.0.17 + '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@24.10.9)) + '@vitest/pretty-format': 4.0.17 + '@vitest/runner': 4.0.17 + '@vitest/snapshot': 4.0.17 + '@vitest/spy': 4.0.17 + '@vitest/utils': 4.0.17 + es-module-lexer: 1.7.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 7.3.1(@types/node@24.10.9) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 24.10.9 + jsdom: 27.4.0 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 @@ -4182,15 +5067,11 @@ snapshots: webidl-conversions@8.0.0: {} - whatwg-encoding@3.1.1: - dependencies: - iconv-lite: 0.6.3 - whatwg-mimetype@4.0.0: {} - whatwg-url@15.0.0: + whatwg-url@15.1.0: dependencies: - tr46: 5.1.1 + tr46: 6.0.0 webidl-conversions: 8.0.0 whatwg-url@5.0.0: @@ -4202,6 +5083,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b1c183148..637f7eecc 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,28 +1,19 @@ packages: - - 'packages/*' - - 'benchmarks/*' + - packages/* + - benchmarks/* catalog: - # TypeScript and tooling - typescript: ^5.9.2 - tslib: ^2.8.1 - '@typescript/native-preview': latest - - # Node types - '@types/node': ^24.10.9 - - # SWC tooling '@swc-node/register': ^1.11.1 '@swc/helpers': ^0.5.18 - - # Testing and coverage - c8: ^10.1.3 - - # JSDOM for testing '@types/jsdom': ^27.0.0 + '@types/node': ^24.10.9 + '@types/react': ^19.2.9 + '@typescript/native-preview': latest + '@vitest/coverage-v8': ^4.0.17 + c8: ^10.1.3 jsdom: ^27.4.0 - - # React - '@types/react': ^19.2.8 react: ^19.2.3 react-dom: ^19.2.3 + tslib: ^2.8.1 + typescript: ^5.9.3 + vitest: ^4.0.17 diff --git a/tsconfig.json b/tsconfig.json index fb25a9637..7b58162dc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,38 +1,45 @@ { "compilerOptions": { - "target": "ESNext", - "jsx": "react-jsx", - "jsxImportSource": "@kitajs/html", - "plugins": [{ "name": "@kitajs/ts-html-plugin" }], - "module": "CommonJS", - "moduleResolution": "node", - "incremental": true, - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitAny": true, - "strictNullChecks": true, + // File Layout + // "rootDir": "./src", + // "outDir": "./dist", + "noEmit": true, + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "target": "esnext", + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, "declaration": true, - "importHelpers": true, "declarationMap": true, - "sourceMap": true, - "strictFunctionTypes": true, - "strictBindCallApply": true, - "strictPropertyInitialization": true, - "noImplicitThis": true, - "useUnknownInCatchVariables": true, - "alwaysStrict": true, - "outDir": "dist", + "incremental": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + "erasableSyntaxOnly": true, + + // Style Options + "noImplicitReturns": true, + "noImplicitOverride": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, - "noUncheckedIndexedAccess": true, - "noImplicitOverride": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true, "skipDefaultLibCheck": true - }, - "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.d.ts", "node_modules/csstype"], - "exclude": ["node_modules", "dist", "coverage", "benchmarks"] + } } From 79be57341b0dbea5508ca6c61e10e9e9f39cf176 Mon Sep 17 00:00:00 2001 From: Arthur Fiorette Date: Thu, 22 Jan 2026 01:54:47 +0700 Subject: [PATCH 03/22] code --- packages/html/package.json | 3 ++- packages/ts-html-plugin/package.json | 2 ++ packages/ts-html-plugin/tsconfig.json | 5 ++--- pnpm-lock.yaml | 14 +++++++------- tsconfig.json | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/html/package.json b/packages/html/package.json index bce70c691..1aba95b16 100644 --- a/packages/html/package.json +++ b/packages/html/package.json @@ -13,7 +13,7 @@ "license": "MIT", "author": "Arthur Fiorette ", "sideEffects": false, - "type": "module", + "type": "commonjs", "exports": { ".": "./dist/index.js", "./*": "./*", @@ -25,6 +25,7 @@ }, "files": [ "dist", + "src", "*.d.ts", "!dist/*.tsbuildinfo" ], diff --git a/packages/ts-html-plugin/package.json b/packages/ts-html-plugin/package.json index 8705731b4..490814eda 100644 --- a/packages/ts-html-plugin/package.json +++ b/packages/ts-html-plugin/package.json @@ -31,12 +31,14 @@ "yargs": "^18.0.0" }, "devDependencies": { + "@kitajs/html": "workspace:^", "@types/node": "catalog:", "@types/yargs": "^17.0.35", "@typescript/native-preview": "catalog:", "@vitest/coverage-v8": "catalog:", "fast-defer": "^1.1.9", "self": "link:", + "typescript": "catalog:", "vitest": "catalog:" }, "peerDependencies": { diff --git a/packages/ts-html-plugin/tsconfig.json b/packages/ts-html-plugin/tsconfig.json index c5b66c772..2fed558be 100644 --- a/packages/ts-html-plugin/tsconfig.json +++ b/packages/ts-html-plugin/tsconfig.json @@ -1,12 +1,11 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "verbatimModuleSyntax": false, "target": "esnext", "jsx": "react-jsx", "jsxImportSource": "@kitajs/html", - "module": "CommonJS", - "moduleResolution": "Node", + "module": "nodenext", + "moduleResolution": "nodenext", "outDir": "./dist", "plugins": [{ "name": "self" }] }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5d494760c..c181ca589 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -368,7 +368,7 @@ importers: specifier: 'catalog:' version: 7.0.0-dev.20260120.1 '@vitest/coverage-v8': - specifier: ^4.0.17 + specifier: 'catalog:' version: 4.0.17(vitest@4.0.17(@types/node@24.10.9)(jsdom@27.4.0)) c8: specifier: 'catalog:' @@ -394,22 +394,19 @@ importers: packages/ts-html-plugin: dependencies: - '@kitajs/html': - specifier: workspace:^ - version: link:../html chalk: specifier: ^5.6.2 version: 5.6.2 tslib: specifier: 'catalog:' version: 2.8.1 - typescript: - specifier: 'catalog:' - version: 5.9.3 yargs: specifier: ^18.0.0 version: 18.0.0 devDependencies: + '@kitajs/html': + specifier: workspace:^ + version: link:../html '@types/node': specifier: 'catalog:' version: 24.10.9 @@ -428,6 +425,9 @@ importers: self: specifier: 'link:' version: 'link:' + typescript: + specifier: 'catalog:' + version: 5.9.3 vitest: specifier: 'catalog:' version: 4.0.17(@types/node@24.10.9)(jsdom@27.4.0) diff --git a/tsconfig.json b/tsconfig.json index 7b58162dc..9d0e5eef0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -35,7 +35,7 @@ // Recommended Options "strict": true, - "verbatimModuleSyntax": true, + "verbatimModuleSyntax": false, "isolatedModules": true, "noUncheckedSideEffectImports": true, "moduleDetection": "force", From f666fe1d9a367d42679bdfcd0e371efe35a13e35 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 23:18:06 -0300 Subject: [PATCH 04/22] Fix tsserver protocol parser for TypeScript 5.9.3 (#455) Co-authored-by: arthurfiorette <47537704+arthurfiorette@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- .../ts-html-plugin/test/util/lang-server.ts | 67 +++++++++++++------ 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/packages/ts-html-plugin/test/util/lang-server.ts b/packages/ts-html-plugin/test/util/lang-server.ts index d3d319d2d..0f8e19ba3 100644 --- a/packages/ts-html-plugin/test/util/lang-server.ts +++ b/packages/ts-html-plugin/test/util/lang-server.ts @@ -65,6 +65,7 @@ export class TSLangServer { server: ChildProcess; sequence = 0; debug: boolean; + buffer = ''; // Add buffer for incomplete messages constructor(projectPath: string, debug = false) { this.debug = debug; @@ -85,32 +86,58 @@ export class TSLangServer { this.server.stdout?.on('data', (data) => { try { - const obj = JSON.parse(data.split('\n', 3)[2]); - - if (this.debug) { - console.dir(obj, { depth: 10 }); - } - - if (obj.success === false) { - this.errorEmitter.emit(obj.type === 'event' ? obj.event : obj.command, obj); - - // Error is fatal, close the server - if (!this.isClosed) { - this.isClosed = true; - this.server.stdin?.end(); - } - } else if (obj.type === 'event') { - this.responseEventEmitter.emit(obj.event, obj); - } else if (obj.type === 'response') { - this.responseCommandEmitter.emit(obj.command, obj); - } + this.buffer += data; + this.#processMessages(); } catch (error) { - console.error(data); + console.error(this.buffer); this.exitPromise.reject(error); } }); } + #processMessages() { + // Process all complete messages in the buffer + let headerMatch = this.buffer.match(/Content-Length: (\d+)\r?\n\r?\n/); + + while (headerMatch?.index && headerMatch[1]) { + // TSServer protocol: Content-Length: N\r\n\r\n{JSON}\r\n + const contentLength = parseInt(headerMatch[1], 10); + const headerEnd = headerMatch.index + headerMatch[0].length; + const messageEnd = headerEnd + contentLength; + + // Check if we have the complete message + if (this.buffer.length < messageEnd) break; + + // Extract and parse the message + const jsonStr = this.buffer.substring(headerEnd, messageEnd); + const obj = JSON.parse(jsonStr); + + // Remove the processed message from buffer + this.buffer = this.buffer.substring(messageEnd); + + if (this.debug) { + console.dir(obj, { depth: 10 }); + } + + if (obj.success === false) { + this.errorEmitter.emit(obj.type === 'event' ? obj.event : obj.command, obj); + + // Error is fatal, close the server + if (!this.isClosed) { + this.isClosed = true; + this.server.stdin?.end(); + } + } else if (obj.type === 'event') { + this.responseEventEmitter.emit(obj.event, obj); + } else if (obj.type === 'response') { + this.responseCommandEmitter.emit(obj.command, obj); + } + + // Check for next message + headerMatch = this.buffer.match(/Content-Length: (\d+)\r?\n\r?\n/); + } + } + /** Opens the project, sends diagnostics request and returns the response */ async openWithDiagnostics(content: TemplateStringsArray, ...args: any[]) { const fileContent = `${TEST_HELPERS}\n${String.raw(content, ...args).trim()}`; From 2aa14b44ebac50ec4bf48c2436f965ad4ba6732f Mon Sep 17 00:00:00 2001 From: Arthur Fiorette Date: Thu, 22 Jan 2026 09:45:31 +0700 Subject: [PATCH 05/22] code --- .vscode/settings.json | 6 +++++- benchmarks/honojsx/tsconfig.json | 1 - benchmarks/jsxte/tsconfig.json | 1 - benchmarks/kitajs/tsconfig.json | 1 - benchmarks/preact/tsconfig.json | 1 - benchmarks/react/tsconfig.json | 1 - benchmarks/reactjsx/tsconfig.json | 1 - benchmarks/templates/tsconfig.json | 3 --- benchmarks/typed-html/tsconfig.json | 1 - benchmarks/vhtml/tsconfig.json | 1 - packages/ts-html-plugin/test/component-xss.test.ts | 2 +- packages/ts-html-plugin/test/util/lang-server.ts | 9 +++++---- 12 files changed, 11 insertions(+), 17 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f9ff80aab..8093cfdd2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,9 @@ "typescript.enablePromptUseWorkspaceTsdk": true, "typescript.experimental.useTsgo": true, "typescript.tsdk": "node_modules/typescript/lib", - "typescript.tsserver.maxTsServerMemory": 4096 + "typescript.tsserver.maxTsServerMemory": 4096, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } } diff --git a/benchmarks/honojsx/tsconfig.json b/benchmarks/honojsx/tsconfig.json index 8349d5fc9..2d7cf0a6e 100644 --- a/benchmarks/honojsx/tsconfig.json +++ b/benchmarks/honojsx/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "baseUrl": "./", "outDir": "dist", "jsx": "react-jsx", "jsxImportSource": "hono/jsx", diff --git a/benchmarks/jsxte/tsconfig.json b/benchmarks/jsxte/tsconfig.json index b2254cbd9..457fa4809 100644 --- a/benchmarks/jsxte/tsconfig.json +++ b/benchmarks/jsxte/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "baseUrl": "./", "outDir": "dist", "module": "Node16", "target": "ESNext", diff --git a/benchmarks/kitajs/tsconfig.json b/benchmarks/kitajs/tsconfig.json index 3d3c1007f..461943ebe 100644 --- a/benchmarks/kitajs/tsconfig.json +++ b/benchmarks/kitajs/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "baseUrl": "./", "outDir": "dist", "module": "Node16", "target": "ESNext", diff --git a/benchmarks/preact/tsconfig.json b/benchmarks/preact/tsconfig.json index ca3fb9aaa..34b21753c 100644 --- a/benchmarks/preact/tsconfig.json +++ b/benchmarks/preact/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "baseUrl": "./", "outDir": "dist", "jsx": "react-jsx", "jsxImportSource": "preact", diff --git a/benchmarks/react/tsconfig.json b/benchmarks/react/tsconfig.json index c3a4080d9..df58f3d55 100644 --- a/benchmarks/react/tsconfig.json +++ b/benchmarks/react/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "baseUrl": "./", "outDir": "dist", "jsx": "react", "declaration": true, diff --git a/benchmarks/reactjsx/tsconfig.json b/benchmarks/reactjsx/tsconfig.json index 1018ee991..32b8661e5 100644 --- a/benchmarks/reactjsx/tsconfig.json +++ b/benchmarks/reactjsx/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "baseUrl": "./", "outDir": "dist", "jsx": "react-jsx", "declaration": true, diff --git a/benchmarks/templates/tsconfig.json b/benchmarks/templates/tsconfig.json index 8cae5be0d..76743a9bc 100644 --- a/benchmarks/templates/tsconfig.json +++ b/benchmarks/templates/tsconfig.json @@ -1,11 +1,8 @@ { "compilerOptions": { - "baseUrl": "./", "outDir": "dist", "module": "Node16", "target": "ESNext", - "jsx": "react-jsx", - "jsxImportSource": "@kitajs/html", "declaration": true, "declarationMap": true, "sourceMap": true diff --git a/benchmarks/typed-html/tsconfig.json b/benchmarks/typed-html/tsconfig.json index 01540693e..b1437cbef 100644 --- a/benchmarks/typed-html/tsconfig.json +++ b/benchmarks/typed-html/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "baseUrl": "./", "outDir": "dist", "module": "Node16", "moduleResolution": "Node16", diff --git a/benchmarks/vhtml/tsconfig.json b/benchmarks/vhtml/tsconfig.json index 266be58a2..ddfd40f02 100644 --- a/benchmarks/vhtml/tsconfig.json +++ b/benchmarks/vhtml/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "baseUrl": "./", "outDir": "dist", "module": "Node16", "moduleResolution": "Node16", diff --git a/packages/ts-html-plugin/test/component-xss.test.ts b/packages/ts-html-plugin/test/component-xss.test.ts index 046eda386..b19487807 100644 --- a/packages/ts-html-plugin/test/component-xss.test.ts +++ b/packages/ts-html-plugin/test/component-xss.test.ts @@ -3,7 +3,7 @@ import { ComponentXss } from '../src/errors'; import { TSLangServer } from './util/lang-server'; it('Ensure children are safe', async () => { - await using server = new TSLangServer(__dirname); + await using server = new TSLangServer(__dirname, true); const diagnostics = await server.openWithDiagnostics /* tsx */ ` export default ( diff --git a/packages/ts-html-plugin/test/util/lang-server.ts b/packages/ts-html-plugin/test/util/lang-server.ts index 0f8e19ba3..591e77aa1 100644 --- a/packages/ts-html-plugin/test/util/lang-server.ts +++ b/packages/ts-html-plugin/test/util/lang-server.ts @@ -64,11 +64,12 @@ export class TSLangServer { isClosed = false; server: ChildProcess; sequence = 0; - debug: boolean; buffer = ''; // Add buffer for incomplete messages - constructor(projectPath: string, debug = false) { - this.debug = debug; + constructor( + projectPath: string, + private readonly debug = false + ) { this.server = fork(require.resolve('typescript/lib/tsserver'), { cwd: projectPath, stdio: ['pipe', 'pipe', 'pipe', 'ipc'], @@ -99,7 +100,7 @@ export class TSLangServer { // Process all complete messages in the buffer let headerMatch = this.buffer.match(/Content-Length: (\d+)\r?\n\r?\n/); - while (headerMatch?.index && headerMatch[1]) { + while (headerMatch && headerMatch.index !== undefined) { // TSServer protocol: Content-Length: N\r\n\r\n{JSON}\r\n const contentLength = parseInt(headerMatch[1], 10); const headerEnd = headerMatch.index + headerMatch[0].length; From faacfcc21b2aaaa2e1207821c19232600edac1e9 Mon Sep 17 00:00:00 2001 From: Arthur Fiorette Date: Thu, 22 Jan 2026 10:03:35 +0700 Subject: [PATCH 06/22] code --- .vscode/settings.json | 1 - package.json | 1 + packages/html/package.json | 2 +- packages/html/src/index.ts | 3 ++- packages/html/tsconfig.json | 2 +- packages/ts-html-plugin/package.json | 2 +- packages/ts-html-plugin/test/tsconfig.json | 2 +- .../ts-html-plugin/test/util/lang-server.ts | 17 ++++++++++------- packages/ts-html-plugin/tsconfig.json | 2 +- pnpm-lock.yaml | 7 +++++-- 10 files changed, 23 insertions(+), 16 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 8093cfdd2..9a44a6ada 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,5 @@ { "typescript.enablePromptUseWorkspaceTsdk": true, - "typescript.experimental.useTsgo": true, "typescript.tsdk": "node_modules/typescript/lib", "typescript.tsserver.maxTsServerMemory": 4096, "editor.defaultFormatter": "esbenp.prettier-vscode", diff --git a/package.json b/package.json index 901f03791..120666b7f 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "prettier-plugin-jsdoc": "^1.8.0", "prettier-plugin-organize-imports": "^4.3.0", "prettier-plugin-packagejson": "^3.0.0", + "self-ts-plugin": "link:packages/ts-html-plugin", "typescript": "catalog:" }, "packageManager": "pnpm@10.28.1", diff --git a/packages/html/package.json b/packages/html/package.json index 1aba95b16..737fc48a3 100644 --- a/packages/html/package.json +++ b/packages/html/package.json @@ -46,7 +46,7 @@ "jsdom": "catalog:", "react": "catalog:", "react-dom": "catalog:", - "self": "link:", + "self-html": "link:", "typescript": "catalog:", "vitest": "catalog:" }, diff --git a/packages/html/src/index.ts b/packages/html/src/index.ts index 3894a3d68..a00db5573 100644 --- a/packages/html/src/index.ts +++ b/packages/html/src/index.ts @@ -1,4 +1,5 @@ -/// +import './jsx.d.ts'; + /// /// diff --git a/packages/html/tsconfig.json b/packages/html/tsconfig.json index cbe7f4e7d..dc25414e5 100644 --- a/packages/html/tsconfig.json +++ b/packages/html/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "jsx": "react-jsx", - "jsxImportSource": "self", + "jsxImportSource": "self-html", "outDir": "./dist" }, "include": ["src", "test"] diff --git a/packages/ts-html-plugin/package.json b/packages/ts-html-plugin/package.json index 490814eda..c4e01bfed 100644 --- a/packages/ts-html-plugin/package.json +++ b/packages/ts-html-plugin/package.json @@ -37,7 +37,7 @@ "@typescript/native-preview": "catalog:", "@vitest/coverage-v8": "catalog:", "fast-defer": "^1.1.9", - "self": "link:", + "self-ts-plugin": "link:", "typescript": "catalog:", "vitest": "catalog:" }, diff --git a/packages/ts-html-plugin/test/tsconfig.json b/packages/ts-html-plugin/test/tsconfig.json index 0775d5429..6df055860 100644 --- a/packages/ts-html-plugin/test/tsconfig.json +++ b/packages/ts-html-plugin/test/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "plugins": [{ "name": "self" }] + "plugins": [{ "name": "self-ts-plugin" }] }, "include": ["**/*.tsx", "*.test.ts"] } diff --git a/packages/ts-html-plugin/test/util/lang-server.ts b/packages/ts-html-plugin/test/util/lang-server.ts index 591e77aa1..62bfad76b 100644 --- a/packages/ts-html-plugin/test/util/lang-server.ts +++ b/packages/ts-html-plugin/test/util/lang-server.ts @@ -11,7 +11,7 @@ export type Requests = | ts.server.protocol.SemanticDiagnosticsSyncRequest; try { - statSync(require.resolve('self')); + statSync(require.resolve('self-ts-plugin')); } catch (error) { throw new Error('You must run pnpm build before running tests'); } @@ -65,11 +65,10 @@ export class TSLangServer { server: ChildProcess; sequence = 0; buffer = ''; // Add buffer for incomplete messages + debug: boolean; - constructor( - projectPath: string, - private readonly debug = false - ) { + constructor(projectPath: string, debug = false) { + this.debug = debug; this.server = fork(require.resolve('typescript/lib/tsserver'), { cwd: projectPath, stdio: ['pipe', 'pipe', 'pipe', 'ipc'], @@ -83,8 +82,12 @@ export class TSLangServer { this.server.on('exit', this.exitPromise.resolve); this.server.on('error', this.exitPromise.reject); - this.server.stdout?.setEncoding('utf-8'); + this.server.stderr?.setEncoding('utf-8'); + this.server.stderr?.on('data', (data) => { + console.error(data); + }); + this.server.stdout?.setEncoding('utf-8'); this.server.stdout?.on('data', (data) => { try { this.buffer += data; @@ -102,7 +105,7 @@ export class TSLangServer { while (headerMatch && headerMatch.index !== undefined) { // TSServer protocol: Content-Length: N\r\n\r\n{JSON}\r\n - const contentLength = parseInt(headerMatch[1], 10); + const contentLength = parseInt(headerMatch[1]!, 10); const headerEnd = headerMatch.index + headerMatch[0].length; const messageEnd = headerEnd + contentLength; diff --git a/packages/ts-html-plugin/tsconfig.json b/packages/ts-html-plugin/tsconfig.json index 2fed558be..fce7d38cd 100644 --- a/packages/ts-html-plugin/tsconfig.json +++ b/packages/ts-html-plugin/tsconfig.json @@ -7,7 +7,7 @@ "module": "nodenext", "moduleResolution": "nodenext", "outDir": "./dist", - "plugins": [{ "name": "self" }] + "plugins": [{ "name": "self-ts-plugin" }] }, "include": ["src", "test"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c181ca589..2ad75deeb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -80,6 +80,9 @@ importers: prettier-plugin-packagejson: specifier: ^3.0.0 version: 3.0.0(prettier@3.8.0) + self-ts-plugin: + specifier: link:packages/ts-html-plugin + version: link:packages/ts-html-plugin typescript: specifier: 'catalog:' version: 5.9.3 @@ -382,7 +385,7 @@ importers: react-dom: specifier: 'catalog:' version: 19.2.3(react@19.2.3) - self: + self-html: specifier: 'link:' version: 'link:' typescript: @@ -422,7 +425,7 @@ importers: fast-defer: specifier: ^1.1.9 version: 1.1.9 - self: + self-ts-plugin: specifier: 'link:' version: 'link:' typescript: From 86301e4b282b424c7f832d4ec0c925103c910e5d Mon Sep 17 00:00:00 2001 From: Arthur Fiorette Date: Thu, 22 Jan 2026 11:21:03 +0700 Subject: [PATCH 07/22] code --- .changeset/metal-corners-type.md | 5 +++ packages/ts-html-plugin/package.json | 4 +-- packages/ts-html-plugin/src/util.ts | 34 ++++++++++++++++++- .../ts-html-plugin/test/component-xss.test.ts | 2 +- packages/ts-html-plugin/tsconfig.build.json | 6 ++++ packages/ts-html-plugin/vitest.config.ts | 9 +++++ 6 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 .changeset/metal-corners-type.md create mode 100644 packages/ts-html-plugin/vitest.config.ts diff --git a/.changeset/metal-corners-type.md b/.changeset/metal-corners-type.md new file mode 100644 index 000000000..d8675de67 --- /dev/null +++ b/.changeset/metal-corners-type.md @@ -0,0 +1,5 @@ +--- +'@kitajs/ts-html-plugin': patch +--- + +Support for multiline TSServer messages and improvements to XSS Children detection diff --git a/packages/ts-html-plugin/package.json b/packages/ts-html-plugin/package.json index c4e01bfed..33394eea2 100644 --- a/packages/ts-html-plugin/package.json +++ b/packages/ts-html-plugin/package.json @@ -21,8 +21,8 @@ }, "scripts": { "build": "tsgo -p tsconfig.build.json", - "prepack": "npm run build", - "pretest": "npm run build", + "prepack": "pnpm run build", + "pretest": "pnpm run build", "test": "vitest --coverage --typecheck --run" }, "dependencies": { diff --git a/packages/ts-html-plugin/src/util.ts b/packages/ts-html-plugin/src/util.ts index d16074e16..f89b95484 100644 --- a/packages/ts-html-plugin/src/util.ts +++ b/packages/ts-html-plugin/src/util.ts @@ -243,13 +243,45 @@ export function isSafeAttribute( return true; } + // Check if this is a property access to .children (from PropsWithChildren) + // This must be checked BEFORE union recursion to avoid false positives + if (ts.isPropertyAccessExpression(node) && node.name.text === 'children') { + return true; + } + + // Consolidated identifier checks - MUST be before union recursion + if (ts.isIdentifier(node)) { + // Destructured or direct `children` parameter (e.g., function Test({ children }: PropsWithChildren)) + if (node.text === 'children') { + return true; + } + + // Check if variable is initialized with JSX (e.g., const element =
) + const symbol = checker.getSymbolAtLocation(node); + if (symbol) { + const declarations = symbol.getDeclarations(); + if (declarations) { + for (const decl of declarations) { + if ( + ts.isVariableDeclaration(decl) && + decl.initializer && + isJsx(ts, decl.initializer) + ) { + return true; + } + } + } + } + } + // Any type is never safe if (type.flags & ts.TypeFlags.Any) { return false; } + // Check type aliases for JSX.Element and Html.Children if (type.aliasSymbol) { - // Allows JSX.Element + // Allows JSX.Element (when the alias is preserved) if ( node && type.aliasSymbol.escapedName === 'Element' && diff --git a/packages/ts-html-plugin/test/component-xss.test.ts b/packages/ts-html-plugin/test/component-xss.test.ts index b19487807..046eda386 100644 --- a/packages/ts-html-plugin/test/component-xss.test.ts +++ b/packages/ts-html-plugin/test/component-xss.test.ts @@ -3,7 +3,7 @@ import { ComponentXss } from '../src/errors'; import { TSLangServer } from './util/lang-server'; it('Ensure children are safe', async () => { - await using server = new TSLangServer(__dirname, true); + await using server = new TSLangServer(__dirname); const diagnostics = await server.openWithDiagnostics /* tsx */ ` export default ( diff --git a/packages/ts-html-plugin/tsconfig.build.json b/packages/ts-html-plugin/tsconfig.build.json index b90fc83e0..4960a34a6 100644 --- a/packages/ts-html-plugin/tsconfig.build.json +++ b/packages/ts-html-plugin/tsconfig.build.json @@ -1,4 +1,10 @@ { "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "outDir": "./dist", + "rootDir": "./src", + "tsBuildInfoFile": "dist/.tsbuildinfo" + }, "include": ["src"] } diff --git a/packages/ts-html-plugin/vitest.config.ts b/packages/ts-html-plugin/vitest.config.ts new file mode 100644 index 000000000..2221df30e --- /dev/null +++ b/packages/ts-html-plugin/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + coverage: { + exclude: ['test/**'] + } + } +}); From 62bdc635a9725f7de6171e5df664b7cd70ae74ea Mon Sep 17 00:00:00 2001 From: Arthur Fiorette Date: Thu, 22 Jan 2026 13:00:29 +0700 Subject: [PATCH 08/22] code --- package.json | 2 +- packages/fastify-html-plugin/LICENSE | 22 +- packages/fastify-html-plugin/index.js | 102 -- packages/fastify-html-plugin/package.json | 27 +- packages/fastify-html-plugin/src/index.ts | 153 +++ .../test/auto-detect.test.tsx | 61 +- .../fastify-html-plugin/test/index.test.tsx | 29 +- .../test/stream-html.test.tsx | 339 +++--- .../fastify-html-plugin/test/types.test-d.tsx | 48 + .../fastify-html-plugin/tsconfig.build.json | 10 + packages/fastify-html-plugin/tsconfig.json | 10 +- packages/fastify-html-plugin/types/index.d.ts | 82 -- .../types/index.test-d.tsx | 35 - packages/html/LICENSE | 22 +- packages/html/package.json | 1 - packages/html/src/index.ts | 4 +- packages/html/src/jsx.ts | 3 - packages/html/test/attributes.test.tsx | 2 +- packages/html/test/suspense.test.tsx | 44 +- packages/ts-html-plugin/LICENSE | 22 +- packages/ts-html-plugin/package.json | 5 + pnpm-lock.yaml | 1071 ++--------------- 22 files changed, 563 insertions(+), 1531 deletions(-) mode change 100644 => 120000 packages/fastify-html-plugin/LICENSE delete mode 100644 packages/fastify-html-plugin/index.js create mode 100644 packages/fastify-html-plugin/src/index.ts create mode 100644 packages/fastify-html-plugin/test/types.test-d.tsx create mode 100644 packages/fastify-html-plugin/tsconfig.build.json delete mode 100644 packages/fastify-html-plugin/types/index.d.ts delete mode 100644 packages/fastify-html-plugin/types/index.test-d.tsx mode change 100644 => 120000 packages/html/LICENSE mode change 100644 => 120000 packages/ts-html-plugin/LICENSE diff --git a/package.json b/package.json index 120666b7f..fd02eece3 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "author": "Arthur Fiorette ", "scripts": { "bench": "pnpm -r --filter \"@kitajs/bench-html-*\" build && pnpm --filter \"@kitajs/bench-html-runner\" start", - "build": "pnpm -r --aggregate-output build", + "build": "pnpm -r --filter \"./packages/*\" --aggregate-output build", "change": "changeset", "ci-publish": "pnpm publish -r --access public && changeset tag", "ci-version": "changeset version && pnpm install --no-frozen-lockfile", diff --git a/packages/fastify-html-plugin/LICENSE b/packages/fastify-html-plugin/LICENSE deleted file mode 100644 index 5b296b873..000000000 --- a/packages/fastify-html-plugin/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023-present Kita - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/packages/fastify-html-plugin/LICENSE b/packages/fastify-html-plugin/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/packages/fastify-html-plugin/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/fastify-html-plugin/index.js b/packages/fastify-html-plugin/index.js deleted file mode 100644 index 5188bc05e..000000000 --- a/packages/fastify-html-plugin/index.js +++ /dev/null @@ -1,102 +0,0 @@ -/// - -const fp = require('fastify-plugin'); -const { resolveHtmlStream } = require('@kitajs/html/suspense'); - -/** @type {import('./types/index').kAutoDoctype} */ -const kAutoDoctype = Symbol.for('fastify-kita-html.autoDoctype'); - -/** - * Returns true if the string starts with `} - */ -function plugin(fastify, opts, next) { - fastify.decorateReply(kAutoDoctype, opts.autoDoctype ?? true); - fastify.decorateReply('html', html); - return next(); -} - -/** @type {import('fastify').FastifyReply['html']} */ -function html(htmlStr) { - if (typeof htmlStr === 'string') { - // @ts-expect-error - generics break the type inference here - return handleHtml(htmlStr, this); - } - - // @ts-expect-error - generics break the type inference here - return handleAsyncHtml(htmlStr, this); -} - -/** - * Simple helper that can be optimized by the JS engine to avoid having async await in the - * main flow - * - * @template {import('fastify').FastifyReply} R - * @param {Promise} promise - * @param {R} reply - * @returns {Promise} - */ -async function handleAsyncHtml(promise, reply) { - return handleHtml(await promise, reply); -} - -/** - * @template {import('fastify').FastifyReply} R - * @param {string} htmlStr - * @param {R} reply - */ -function handleHtml(htmlStr, reply) { - // @ts-expect-error - prepends doctype if the html is a full html document - if (reply[kAutoDoctype] && isTagHtml(htmlStr)) { - htmlStr = `${htmlStr}`; - } - - reply.type('text/html; charset=utf-8'); - - // If no suspense component was used, this will not be defined. - const requestData = SUSPENSE_ROOT.requests.get(reply.request.id); - - if (requestData === undefined) { - return reply - .header('content-length', Buffer.byteLength(htmlStr, 'utf-8')) - .send(htmlStr); - } - - // Content-length is optional as long as the connection is closed after the response is done - // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.3 - return reply.send( - // htmlStr might resolve after one of its suspense components - resolveHtmlStream(htmlStr, requestData) - ); -} - -const fastifyKitaHtml = fp(plugin, { - fastify: '4.x || 5.x', - name: '@kitajs/fastify-html-plugin' -}); - -/** - * These export configurations enable JS and TS developers to consume - * - * @kitajs/fastify-html-plugin in whatever way best suits their needs. Some examples of - * supported import syntax includes: - * - * - `const fastifyKitaHtml = require('@kitajs/fastify-html-plugin')` - * - `const { fastifyKitaHtml } = require('@kitajs/fastify-html-plugin')` - * - `import * as fastifyKitaHtml from '@kitajs/fastify-html-plugin'` - * - `import { fastifyKitaHtml } from '@kitajs/fastify-html-plugin'` - * - `import fastifyKitaHtml from '@kitajs/fastify-html-plugin'` - */ -module.exports = fastifyKitaHtml; -module.exports.default = fastifyKitaHtml; // supersedes fastifyKitaHtml.default = fastifyKitaHtml -module.exports.fastifyKitaHtml = fastifyKitaHtml; // supersedes fastifyKitaHtml.fastifyKitaHtml = fastifyKitaHtml -module.exports.kAutoDoctype = kAutoDoctype; diff --git a/packages/fastify-html-plugin/package.json b/packages/fastify-html-plugin/package.json index 49586229f..4c4f3e3ff 100644 --- a/packages/fastify-html-plugin/package.json +++ b/packages/fastify-html-plugin/package.json @@ -13,30 +13,35 @@ "license": "MIT", "author": "Arthur Fiorette ", "type": "commonjs", - "main": "index.js", - "types": "types/index.d.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist", + "src", + "!dist/*.tsbuildinfo" + ], "scripts": { - "test": "tsd && c8 --reporter lcov --reporter text node -r @swc-node/register --test test/**/*.test.tsx", - "test:watch": "c8 --reporter lcov --reporter text node -r @swc-node/register --test --watch test/**/*.test.tsx" + "build": "tsgo -p tsconfig.build.json", + "test": "vitest --coverage --typecheck --run" }, "dependencies": { "fastify-plugin": "^5.0.1" }, "devDependencies": { "@fastify/formbody": "^8.0.2", - "@swc-node/register": "catalog:", - "@swc/helpers": "catalog:", "@types/jsdom": "catalog:", "@types/node": "catalog:", - "c8": "catalog:", + "@typescript/native-preview": "catalog:", + "@vitest/coverage-v8": "catalog:", "fastify": "^5.6.0", "jsdom": "catalog:", - "tsd": "^0.33.0", - "tslib": "catalog:" + "tslib": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" }, "peerDependencies": { - "@kitajs/html": "workspace:^4.2.10", - "@kitajs/ts-html-plugin": "workspace:^4.1.3" + "@kitajs/html": "workspace:^", + "@kitajs/ts-html-plugin": "workspace:^" }, "peerDependenciesMeta": { "@kitajs/ts-html-plugin": { diff --git a/packages/fastify-html-plugin/src/index.ts b/packages/fastify-html-plugin/src/index.ts new file mode 100644 index 000000000..6bcba75c4 --- /dev/null +++ b/packages/fastify-html-plugin/src/index.ts @@ -0,0 +1,153 @@ +import { resolveHtmlStream } from '@kitajs/html/suspense'; +import type { FastifyPluginCallback, FastifyReply } from 'fastify'; +import fp from 'fastify-plugin'; + +/** Options for @kitajs/fastify-html-plugin plugin. */ +export interface FastifyKitaHtmlOptions { + /** + * Whether to automatically add `` to a response starting with , if + * not found. + * + * ```tsx + * // With autoDoctype: true you can just return the html + * app.get('/', () => ) + * + * // With autoDoctype: false you must use rep.html + * app.get('/', (req, rep) => rep.html() + * ``` + * + * @default true + */ + autoDoctype: boolean; +} + +/** + * This gets assigned to every reply instance. You can manually change this value to + * `false` if you want to "hand pick" when or when not to add the doctype. + */ +export const kAutoDoctype = Symbol.for('fastify-kita-html.autoDoctype'); + +/** Returns true if the string starts with `>> = + function (fastify, opts, next) { + fastify.decorateReply(kAutoDoctype, opts.autoDoctype ?? true); + fastify.decorateReply('html', html); + return next(); + }; + +function html( + this: FastifyReply, + htmlStr: H +): H extends Promise ? Promise : void { + if (typeof htmlStr === 'string') { + // @ts-expect-error - generics break the type inference here + return handleHtml(htmlStr, this); + } + + // @ts-expect-error - generics break the type inference here + return handleAsyncHtml(htmlStr, this); +} + +/** + * Simple helper that can be optimized by the JS engine to avoid having async await in the + * main flow + */ +async function handleAsyncHtml( + promise: Promise, + reply: R +): Promise { + return handleHtml(await promise, reply); +} + +function handleHtml(htmlStr: string, reply: R): R { + // Prepends doctype if the html is a full html document + if (reply[kAutoDoctype] && isTagHtml(htmlStr)) { + htmlStr = `${htmlStr}`; + } + + reply.type('text/html; charset=utf-8'); + + // If no suspense component was used, this will not be defined. + const requestData = SUSPENSE_ROOT.requests.get(reply.request.id); + + if (requestData === undefined) { + return reply + .header('content-length', Buffer.byteLength(htmlStr, 'utf-8')) + .send(htmlStr) as R; + } + + // Content-length is optional as long as the connection is closed after the response is done + // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.3 + return reply.send( + // htmlStr might resolve after one of its suspense components + resolveHtmlStream(htmlStr, requestData) + ) as R; +} + +const plugin_ = fp(plugin, { + fastify: '4.x || 5.x', + name: '@kitajs/fastify-html-plugin' +}); + +export const fastifyKitaHtml = Object.assign(plugin_, { kAutoDoctype }); + +/** + * These export configurations enable JS and TS developers to consume + * + * @kitajs/fastify-html-plugin in whatever way best suits their needs. Some examples of + * supported import syntax includes: + * + * - `const fastifyKitaHtml = require('@kitajs/fastify-html-plugin')` + * - `const { fastifyKitaHtml } = require('@kitajs/fastify-html-plugin')` + * - `import * as fastifyKitaHtml from '@kitajs/fastify-html-plugin'` + * - `import { fastifyKitaHtml } from '@kitajs/fastify-html-plugin'` + * - `import fastifyKitaHtml from '@kitajs/fastify-html-plugin'` + */ +export default fastifyKitaHtml; + +// Module augmentation for FastifyReply +declare module 'fastify' { + interface FastifyReply { + /** + * This gets assigned to every reply instance. You can manually change this value to + * `false` if you want to "hand pick" when or when not to add the doctype. + */ + [kAutoDoctype]: boolean; + + /** + * **Synchronously** waits for the component tree to resolve and sends it at once to + * the browser. + * + * This method does not support the usage of ``, please use + * {@linkcode streamHtml} instead. + * + * If the HTML does not start with a doctype and `opts.autoDoctype` is enabled, it + * will be added automatically. + * + * The correct `Content-Type` header will also be defined. + * + * @example + * + * ```tsx + * app.get('/', (req, reply) => + * reply.html( + * + * + *

Hello, world!

+ * + * + * ) + * ); + * ``` + * + * @param html The HTML to send. + * @returns The response. + */ + html( + this: this, + html: H + ): H extends Promise ? Promise : void; + } +} diff --git a/packages/fastify-html-plugin/test/auto-detect.test.tsx b/packages/fastify-html-plugin/test/auto-detect.test.tsx index a540d32a6..e0412a61d 100644 --- a/packages/fastify-html-plugin/test/auto-detect.test.tsx +++ b/packages/fastify-html-plugin/test/auto-detect.test.tsx @@ -1,46 +1,57 @@ import fastify from 'fastify'; -import assert from 'node:assert'; -import test from 'node:test'; +import { describe, expect, test } from 'vitest'; import { fastifyKitaHtml } from '../'; -test('opts.autoDoctype', async (t) => { - await using app = fastify(); - app.register(fastifyKitaHtml); +describe('opts.autoDoctype', () => { + test('Default', async () => { + await using app = fastify(); + app.register(fastifyKitaHtml); - app.get('/default', () =>
Not a html root element
); - app.get('/default/root', () => ); - app.get('/html', (_, res) => res.html(
Not a html root element
)); - app.get('/html/root', (_, res) => res.html()); + app.get('/default', () =>
Not a html root element
); - await t.test('Default', async () => { const res = await app.inject({ method: 'GET', url: '/default' }); - assert.strictEqual(res.statusCode, 200); - assert.strictEqual(res.headers['content-type'], 'text/plain; charset=utf-8'); - assert.strictEqual(res.body, '
Not a html root element
'); + expect(res.statusCode).toBe(200); + expect(res.headers['content-type']).toBe('text/plain; charset=utf-8'); + expect(res.body).toBe('
Not a html root element
'); }); - await t.test('Default root', async () => { + test('Default root', async () => { + await using app = fastify(); + app.register(fastifyKitaHtml); + + app.get('/default/root', () => ); + const res = await app.inject({ method: 'GET', url: '/default/root' }); - assert.strictEqual(res.statusCode, 200); - assert.strictEqual(res.headers['content-type'], 'text/plain; charset=utf-8'); - assert.strictEqual(res.body, ''); + expect(res.statusCode).toBe(200); + expect(res.headers['content-type']).toBe('text/plain; charset=utf-8'); + expect(res.body).toBe(''); }); - await t.test('Html ', async () => { + test('Html', async () => { + await using app = fastify(); + app.register(fastifyKitaHtml); + + app.get('/html', (_, res) => res.html(
Not a html root element
)); + const res = await app.inject({ method: 'GET', url: '/html' }); - assert.strictEqual(res.statusCode, 200); - assert.strictEqual(res.headers['content-type'], 'text/html; charset=utf-8'); - assert.strictEqual(res.body, '
Not a html root element
'); + expect(res.statusCode).toBe(200); + expect(res.headers['content-type']).toBe('text/html; charset=utf-8'); + expect(res.body).toBe('
Not a html root element
'); }); - await t.test('Html root', async () => { + test('Html root', async () => { + await using app = fastify(); + app.register(fastifyKitaHtml); + + app.get('/html/root', (_, res) => res.html()); + const res = await app.inject({ method: 'GET', url: '/html/root' }); - assert.strictEqual(res.statusCode, 200); - assert.strictEqual(res.headers['content-type'], 'text/html; charset=utf-8'); - assert.strictEqual(res.body, ''); + expect(res.statusCode).toBe(200); + expect(res.headers['content-type']).toBe('text/html; charset=utf-8'); + expect(res.body).toBe(''); }); }); diff --git a/packages/fastify-html-plugin/test/index.test.tsx b/packages/fastify-html-plugin/test/index.test.tsx index c0c117a7e..b02d3764e 100644 --- a/packages/fastify-html-plugin/test/index.test.tsx +++ b/packages/fastify-html-plugin/test/index.test.tsx @@ -1,7 +1,6 @@ import fastify from 'fastify'; -import assert from 'node:assert'; -import test, { describe } from 'node:test'; import { setImmediate } from 'node:timers/promises'; +import { describe, expect, test } from 'vitest'; import { fastifyKitaHtml } from '..'; describe('reply.html()', () => { @@ -13,9 +12,9 @@ describe('reply.html()', () => { const res = await app.inject({ method: 'GET', url: '/' }); - assert.strictEqual(res.body, '
Hello from JSX!
'); - assert.strictEqual(res.headers['content-type'], 'text/html; charset=utf-8'); - assert.strictEqual(res.statusCode, 200); + expect(res.body).toBe('
Hello from JSX!
'); + expect(res.headers['content-type']).toBe('text/html; charset=utf-8'); + expect(res.statusCode).toBe(200); }); test('renders async html', async () => { @@ -23,14 +22,14 @@ describe('reply.html()', () => { app.register(fastifyKitaHtml); app.get('/', (_, res) => - res.html(
{setImmediate('Hello from async JSX!')}
) + res.html(
{setImmediate('Hello from async JSX!')}
) ); const res = await app.inject({ method: 'GET', url: '/' }); - assert.strictEqual(res.body, '
Hello from async JSX!
'); - assert.strictEqual(res.headers['content-type'], 'text/html; charset=utf-8'); - assert.strictEqual(res.statusCode, 200); + expect(res.body).toBe('
Hello from async JSX!
'); + expect(res.headers['content-type']).toBe('text/html; charset=utf-8'); + expect(res.statusCode).toBe(200); }); test('fails when html is not a string', async () => { @@ -44,9 +43,9 @@ describe('reply.html()', () => { const res = await app.inject({ method: 'GET', url: '/' }); - assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); - assert.strictEqual(res.statusCode, 500); - assert.deepStrictEqual(res.json(), { + expect(res.headers['content-type']).toBe('application/json; charset=utf-8'); + expect(res.statusCode).toBe(500); + expect(res.json()).toEqual({ statusCode: 500, code: 'ERR_INVALID_ARG_TYPE', error: 'Internal Server Error', @@ -66,9 +65,9 @@ describe('reply.html()', () => { const res = await app.inject({ method: 'GET', url: '/' }); - assert.strictEqual(res.statusCode, 500); - assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); - assert.deepStrictEqual(res.json(), { + expect(res.statusCode).toBe(500); + expect(res.headers['content-type']).toBe('application/json; charset=utf-8'); + expect(res.json()).toEqual({ statusCode: 500, code: 'ERR_INVALID_ARG_TYPE', error: 'Internal Server Error', diff --git a/packages/fastify-html-plugin/test/stream-html.test.tsx b/packages/fastify-html-plugin/test/stream-html.test.tsx index 5d83e9076..2aaf1bba7 100644 --- a/packages/fastify-html-plugin/test/stream-html.test.tsx +++ b/packages/fastify-html-plugin/test/stream-html.test.tsx @@ -5,12 +5,11 @@ // This was adapted to work inside a fastify route handler. import Html, { type PropsWithChildren } from '@kitajs/html'; -import { Suspense, SuspenseScript } from '@kitajs/html/suspense'; +import { Suspense, SuspenseScript as safeSuspenseScript } from '@kitajs/html/suspense'; import fastify from 'fastify'; import { JSDOM } from 'jsdom'; -import assert from 'node:assert'; -import { afterEach, describe, test } from 'node:test'; import { setTimeout } from 'node:timers/promises'; +import { afterEach, describe, expect, test } from 'vitest'; import { fastifyKitaHtml } from '..'; async function SleepForMs({ ms, children }: PropsWithChildren<{ ms: number }>) { @@ -21,7 +20,7 @@ async function SleepForMs({ ms, children }: PropsWithChildren<{ ms: number }>) { describe('Suspense', () => { // Detect leaks of pending promises afterEach(() => { - assert.equal(SUSPENSE_ROOT.requests.size, 0, 'Suspense root left pending resources'); + expect(SUSPENSE_ROOT.requests.size).toBe(0); // Reset suspense root SUSPENSE_ROOT.autoScript = true; @@ -37,9 +36,9 @@ describe('Suspense', () => { const res = await app.inject({ method: 'GET', url: '/' }); - assert.strictEqual(res.body, '
'); - assert.strictEqual(res.statusCode, 200); - assert.strictEqual(res.headers['content-type'], 'text/html; charset=utf-8'); + expect(res.body).toBe('
'); + expect(res.statusCode).toBe(200); + expect(res.headers['content-type']).toBe('text/html; charset=utf-8'); }); test('Suspense sync children', async () => { @@ -56,9 +55,9 @@ describe('Suspense', () => { const res = await app.inject({ method: 'GET', url: '/' }); - assert.strictEqual(res.body, '
2
'); - assert.strictEqual(res.statusCode, 200); - assert.strictEqual(res.headers['content-type'], 'text/html; charset=utf-8'); + expect(res.body).toBe('
2
'); + expect(res.statusCode).toBe(200); + expect(res.headers['content-type']).toBe('text/html; charset=utf-8'); }); test('Suspense async children', async () => { @@ -75,16 +74,15 @@ describe('Suspense', () => { const res = await app.inject({ method: 'GET', url: '/' }); - assert.strictEqual(res.statusCode, 200); - assert.strictEqual(res.headers['content-type'], 'text/html; charset=utf-8'); - assert.strictEqual( - res.body, + expect(res.statusCode).toBe(200); + expect(res.headers['content-type']).toBe('text/html; charset=utf-8'); + expect(res.body).toBe( <>
1
- {SuspenseScript} + {safeSuspenseScript}