Skip to content

Commit c038688

Browse files
hyochanclaude
andauthored
refactor(gql): migrate to IR-based code generation architecture (#73)
## Summary - Replace 4 individual language generator scripts with unified IR-based plugin system - Single GraphQL schema parsing instead of 5 separate parsers - Generated output is 100% identical to previous scripts ## Architecture ``` GraphQL Schema (src/*.graphql) ↓ [1] Parser (codegen/core/parser.ts) ↓ [2] Transformer → IR (codegen/core/transformer.ts) ↓ [3] Language Plugins (codegen/plugins/*.ts) ↓ Generated Files (src/generated/*) ``` ## Changes ### New Plugin System (`codegen/plugins/`) | Plugin | Features | |--------|----------| | **swift.ts** | Codable protocol, ErrorCode custom init, platform defaults | | **kotlin.ts** | Sealed interface, fromJson/toJson, nullable patterns | | **dart.ts** | Sealed class, factory constructors, extends/implements | | **gdscript.ts** | _init() pattern, from_json/to_json, Variant type | ### Deleted Scripts (3,687 lines removed) - `generate-swift-types.mjs` (831 lines) - `generate-kotlin-types.mjs` (939 lines) - `generate-dart-types.mjs` (1,105 lines) - `generate-gdscript-types.mjs` (812 lines) ### Documentation Updates - `CONTRIBUTING.md` - Added IR architecture documentation - `CLAUDE.md` - Added code generation system section - `packages/gql/CONVENTION.md` - Added code generation architecture section - `knowledge/internal/04-platform-packages.md` - Comprehensive GQL section ## Test plan - [x] `bun run generate` completes successfully - [x] Generated Swift types match previous output (byte-identical) - [x] Generated Kotlin types match previous output (byte-identical) - [x] Generated Dart types match previous output (byte-identical) - [x] Generated GDScript types match previous output (byte-identical) - [x] Types synced to `packages/apple` and `packages/google` 🤖 Generated with [Claude Code](https://claude.ai/code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Centralized IR-based GraphQL code generation with language plugins producing Swift, Kotlin, Dart, and GDScript outputs and a CLI to generate per-language artifacts. * **Documentation** * Extensive guides added: codegen architecture, IR types, plugin model, templates, and updated regeneration instructions. * **Chores** * Replaced legacy per-language generator scripts with the new centralized generator; added template tooling dependency and updated generate scripts. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent a3932a4 commit c038688

66 files changed

Lines changed: 6896 additions & 3734 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/commands/review-pr.md

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,30 @@ When reviewing, check these project-specific rules:
3131

3232
See [CLAUDE.md](../../CLAUDE.md) and [knowledge/internal/](../../knowledge/internal/) for full conventions.
3333

34-
## Reply Format Rules
34+
## Reply Format Rules (CRITICAL)
3535

3636
When replying to PR comments:
3737

38-
- **Commit hash references**: Write commit hashes as plain text, NOT in code blocks
39-
- CORRECT: `Fixed in f3b5fec.`
40-
- WRONG: `Fixed in \`f3b5fec\`.`
41-
- This ensures GitHub auto-links the commit hash to the actual commit
38+
### Commit Hash Formatting
39+
40+
**NEVER wrap commit hashes in backticks or code blocks.** GitHub only auto-links plain text commit hashes.
41+
42+
| Format | Example | Result |
43+
|--------|---------|--------|
44+
| ✅ CORRECT | `Fixed in f3b5fec.` | Clickable link to commit |
45+
| ❌ WRONG | `Fixed in \`f3b5fec\`.` | Plain text, no link |
46+
47+
**Examples of correct replies:**
48+
49+
```text
50+
Fixed in f3b5fec.
51+
52+
**Changes:**
53+
- Updated header to use bun run generate
54+
```
55+
56+
```text
57+
Fixed in abc1234 along with other review items.
58+
```
59+
60+
**Do NOT use backticks around the commit hash** - this breaks GitHub's auto-linking feature.

.claude/commands/sync-godot-iap.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ Synchronize OpenIAP changes to the [godot-iap](https://github.com/hyochan/godot-
7676

7777
## Type Generation Source
7878

79-
**OpenIAP has a built-in GDScript type generator:**
79+
**OpenIAP has a built-in GDScript type generator (IR-based):**
8080

81-
- **Generator:** `/Users/crossplatformkorea/Github/hyodotdev/openiap/packages/gql/scripts/generate-gdscript-types.mjs`
81+
- **Generator:** `/Users/crossplatformkorea/Github/hyodotdev/openiap/packages/gql/codegen/plugins/gdscript.ts`
82+
- **Entry Point:** `/Users/crossplatformkorea/Github/hyodotdev/openiap/packages/gql/codegen/index.ts`
8283
- **Output:** `/Users/crossplatformkorea/Github/hyodotdev/openiap/packages/gql/src/generated/types.gd`
8384

8485
---
@@ -713,6 +714,7 @@ Now update `docs/docs/` with new API documentation for the new version.
713714

714715
## References
715716

716-
- **OpenIAP GDScript Generator:** `/Users/crossplatformkorea/Github/hyodotdev/openiap/packages/gql/scripts/generate-gdscript-types.mjs`
717+
- **OpenIAP GDScript Generator:** `/Users/crossplatformkorea/Github/hyodotdev/openiap/packages/gql/codegen/plugins/gdscript.ts`
718+
- **OpenIAP Codegen Entry:** `/Users/crossplatformkorea/Github/hyodotdev/openiap/packages/gql/codegen/index.ts`
717719
- **OpenIAP Docs:** https://openiap.dev/docs
718720
- **Godot IAP Docs:** Check README.md

CLAUDE.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,30 @@ openiap/
5454

5555
- `packages/apple/Sources/Models/Types.swift`
5656
- `packages/google/openiap/src/main/Types.kt`
57+
- `packages/gql/src/generated/*` - All generated type files
5758
- `openiap-versions.json` - Managed by CI/CD workflows only
5859

59-
Regenerate types with: `./scripts/generate-types.sh`
60+
Regenerate types: `cd packages/gql && bun run generate`
61+
62+
### GQL Code Generation System
63+
64+
The type generation uses an **IR-based (Intermediate Representation)** architecture:
65+
66+
```text
67+
GraphQL Schema → Parser → IR → Language Plugins → Generated Code
68+
69+
codegen/core/ codegen/plugins/
70+
├── types.ts ├── swift.ts
71+
├── parser.ts ├── kotlin.ts
72+
└── transformer.ts├── dart.ts
73+
└── gdscript.ts
74+
```
75+
76+
**Language plugins handle:**
77+
- **Swift**: Codable protocol, ErrorCode custom initializer, platform defaults
78+
- **Kotlin**: sealed interface, fromJson/toJson with nullable patterns
79+
- **Dart**: sealed class, factory constructors, extends/implements
80+
- **GDScript**: _init() pattern, Variant type for unions
6081

6182
### Git Commit Format
6283

CONTRIBUTING.md

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ bun install
4242

4343
### `@hyodotdev/openiap-gql`
4444

45-
GraphQL schema and type generation for all platforms.
45+
GraphQL schema and **IR-based type generation** for all platforms.
4646

4747
```bash
4848
cd packages/gql
@@ -51,12 +51,20 @@ cd packages/gql
5151
bun run generate
5252

5353
# Generate for specific platform
54-
bun run generate:ts # TypeScript
55-
bun run generate:swift # Swift
56-
bun run generate:kotlin # Kotlin
57-
bun run generate:dart # Dart
54+
bun run generate:ts # TypeScript (graphql-codegen)
55+
bun run generate:swift # Swift (IR-based plugin)
56+
bun run generate:kotlin # Kotlin (IR-based plugin)
57+
bun run generate:dart # Dart (IR-based plugin)
58+
bun run generate:gdscript # GDScript (IR-based plugin)
5859
```
5960

61+
**Architecture:**
62+
```text
63+
GraphQL Schema → Parser → IR (Intermediate Representation) → Language Plugins → Generated Code
64+
```
65+
66+
See [Code Generation Architecture](#code-generation-architecture) for details.
67+
6068
### `@hyodotdev/openiap-docs`
6169

6270
Documentation website at [openiap.dev](https://openiap.dev)
@@ -275,23 +283,83 @@ Each package has its own scripts. See individual `package.json` files for detail
275283
```text
276284
GraphQL Schema (packages/gql/src/*.graphql)
277285
278-
Type Generation (bun run generate)
286+
[1] Parser (codegen/core/parser.ts)
287+
288+
[2] Transformer → IR (codegen/core/transformer.ts)
289+
290+
[3] Language Plugins (codegen/plugins/*.ts)
291+
292+
├─→ TypeScript (src/generated/types.ts) [graphql-codegen]
293+
├─→ Swift (src/generated/Types.swift) [IR plugin]
294+
├─→ Kotlin (src/generated/Types.kt) [IR plugin]
295+
├─→ Dart (src/generated/types.dart) [IR plugin]
296+
└─→ GDScript (src/generated/types.gd) [IR plugin]
297+
298+
Auto Sync (bun run sync)
279299
280-
├─→ TypeScript (src/generated/types.ts)
281-
├─→ Swift (src/generated/Types.swift) ──┐
282-
├─→ Kotlin (src/generated/Types.kt) ──┐ │
283-
└─→ Dart (src/generated/types.dart) │ │
284-
│ │
285-
Auto Sync ───────────────┘ │
286-
287-
┌───────────────────────────────────────┘
288-
289300
├─→ packages/apple/Sources/Models/Types.swift
290-
└─→ packages/google/.../openiap/Types.kt (+ post-processing)
301+
└─→ packages/google/.../openiap/Types.kt
291302
```
292303

293304
**Key Feature:** One `generate` command updates all platforms automatically!
294305

306+
## 🏗️ Code Generation Architecture
307+
308+
The GQL package uses an **IR-based (Intermediate Representation) code generation system**:
309+
310+
### Directory Structure
311+
312+
```text
313+
packages/gql/codegen/
314+
├── index.ts # Main entry point
315+
├── core/
316+
│ ├── types.ts # IR type definitions (IREnum, IRObject, etc.)
317+
│ ├── parser.ts # GraphQL schema parser
318+
│ ├── transformer.ts # AST → IR transformer
319+
│ └── utils.ts # Case conversion, keyword escaping
320+
└── plugins/
321+
├── base-plugin.ts # Abstract base class
322+
├── swift.ts # Swift: Codable, ErrorCode handling
323+
├── kotlin.ts # Kotlin: sealed interface, fromJson/toJson
324+
├── dart.ts # Dart: sealed class, factory constructors
325+
└── gdscript.ts # GDScript: Godot engine types
326+
```
327+
328+
### IR Types
329+
330+
| IR Type | Description |
331+
|---------|-------------|
332+
| `IREnum` | Enum with values, raw values (kebab-case), legacy aliases |
333+
| `IRInterface` | Protocol/Interface with typed fields |
334+
| `IRObject` | Struct/Class with fields, implements, union membership |
335+
| `IRInput` | Input type with required field tracking |
336+
| `IRUnion` | Union with members, nested union support |
337+
| `IROperation` | Query/Mutation/Subscription definitions |
338+
339+
### Language Plugin Features
340+
341+
| Plugin | Key Features |
342+
|--------|--------------|
343+
| **Swift** | Codable protocol, ErrorCode custom init, platform defaults (ProductIOS) |
344+
| **Kotlin** | sealed interface, fromJson/toJson, nullable patterns, type casting |
345+
| **Dart** | extends/implements, factory constructors, sealed class, @override |
346+
| **GDScript** | _init() pattern, from_json/to_json, Variant for unions |
347+
348+
### Schema Markers
349+
350+
Special comments in GraphQL SDL:
351+
352+
```graphql
353+
# => Union
354+
type RequestPurchaseResult {
355+
purchase: Purchase # Generates union variant
356+
purchases: [Purchase!]
357+
}
358+
359+
# Future
360+
fetchProducts(...): FetchProductsResult # Wraps in Promise/async
361+
```
362+
295363
## 🔄 Common Workflows
296364

297365
### Adding a New Feature

bun.lock

Lines changed: 15 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)