Skip to content

Commit bf4bb60

Browse files
authored
Ellyse/ct 665 ast handlers with type annotations cause typescript errors (#1505)
* fix type-to-schema-input.ts , was failing running, added recipe * fixed recipe, kept strongly typed handlers
1 parent 782da23 commit bf4bb60

File tree

4 files changed

+129
-225
lines changed

4 files changed

+129
-225
lines changed
Lines changed: 73 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,173 +1,127 @@
11
/// <cts-enable />
2-
import { recipe, handler, h, UI, NAME, str, Cell, derive, JSONSchema } from "commontools";
3-
// Define types using TypeScript interfaces
4-
interface TodoItem {
5-
id: string;
6-
text: string;
7-
completed: boolean;
8-
createdAt: Date;
2+
import { recipe, h, UI, NAME, Cell, Default, handler, JSONSchema } from "commontools";
3+
interface Item {
4+
text: Default<string, "">;
95
}
10-
interface TodoInput {
11-
todos: Cell<TodoItem[]>;
6+
interface InputSchemaInterface {
7+
title: Default<string, "untitled">;
8+
items: Default<Item[], [
9+
]>;
1210
}
13-
interface TodoOutput extends TodoInput {
14-
completedCount: number;
15-
pendingCount: number;
11+
interface OutputSchemaInterface extends InputSchemaInterface {
12+
items_count: number;
1613
}
17-
interface AddTodoEvent {
18-
text: string;
19-
}
20-
interface ToggleTodoEvent {
21-
id: string;
22-
}
23-
// Transform to schemas at compile time
14+
type InputEventType = {
15+
detail: {
16+
message: string;
17+
};
18+
};
2419
const inputSchema = {
2520
type: "object",
2621
properties: {
27-
todos: {
22+
title: {
23+
type: "string",
24+
default: "untitled"
25+
},
26+
items: {
2827
type: "array",
2928
items: {
3029
type: "object",
3130
properties: {
32-
id: {
33-
type: "string"
34-
},
3531
text: {
36-
type: "string"
37-
},
38-
completed: {
39-
type: "boolean"
40-
},
41-
createdAt: {
4232
type: "string",
43-
format: "date-time"
33+
default: ""
4434
}
4535
},
46-
required: ["id", "text", "completed", "createdAt"]
36+
required: ["text"]
4737
},
48-
asCell: true
38+
default: []
4939
}
5040
},
51-
required: ["todos"],
52-
default: {
53-
todos: []
54-
}
41+
required: ["title", "items"]
5542
} as const satisfies JSONSchema;
5643
const outputSchema = {
5744
type: "object",
5845
properties: {
59-
completedCount: {
46+
items_count: {
6047
type: "number"
6148
},
62-
pendingCount: {
63-
type: "number"
49+
title: {
50+
type: "string",
51+
default: "untitled"
6452
},
65-
todos: {
53+
items: {
6654
type: "array",
6755
items: {
6856
type: "object",
6957
properties: {
70-
id: {
71-
type: "string"
72-
},
7358
text: {
74-
type: "string"
75-
},
76-
completed: {
77-
type: "boolean"
78-
},
79-
createdAt: {
8059
type: "string",
81-
format: "date-time"
60+
default: ""
8261
}
8362
},
84-
required: ["id", "text", "completed", "createdAt"]
63+
required: ["text"]
8564
},
86-
asCell: true
65+
default: []
8766
}
8867
},
89-
required: ["completedCount", "pendingCount", "todos"]
68+
required: ["items_count", "title", "items"]
9069
} as const satisfies JSONSchema;
91-
const addTodoSchema = {
70+
// Handler that logs the message event
71+
const addItem = handler({
9272
type: "object",
9373
properties: {
94-
text: {
95-
type: "string"
74+
detail: {
75+
type: "object",
76+
properties: {
77+
message: {
78+
type: "string"
79+
}
80+
},
81+
required: ["message"]
9682
}
9783
},
98-
required: ["text"],
99-
title: "Add Todo",
100-
description: "Add a new todo item",
101-
examples: [{
102-
text: "Buy groceries"
103-
}]
104-
} as const satisfies JSONSchema;
105-
const toggleTodoSchema = {
84+
required: ["detail"]
85+
} as const satisfies JSONSchema, {
10686
type: "object",
10787
properties: {
108-
id: {
109-
type: "string"
88+
items: {
89+
type: "array",
90+
items: {
91+
type: "object",
92+
properties: {
93+
text: {
94+
type: "string",
95+
default: ""
96+
}
97+
},
98+
required: ["text"]
99+
},
100+
asCell: true
110101
}
111102
},
112-
required: ["id"],
113-
title: "Toggle Todo",
114-
description: "Toggle the completion status of a todo"
115-
} as const satisfies JSONSchema;
116-
// Handlers with full type safety
117-
const addTodo = handler(addTodoSchema, inputSchema, (event: AddTodoEvent, state: TodoInput) => {
118-
state.todos.push({
119-
id: Date.now().toString(),
120-
text: event.text,
121-
completed: false,
122-
createdAt: new Date()
123-
});
103+
required: ["items"]
104+
} as const satisfies JSONSchema, (event: InputEventType, { items }: {
105+
items: Cell<Item[]>;
106+
}) => {
107+
items.push({ text: event.detail.message });
124108
});
125-
const toggleTodo = handler(toggleTodoSchema, inputSchema, (event: ToggleTodoEvent, state: TodoInput) => {
126-
const todos = state.todos.get();
127-
const todo = todos.find((t: any) => t.id === event.id);
128-
if (todo) {
129-
todo.completed = !todo.completed;
130-
state.todos.set(todos);
131-
}
132-
});
133-
export default recipe(inputSchema, outputSchema, ({ todos }) => {
134-
const completedCount = derive(todos, (todos: TodoItem[]) => todos.filter((t: TodoItem) => t.completed).length);
135-
const pendingCount = derive(todos, (todos: TodoItem[]) => todos.filter((t: TodoItem) => !t.completed).length);
109+
export default recipe(inputSchema, outputSchema, ({ title, items }) => {
110+
const items_count = items.length;
136111
return {
137-
[NAME]: str `Todo List (${pendingCount} pending)`,
112+
[NAME]: title,
138113
[UI]: (<div>
139-
<form onSubmit={(e: any) => {
140-
e.preventDefault();
141-
const input = e.target.text;
142-
if (input.value) {
143-
addTodo({ text: input.value });
144-
input.value = '';
145-
}
146-
}}>
147-
<input name="text" placeholder="Add todo..."/>
148-
<button type="submit">Add</button>
149-
</form>
150-
114+
<h3>{title}</h3>
115+
<p>Basic recipe</p>
116+
<p>Items count: {items_count}</p>
151117
<ul>
152-
{todos.map((todo: TodoItem) => (<li key={todo.id}>
153-
<label>
154-
<input type="checkbox" checked={todo.completed} onChange={() => toggleTodo({ id: todo.id })}/>
155-
<span style={{
156-
textDecoration: todo.completed ? 'line-through' : 'none'
157-
}}>
158-
{todo.text}
159-
</span>
160-
</label>
161-
</li>))}
118+
{items.map((item: Item, index: number) => (<li key={index}>{item.text}</li>))}
162119
</ul>
163-
164-
<div>
165-
Completed: {completedCount} | Pending: {pendingCount}
166-
</div>
120+
<common-send-message name="Send" placeholder="Type a message..." appearance="rounded" onmessagesend={addItem({ items })}/>
167121
</div>),
168-
todos,
169-
completedCount,
170-
pendingCount
122+
title,
123+
items,
124+
items_count
171125
};
172126
});
173127

0 commit comments

Comments
 (0)