import { assertEquals, assertExists } from "jsr:@std/assert"; import { normalizeLexicons, nsidToPascalCase, nsidToNamespace, defNameToPascalCase, capitalizeFirst, sanitizeIdentifier, isPropertyRequired, isFieldSortable, createProject, generateUsageExample, generateHeaderComment, type Lexicon, type LexiconRecord, } from "../src/mod.ts"; Deno.test("normalizeLexicons - handles both id and nsid properties", () => { const input = [ { id: "app.bsky.actor.profile", definitions: {} }, { nsid: "com.example.post", defs: {} }, { id: "network.slices.slice", definitions: {} }, ]; const result = normalizeLexicons(input); assertEquals(result[0].id, "app.bsky.actor.profile"); assertEquals(result[1].id, "com.example.post"); assertEquals(result[1].definitions, {}); assertEquals(result[2].id, "network.slices.slice"); }); Deno.test("nsidToPascalCase - converts NSID to PascalCase", () => { assertEquals(nsidToPascalCase("app.bsky.actor.profile"), "AppBskyActorProfile"); assertEquals(nsidToPascalCase("com.example.my-post"), "ComExampleMyPost"); assertEquals(nsidToPascalCase("network.slices.slice"), "NetworkSlicesSlice"); }); Deno.test("nsidToNamespace - converts NSID to namespace format", () => { assertEquals(nsidToNamespace("app.bsky.embed.defs"), "AppBskyEmbedDefs"); assertEquals(nsidToNamespace("com.example.test-case"), "ComExampleTestCase"); }); Deno.test("defNameToPascalCase - converts definition names", () => { assertEquals(defNameToPascalCase("aspectRatio"), "AspectRatio"); assertEquals(defNameToPascalCase("my-property"), "MyProperty"); assertEquals(defNameToPascalCase("test_case"), "TestCase"); }); Deno.test("capitalizeFirst - capitalizes first letter", () => { assertEquals(capitalizeFirst("hello"), "Hello"); assertEquals(capitalizeFirst("world"), "World"); assertEquals(capitalizeFirst(""), ""); }); Deno.test("sanitizeIdentifier - converts hyphens to camelCase", () => { assertEquals(sanitizeIdentifier("cyber-meteor-1637"), "cyberMeteor1637"); assertEquals(sanitizeIdentifier("test-name"), "testName"); assertEquals(sanitizeIdentifier("already-camel-case"), "alreadyCamelCase"); assertEquals(sanitizeIdentifier("single"), "single"); assertEquals(sanitizeIdentifier("with_underscore"), "withUnderscore"); assertEquals(sanitizeIdentifier("mixed-name_test"), "mixedNameTest"); }); Deno.test("isPropertyRequired - checks if property is required", () => { const record: LexiconRecord = { type: "record", required: ["name", "email"], properties: { name: { type: "string" }, email: { type: "string" }, age: { type: "integer" }, }, }; assertEquals(isPropertyRequired(record, "name"), true); assertEquals(isPropertyRequired(record, "email"), true); assertEquals(isPropertyRequired(record, "age"), false); }); Deno.test("isFieldSortable - identifies sortable field types", () => { assertEquals(isFieldSortable({ type: "string" }), true); assertEquals(isFieldSortable({ type: "integer" }), true); assertEquals(isFieldSortable({ type: "number" }), true); assertEquals(isFieldSortable({ type: "datetime" }), true); assertEquals(isFieldSortable({ type: "string", format: "datetime" }), true); assertEquals(isFieldSortable({ type: "string", format: "at-identifier" }), true); assertEquals(isFieldSortable({ type: "string", format: "at-uri" }), true); assertEquals(isFieldSortable({ type: "array" }), false); assertEquals(isFieldSortable({ type: "object" }), false); assertEquals(isFieldSortable({ type: "blob" }), false); }); Deno.test("createProject - creates ts-morph project", () => { const project = createProject(); assertExists(project); assertEquals(typeof project.createSourceFile, "function"); }); Deno.test("generateUsageExample - creates usage documentation", () => { const lexicons: Lexicon[] = [ { id: "com.example.post", definitions: { main: { type: "record", record: { type: "record", properties: { text: { type: "string" }, }, }, }, }, }, ]; const result = generateUsageExample(lexicons, "at://test/slice"); assertEquals(typeof result, "string"); assertEquals(result.includes("com.example.post"), true); assertEquals(result.includes("at://test/slice"), true); assertEquals(result.includes("client.com.example.post.getRecords()"), true); }); Deno.test("generateUsageExample - handles network.slices lexicons", () => { const lexicons: Lexicon[] = [ { id: "network.slices.slice", definitions: { main: { type: "record", record: { type: "record", properties: { name: { type: "string" }, }, }, }, }, }, ]; const result = generateUsageExample(lexicons, "at://test/slice"); assertEquals(typeof result, "string"); // Should fallback to using network.slices lexicons when no other record types exist assertEquals(result.includes("network.slices.slice"), true); }); Deno.test("generateHeaderComment - creates header with imports", () => { const lexicons: Lexicon[] = [ { id: "test.lexicon", definitions: {} }, ]; const usageExample = "/** Example usage */"; const result = generateHeaderComment(lexicons, usageExample); assertEquals(typeof result, "string"); assertEquals(result.includes("Generated TypeScript client"), true); assertEquals(result.includes("Lexicons: 1"), true); assertEquals(result.includes(usageExample), true); assertEquals(result.includes("@slices/client"), true); assertEquals(result.includes("@slices/oauth"), true); }); Deno.test("generateHeaderComment - generates consistent imports", () => { const lexicons: Lexicon[] = []; const usageExample = "/** Example */"; const result = generateHeaderComment(lexicons, usageExample); assertEquals(result.includes("SlicesClient"), true); assertEquals(result.includes("@slices/client"), true); assertEquals(result.includes("@slices/oauth"), true); });