forked from
slices.network/slices
Highly ambitious ATProtocol AppView service and sdks
1import { assertEquals, assertStringIncludes } from "jsr:@std/assert";
2import { generateTypeScript } from "../src/mod.ts";
3import type { Lexicon } from "../src/mod.ts";
4
5Deno.test("generateTypeScript - full integration test", async () => {
6 const lexicons: Lexicon[] = [
7 {
8 id: "com.example.post",
9 definitions: {
10 main: {
11 type: "record",
12 record: {
13 type: "record",
14 properties: {
15 text: { type: "string" },
16 createdAt: { type: "string" },
17 likes: { type: "integer" },
18 tags: {
19 type: "array",
20 items: { type: "string" },
21 },
22 },
23 required: ["text", "createdAt"],
24 },
25 },
26 },
27 },
28 {
29 id: "com.example.user",
30 definitions: {
31 main: {
32 type: "record",
33 record: {
34 type: "record",
35 properties: {
36 handle: { type: "string" },
37 displayName: { type: "string" },
38 },
39 required: ["handle"],
40 },
41 },
42 },
43 },
44 {
45 id: "network.slices.slice",
46 definitions: {
47 main: {
48 type: "record",
49 record: {
50 type: "record",
51 properties: {
52 name: { type: "string" },
53 },
54 required: ["name"],
55 },
56 },
57 },
58 },
59 ];
60
61 const result = await generateTypeScript(lexicons, {
62 sliceUri: "at://did:example/com.example.slice/abc123",
63 });
64
65 // Should include header comment with usage example
66 assertStringIncludes(result, "Generated TypeScript client for AT Protocol records");
67 assertStringIncludes(result, "Lexicons: 3");
68 assertStringIncludes(result, "at://did:example/com.example.slice/abc123");
69
70 // Should include imports
71 assertStringIncludes(result, 'SlicesClient');
72 assertStringIncludes(result, 'OAuthClient');
73
74 // Should include record interfaces
75 assertStringIncludes(result, "export interface ComExamplePost");
76 assertStringIncludes(result, "export interface ComExampleUser");
77 assertStringIncludes(result, "text: string;");
78 assertStringIncludes(result, "handle: string;");
79 assertStringIncludes(result, "displayName?: string;");
80
81 // Should include sort fields types
82 assertStringIncludes(result, "export type ComExamplePostSortFields");
83 assertStringIncludes(result, "export type ComExampleUserSortFields");
84
85 // Should include client class
86 assertStringIncludes(result, "export class AtProtoClient extends SlicesClient");
87 assertStringIncludes(result, "readonly com: ComClient;");
88
89 // Should include CRUD methods
90 assertStringIncludes(result, "async getRecords(");
91 assertStringIncludes(result, "async createRecord(");
92
93 // Should include standard client methods for all lexicons
94
95 // Code should be formatted (no obvious formatting issues)
96 assertEquals(result.includes(" ;"), false); // Double spaces before semicolons
97 assertEquals(result.includes("\t\t\t"), false); // Triple tabs
98});
99
100Deno.test("generateTypeScript - generates client for standard lexicons", async () => {
101 const lexicons: Lexicon[] = [
102 {
103 id: "app.bsky.feed.post",
104 definitions: {
105 main: {
106 type: "record",
107 record: {
108 type: "record",
109 properties: {
110 text: { type: "string" },
111 },
112 },
113 },
114 },
115 },
116 ];
117
118 const result = await generateTypeScript(lexicons, {
119 sliceUri: "at://test/slice",
120 });
121
122 // Should include basic functionality
123 assertStringIncludes(result, "export interface AppBskyFeedPost");
124 assertStringIncludes(result, "export class AtProtoClient");
125 assertStringIncludes(result, "async getRecords(");
126 assertStringIncludes(result, "text?: string;");
127
128 // Should include imports
129 assertStringIncludes(result, 'SlicesClient');
130 assertStringIncludes(result, 'OAuthClient');
131});
132
133Deno.test("generateTypeScript - handles empty lexicons", async () => {
134 const result = await generateTypeScript([], {
135 sliceUri: "at://test/slice",
136 });
137
138 // Should include basic structure even with no lexicons
139 assertStringIncludes(result, "Generated TypeScript client");
140 assertStringIncludes(result, "Lexicons: 0");
141 assertStringIncludes(result, 'SlicesClient');
142
143 // Should include imports even with no lexicons
144 assertStringIncludes(result, "@slices/client");
145
146 // Should not create any client class (no records to work with)
147 assertEquals(result.includes("export class AtProtoClient"), false);
148});
149
150Deno.test("generateTypeScript - creates correct usage example", async () => {
151 const lexicons: Lexicon[] = [
152 {
153 id: "social.app.post",
154 definitions: {
155 main: {
156 type: "record",
157 record: {
158 type: "record",
159 properties: {
160 message: { type: "string" },
161 },
162 },
163 },
164 },
165 },
166 ];
167
168 const result = await generateTypeScript(lexicons, {
169 sliceUri: "at://did:example/slice/123",
170 });
171
172 // Should create usage example with the first non-network.slices lexicon
173 assertStringIncludes(result, "client.social.app.post.getRecords()");
174 assertStringIncludes(result, "at://did:example/slice/123");
175 assertStringIncludes(result, "social.app.post");
176 assertStringIncludes(result, "getRecords()");
177});