返回 DeepSeek-Reasonix
typescript_test.go
根目录 / desktop / internal / hostrpc / typescript_test.go
1 package hostrpc
2
3 import (
4 "fmt"
5 "strings"
6 "testing"
7 )
8
9 type tsOther struct {
10 Name string `json:"name"`
11 }
12
13 type tsRecord struct {
14 Label string `json:"label"`
15 Weird string `json:"content-type"`
16 Next *tsRecord `json:"next"`
17 Tags []string `json:"tags,omitempty"`
18 Owners []*tsOther `json:"owners"`
19 Extra map[string]any `json:"extra"`
20 Payload any `json:"payload"`
21 Nested struct{ On bool } `json:"nested"`
22 }
23
24 type tsTarget struct{}
25
26 func (*tsTarget) Version() string { return "" }
27 func (*tsTarget) Reset() {}
28 func (*tsTarget) Save(r tsRecord, force bool) (tsRecord, error) { return r, nil }
29 func (*tsTarget) List() ([]tsRecord, error) { return nil, nil }
30 func (*tsTarget) Others() map[string][]tsOther { return nil }
31
32 func TestWriteTypeScriptEmitsContractDeclarations(t *testing.T) {
33 c := Build(mustRegistry(t, &tsTarget{}, nil), []string{"agent:event", "runtime:rebuilt"})
34 var b strings.Builder
35 if err := WriteTypeScript(&b, c); err != nil {
36 t.Fatal(err)
37 }
38 out := b.String()
39 if !strings.HasPrefix(out, "// Code generated by go run . -emit-contract; DO NOT EDIT.\n") {
40 t.Fatalf("header = %.80q", out)
41 }
42 for _, want := range []string{
43 fmt.Sprintf("export const DESKTOP_PROTOCOL_VERSION = %d;", ProtocolVersion),
44 `export const DESKTOP_CONTRACT_DIGEST = "` + c.Digest() + `";`,
45 "export const DESKTOP_COMMANDS = [\n \"List\",\n \"Others\",\n \"Reset\",\n \"Save\",\n \"Version\",\n] as const;",
46 "export const DESKTOP_EVENTS = [\n \"agent:event\",\n \"runtime:rebuilt\",\n] as const;",
47 "export type DesktopCommandName = (typeof DESKTOP_COMMANDS)[number];",
48 "export interface tsOther {\n name: string;\n}",
49 "export interface tsRecord {\n",
50 " label: string;\n",
51 " \"content-type\": string;\n",
52 " next?: tsRecord | null;\n",
53 " tags?: string[];\n",
54 " owners: (tsOther | null)[];\n",
55 " extra: Record<string, unknown>;\n",
56 " payload: unknown;\n",
57 " nested: tsRecord_Nested;\n",
58 "export interface tsRecord_Nested {\n On: boolean;\n}",
59 "export interface GeneratedDesktopCommands {\n",
60 " List(): Promise<tsRecord[]>;\n",
61 " Others(): Promise<Record<string, tsOther[]>>;\n",
62 " Reset(): Promise<void>;\n",
63 " Save(arg0: tsRecord, arg1: boolean): Promise<tsRecord>;\n",
64 " Version(): Promise<string>;\n",
65 } {
66 if !strings.Contains(out, want) {
67 t.Errorf("output lacks %q\n%s", want, out)
68 }
69 }
70 }
71
72 func TestTypeScriptNamesDisambiguateCollisions(t *testing.T) {
73 names := tsTypeNames(map[string]ObjectType{
74 "main.Item": {},
75 "taskmonitor.Item": {},
76 "main.Solo": {},
77 "main.Box[int]": {},
78 })
79 want := map[string]string{
80 "main.Item": "main_Item",
81 "taskmonitor.Item": "taskmonitor_Item",
82 "main.Solo": "Solo",
83 "main.Box[int]": "Box_int_",
84 }
85 for key, name := range want {
86 if names[key] != name {
87 t.Errorf("%s -> %q, want %q", key, names[key], name)
88 }
89 }
90 }
91
92 func TestTypeScriptNamesDoNotShadowGeneratedHelpers(t *testing.T) {
93 names := tsTypeNames(map[string]ObjectType{
94 "transcript.Record": {}, "main.Promise": {}, "main.GeneratedDesktopCommands": {},
95 })
96 for key, want := range map[string]string{
97 "transcript.Record": "transcript_Record", "main.Promise": "main_Promise",
98 "main.GeneratedDesktopCommands": "main_GeneratedDesktopCommands",
99 } {
100 if names[key] != want {
101 t.Errorf("%s = %s, want %s", key, names[key], want)
102 }
103 }
104 }
105
105 lines GO