Skip to content
Merged
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
19 changes: 10 additions & 9 deletions .github/workflows/deploy_maven_central.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,28 @@ jobs:
gpg_private_key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Make gradlew executable
run: chmod +x ./gradlew
- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1
- name: Display version info
run: |
echo "Branch name from GITHUB_REF_NAME: $GITHUB_REF_NAME"
echo "Branch name from GITHUB_HEAD_REF: $GITHUB_HEAD_REF"
./gradlew -q printVersion
- name: Publish package
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: |
-PmavenCentralUsername=${{ secrets.MAVEN_USERNAME }}
-PmavenCentralPassword=${{ secrets.MAVEN_PASSWORD }}
-PsigningInMemoryKeyId=${{ secrets.MAVEN_GPG_KEY_ID }}
-PsigningInMemoryPassword=${{ secrets.MAVEN_GPG_PASSPHRASE }}
cache-read-only: false
- name: Publish package
run: |
./gradlew \
-PmavenCentralUsername=${{ secrets.MAVEN_USERNAME }} \
-PmavenCentralPassword=${{ secrets.MAVEN_PASSWORD }} \
-PsigningInMemoryKeyId=${{ secrets.MAVEN_GPG_KEY_ID }} \
-PsigningInMemoryPassword=${{ secrets.MAVEN_GPG_PASSPHRASE }} \
allTests publishAndReleaseToMavenCentral
env:
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Make gradlew executable
run: chmod +x ./gradlew
- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1
- name: run test
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: allTests
cache-read-only: false
- name: Run tests
run: ./gradlew allTests
####
27 changes: 24 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
# CLAUDE.md

日本語で会話する
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## プロジェクト概要

RenlinはHTML UIを型安全なDSLアプローチで構築するためのKotlinマルチプラットフォームライブラリです。主にJavaScript/ブラウザターゲット向けのWeb開発用に設計されていますが、JVMもサポートしています。HakateステートマネジメントシステムとCSS-in-JS機能を統合しています。
RenlinはHTML
UIを型安全なDSLアプローチで構築するためのKotlinマルチプラットフォームライブラリです。主にJavaScript/ブラウザターゲット向けのWeb開発用に設計されていますが、JVMもサポートしています。HakateステートマネジメントシステムとCSS-in-JS機能を統合しています。

## 主要アーキテクチャ

### モジュール構造

