diff --git a/.changeset/config.json b/.changeset/config.json index f8dfd84df..a8994ef79 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -7,7 +7,7 @@ "access": "public", "baseBranch": "master", "updateInternalDependencies": "patch", - "ignore": ["@kitajs/bench-*"], + "ignore": ["@kitajs/bench-*", "@kitajs/example-*", "@kitajs/docs-*"], "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { "onlyUpdatePeerDependentsWhenOutOfRange": true } diff --git a/.changeset/hip-trams-roll.md b/.changeset/hip-trams-roll.md new file mode 100644 index 000000000..c53a8f6dc --- /dev/null +++ b/.changeset/hip-trams-roll.md @@ -0,0 +1,5 @@ +--- +'@kitajs/ts-html-plugin': patch +--- + +Skip xss check for `str &&` cases 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/.changeset/metal-hairs-juggle.md b/.changeset/metal-hairs-juggle.md new file mode 100644 index 000000000..111d507e9 --- /dev/null +++ b/.changeset/metal-hairs-juggle.md @@ -0,0 +1,5 @@ +--- +'@kitajs/ts-html-plugin': patch +--- + +Fixed CLI inconsistencies with a dedicated bin js file diff --git a/.changeset/slimy-wolves-buy.md b/.changeset/slimy-wolves-buy.md new file mode 100644 index 000000000..ff4ca0534 --- /dev/null +++ b/.changeset/slimy-wolves-buy.md @@ -0,0 +1,5 @@ +--- +'@kitajs/html': patch +--- + +Broather and more reliable test suite diff --git a/.changeset/stale-shrimps-spend.md b/.changeset/stale-shrimps-spend.md new file mode 100644 index 000000000..2367548f8 --- /dev/null +++ b/.changeset/stale-shrimps-spend.md @@ -0,0 +1,5 @@ +--- +'@kitajs/html': major +--- + +Removed deprecated @kitajs/html/register 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/.claude/agents/docs-writer/CLAUDE.md b/.claude/agents/docs-writer/CLAUDE.md new file mode 100644 index 000000000..2576675d1 --- /dev/null +++ b/.claude/agents/docs-writer/CLAUDE.md @@ -0,0 +1,94 @@ +--- +name: docs-writer +description: + Documentation writer for the Kita Html project. Use when creating, editing, or reviewing + documentation pages. Follows Information Mapping methodology and Rspress conventions. +tools: Read, Write, Edit, Glob, Grep, Bash, WebFetch, WebSearch +model: sonnet +--- + +# Kita Html Documentation Writer + +You are a documentation writer for the Kita Html project (https://html.kitajs.org). You +write technical documentation that follows the Information Mapping (Structured Writing) +methodology and the project's Rspress site conventions. + +## Your Skills + +You have two core skills loaded: + +1. **information-mapping**: The Information Mapping methodology by Robert Horn. Every page + gets exactly one information type (Concept, Procedure, Process, Principle, Structure, + or Fact). Types are never mixed. + +2. **rspress-writing**: The Rspress site conventions for file structure, sidebar ordering, + markdown compatibility, and writing style. + +Read both skill files before starting any work. + +## Workflow + +When asked to write a new documentation page: + +1. Read `packages/docs/CLAUDE.md` to understand the site architecture +2. Determine which information type the page should be +3. Decide where in the file tree it belongs +4. Write the page following all style and methodology rules +5. Update the relevant `_meta.json` to include the new page +6. Run `pnpm format -- ` to apply Prettier +7. Run `pnpm -F @kitajs/docs-html build` to verify the build passes +8. If the build fails, fix the issue and rebuild + +When asked to edit an existing page: + +1. Read the current page content +2. Identify its information type +3. Make the requested changes while preserving the type and style +4. Format and build to verify + +When asked to review documentation: + +1. Read each page and identify its information type +2. Check for type mixing (the most common violation) +3. Check for style violations (emojis, em dashes, excessive bullets, filler language) +4. Check that headings follow naming conventions for the page type +5. Verify word count is within 200-800 range +6. Report findings with specific file paths and line numbers + +## Project Context + +Kita Html is a JSX runtime that produces HTML strings instead of a virtual DOM. Key +concepts to understand: + +- `JSX.Element` is `string | Promise`, not an object +- Children are NOT escaped by default (the XSS trade-off) +- Three XSS protection layers: `safe` attribute, TS plugin, `xss-scan` CLI +- Async components propagate promises up the tree automatically +- Suspense streams fallbacks immediately and replaces them when async content resolves +- Three packages: `@kitajs/html` (core), `@kitajs/ts-html-plugin` (XSS detection), + `@kitajs/fastify-html-plugin` (Fastify integration) +- `@elysiajs/html` is an external Elysia integration maintained by the same author + +## TypeDoc API Docs + +The `api/html/` and `api/fastify/` directories are auto-generated by TypeDoc from source +JSDoc comments. Never edit these `.md` files directly. To fix or improve API docs, update +the JSDoc in `packages/html/src/` or `packages/fastify-html-plugin/src/` and rebuild. Mark +internal helpers with `@internal` to exclude them from the generated output. + +Each generated directory has a `_meta.json` for sidebar ordering. TypeDoc only creates +this file if missing, so edits persist. Always remove the `"index"` entry from these files +to hide the useless module-list pages. + +## Quality Checks + +Before considering any task complete: + +- No emojis in any documentation file +- No em dashes anywhere +- No "Overview", "Introduction", "Conclusion" headings unless necessary +- Maximum 2-4 `##` headings per page +- Maximum 5 bullet points per page +- Every page has exactly one information type with no mixing +- All internal links use absolute paths from docs root +- `pnpm -F @kitajs/docs-html build` exits with code 0 diff --git a/.claude/skills/information-mapping/SKILL.md b/.claude/skills/information-mapping/SKILL.md new file mode 100644 index 000000000..0d95d417f --- /dev/null +++ b/.claude/skills/information-mapping/SKILL.md @@ -0,0 +1,73 @@ +--- +name: information-mapping +description: + Information Mapping (Structured Writing) methodology for technical documentation. Use + when writing, reviewing, or planning documentation pages. +user-invocable: false +--- + +# Information Mapping Methodology + +You are applying Robert Horn's Information Mapping (Structured Writing) methodology to +technical documentation. Follow these rules strictly. + +## Six Information Types + +Every page or document unit must be assigned exactly one type. Never mix types within a +single page. + +| Type | Purpose | Contains | Never contains | +| --------- | -------------------------------------- | ----------------------------------------------------------- | -------------------------------------------- | +| Concept | What something is, why it matters | Definitions, explanations, comparisons, positioning | Numbered steps, API signatures, benchmarks | +| Procedure | How to do something step-by-step | Sequential instructions, code examples showing usage | Internal mechanism details, design rationale | +| Process | How something works internally | Data flow, mechanism descriptions, stage-by-stage breakdown | "Do this, then do that" user instructions | +| Principle | Rules, guidelines, design decisions | Rationale, constraints, trade-offs, recommendations | Setup steps, API signatures | +| Structure | API references, component organization | Signatures, parameters, return types, minimal examples | Design philosophy, tutorials | +| Fact | Data, measurements, specifications | Tables, benchmarks, version numbers, compatibility data | Opinions, instructions, rationale | + +## Core Principles + +**Chunking**: Break content into small, manageable units. Each page addresses one tightly +scoped topic. Target 200-800 words per page. Larger pages are acceptable only when the +subject density requires it. + +**Relevance**: Every sentence on a page must relate to that page's single topic. If +content belongs to another topic, move it to the appropriate page and link to it. + +**Labelling**: Give every page a concrete, descriptive title. Concept pages use noun +phrases ("Async Components"). Procedure pages use action-oriented phrases ("Using +Suspense", "Getting Started"). Process pages use "How X Works" phrasing. Structure pages +use the module/API name. Fact pages use the data category ("Benchmarks", "Compatibility"). + +**Consistency**: All pages of the same type follow the same internal structure and +formatting conventions. + +**No type mixing**: This is the most important rule. A Concept page never contains +numbered setup steps. A Procedure page never explains internal mechanisms. A Structure +page never contains design rationale. If you find yourself mixing types, split the content +into separate pages. + +## Applying the Methodology + +When writing a new page: + +1. Determine the single information type before writing any content +2. Write a title that reflects the type (see Labelling above) +3. Keep all content within the boundaries of that type +4. If you need to reference content of another type, link to it rather than including it + inline +5. Review the completed page and verify no type mixing occurred + +When reviewing existing pages: + +1. Identify what information type the page should be +2. Flag any content that belongs to a different type +3. Suggest splitting mixed-type pages into separate focused pages + +When planning a documentation structure: + +1. List all topics that need documentation +2. Assign each topic an information type +3. Order pages within sections so that Concepts come before Procedures (understand before + do), with Process and Principle pages providing depth for those who need it +4. Place Structure (API reference) and Fact (data) pages in dedicated reference sections diff --git a/.claude/skills/rspress-writing/SKILL.md b/.claude/skills/rspress-writing/SKILL.md new file mode 100644 index 000000000..5d58876cd --- /dev/null +++ b/.claude/skills/rspress-writing/SKILL.md @@ -0,0 +1,184 @@ +--- +name: rspress-writing +description: + Writing conventions and structure for the Kita Html Rspress documentation site. Use when + creating or editing doc pages. +user-invocable: false +--- + +# Rspress Documentation Writing + +You are writing documentation for the Kita Html Rspress site at `packages/docs/`. Follow +these conventions exactly. + +## File Structure + +All doc pages live under `packages/docs/docs/`. The structure is: + +``` +docs/ + index.md Homepage (Rspress home layout) + _nav.json Top navigation bar + guide/ Guide section (learning-oriented) + _meta.json Sidebar ordering for this directory + xss/ XSS protection subsection + async/ Async & streaming subsection + jsx/ JSX syntax subsection + reference/ Benchmarks, compatibility, migration + integrations/ Framework and library integrations + frameworks/ Fastify, Elysia + type-extensions/ HTMX, Alpine.js, Hotwire Turbo + api/ API reference + html/ Auto-generated from @kitajs/html (TypeDoc) + fastify/ Auto-generated from @kitajs/fastify-html-plugin (TypeDoc) +``` + +## Sidebar Ordering + +Each directory has a `_meta.json` that controls sidebar order. Files are listed by +filename without extension. Two directory entry types exist: + +`dir-section-header`: Renders a directory as a section header with its children below. Use +this for directories that should appear as top-level groups. + +`section-header`: A visual label for grouping loose files (not directories). + +Never combine a `section-header` with a `dir` of the same label. This creates duplicate +entries. Use `dir-section-header` instead. + +```json +[ + { + "type": "section-header", + "label": "Getting Started" + }, + "introduction", + "getting-started", + { + "type": "dir-section-header", + "name": "xss", + "label": "XSS Protection" + } +] +``` + +## Auto-generated API Docs + +The `api/html/` and `api/fastify/` directories are generated by TypeDoc on each build. Do +not edit the generated `.md` files. To improve output, update JSDoc comments in the source +and mark internal helpers with `@internal`. + +Each generated directory has a `_meta.json` that persists across builds. Remove `"index"` +from these files to hide the module-list landing pages from the sidebar. + +## Adding a New Page + +1. Create the `.md` file in the correct directory +2. Add the filename (without `.md`) to the directory's `_meta.json` +3. If creating a new directory, create a `_meta.json` inside it and add a dir entry in the + parent's `_meta.json` + +## Writing Style + +Professional and technical. Direct, concise, information-dense. No filler, no motivational +language, no repetition. + +- No emojis anywhere +- No em dashes. Use periods, commas, or rephrase +- No decorative separators or horizontal rules +- No excessive bold formatting +- No "Overview", "Introduction", or "Conclusion" as section headings unless truly + necessary +- Maximum 2-4 headings (##) per page +- Prefer short paragraphs over bullet lists. Maximum 5 bullet points per page +- Only include code blocks when essential to understand usage +- Keep pages under 800 words unless complexity requires more +- Inline code only for identifiers, types, and short code references + +## Code Blocks + +Rspress uses Shiki for syntax highlighting with several features available. + +**Language identifier**: Always specify the language after the opening backticks: `tsx`, +`ts`, `json`, `bash`, `html`, `css`, `js`. + +**Titles**: Use the `title` attribute for filenames and descriptive labels. Always add +titles to config file examples and when the file path helps the reader understand context. + +```` +```json title="tsconfig.json" +{ "compilerOptions": { "jsx": "react-jsx" } } +``` +```` + +**Line highlighting**: Use `// [!code highlight]` at the end of a line, or +`// [!code highlight:N]` for N consecutive lines. + +**Diff notation**: Use `// [!code ++]` and `// [!code --]` for additions and removals. + +**Focus**: Use `// [!code focus]` to dim surrounding lines. + +**Error/warning**: Use `// [!code error]` and `// [!code warning]` for annotations. + +Line numbers are enabled globally and do not need per-block configuration. + +## Package Install Commands + +For install commands, use the `PackageManagerTabs` component instead of plain bash code +blocks. This renders a tabbed selector for npm, yarn, pnpm, and bun. + +Add the import at the top of the `.mdx` file (Rename from `.md` to `.mdx` if needed): + +``` +import { PackageManagerTabs } from '@rspress/core/theme-original'; +``` + +Then use the component: + +``` + +``` + +Only use this for user-facing install commands. Internal dev commands (`pnpm build`, etc.) +stay as plain bash blocks. + +## Type Extension Setup + +When documenting type extensions (HTMX, Alpine.js, Turbo, all-types), instruct users to +create a `src/kita.d.ts` file with triple-slash directives. Multiple extensions go in the +same file. Do not suggest per-file directives as the primary approach. + +## Markdown Compatibility + +All markdown must be Rspress compatible: + +- Use standard markdown links: `[text](/path/to/page)` +- Internal links use absolute paths from docs root: `/guide/introduction`, `/api/core` +- React component imports go at the very top of the file, before the heading +- No raw HTML in markdown unless absolutely necessary +- Tables use standard markdown pipe syntax + +## Verification + +After writing or editing any page: + +1. Run `pnpm format` to apply Prettier formatting +2. Run `pnpm -F @kitajs/docs-html build` to verify the site compiles +3. Check that the build exits with code 0 and no errors + +## Section-Specific Conventions + +**XSS section**: Solution-first ordering. Safe attribute and detection tooling before the +"why not auto-escape" explanation. + +**API section**: XSS tooling documented by capability (analysis engine, editor plugin, CLI +scanner) not by package name. This anticipates the ts-html-plugin package split. + +**Integrations section**: Split into Frameworks (with official plugins) and Type +Extensions (HTMX, Alpine, Turbo). When mentioning specific frameworks, link to the +integrations overview rather than just naming one framework. diff --git a/.claude/skills/rspress-writing/style-examples.md b/.claude/skills/rspress-writing/style-examples.md new file mode 100644 index 000000000..931e2ddd1 --- /dev/null +++ b/.claude/skills/rspress-writing/style-examples.md @@ -0,0 +1,85 @@ +# Style Examples + +## Good: Direct, information-dense opening + +```markdown +Kita Html is a JSX runtime where every element evaluates to a string. Where React's +`
` produces a virtual DOM node that must be reconciled and serialized, Kita Html's +`
` returns `'
'` directly. +``` + +## Bad: Filler, motivational, generic + +```markdown +Welcome to Kita Html! 🚀 In this guide, we'll explore how this amazing library can help +you build faster web applications. Let's get started! +``` + +## Good: Short paragraphs, no unnecessary bullets + +```markdown +The `safe` attribute escapes children at render time. Adding it to any native element +causes the runtime to pass all children through HTML entity escaping before concatenation. + +A TypeScript language service plugin analyzes every JSX expression in your editor and +flags any child whose type could carry unescaped HTML. +``` + +## Bad: Bullet-heavy, over-fragmented + +```markdown +### Features + +- ⚡ **Super fast** rendering +- 🔒 **Secure** by default +- 📦 **Zero dependencies** +- 🎯 **Type safe** +- 🚀 **Easy to use** + +### Benefits + +- Great performance +- Works with any framework +``` + +## Good: Procedure page with minimal headings + +```markdown +# Getting Started + +Install `@kitajs/html` and `@kitajs/ts-html-plugin` together. + +## TypeScript configuration + +Add the following to your `tsconfig.json`. + +## Verification + +Write the following in a `.tsx` file: +``` + +## Bad: Over-structured with many sub-headings + +```markdown +# Getting Started + +## Prerequisites + +### System Requirements + +### Node.js Version + +## Step 1: Installation + +### Using npm + +### Using yarn + +### Using pnpm + +## Step 2: Configuration + +### Step 2a: TypeScript + +### Step 2b: Editor +``` diff --git a/.github/workflows/dependabot.yml b/.github/workflows/automerge.yml similarity index 100% rename from .github/workflows/dependabot.yml rename to .github/workflows/automerge.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 265762c35..20474dfde 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,10 +2,16 @@ name: CI Flow on: push: + branches: + - master pull_request: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: +permissions: + pages: write + id-token: write + jobs: build: runs-on: ${{ matrix.os }} @@ -13,8 +19,8 @@ jobs: strategy: matrix: - os: [macos-latest, windows-latest, ubuntu-latest] - node: [20] + os: [ubuntu-latest, windows-latest, macos-latest] + node: [lts/-2, lts/-1, lts] steps: - name: Checkout @@ -29,11 +35,21 @@ jobs: node-version: ${{ matrix.node }} cache: 'pnpm' + - run: echo "Using Node $(node --version) on ${{ matrix.os }}" + - name: Install packages run: pnpm install --frozen-lockfile + - name: Cache turbo build setup + uses: actions/cache@v4 + with: + path: .turbo + key: ${{ runner.os }}-turbo-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-turbo- + - name: Build - run: pnpm build + run: pnpm build-all - name: Test run: pnpm test @@ -44,3 +60,49 @@ jobs: # Codecov backend may be unstable fail_ci_if_error: false token: ${{ secrets.CODECOV_TOKEN }} + + deploy-docs: + needs: build + if: github.ref == 'refs/heads/arthurfiorette/serena' + runs-on: ubuntu-latest + name: Deploy Docs + + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup node and restore cached dependencies + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + + - name: Install packages + run: pnpm install --frozen-lockfile + + - name: Cache turbo build setup + uses: actions/cache@v4 + with: + path: .turbo + key: ${{ runner.os }}-turbo-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-turbo- + + - name: Build docs + run: pnpm turbo build -F @kitajs/html-docs + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: packages/docs/dist + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 0b65cfcd8..000000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: 'CodeQL' - -on: - push: - branches: [master] - paths: ['**.js', '**.jsx', '**.ts', '**.tsx'] - pull_request: - branches: [master] - schedule: - - cron: '0 0/12 * * *' - -permissions: write-all - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - language: ['javascript'] - - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - - - name: Setup node and restore cached dependencies - uses: actions/setup-node@v4 - with: - node-version-file: '.nvmrc' - cache: 'pnpm' - - - name: Install packages - run: pnpm install --frozen-lockfile - - - name: Build - run: pnpm build - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9c2382666..43fa884a6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,6 +44,14 @@ jobs: - name: Install packages run: pnpm install --frozen-lockfile + - name: Cache turbo build setup + uses: actions/cache@v4 + with: + path: .turbo + key: ${{ runner.os }}-turbo-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-turbo- + - name: Build run: pnpm build diff --git a/.gitignore b/.gitignore index 0310715b3..0f899f76a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,10 @@ - -node_modules - -index.tsbuildinfo -dist -coverage - +.DS_Store +.turbo +*.cpuprofile *.log - -benchmarks/runner/profile.cpuprofile \ No newline at end of file +*.tsbuildinfo +*.tsbuildinfo +coverage +dist +node_modules +.playwright-mcp \ No newline at end of file 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..c15bf57bd --- /dev/null +++ b/.serena/memories/architecture_and_patterns.md @@ -0,0 +1,228 @@ +# 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": { + ".": "./dist/index.js", + "./jsx-runtime": "./dist/jsx-runtime.js", + "./suspense": "./dist/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. Vitest Test Runner + +Uses Vitest with coverage and type checking: + +```typescript +import { describe, it, expect } from 'vitest'; + +describe('component', () => { + it('renders correctly', () => { + expect(
hello
).toBe('
hello
'); + }); +}); +``` + +### 2. JSDOM for DOM Testing + +When DOM testing is needed: + +```typescript +import { JSDOM } from 'jsdom'; +const dom = new JSDOM(htmlString); +``` + +### 3. Vitest Type Testing + +For TypeScript type definitions (using vitest --typecheck): + +```typescript +// Uses vitest's built-in type testing capabilities +import { expectTypeOf } from 'vitest'; +expectTypeOf(
foo
).toEqualTypeOf(); +``` + +## 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..15e186620 --- /dev/null +++ b/.serena/memories/code_style_and_conventions.md @@ -0,0 +1,84 @@ +# 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 `src/` directory +- Tests in `test/` directory with `.test.tsx` or `.test.ts` extension +- Type definitions generated alongside compiled files in `dist/` +- Build output in `dist/` directory +- Additional type definition files (htmx.d.ts, alpine.d.ts, etc.) in package root + +## 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..072014967 --- /dev/null +++ b/.serena/memories/project_overview.md @@ -0,0 +1,55 @@ +# Kita Html - Project Overview + +## Purpose + +Kita 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+ +- **Runtime**: Node.js >= 20.13 +- **Package Manager**: pnpm >= 10 (required via preinstall hook) +- **JSX Transform**: react-jsx with jsxImportSource: @kitajs/html +- **Module System**: CommonJS +- **Build Tool**: tsgo (@typescript/native-preview) +- **Testing**: Vitest with @vitest/coverage-v8 +- **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 (build tools) +- JSDOM (for DOM testing) +- Vitest with v8 coverage diff --git a/.serena/memories/suggested_commands.md b/.serena/memories/suggested_commands.md new file mode 100644 index 000000000..432a06086 --- /dev/null +++ b/.serena/memories/suggested_commands.md @@ -0,0 +1,141 @@ +# Suggested Development Commands + +## Package Manager + +**Always use pnpm** - The project enforces this via preinstall hook. Requires pnpm >= 10. + +## Main Development Commands + +### Building + +```bash +# Build all packages +pnpm build + +# Build specific package (from root) +pnpm --filter "@kitajs/html" build + +# Build uses tsgo (native TypeScript compiler preview) +# Each package has: pnpm build -> tsgo -p tsconfig.build.json +``` + +### Testing + +```bash +# Run all tests in all packages +pnpm test + +# Run tests in a specific package +pnpm --filter "@kitajs/html" test +cd packages/html && pnpm test + +# Test command runs Vitest with coverage and type checking: +# vitest --coverage --typecheck --run +``` + +### 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 changeset + +# 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 build # Build with tsgo +pnpm test # Run vitest with coverage and typecheck +``` + +### @kitajs/ts-html-plugin + +```bash +cd packages/ts-html-plugin +pnpm build # Build with tsgo +pnpm test # Run vitest with coverage and typecheck +``` + +### @kitajs/fastify-html-plugin + +```bash +cd packages/fastify-html-plugin +pnpm build # Build with tsgo +pnpm test # Run vitest with coverage and typecheck +``` + +## Common Workflows + +### After making changes: + +1. Format code: `pnpm format` (or let pre-commit hook handle it) +2. Build: `pnpm build` +3. Run tests: `pnpm test` + +### 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 +``` + +### Running examples: + +```bash +npx tsx examples/fastify-htmx.tsx +npx tsx examples/http-server.tsx +``` diff --git a/.serena/memories/task_completion_checklist.md b/.serena/memories/task_completion_checklist.md new file mode 100644 index 000000000..32e613a6d --- /dev/null +++ b/.serena/memories/task_completion_checklist.md @@ -0,0 +1,93 @@ +# 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 (Vitest v8 coverage) +- [ ] For new features: Add appropriate tests in `test/` directory +- [ ] Type tests pass: Vitest runs with `--typecheck` flag + +## 5. Build + +- [ ] Build succeeds: `pnpm build` (uses tsgo - native TypeScript compiler) +- [ ] No build warnings or errors +- [ ] Type definitions (.d.ts) are correctly generated in `dist/` + +## 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 changeset` +- [ ] 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..663799e6d --- /dev/null +++ b/.serena/project.yml @@ -0,0 +1,112 @@ +# 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: '' +# the name by which the project can be referenced within Serena +project_name: 'html' + +# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default) +included_optional_tools: [] + +# list of mode names to that are always to be included in the set of active modes +# The full set of modes to be activated is base_modes + default_modes. +# If the setting is undefined, the base_modes from the global configuration (serena_config.yml) apply. +# Otherwise, this setting overrides the global configuration. +# Set this to [] to disable base modes for this project. +# Set this to a list of mode names to always include the respective modes for this project. +base_modes: + +# list of mode names that are to be activated by default. +# The full set of modes to be activated is base_modes + default_modes. +# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply. +# Otherwise, this overrides the setting from the global configuration (serena_config.yml). +# This setting can, in turn, be overridden by CLI parameters (--mode). +default_modes: + +# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools. +# This cannot be combined with non-empty excluded_tools or included_optional_tools. +fixed_tools: [] + +# override of the corresponding setting in serena_config.yml, see the documentation there. +# If null or missing, the value from the global config is used. +symbol_info_budget: diff --git a/.vscode/settings.json b/.vscode/settings.json index edc22acec..d14b42c27 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,26 @@ { - "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, - "cSpell.words": ["KITA"] + "typescript.tsdk": "node_modules/typescript/lib", + "typescript.tsserver.maxTsServerMemory": 4096, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "workbench.colorCustomizations": { + "statusBar.background": "#bd695e", + "statusBar.foreground": "#15202b", + "activityBar.activeBackground": "#c97c72", + "activityBar.background": "#c97c72", + "activityBar.foreground": "#15202b", + "activityBar.inactiveForeground": "#15202b99", + "commandCenter.border": "#15202b99", + "sash.hoverBorder": "#c97c72", + "statusBarItem.hoverBackground": "#ad4336", + "statusBarItem.remoteBackground": "#bd695e", + "statusBarItem.remoteForeground": "#15202b", + "titleBar.activeBackground": "#bd695e", + "titleBar.activeForeground": "#15202b", + "titleBar.inactiveBackground": "#bd695e99", + "titleBar.inactiveForeground": "#15202b99" + } } diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..dc97ee038 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,291 @@ +# Kita Html Monorepo - Developer Guide + +## Overview + +Kita Html is a monorepo containing a super-fast JSX runtime that generates HTML strings. +Unlike React, which builds a virtual DOM, this library directly produces HTML strings, +making it ideal for server-side rendering, static site generation, and HTMX-style +applications. + +## Repository Structure + +``` +kitajs/html/ +├── packages/ +│ ├── html/ # Core JSX runtime (@kitajs/html) +│ ├── ts-html-plugin/ # XSS detection TypeScript plugin (@kitajs/ts-html-plugin) +│ ├── fastify-html-plugin/# Fastify integration (@kitajs/fastify-html-plugin) +│ └── docs/ # Documentation site (@kitajs/docs-html) +├── benchmarks/ # Performance benchmarks +└── examples/ # Usage examples +``` + +## Package Dependencies + +``` +@kitajs/html (core) + ↑ + ├── @kitajs/ts-html-plugin (peer dependency) + │ + └── @kitajs/fastify-html-plugin (peer dependency) +``` + +## Quick Start + +```bash +pnpm install # Install dependencies (pnpm required) +pnpm build # Build all packages +pnpm test # Run all tests +pnpm format # Format code +pnpm bench # Run benchmarks +``` + +See [CONTRIBUTING.md](CONTRIBUTING.md) for full development workflow, per-package +commands, and pull request guidelines. + +## Architecture Overview + +### Core Concept: JSX → String + +```tsx +// Input (JSX) +
{name}
; + +// TypeScript transforms to +jsx('div', { class: 'hello', children: name }); + +// Output (string) +('
Arthur
'); +``` + +### Key Architectural Decisions + +1. **No Virtual DOM**: Direct string concatenation for maximum performance +2. **Type as String**: `JSX.Element = string | Promise` +3. **Async Propagation**: Promise children make parent promises +4. **XSS by Default**: Children are NOT escaped unless `safe` attribute is used +5. **Compile-Time Safety**: TypeScript plugin catches XSS at development time + +### Data Flow + +``` +User Code (TSX) + │ + ▼ +TypeScript Compiler + │ (jsx: "react-jsx", jsxImportSource: "@kitajs/html") + ▼ +jsx-runtime.ts (jsx/jsxs functions) + │ + ▼ +index.ts (createElement, attributesToString, contentsToString) + │ + ▼ +HTML String (or Promise for async) +``` + +### XSS Protection Flow + +``` +User writes JSX + │ + ▼ +ts-html-plugin (LSP) ─────► Warnings/Errors in Editor + │ + ▼ +xss-scan (CLI) ────────────► CI/CD Pipeline Check + │ + ▼ +Runtime (safe attribute) ──► Escapes at render time +``` + +## Package Summaries + +### @kitajs/html + +The core JSX runtime. Key files: + +- `src/index.ts`: Escaping, attribute handling, element creation +- `src/jsx-runtime.ts`: Modern JSX transform (`jsx`, `jsxs`, `Fragment`) +- `src/suspense.ts`: Streaming HTML with async components +- `src/error-boundary.ts`: Error handling for async trees + +**See:** [`packages/html/CLAUDE.md`](packages/html/CLAUDE.md) + +### @kitajs/ts-html-plugin + +TypeScript plugin for XSS detection. Key files: + +- `src/index.ts`: Language Service Plugin entry +- `src/cli.ts`: `xss-scan` CLI tool +- `src/util.ts`: Core detection algorithms +- `src/errors.ts`: Error codes (K601-K604) + +**See:** [`packages/ts-html-plugin/CLAUDE.md`](packages/ts-html-plugin/CLAUDE.md) + +### @kitajs/fastify-html-plugin + +Fastify integration. Key file: + +- `src/index.ts`: Plugin registration, `reply.html()`, Suspense streaming + +**See:** +[`packages/fastify-html-plugin/CLAUDE.md`](packages/fastify-html-plugin/CLAUDE.md) + +### @kitajs/docs-html + +Documentation site at https://html.kitajs.org. Uses Rspress, follows Information Mapping +methodology. + +**See:** [`packages/docs/CLAUDE.md`](packages/docs/CLAUDE.md) + +## Tech Stack + +| Tool | Purpose | +| ------------------- | ------------------------------------ | +| **pnpm** | Package manager (required) | +| **TypeScript 5.9+** | Language | +| **tsgo** | TypeScript compiler (native preview) | +| **Vitest** | Test runner | +| **c8/v8** | Code coverage | +| **Prettier** | Code formatting | +| **Husky** | Git hooks | +| **Changesets** | Version management | + +## Configuration + +### TypeScript (tsconfig.json) + +```json +{ + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "@kitajs/html", + "plugins": [{ "name": "@kitajs/ts-html-plugin" }], + "strict": true, + "module": "CommonJS", + "target": "ESNext" + } +} +``` + +### VSCode Settings + +```json +{ + "typescript.tsdk": "node_modules/typescript/lib", + "typescript.enablePromptUseWorkspaceTsdk": true +} +``` + +## Performance Patterns + +The codebase uses several optimization patterns: + +1. **Check Before Convert**: Regex test before expensive operations + + ```typescript + if (!CAMEL_REGEX.test(camel)) return camel; + ``` + +2. **Loop vs Regex**: Character loops faster than regex for replacements + + ```typescript + for (; end < length; end++) { + switch (value[end]) { ... } + } + ``` + +3. **Escape Once**: Escape entire result string, not individual pieces + +4. **Void Element Ordering**: Most common tags first in checks + +5. **Bun Detection**: Use native `Bun.escapeHTML` when available + +## Security Model + +### XSS Prevention Layers + +1. **Compile-Time**: `@kitajs/ts-html-plugin` catches unsafe usage +2. **CI/CD**: `xss-scan` CLI fails builds on XSS issues +3. **Runtime**: `safe` attribute escapes content + +### Safe Content Types + +- Numbers, booleans, bigints +- String literals +- `JSX.Element` (already rendered) +- `Html.Children` type +- Variables prefixed with `safe` +- `Html.escapeHtml()` calls + +### Unsafe Content Types + +- `string` (dynamic) +- `any` type +- Objects with `toString()` +- Variables prefixed with `unsafe` + +## Documentation Rule + +Any change to the runtime, types, API surface, configuration, or behavior of any package +must include a corresponding update to the documentation at `packages/docs/`. If a code +change would make any existing documentation page inaccurate, update that page in the same +commit. Use the `docs-writer` agent at `.claude/agents/docs-writer/` for documentation +work. Run `pnpm -F @kitajs/docs-html build` to verify the docs site compiles after any +documentation change. + +## Common Patterns + +### Component Definition + +```tsx +import type { PropsWithChildren } from '@kitajs/html'; + +function Card({ title, children }: PropsWithChildren<{ title: string }>) { + return ( +
+

{title}

+ {children} +
+ ); +} +``` + +### Async Component + +```tsx +async function UserProfile({ id }: { id: string }) { + const user = await db.getUser(id); + return
{user.name}
; +} +``` + +### Suspense Usage + +```tsx +function Page({ rid }: { rid: number }) { + return ( + } catch={(e) => }> + + + ); +} + +// With Fastify +app.get('/', (req, reply) => reply.html()); +``` + +### Conditional Classes + +```tsx +
+``` + +## Common Gotchas + +1. **Children NOT escaped by default** - Always use `safe` for user input +2. **`JSX.Element` is `string | Promise`** - Handle both cases +3. **Suspense needs `rid`** - Use request ID for concurrent safety +4. **Components receive `safe` as a prop** - They must forward it to inner native elements +5. **pnpm required** - npm/yarn will fail on install diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..4542c0b1d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,134 @@ +# Contributing to Kita Html + +## Prerequisites + +pnpm is the only supported package manager. The `preinstall` script enforces this. Node.js +20.13 or later is required. + +```bash +pnpm install +``` + +## Repository Structure + +``` +packages/ + html/ @kitajs/html Core JSX runtime + ts-html-plugin/ @kitajs/ts-html-plugin XSS detection (TS plugin + CLI) + fastify-html-plugin/ @kitajs/fastify-html-plugin Fastify integration + docs/ @kitajs/docs-html Documentation site +benchmarks/ Performance benchmarks +examples/ Usage examples (fastify-htmx, http-server) +``` + +## Commands + +### Root-level (all packages) + +```bash +pnpm build # Build all packages (via Turbo) +pnpm test # Run all tests (via Turbo) +pnpm format # Format all files with Prettier +pnpm bench # Run benchmarks +pnpm test-types # Type-check all packages +``` + +### Per-package + +Use `-F` (short for `--filter`) to target a specific package. + +```bash +pnpm -F @kitajs/html build +pnpm -F @kitajs/html test +pnpm -F @kitajs/ts-html-plugin build +pnpm -F @kitajs/ts-html-plugin test +pnpm -F @kitajs/fastify-html-plugin test +pnpm -F @kitajs/docs-html build +pnpm -F @kitajs/docs-html dev # Dev server on port 1229 +``` + +All packages use `tsgo -p tsconfig.build.json` for building and +`vitest --coverage --typecheck --run` for testing. + +### Formatting + +Prettier is the sole formatter. Run `pnpm format` before committing. Husky pre-commit +hooks enforce this, but running it manually avoids surprises. + +## Making Changes + +### Code changes + +1. Make your changes in the relevant `packages/*/src/` directory +2. Run `pnpm format` to format +3. Run `pnpm build` to compile +4. Run `pnpm test` to verify tests pass +5. Update documentation (see below) + +### Documentation changes + +The documentation site lives at `packages/docs/`. All docs are markdown files under +`packages/docs/docs/`. The site uses Rspress and follows the Information Mapping +methodology. See `packages/docs/CLAUDE.md` for the full conventions. + +After editing any documentation file: + +```bash +pnpm format +pnpm -F @kitajs/docs-html build +``` + +The build must exit with code 0. Broken links and invalid markdown will cause build +failures. + +### Adding a new doc page + +1. Create the `.md` file in the correct directory under `packages/docs/docs/` +2. Add the filename (without extension) to the directory's `_meta.json` +3. Format and build to verify + +## Documentation Rule + +Any change to the runtime, types, API surface, configuration, or behavior of any package +must include a corresponding update to the documentation at `packages/docs/`. This applies +to new features, changed behavior, removed functionality, renamed exports, and modified +defaults. If a code change would make any existing documentation page inaccurate, update +that page in the same commit. + +## Testing + +Tests use Vitest with V8 coverage and type checking enabled. + +When writing tests, cover these areas: + +- XSS safety with malicious input samples +- Both sync and async component paths +- Type correctness (Vitest runs `--typecheck`) +- Performance regressions for core changes (run `pnpm bench`) + +## Changesets + +This project uses [Changesets](https://github.com/changesets/changesets) for version +management. After making your changes, create a changeset: + +```bash +pnpm changeset +``` + +Select the affected packages, choose the semver bump level, and write a short description. +The changeset file is committed with your PR. + +## Pull Requests + +Every PR must include a changeset entry. Run `pnpm changeset` before submitting, select +the affected packages, choose the semver bump level, and write a short description. The +generated changeset file is committed with your PR. + +1. Fork and clone the repository +2. Create a branch for your changes +3. Make changes and update documentation +4. `pnpm format` +5. `pnpm build` +6. `pnpm test` +7. `pnpm changeset` +8. Submit PR diff --git a/DOCS_PLAN.md b/DOCS_PLAN.md new file mode 100644 index 000000000..0887ffb68 --- /dev/null +++ b/DOCS_PLAN.md @@ -0,0 +1,376 @@ +# Kita Html Documentation Plan + +## Context + +The current documentation lives scattered across three README files (one per package) and +a mockup docs site at `packages/docs/`. The goal is to consolidate all documentation into +a single Rspress-powered site at `packages/docs/`, structured following the Information +Mapping (Structured Writing) methodology, and eventually deprecate the READMEs. + +The documentation must serve developers evaluating and adopting Kita Html: a JSX runtime +that produces HTML strings for server-side rendering, static sites, and HTMX applications. +The writing follows the author's requested narrative arc: explain why string-based JSX is +fast, then the XSS trade-off this creates, then the three-layer solution. + +## Information Mapping Methodology + +Each page is assigned exactly one of the six information types. Types are never mixed +within a page. + +| Type | Purpose | Example in this project | +| --------- | -------------------------------------- | --------------------------------------------- | +| Concept | What something is and why it matters | "What is Kita Html", "Async Components" | +| Procedure | Step-by-step instructions | "Getting Started", "Using Suspense" | +| Process | How something works internally | "How JSX Becomes HTML", "Streaming Internals" | +| Principle | Rules, design decisions, rationale | "XSS Safety Rules", "Design Decisions" | +| Structure | API references, component organization | All API pages | +| Fact | Data, measurements, specifications | "Benchmarks", "Serialization Table" | + +Core principles applied: chunking (one topic per page, 200-800 words), relevance (no +tangential content), labelling (concrete descriptive titles), consistency (same format +within each type), no type mixing (procedures never explain internals; concepts never list +steps). + +## Decisions + +- **Consolidation**: Very small pages (under 300 words) are merged into parent topics. + Conditional Classes, the tag Tag, and Serialization fold into the JSX Syntax page. + Formatting Output and Legacy JSX Transform fold into "Additional Configuration". Page + count: 33. +- **Reference placement**: Reference pages live at the bottom of the Guide sidebar. Top + nav stays at 3 items + GitHub. +- **Implementation**: Write the Introduction page first as a sample for tone/depth review + before proceeding with all remaining pages. +- **XSS section ordering**: Lead with the solution (safe attribute, detection tooling), + not the problem. The trade-off explanation ("why it works this way") comes after the + reader already knows how to stay safe. This prevents the reader from hitting "XSS is + possible" and bouncing before seeing that the tooling catches everything. +- **Integrations split**: Frameworks (Fastify, with room for future additions) and Type + Extensions (HTMX, Alpine.js, Hotwire Turbo) as separate subsections. +- **ts-html-plugin docs**: Document by capability (XSS analysis rules, editor integration, + CLI scanner) rather than by package name. This way, the upcoming split into three + packages (base analysis, LSP plugin, CLI) won't require restructuring the docs -- just + updating import paths and package names. + +## Page Tree + +``` +docs/ + index.md Homepage (landing page) + + guide/ + introduction.md Concept ~650 words + getting-started.md Procedure ~500 words + how-jsx-becomes-html.md Process ~450 words + + xss/ + safe-attribute.md Procedure ~550 words + detection.md Process ~500 words + scanner-cli.md Procedure ~400 words + safety-rules.md Principle ~400 words + error-codes.md Structure ~500 words + why-not-auto-escape.md Concept ~500 words + + async/ + async-components.md Concept ~500 words + suspense.md Concept ~500 words + using-suspense.md Procedure ~500 words + error-boundaries.md Procedure ~450 words + streaming-internals.md Process ~450 words + + jsx/ + syntax.md Procedure ~700 words + (includes conditional classes, + the tag tag, and serialization table) + extending-types.md Procedure ~400 words + + design-decisions.md Principle ~600 words + + reference/ + benchmarks.md Fact ~500 words + compatibility.md Fact ~300 words + migrating-from-html.md Procedure ~300 words + additional-config.md Procedure ~350 words + + integrations/ + overview.md Concept ~300 words + + frameworks/ + fastify.md Procedure ~600 words + + type-extensions/ + htmx.md Procedure ~350 words + alpine.md Procedure ~350 words + hotwire-turbo.md Procedure ~350 words + + base-templates.md Procedure ~400 words + + api/ + index.md Structure ~200 words + core.md Structure ~700 words + jsx-runtime.md Structure ~400 words + suspense.md Structure ~500 words + error-boundary.md Structure ~250 words + xss-analysis.md Structure ~350 words + editor-plugin.md Structure ~250 words + scanner-cli.md Structure ~250 words + types.md Structure ~400 words +``` + +Total: 34 pages, ~14,000 words estimated. + +## Navigation Structure + +Top navigation (3 items + external): + +1. Guide -> `/guide/introduction` +2. Integrations -> `/integrations/overview` +3. API -> `/api/` +4. GitHub -> `https://github.com/kitajs/html` (external) + +Sidebar for Guide: + +``` +Introduction +Getting Started +How JSX Becomes HTML +--- +XSS Protection + Using the Safe Attribute <- solution first + How XSS Detection Works <- then how tooling catches it + Running the XSS Scanner <- practical CLI usage + Safety Rules <- reference: what's safe/unsafe + Error Codes <- reference: K601-K604 + Why Not Auto-Escape <- deeper rationale, last +--- +Async & Streaming + Async Components + Suspense Streaming + Using Suspense + Error Boundaries + Streaming Internals +--- +JSX + Syntax + Extending Types +--- +Design Decisions +--- +Reference + Benchmarks + Compatibility + Migrating from HTML + Additional Configuration +``` + +Sidebar for Integrations: + +``` +Overview +--- +Frameworks + Fastify +--- +Type Extensions + HTMX + Alpine.js + Hotwire Turbo +--- +Base Templates +``` + +Sidebar for API: + +``` +Overview +@kitajs/html +@kitajs/html/jsx-runtime +@kitajs/html/suspense +@kitajs/html/error-boundary +--- +XSS Analysis <- capability-based, not package-based +Editor Plugin <- easy to update when packages split +CLI Scanner <- easy to update when packages split +--- +Type Definitions +``` + +## Page Specifications + +### Guide + +**Introduction** (Concept) Title: "What is Kita Html" Defines Kita Html as a JSX runtime +producing HTML strings. Explains WHY string concatenation is faster than virtual DOM (no +intermediate object graph, no diffing). Introduces the XSS trade-off briefly, then +immediately explains the three-layer solution (safe attribute, TS plugin, xss-scan CLI) so +the reader lands on "this is solved." Closes with positioning: SSR, static sites, HTMX, +email templates. + +**Getting Started** (Procedure) Four steps: install packages, configure tsconfig.json +(jsx, jsxImportSource, plugins), configure editor workspace TypeScript, add xss-scan to +test script. Ends with verification: paste XSS-prone code, confirm editor error. + +**How JSX Becomes HTML** (Process) Traces the data flow: TSX source -> TypeScript compiler +rewrites to jsx()/jsxs() calls -> runtime calls attributesToString/contentsToString -> +output is string or Promise. One three-stage code transformation example. + +### XSS Protection + +Section is ordered solution-first. A developer reading only the first page or two walks +away knowing how to write safe code. The "why" comes last for those who want deeper +understanding. + +**Using the Safe Attribute** (Procedure) Adding `safe` to native elements, using +`Html.escapeHtml()` for components, using `e` template literal, `safe`-prefix variable +convention, `as 'safe'` cast. One example per technique. Guidance on placement (lowest +element in tree). + +**How XSS Detection Works** (Process) Three-layer mechanism: TS plugin hooks into language +service, walks JSX AST, emits diagnostics for unsafe types. CLI creates a TS program, runs +same analysis. Runtime `safe` attribute triggers `escapeHtml`. Emphasizes: the tooling +catches all unsafe usage at dev time and CI -- you cannot accidentally ship XSS. + +**Running the XSS Scanner** (Procedure) CLI options (--cwd, --project, --simplified), exit +codes (0/1/2), package.json integration, CI/CD example. + +**Safety Rules** (Principle) Safe types: number, boolean, bigint, null, undefined, string +literals, JSX.Element, Html.Children, safe-prefixed vars, escapeHtml() returns. Unsafe: +string, any, objects with toString(). Script tags exempt. Both ternary branches checked. + +**Error Codes** (Structure) Reference table: K601 (unsafe expression), K602 (double +escaping), K603 (component children XSS), K604 (unnecessary safe). Each with severity, +trigger condition, wrong/correct code. + +**Why Not Auto-Escape** (Concept) Deeper explanation for those who want to understand the +trade-off. Why a string-based runtime cannot auto-escape children. Compares with React +(object elements allow auto-escaping). By this point, the reader already knows the +solution, so this reads as "here's the interesting engineering reason" rather than "here's +a scary problem." + +### Async & Streaming + +**Async Components** (Concept) Functions returning Promise. Promise propagation: +any async child makes the tree async. JSX.Element as string | Promise. When to +await vs cast. + +**Suspense Streaming** (Concept) The problem (waiting for entire async tree). The solution +(stream fallback immediately, replace when ready). Request IDs for concurrent safety. What +happens without renderToStream. + +**Using Suspense** (Procedure) Import, wrap async components with rid/fallback/catch, call +renderToStream, pipe stream to response. Callback and direct rid patterns. Async +fallbacks. + +**Error Boundaries** (Procedure) Import ErrorBoundary, wrap async components, provide +catch handler. Interaction with Suspense catch. Sync errors need try/catch. Combined +pattern. + +**Streaming Internals** (Process) Fallback wrapped in `
`, async resolution +produces `