Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"ignore": ["@kitajs/bench-*"],
"ignore": ["@kitajs/bench-*", "@kitajs/example-*"],
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
}
Expand Down
5 changes: 5 additions & 0 deletions .changeset/hip-trams-roll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@kitajs/ts-html-plugin': patch
---

Skip xss check for `str &&` cases
5 changes: 5 additions & 0 deletions .changeset/metal-corners-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@kitajs/ts-html-plugin': patch
---

Support for multiline TSServer messages and improvements to XSS Children detection
5 changes: 5 additions & 0 deletions .changeset/metal-hairs-juggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@kitajs/ts-html-plugin': patch
---

Fixed CLI inconsistencies with a dedicated bin js file
5 changes: 5 additions & 0 deletions .changeset/slimy-wolves-buy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@kitajs/html': patch
---

Broather and more reliable test suite
5 changes: 5 additions & 0 deletions .changeset/stale-shrimps-spend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@kitajs/html': major
---

Removed deprecated @kitajs/html/register
5 changes: 5 additions & 0 deletions .changeset/warm-seas-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@kitajs/html': major
---

Major overhaul
10 changes: 9 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,16 @@ 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
run: pnpm build-all

- name: Test
run: pnpm test
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
17 changes: 8 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@

node_modules

index.tsbuildinfo
dist
coverage

.DS_Store
.turbo
*.cpuprofile
*.log

benchmarks/runner/profile.cpuprofile
*.tsbuildinfo
*.tsbuildinfo
coverage
dist
node_modules
1 change: 1 addition & 0 deletions .serena/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/cache
228 changes: 228 additions & 0 deletions .serena/memories/architecture_and_patterns.md
Original file line number Diff line number Diff line change
@@ -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
<div class="foo">{content}</div>;
// Transpiles to:
jsx('div', { class: 'foo', children: content });
// Returns: '<div class="foo">content</div>'
```

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)}</${tag}>`;
}
```

### 2. Async/Await Pattern

Async components are seamlessly integrated:

- Sync components return `string`
- Async components return `Promise<string>`
- 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
<Suspense rid={rid} fallback={<Loading />} catch={(err) => <Error />}>
<AsyncComponent />
</Suspense>
```

Uses request IDs (rid) for concurrent request safety.

### 5. Error Boundary Pattern

Catch errors in async component trees:

```tsx
<ErrorBoundary catch={(err) => <ErrorView />}>
<AsyncComponent />
</ErrorBoundary>
```

## 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<string>` 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(<div>hello</div>).toBe('<div>hello</div>');
});
});
```

### 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(<div>foo</div>).toEqualTypeOf<string>();
```

## 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
Loading
Loading