- **renlin/**: マルチプラットフォームソースセット(commonMain、jsMain、jvmMain)を持つメインライブラリモジュール
- **sample/**: ライブラリの使用パターンを示すサンプル実装
- **generate/**: HTML タグDSL作成用のコード生成ツール
- **convention-plugins/**: 一貫したビルド設定のためのGradle規約プラグイン

### 主要概念

- **コンポーネントシステム**: レンダー関数を持つ`Component<TAG>`インターフェースを使用した型安全なコンポーネント
- **DSLアーキテクチャ**: `@Html`マーカーアノテーションと型安全なコンテンツカテゴリを使用したHTML DSL構築
- **ステート管理**: `StateDispatcher`を介したリアクティブステートハンドリングのためのHakateライブラリとの統合
Expand All @@ -23,19 +27,22 @@ RenlinはHTML UIを型安全なDSLアプローチで構築するためのKotlin
- **属性システム**: `DslStateData`を通じた型安全な HTML 属性管理(href、onClick など)

### プラットフォームターゲット

- **JavaScript**: DOM操作によるブラウザベースレンダリング(`DomTagElement` 経由)
- **JVM**: サーバーサイドHTML生成機能

## 開発コマンド

### ビルド

```bash
./gradlew build # 全モジュールをビルド
./gradlew :renlin:build # メインライブラリのみをビルド
./gradlew :sample:build # サンプルアプリケーションをビルド
```

### テスト

```bash
./gradlew test # 全テストを実行
./gradlew :renlin:test # メインライブラリをテスト
Expand All @@ -44,17 +51,20 @@ RenlinはHTML UIを型安全なDSLアプローチで構築するためのKotlin
```

### サンプル開発

```bash
./gradlew :sample:jsBrowserRun # ブラウザでサンプルを実行(開発用)
./gradlew :sample:jsBrowserDevelopmentExecutableDistribution # サンプル配布版をビルド
```

### コード生成

```bash
./gradlew :generate:run # HTML タグDSLコードを生成
```

### パブリッシング

```bash
./gradlew publishToMavenLocal # ローカルMavenリポジトリに公開
./gradlew publish # 設定されたリポジトリに公開
Expand All @@ -63,31 +73,39 @@ RenlinはHTML UIを型安全なDSLアプローチで構築するためのKotlin
## 主要実装パターン

### コンポーネント作成
コンポーネントは`Component<TAG>`を継承し、`.component {}`DSLビルダーパターンを使用します。ステート統合は`StateDispatcher`を通じて行われ、`useValue()`によるリアクティブレンダリングが可能です。

コンポーネントは`Component<TAG>`を継承し、`.component {}`DSLビルダーパターンを使用します。ステート統合は`StateDispatcher`
を通じて行われ、`useValue()`によるリアクティブレンダリングが可能です。

### エントリーポイントパターン

JSアプリケーションは`Entrypoint(domElement).render(component, dispatcher)`を使用してコンポーネントをDOM要素にマウントします。

### CSS統合

自動クラス生成のために`cssManager`プロパティを使用してスタイリングを行います。CSSプロパティは型安全で疑似クラスをサポートしています。

### コンテンツ型安全性

DSLはW3Cコンテンツカテゴリをコンパイル時に強制します - FlowContentはPhrasingContentを含むことができますが、その逆はできません。

### 属性とイベント管理

- **DslStateData パターン**: 属性(href など)とイベントハンドラー(onClick など)は`DslStateData`を通じて管理されます
- **型安全な属性**: `Href`クラスなどのvalue objectsを使用して属性値を型安全に扱います
- **自動DOM同期**: `TagNodeCommon.setDslStateData`が属性とイベントの DOM への同期を自動的に行います

## アーキテクチャの理解

### レイヤー構造

1. **Component レイヤー**: `Component<TAG>` - 最上位のコンポーネント抽象化
2. **DSL レイヤー**: `DslBase` - HTML構造構築とライフサイクル管理
3. **State レイヤー**: `DslState` / `DslStateData` - 状態管理と属性/イベント管理
4. **Platform レイヤー**: `TagNode` implementations - プラットフォーム固有のレンダリング

### W3C カテゴリシステム

- `w3c/category/native/` - W3C HTML仕様に基づくコンテンツカテゴリ型定義
- `w3c/category/dsl/` - 各カテゴリ用のDSLインターフェース
- `w3c/category/integration/` - カテゴリ間の統合型定義
Expand All @@ -105,16 +123,19 @@ DSLはW3Cコンテンツカテゴリをコンパイル時に強制します - Fl

## ステート管理統合

ライブラリはステート管理にHakateが必要です。コンポーネントは`MutableState<T>`を通じてリアクティブステートにアクセスし、`useValue()`を介して再レンダリングをトリガーします。ステートの変更は自動的にコンポーネントツリー全体に伝播されます。
ライブラリはステート管理にHakateが必要です。コンポーネントは`MutableState<T>`を通じてリアクティブステートにアクセスし、
`useValue()`を介して再レンダリングをトリガーします。ステートの変更は自動的にコンポーネントツリー全体に伝播されます。

## 拡張とカスタマイズ

### 新しい属性の追加

1. `DslStateData`にプロパティを追加
2. `TagNodeCommon.setDslStateData`で属性をDOMに適用するロジックを追加
3. 対象DSLクラス用の拡張プロパティを`w3c/attribute/`に作成

### 新しいHTMLタグの追加

1. `generate/`モジュールのコード生成を使用するか、手動でタグクラスを作成
2. 適切なW3Cコンテンツカテゴリに従ってDSLクラスを実装
3. プラットフォーム固有の実装が必要な場合は、各プラットフォームモジュールで対応
5 changes: 4 additions & 1 deletion convention-plugins/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
plugins {
`kotlin-dsl`
kotlin("jvm") version "2.1.0"
}
fun pluginId(pluginName: String, version: String) = "$pluginName:$pluginName.gradle.plugin:$version"

dependencies {
implementation(libs.nexus.publish)
implementation(pluginId("org.jetbrains.kotlin.multiplatform", "2.1.0"))
implementation(pluginId("net.kigawa.renlin-compiler", "1.3.8"))
// Temporarily disabled due to Kotlin version compatibility with kotlin-dsl plugin
implementation(pluginId("net.kigawa.renlin-compiler", "1.3.11"))
// https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-gradle-plugin
}
1 change: 1 addition & 0 deletions convention-plugins/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
kotlin.daemon.jvm.options=-Xskip-metadata-version-check
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ kotlin {
}
sourceSets["commonMain"].dependencies {
implementation("net.kigawa:hakate:3.3.2")
implementation("net.kigawa.renlin-compiler:renlin-kotlin-plugin:1.3.11")
}
sourceSets["commonTest"].dependencies {

Expand Down
30 changes: 24 additions & 6 deletions generate/src/jvmMain/kotlin/tagCategories.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,30 @@ val tagCategories = setOf(
),
TagInfo("footer", TagCategories(setOf("FlowContent", "PalpableContent")), AllowedCategories()),
TagInfo("header", TagCategories(setOf("FlowContent", "PalpableContent")), AllowedCategories()),
TagInfo("h1", TagCategories(setOf("FlowContent", "HeadingContent", "PalpableContent")), AllowedCategories()),
TagInfo("h2", TagCategories(setOf("FlowContent", "HeadingContent", "PalpableContent")), AllowedCategories()),
TagInfo("h3", TagCategories(setOf("FlowContent", "HeadingContent", "PalpableContent")), AllowedCategories()),
TagInfo("h4", TagCategories(setOf("FlowContent", "HeadingContent", "PalpableContent")), AllowedCategories()),
TagInfo("h5", TagCategories(setOf("FlowContent", "HeadingContent", "PalpableContent")), AllowedCategories()),
TagInfo("h6", TagCategories(setOf("FlowContent", "HeadingContent", "PalpableContent")), AllowedCategories()),
TagInfo(
"h1", TagCategories(setOf("FlowContent", "HeadingContent", "PalpableContent")),
AllowedCategories("PhrasingContent")
),
TagInfo(
"h2", TagCategories(setOf("FlowContent", "HeadingContent", "PalpableContent")),
AllowedCategories("PhrasingContent")
),
TagInfo(
"h3", TagCategories(setOf("FlowContent", "HeadingContent", "PalpableContent")),
AllowedCategories("PhrasingContent")
),
TagInfo(
"h4", TagCategories(setOf("FlowContent", "HeadingContent", "PalpableContent")),
AllowedCategories("PhrasingContent")
),
TagInfo(
"h5", TagCategories(setOf("FlowContent", "HeadingContent", "PalpableContent")),
AllowedCategories("PhrasingContent")
),
TagInfo(
"h6", TagCategories(setOf("FlowContent", "HeadingContent", "PalpableContent")),
AllowedCategories("PhrasingContent")
),
TagInfo("hgroup", TagCategories(setOf("FlowContent", "HeadingContent")), AllowedCategories()),
TagInfo("main", TagCategories(setOf("FlowContent", "PalpableContent")), AllowedCategories()),
TagInfo(
Expand Down
5 changes: 4 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ kotlin.daemon.jvmargs=-Xmx4096M
org.gradle.caching=true
# https://github.com/gradle/gradle/issues/22779 le sigh
#org.gradle.configuration-cache=true
# org.gradle.java.home=/usr/lib/jvm/java-17-openjdk-amd64 # GitHub Actionsでは不要
#Kotlin
kotlin.code.style=official
kotlin.js.compiler=ir
kotlin.compiler.execution.strategy=in-process
kotlin.compiler.incremental=true
kotlin.daemon.jvm.options=-Xskip-metadata-version-check

5 changes: 2 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
[versions]
kotlin-version = "2.1.0"
coroutines-version = "1.9.0"
coroutines-test-version = "1.10.1"
datetime-version = "0.6.1"
hakate-version = "3.3.0"
hakate-version = "3.3.2"
nexus-publish = "2.0.0-rc-1"
dokka = "1.9.20"
vanniktech-maven-publish = "0.29.0"
Expand All @@ -12,7 +11,7 @@ vanniktech-maven-publish = "0.29.0"
kotlin-stdlib-js = { module = "org.jetbrains.kotlin:kotlin-stdlib-js", version.ref = "kotlin-version" }
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin-version" }
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin-version" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines-version" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines-test-version" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines-test-version" }
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime-version" }
nexus-publish = { module = "io.github.gradle-nexus.publish-plugin:io.github.gradle-nexus.publish-plugin.gradle.plugin", version.ref = "nexus-publish" }
Expand Down
Loading
Loading