Skip to content

Commit 0968f48

Browse files
committed
wip
1 parent 641233f commit 0968f48

File tree

7 files changed

+70
-98
lines changed

7 files changed

+70
-98
lines changed

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"gen": "bun run gen:schemas && bun run gen:client && bun run format",
1111
"test": "bun test",
1212
"typecheck": "tsc --noEmit",
13-
"format": "biome format --write",
13+
"format": "biome check --write --linter-enabled=false",
1414
"build": "bunx --bun tsdown",
1515
"prepublishOnly": "bun run build"
1616
},
@@ -32,8 +32,6 @@
3232
"@typescript/native-preview": "^7.0.0-dev.20260124.1",
3333
"tsdown": "^0.20.1"
3434
},
35-
"main": "./dist/index.mjs",
36-
"module": "./dist/index.mjs",
3735
"types": "./dist/index.d.mts",
3836
"exports": {
3937
".": "./dist/index.mjs",

scripts/gen-client.ts

Lines changed: 53 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import * as z from "zod";
22

33
import {
4-
SchemaSchemaRef,
5-
SchemaSchema,
6-
convertToZod,
7-
Primitive,
8-
SchemaSchemaPrimitive,
9-
SchemaSchemaBoolean,
104
assertNever,
5+
convertToZod,
6+
OperationParameterBase,
117
type Schema,
8+
SchemaSchema,
9+
SchemaSchemaBoolean,
10+
SchemaSchemaPrimitive,
11+
SchemaSchemaRef,
1212
} from "./shared";
1313

1414
const Semver = z.string().brand("Semver");
@@ -21,9 +21,7 @@ const OpenApiSchemaInfo = z.object({
2121
url: z.url(),
2222
email: z.email(),
2323
}),
24-
"x-logo": z.object({
25-
url: z.url(),
26-
}),
24+
"x-logo": z.object({ url: z.url() }),
2725
license: z.object({
2826
name: z.string(),
2927
url: z.url(),
@@ -90,13 +88,11 @@ const OAuth2Schema = z.tuple([z.object({ OAuth2: z.array(OAuth2Scope) })]);
9088
const SecuritySchema = z.union([z.array(AccessTokenScopeSchema), OAuth2Schema]);
9189

9290
const StringJsonRef = z
93-
.string()
94-
.refine((str) => str.endsWith(".json"))
91+
.templateLiteral([z.string(), ".json"])
9592
.brand("StringJsonRef");
9693

9794
const SchemaSchemaExampleRef = z
98-
.object({ $ref: StringJsonRef })
99-
.strict()
95+
.strictObject({ $ref: StringJsonRef })
10096
.transform((s) => ({ ...s, __schema: "$ref" as const }));
10197

10298
const ResponseContentBaseContent = z.object({
@@ -124,37 +120,34 @@ const ResponseContentChessPgnContent = ResponseContentBaseContent.extend({})
124120
const ResponseContentJson = z
125121
.union([
126122
z
127-
.object({ "application/json": ResponseContentJsonContent })
128-
.strict()
123+
.strictObject({ "application/json": ResponseContentJsonContent })
129124
.transform((x) => x["application/json"]),
130125
z
131-
.object({ "application/vnd.lichess.v3+json": ResponseContentJsonContent })
132-
.strict()
126+
.strictObject({
127+
"application/vnd.lichess.v3+json": ResponseContentJsonContent,
128+
})
133129
.transform((x) => x["application/vnd.lichess.v3+json"]),
134130
])
135131
.transform((x) => ({ ...x, __content_type: "json" as const }));
136132

137133
const ResponseContentNdjson = z
138-
.object({ "application/x-ndjson": ResponseContentNdjsonContent })
139-
.strict()
134+
.strictObject({ "application/x-ndjson": ResponseContentNdjsonContent })
140135
.transform((x) => x["application/x-ndjson"])
141136
.transform((x) => ({ ...x, __content_type: "ndjson" as const }));
142137

143138
const ResponseContentChessPgn = z
144-
.object({ "application/x-chess-pgn": ResponseContentChessPgnContent })
145-
.strict()
139+
.strictObject({ "application/x-chess-pgn": ResponseContentChessPgnContent })
146140
.transform((x) => x["application/x-chess-pgn"])
147141
.transform((x) => ({ ...x, __content_type: "chess-pgn" as const }));
148142

149143
const ResponseContentMixed = z
150-
.object({
144+
.strictObject({
151145
"text/plain": ResponseContextPlainTextContent.optional(),
152146
"application/json": ResponseContentJsonContent.optional(),
153147
"application/vnd.lichess.v3+json": ResponseContentJsonContent.optional(),
154148
"application/x-chess-pgn": ResponseContentChessPgnContent.optional(),
155149
"application/x-ndjson": ResponseContentNdjsonContent.optional(),
156150
})
157-
.strict()
158151
.transform((x) => ({ ...x, __content_type: "mixed" as const }));
159152

160153
const ResponseContentNoContent = z
@@ -170,50 +163,34 @@ const ResponseContent = z.union([
170163
]);
171164
type ResponseCaseContent = z.infer<typeof ResponseContent>;
172165

173-
const ResponseSchemaHeaders = z
174-
.object({
175-
"Access-Control-Allow-Origin": z
176-
.object({
177-
schema: z.object({
178-
type: z.literal("string"),
179-
default: z.literal("'*'"),
180-
}),
181-
})
182-
.strict(),
183-
"Last-Modified": z
184-
.object({
185-
schema: z.object({
186-
type: z.literal("string"),
187-
example: z.string(),
188-
}),
189-
})
190-
.strict()
191-
.optional(),
192-
})
193-
.strict();
166+
const ResponseSchemaHeaders = z.strictObject({
167+
"Access-Control-Allow-Origin": z.strictObject({
168+
schema: z.object({
169+
type: z.literal("string"),
170+
default: z.literal("'*'"),
171+
}),
172+
}),
173+
"Last-Modified": z
174+
.strictObject({
175+
schema: z.object({
176+
type: z.literal("string"),
177+
example: z.string(),
178+
}),
179+
})
180+
.optional(),
181+
});
194182

195-
const ResponseSchema = z
196-
.object({
197-
description: z.string(),
198-
headers: ResponseSchemaHeaders.optional(),
199-
content: ResponseContent,
200-
})
201-
.strict();
183+
const ResponseSchema = z.strictObject({
184+
description: z.string(),
185+
headers: ResponseSchemaHeaders.optional(),
186+
content: ResponseContent,
187+
});
202188
type ResponseCase = z.infer<typeof ResponseSchema>;
203189

204-
const OperationParameterBase = z
205-
.object({
206-
name: z.string(),
207-
description: z.string().optional(),
208-
example: Primitive.optional(),
209-
})
210-
.strict();
211-
212190
const SchemaSchemaNullableRefToPrimitive = z
213-
.object({
191+
.strictObject({
214192
allOf: z.tuple([SchemaSchemaRef, z.object({ default: z.null() })]),
215193
})
216-
.strict()
217194
.transform((s) => ({
218195
...s,
219196
__schema: "notverified:reftoprimitive:nullable" as const,
@@ -225,25 +202,22 @@ const SchemaSchemaRefToPrimitive = SchemaSchemaRef.brand(
225202
).transform((s) => ({ ...s, __schema: "notverified:reftoprimitive" as const }));
226203

227204
const SchemaSchemaBooleanLike = z
228-
.object({
205+
.strictObject({
229206
anyOf: z.tuple([
230207
SchemaSchemaBoolean,
231208
z.object({ type: z.literal("string"), const: z.literal("yes") }),
232209
]),
233210
example: z.literal("yes"),
234211
})
235-
.strict()
236212
.transform((s) => ({ ...s, __schema: "boolean-like" as const }))
237213
.brand("SchemaSchemaBooleanLike");
238214

239215
const SchemaSchemaArrayOfPrimitive = z
240-
.object({ type: z.literal("array"), items: SchemaSchemaPrimitive })
241-
.strict()
216+
.strictObject({ type: z.literal("array"), items: SchemaSchemaPrimitive })
242217
.transform((s) => ({ ...s, __schema: "array:primitive" as const }));
243218

244219
const SchemaSchemaArrayOfRefToPrimitive = z
245-
.object({ type: z.literal("array"), items: SchemaSchemaRefToPrimitive })
246-
.strict()
220+
.strictObject({ type: z.literal("array"), items: SchemaSchemaRefToPrimitive })
247221
.transform((s) => ({
248222
...s,
249223
__schema: "array:notverified:reftoprimitive" as const,
@@ -315,20 +289,17 @@ const BaseTagSchemaOperation = z.object({
315289
});
316290

317291
const RequestBodyContentJson = z
318-
.object({ "application/json": z.object({ schema: SchemaSchema }) })
319-
.strict()
292+
.strictObject({ "application/json": z.object({ schema: SchemaSchema }) })
320293
.transform((s) => ({ ...s, __type: "json" as const }));
321294

322295
const RequestBodyContentPlainText = z
323-
.object({ "text/plain": z.object({ schema: SchemaSchema }) })
324-
.strict()
296+
.strictObject({ "text/plain": z.object({ schema: SchemaSchema }) })
325297
.transform((s) => ({ ...s, __type: "text/plain" as const }));
326298

327299
const RequestBodyContentWebFormUrlEncoded = z
328-
.object({
300+
.strictObject({
329301
"application/x-www-form-urlencoded": z.object({ schema: SchemaSchema }),
330302
})
331-
.strict()
332303
.transform((s) => ({ ...s, __type: "x-www-form-urlencoded" as const }));
333304

334305
const RequestBodyContent = z.union([
@@ -337,13 +308,11 @@ const RequestBodyContent = z.union([
337308
RequestBodyContentWebFormUrlEncoded,
338309
]);
339310

340-
const RequestBodySchema = z
341-
.object({
342-
description: z.string().optional(),
343-
required: z.boolean().optional(),
344-
content: RequestBodyContent,
345-
})
346-
.strict();
311+
const RequestBodySchema = z.strictObject({
312+
description: z.string().optional(),
313+
required: z.boolean().optional(),
314+
content: RequestBodyContent,
315+
});
347316

348317
const TagSchemaSchemaGet = BaseTagSchemaOperation.extend({})
349318
.strict()
@@ -821,7 +790,6 @@ function processTag(tagSchema: TagSchema, rawApiPath: string) {
821790
sharedPathParams,
822791
baseUrl,
823792
});
824-
console.log(processedOperation);
825793
if (processedOperation.__type === "__parameters") {
826794
sharedPathParams = processedOperation.parameters;
827795
}
@@ -843,7 +811,6 @@ async function processSchema(schema: OpenApiSchema): Promise<void> {
843811
const fullYamlPath = `${tagsDir}/${tagPath}` as const;
844812
const yamlStr = await Bun.file(fullYamlPath).text();
845813
const schema = Bun.YAML.parse(yamlStr);
846-
console.log({ fullYamlPath, schema });
847814
const tagSchema = TagSchemaSchema.parse(schema);
848815
const newMethods = processTag(tagSchema, rawApiPath);
849816
methodsCode.push(...newMethods);
@@ -855,10 +822,10 @@ async function processSchema(schema: OpenApiSchema): Promise<void> {
855822

856823
const clientCodeTs = `import * as z from "zod";
857824
858-
import * as schemas from "~/schemas";
859-
860825
import { ndjsonStream } from "~/lib/ndjson";
861826
827+
import * as schemas from "~/schemas";
828+
862829
import { Requestor } from "./requestor";
863830
864831
export const BASE_URL = "${API_URL}";
@@ -883,11 +850,13 @@ export class Lichess {
883850
}
884851

885852
async function main() {
853+
console.log("Generating client...");
886854
const filePath = "specs/lichess-api.yaml" as const;
887855
const yamlStr = await Bun.file(filePath).text();
888856
const yamlContent = Bun.YAML.parse(yamlStr);
889857
const parsedSchema = OpenApiSchemaSchema.parse(yamlContent);
890858
await processSchema(parsedSchema);
859+
console.log("Client generated");
891860
}
892861

893862
await main();

scripts/gen-schemas.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import { convertToZod, SchemaSchema } from "./shared";
2-
31
import { readdirSync } from "node:fs";
4-
import path from "node:path";
52
import * as fs from "node:fs/promises";
3+
import * as path from "node:path";
64
import { prettifyError } from "zod/mini";
5+
import { convertToZod, SchemaSchema } from "./shared";
76

87
async function processFile(filePath: string) {
98
const normalizedFilePath = filePath.replaceAll("\\", "/");
@@ -18,8 +17,8 @@ async function processFile(filePath: string) {
1817
}
1918
const { zodSchema, refs: uniqueRefs } = convertToZod(parsedSchema.data);
2019

21-
uniqueRefs.sort();
2220
const refImports = uniqueRefs
21+
.toSorted()
2322
.map((refName) => `import { ${refName} } from "./${refName}";` as const)
2423
.join("\n");
2524
const spacedRefImports = refImports
@@ -48,8 +47,8 @@ async function main() {
4847
const schemasDir = "specs/schemas" as const;
4948
const glob = new Bun.Glob(`${schemasDir}/*.{yaml}` as const);
5049
const yamlFiles = await Array.fromAsync(glob.scan());
51-
const filesToProcess = yamlFiles.filter((f) => !f.includes("_index.yaml"));
52-
for (const fullPath of filesToProcess) {
50+
for (const fullPath of yamlFiles) {
51+
if (fullPath.includes("_index.yaml")) continue;
5352
await processFile(fullPath);
5453
}
5554
const tsFiles = readdirSync(outDir)

scripts/shared.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ const SchemaSchemaAnyOf = BaseSchema.extend({
161161
.strict()
162162
.transform((s) => ({ ...s, __schema: "anyOf" as const }));
163163

164+
export const OperationParameterBase = z.strictObject({
165+
name: z.string(),
166+
description: z.string().optional(),
167+
example: Primitive.optional(),
168+
});
169+
164170
const SchemaSchema = z.union([
165171
SchemaSchemaRef,
166172
SchemaSchemaNull,

src/client/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import * as z from "zod";
22

3-
import * as schemas from "~/schemas";
4-
53
import { ndjsonStream } from "~/lib/ndjson";
64

5+
import * as schemas from "~/schemas";
6+
77
import { Requestor } from "./requestor";
88

99
export const BASE_URL = "https://lichess.org";

src/schemas/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ export { OpponentGoneEvent } from "./OpponentGoneEvent";
103103
export { Patron } from "./Patron";
104104
export { PatronColor } from "./PatronColor";
105105
export { Perf } from "./Perf";
106-
export { Perfs } from "./Perfs";
107106
export { PerfStat } from "./PerfStat";
107+
export { Perfs } from "./Perfs";
108108
export { PerfTop10 } from "./PerfTop10";
109109
export { PerfType } from "./PerfType";
110110
export { PlayTime } from "./PlayTime";
@@ -118,8 +118,8 @@ export { PuzzleDashboard } from "./PuzzleDashboard";
118118
export { PuzzleGlicko } from "./PuzzleGlicko";
119119
export { PuzzleModePerf } from "./PuzzleModePerf";
120120
export { PuzzlePerformance } from "./PuzzlePerformance";
121-
export { PuzzleRacer } from "./PuzzleRacer";
122121
export { PuzzleRaceResults } from "./PuzzleRaceResults";
122+
export { PuzzleRacer } from "./PuzzleRacer";
123123
export { PuzzleReplay } from "./PuzzleReplay";
124124
export { PuzzleStormDashboard } from "./PuzzleStormDashboard";
125125
export { RatingHistory } from "./RatingHistory";

tests/index.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, it, expect } from "bun:test";
1+
import { describe, expect, it } from "bun:test";
22

33
import { Lichess } from "@lichess/api";
44

0 commit comments

Comments
 (0)