prototypey.org - atproto lexicon typescript toolkit - mirror https://github.com/tylersayshi/prototypey

rename namespace => lexicon

Tyler 55d5e4b1 b8ada449

+125 -125
+1 -1
README.md
··· 29 29 **what you'd write:** 30 30 31 31 ```typescript 32 - const profileNamespace = lx.namespace("app.bsky.actor.profile", { 32 + const profileNamespace = lx.lexicon("app.bsky.actor.profile", { 33 33 main: lx.record({ 34 34 key: "self", 35 35 record: lx.object({
+2 -2
packages/cli/README.md
··· 67 67 68 68 **What it does:** 69 69 70 - - Scans TypeScript files for exported lexicon namespace definitions 71 - - Extracts the `.json` property from each namespace 70 + - Scans TypeScript files for exported lexicon definitions 71 + - Extracts the `.json` property from each lexicon 72 72 - Emits properly formatted JSON lexicon schema files 73 73 - Names output files by lexicon ID (e.g., `app.bsky.feed.post.json`) 74 74
+10 -10
packages/cli/src/commands/gen-emit.ts
··· 57 57 // Dynamically import the module 58 58 const module = await import(fileUrl); 59 59 60 - // Find all exported namespaces 61 - const namespaces: LexiconNamespace[] = []; 60 + // Find all exported lexicons 61 + const lexicons: LexiconNamespace[] = []; 62 62 for (const key of Object.keys(module)) { 63 63 const exported = module[key]; 64 - // Check if it's a namespace with a json property 64 + // Check if it's a lexicon with a json property 65 65 if ( 66 66 exported && 67 67 typeof exported === "object" && ··· 72 72 "id" in exported.json && 73 73 "defs" in exported.json 74 74 ) { 75 - namespaces.push(exported as LexiconNamespace); 75 + lexicons.push(exported as LexiconNamespace); 76 76 } 77 77 } 78 78 79 - if (namespaces.length === 0) { 80 - console.warn(` ⚠ ${sourcePath}: No lexicon namespaces found`); 79 + if (lexicons.length === 0) { 80 + console.warn(` ⚠ ${sourcePath}: No lexicon lexicons found`); 81 81 return; 82 82 } 83 83 84 - // Emit JSON for each namespace 85 - for (const namespace of namespaces) { 86 - const { id } = namespace.json; 84 + // Emit JSON for each lexicon 85 + for (const lexicon of lexicons) { 86 + const { id } = lexicon.json; 87 87 const outputPath = join(outdir, `${id}.json`); 88 88 89 89 // Write the JSON file 90 90 await writeFile( 91 91 outputPath, 92 - JSON.stringify(namespace.json, null, "\t"), 92 + JSON.stringify(lexicon.json, null, "\t"), 93 93 "utf-8", 94 94 ); 95 95
+10 -10
packages/cli/tests/commands/gen-emit.test.ts
··· 29 29 ` 30 30 import { lx } from "prototypey"; 31 31 32 - export const profileNamespace = lx.namespace("app.bsky.actor.profile", { 32 + export const profileNamespace = lx.lexicon("app.bsky.actor.profile", { 33 33 main: lx.record({ 34 34 key: "self", 35 35 record: lx.object({ ··· 85 85 ` 86 86 import { lx } from "prototypey"; 87 87 88 - export const profile = lx.namespace("app.bsky.actor.profile", { 88 + export const profile = lx.lexicon("app.bsky.actor.profile", { 89 89 main: lx.record({ 90 90 key: "self", 91 91 record: lx.object({ ··· 94 94 }), 95 95 }); 96 96 97 - export const post = lx.namespace("app.bsky.feed.post", { 97 + export const post = lx.lexicon("app.bsky.feed.post", { 98 98 main: lx.record({ 99 99 key: "tid", 100 100 record: lx.object({ ··· 129 129 join(lexicons, "profile.ts"), 130 130 ` 131 131 import { lx } from "prototypey"; 132 - export const schema = lx.namespace("app.bsky.actor.profile", { 132 + export const schema = lx.lexicon("app.bsky.actor.profile", { 133 133 main: lx.record({ key: "self", record: lx.object({}) }), 134 134 }); 135 135 `, ··· 139 139 join(lexicons, "post.ts"), 140 140 ` 141 141 import { lx } from "prototypey"; 142 - export const schema = lx.namespace("app.bsky.feed.post", { 142 + export const schema = lx.lexicon("app.bsky.feed.post", { 143 143 main: lx.record({ key: "tid", record: lx.object({}) }), 144 144 }); 145 145 `, ··· 169 169 ` 170 170 import { lx } from "prototypey"; 171 171 172 - export const searchPosts = lx.namespace("app.bsky.feed.searchPosts", { 172 + export const searchPosts = lx.lexicon("app.bsky.feed.searchPosts", { 173 173 main: lx.query({ 174 174 description: "Find posts matching search criteria", 175 175 parameters: lx.params({ ··· 238 238 ` 239 239 import { lx } from "prototypey"; 240 240 241 - export const createPost = lx.namespace("com.atproto.repo.createRecord", { 241 + export const createPost = lx.lexicon("com.atproto.repo.createRecord", { 242 242 main: lx.procedure({ 243 243 description: "Create a record", 244 244 input: { ··· 309 309 ` 310 310 import { lx } from "prototypey"; 311 311 312 - export const subscribeRepos = lx.namespace("com.atproto.sync.subscribeRepos", { 312 + export const subscribeRepos = lx.lexicon("com.atproto.sync.subscribeRepos", { 313 313 main: lx.subscription({ 314 314 description: "Repository event stream", 315 315 parameters: lx.params({ ··· 396 396 ` 397 397 import { lx } from "prototypey"; 398 398 399 - export const feedDefs = lx.namespace("app.bsky.feed.defs", { 399 + export const feedDefs = lx.lexicon("app.bsky.feed.defs", { 400 400 postView: lx.object({ 401 401 uri: lx.string({ required: true, format: "at-uri" }), 402 402 cid: lx.string({ required: true, format: "cid" }), ··· 460 460 ` 461 461 import { lx } from "prototypey"; 462 462 463 - export const imagePost = lx.namespace("app.example.imagePost", { 463 + export const imagePost = lx.lexicon("app.example.imagePost", { 464 464 main: lx.record({ 465 465 key: "tid", 466 466 record: lx.object({
+1 -1
packages/cli/tests/fixtures/simple-lexicon.ts
··· 1 1 import { lx } from "prototypey"; 2 2 3 - export const profileNamespace = lx.namespace("app.bsky.actor.profile", { 3 + export const profileNamespace = lx.lexicon("app.bsky.actor.profile", { 4 4 main: lx.record({ 5 5 key: "self", 6 6 record: lx.object({
+2 -2
packages/prototypey/src/lib.ts
··· 563 563 } as T & { type: "subscription" }; 564 564 }, 565 565 /** 566 - * Creates a lexicon namespace document. 566 + * Creates a lexicon schema document. 567 567 * @see https://atproto.com/specs/lexicon#lexicon-document 568 568 */ 569 - namespace<ID extends string, D extends LexiconNamespace["defs"]>( 569 + lexicon<ID extends string, D extends LexiconNamespace["defs"]>( 570 570 id: ID, 571 571 defs: D, 572 572 ): Namespace<{ lexicon: 1; id: ID; defs: D }> {
+1 -1
packages/prototypey/tests/base-case.test.ts
··· 2 2 import { lx } from "../src/lib.ts"; 3 3 4 4 test("app.bsky.actor.profile", () => { 5 - const profileNamespace = lx.namespace("app.bsky.actor.profile", { 5 + const profileNamespace = lx.lexicon("app.bsky.actor.profile", { 6 6 main: lx.record({ 7 7 key: "self", 8 8 record: lx.object({
+2 -2
packages/prototypey/tests/bsky-actor.test.ts
··· 830 830 }); 831 831 }); 832 832 833 - test("app.bsky.actor.defs - full namespace", () => { 834 - const actorDefs = lx.namespace("app.bsky.actor.defs", { 833 + test("app.bsky.actor.defs - full lexicon", () => { 834 + const actorDefs = lx.lexicon("app.bsky.actor.defs", { 835 835 profileViewBasic: lx.object({ 836 836 did: lx.string({ required: true, format: "did" }), 837 837 handle: lx.string({ required: true, format: "handle" }),
+2 -2
packages/prototypey/tests/bsky-feed.test.ts
··· 607 607 }); 608 608 }); 609 609 610 - test("app.bsky.feed.defs - full namespace", () => { 611 - const feedDefs = lx.namespace("app.bsky.feed.defs", { 610 + test("app.bsky.feed.defs - full lexicon", () => { 611 + const feedDefs = lx.lexicon("app.bsky.feed.defs", { 612 612 postView: lx.object({ 613 613 uri: lx.string({ required: true, format: "at-uri" }), 614 614 cid: lx.string({ required: true, format: "cid" }),
+5 -5
packages/prototypey/tests/infer.bench.ts
··· 2 2 import { lx } from "../src/lib.ts"; 3 3 4 4 bench("infer with simple object", () => { 5 - const schema = lx.namespace("test.simple", { 5 + const schema = lx.lexicon("test.simple", { 6 6 main: lx.object({ 7 7 id: lx.string({ required: true }), 8 8 name: lx.string({ required: true }), ··· 12 12 }).types([741, "instantiations"]); 13 13 14 14 bench("infer with complex nested structure", () => { 15 - const schema = lx.namespace("test.complex", { 15 + const schema = lx.lexicon("test.complex", { 16 16 user: lx.object({ 17 17 handle: lx.string({ required: true }), 18 18 displayName: lx.string(), ··· 35 35 }).types([1040, "instantiations"]); 36 36 37 37 bench("infer with circular reference", () => { 38 - const ns = lx.namespace("test", { 38 + const ns = lx.lexicon("test", { 39 39 user: lx.object({ 40 40 name: lx.string({ required: true }), 41 41 posts: lx.array(lx.ref("#post")), ··· 51 51 return ns.infer; 52 52 }).types([692, "instantiations"]); 53 53 54 - bench("infer with app.bsky.feed.defs namespace", () => { 55 - const schema = lx.namespace("app.bsky.feed.defs", { 54 + bench("infer with app.bsky.feed.defs lexicon", () => { 55 + const schema = lx.lexicon("app.bsky.feed.defs", { 56 56 viewerState: lx.object({ 57 57 repost: lx.string({ format: "at-uri" }), 58 58 like: lx.string({ format: "at-uri" }),
+82 -82
packages/prototypey/tests/infer.test.ts
··· 3 3 import { lx } from "../src/lib.ts"; 4 4 5 5 test("InferNS produces expected type shape", () => { 6 - const exampleLexicon = lx.namespace("com.example.post", { 6 + const exampleLexicon = lx.lexicon("com.example.post", { 7 7 main: lx.record({ 8 8 key: "tid", 9 9 record: lx.object({ ··· 26 26 }); 27 27 28 28 test("InferObject handles required fields", () => { 29 - const schema = lx.namespace("test", { 29 + const schema = lx.lexicon("test", { 30 30 main: lx.object({ 31 31 required: lx.string({ required: true }), 32 32 optional: lx.string(), ··· 41 41 }); 42 42 43 43 test("InferObject handles nullable fields", () => { 44 - const schema = lx.namespace("test", { 44 + const schema = lx.lexicon("test", { 45 45 main: lx.object({ 46 46 nullable: lx.string({ nullable: true, required: true }), 47 47 }), ··· 57 57 // ============================================================================ 58 58 59 59 test("InferType handles string primitive", () => { 60 - const namespace = lx.namespace("test.string", { 60 + const lexicon = lx.lexicon("test.string", { 61 61 main: lx.object({ 62 62 simpleString: lx.string(), 63 63 }), 64 64 }); 65 65 66 - attest(namespace.infer).type.toString.snap(`{ 66 + attest(lexicon.infer).type.toString.snap(`{ 67 67 $type: "test.string" 68 68 simpleString?: string | undefined 69 69 }`); 70 70 }); 71 71 72 72 test("InferType handles integer primitive", () => { 73 - const namespace = lx.namespace("test.integer", { 73 + const lexicon = lx.lexicon("test.integer", { 74 74 main: lx.object({ 75 75 count: lx.integer(), 76 76 age: lx.integer({ minimum: 0, maximum: 120 }), 77 77 }), 78 78 }); 79 79 80 - attest(namespace.infer).type.toString.snap(`{ 80 + attest(lexicon.infer).type.toString.snap(`{ 81 81 $type: "test.integer" 82 82 count?: number | undefined 83 83 age?: number | undefined ··· 85 85 }); 86 86 87 87 test("InferType handles boolean primitive", () => { 88 - const namespace = lx.namespace("test.boolean", { 88 + const lexicon = lx.lexicon("test.boolean", { 89 89 main: lx.object({ 90 90 isActive: lx.boolean(), 91 91 hasAccess: lx.boolean({ required: true }), 92 92 }), 93 93 }); 94 94 95 - attest(namespace.infer).type.toString.snap(`{ 95 + attest(lexicon.infer).type.toString.snap(`{ 96 96 $type: "test.boolean" 97 97 isActive?: boolean | undefined 98 98 hasAccess: boolean ··· 100 100 }); 101 101 102 102 test("InferType handles null primitive", () => { 103 - const namespace = lx.namespace("test.null", { 103 + const lexicon = lx.lexicon("test.null", { 104 104 main: lx.object({ 105 105 nullValue: lx.null(), 106 106 }), 107 107 }); 108 108 109 - attest(namespace.infer).type.toString.snap(`{ 109 + attest(lexicon.infer).type.toString.snap(`{ 110 110 $type: "test.null" 111 111 nullValue?: null | undefined 112 112 }`); 113 113 }); 114 114 115 115 test("InferType handles unknown primitive", () => { 116 - const namespace = lx.namespace("test.unknown", { 116 + const lexicon = lx.lexicon("test.unknown", { 117 117 main: lx.object({ 118 118 metadata: lx.unknown(), 119 119 }), 120 120 }); 121 121 122 - attest(namespace.infer).type.toString.snap( 122 + attest(lexicon.infer).type.toString.snap( 123 123 '{ $type: "test.unknown"; metadata?: unknown }', 124 124 ); 125 125 }); 126 126 127 127 test("InferType handles bytes primitive", () => { 128 - const namespace = lx.namespace("test.bytes", { 128 + const lexicon = lx.lexicon("test.bytes", { 129 129 main: lx.object({ 130 130 data: lx.bytes(), 131 131 }), 132 132 }); 133 133 134 - attest(namespace.infer).type.toString.snap(`{ 134 + attest(lexicon.infer).type.toString.snap(`{ 135 135 $type: "test.bytes" 136 136 data?: Uint8Array<ArrayBufferLike> | undefined 137 137 }`); 138 138 }); 139 139 140 140 test("InferType handles blob primitive", () => { 141 - const namespace = lx.namespace("test.blob", { 141 + const lexicon = lx.lexicon("test.blob", { 142 142 main: lx.object({ 143 143 image: lx.blob({ accept: ["image/png", "image/jpeg"] }), 144 144 }), 145 145 }); 146 146 147 - attest(namespace.infer).type.toString.snap( 147 + attest(lexicon.infer).type.toString.snap( 148 148 '{ $type: "test.blob"; image?: Blob | undefined }', 149 149 ); 150 150 }); ··· 154 154 // ============================================================================ 155 155 156 156 test("InferToken handles basic token without enum", () => { 157 - const namespace = lx.namespace("test.token", { 157 + const lexicon = lx.lexicon("test.token", { 158 158 main: lx.object({ 159 159 symbol: lx.token("A symbolic value"), 160 160 }), 161 161 }); 162 162 163 - attest(namespace.infer).type.toString.snap(`{ 163 + attest(lexicon.infer).type.toString.snap(`{ 164 164 $type: "test.token" 165 165 symbol?: string | undefined 166 166 }`); ··· 171 171 // ============================================================================ 172 172 173 173 test("InferArray handles string arrays", () => { 174 - const namespace = lx.namespace("test.array.string", { 174 + const lexicon = lx.lexicon("test.array.string", { 175 175 main: lx.object({ 176 176 tags: lx.array(lx.string()), 177 177 }), 178 178 }); 179 179 180 - attest(namespace.infer).type.toString.snap(`{ 180 + attest(lexicon.infer).type.toString.snap(`{ 181 181 $type: "test.array.string" 182 182 tags?: string[] | undefined 183 183 }`); 184 184 }); 185 185 186 186 test("InferArray handles integer arrays", () => { 187 - const namespace = lx.namespace("test.array.integer", { 187 + const lexicon = lx.lexicon("test.array.integer", { 188 188 main: lx.object({ 189 189 scores: lx.array(lx.integer(), { minLength: 1, maxLength: 10 }), 190 190 }), 191 191 }); 192 192 193 - attest(namespace.infer).type.toString.snap(`{ 193 + attest(lexicon.infer).type.toString.snap(`{ 194 194 $type: "test.array.integer" 195 195 scores?: number[] | undefined 196 196 }`); 197 197 }); 198 198 199 199 test("InferArray handles boolean arrays", () => { 200 - const namespace = lx.namespace("test.array.boolean", { 200 + const lexicon = lx.lexicon("test.array.boolean", { 201 201 main: lx.object({ 202 202 flags: lx.array(lx.boolean()), 203 203 }), 204 204 }); 205 205 206 - attest(namespace.infer).type.toString.snap(`{ 206 + attest(lexicon.infer).type.toString.snap(`{ 207 207 $type: "test.array.boolean" 208 208 flags?: boolean[] | undefined 209 209 }`); 210 210 }); 211 211 212 212 test("InferArray handles unknown arrays", () => { 213 - const namespace = lx.namespace("test.array.unknown", { 213 + const lexicon = lx.lexicon("test.array.unknown", { 214 214 main: lx.object({ 215 215 items: lx.array(lx.unknown()), 216 216 }), 217 217 }); 218 218 219 - attest(namespace.infer).type.toString.snap(`{ 219 + attest(lexicon.infer).type.toString.snap(`{ 220 220 $type: "test.array.unknown" 221 221 items?: unknown[] | undefined 222 222 }`); ··· 227 227 // ============================================================================ 228 228 229 229 test("InferObject handles mixed optional and required fields", () => { 230 - const namespace = lx.namespace("test.mixed", { 230 + const lexicon = lx.lexicon("test.mixed", { 231 231 main: lx.object({ 232 232 id: lx.string({ required: true }), 233 233 name: lx.string({ required: true }), ··· 236 236 }), 237 237 }); 238 238 239 - attest(namespace.infer).type.toString.snap(`{ 239 + attest(lexicon.infer).type.toString.snap(`{ 240 240 $type: "test.mixed" 241 241 age?: number | undefined 242 242 email?: string | undefined ··· 246 246 }); 247 247 248 248 test("InferObject handles all optional fields", () => { 249 - const namespace = lx.namespace("test.allOptional", { 249 + const lexicon = lx.lexicon("test.allOptional", { 250 250 main: lx.object({ 251 251 field1: lx.string(), 252 252 field2: lx.integer(), ··· 254 254 }), 255 255 }); 256 256 257 - attest(namespace.infer).type.toString.snap(`{ 257 + attest(lexicon.infer).type.toString.snap(`{ 258 258 $type: "test.allOptional" 259 259 field1?: string | undefined 260 260 field2?: number | undefined ··· 263 263 }); 264 264 265 265 test("InferObject handles all required fields", () => { 266 - const namespace = lx.namespace("test.allRequired", { 266 + const lexicon = lx.lexicon("test.allRequired", { 267 267 main: lx.object({ 268 268 field1: lx.string({ required: true }), 269 269 field2: lx.integer({ required: true }), ··· 271 271 }), 272 272 }); 273 273 274 - attest(namespace.infer).type.toString.snap(`{ 274 + attest(lexicon.infer).type.toString.snap(`{ 275 275 $type: "test.allRequired" 276 276 field1: string 277 277 field2: number ··· 284 284 // ============================================================================ 285 285 286 286 test("InferObject handles nullable optional field", () => { 287 - const namespace = lx.namespace("test.nullableOptional", { 287 + const lexicon = lx.lexicon("test.nullableOptional", { 288 288 main: lx.object({ 289 289 description: lx.string({ nullable: true }), 290 290 }), 291 291 }); 292 292 293 - attest(namespace.infer).type.toString.snap(`{ 293 + attest(lexicon.infer).type.toString.snap(`{ 294 294 $type: "test.nullableOptional" 295 295 description?: string | null | undefined 296 296 }`); 297 297 }); 298 298 299 299 test("InferObject handles multiple nullable fields", () => { 300 - const namespace = lx.namespace("test.multipleNullable", { 300 + const lexicon = lx.lexicon("test.multipleNullable", { 301 301 main: lx.object({ 302 302 field1: lx.string({ nullable: true }), 303 303 field2: lx.integer({ nullable: true }), ··· 305 305 }), 306 306 }); 307 307 308 - attest(namespace.infer).type.toString.snap(`{ 308 + attest(lexicon.infer).type.toString.snap(`{ 309 309 $type: "test.multipleNullable" 310 310 field1?: string | null | undefined 311 311 field2?: number | null | undefined ··· 314 314 }); 315 315 316 316 test("InferObject handles nullable and required field", () => { 317 - const namespace = lx.namespace("test.nullableRequired", { 317 + const lexicon = lx.lexicon("test.nullableRequired", { 318 318 main: lx.object({ 319 319 value: lx.string({ nullable: true, required: true }), 320 320 }), 321 321 }); 322 322 323 - attest(namespace.infer).type.toString.snap(`{ 323 + attest(lexicon.infer).type.toString.snap(`{ 324 324 $type: "test.nullableRequired" 325 325 value: string | null 326 326 }`); 327 327 }); 328 328 329 329 test("InferObject handles mixed nullable, required, and optional", () => { 330 - const namespace = lx.namespace("test.mixedNullable", { 330 + const lexicon = lx.lexicon("test.mixedNullable", { 331 331 main: lx.object({ 332 332 requiredNullable: lx.string({ required: true, nullable: true }), 333 333 optionalNullable: lx.string({ nullable: true }), ··· 336 336 }), 337 337 }); 338 338 339 - attest(namespace.infer).type.toString.snap(`{ 339 + attest(lexicon.infer).type.toString.snap(`{ 340 340 $type: "test.mixedNullable" 341 341 optional?: string | undefined 342 342 required: string ··· 350 350 // ============================================================================ 351 351 352 352 test("InferRef handles basic reference", () => { 353 - const namespace = lx.namespace("test.ref", { 353 + const lexicon = lx.lexicon("test.ref", { 354 354 main: lx.object({ 355 355 post: lx.ref("com.example.post"), 356 356 }), 357 357 }); 358 358 359 - attest(namespace.infer).type.toString.snap(`{ 359 + attest(lexicon.infer).type.toString.snap(`{ 360 360 $type: "test.ref" 361 361 post?: 362 362 | { [x: string]: unknown; $type: "com.example.post" } ··· 365 365 }); 366 366 367 367 test("InferRef handles required reference", () => { 368 - const namespace = lx.namespace("test.refRequired", { 368 + const lexicon = lx.lexicon("test.refRequired", { 369 369 main: lx.object({ 370 370 author: lx.ref("com.example.user", { required: true }), 371 371 }), 372 372 }); 373 373 374 - attest(namespace.infer).type.toString.snap(`{ 374 + attest(lexicon.infer).type.toString.snap(`{ 375 375 $type: "test.refRequired" 376 376 author?: 377 377 | { [x: string]: unknown; $type: "com.example.user" } ··· 380 380 }); 381 381 382 382 test("InferRef handles nullable reference", () => { 383 - const namespace = lx.namespace("test.refNullable", { 383 + const lexicon = lx.lexicon("test.refNullable", { 384 384 main: lx.object({ 385 385 parent: lx.ref("com.example.node", { nullable: true }), 386 386 }), 387 387 }); 388 388 389 - attest(namespace.infer).type.toString.snap(`{ 389 + attest(lexicon.infer).type.toString.snap(`{ 390 390 $type: "test.refNullable" 391 391 parent?: 392 392 | { [x: string]: unknown; $type: "com.example.node" } ··· 399 399 // ============================================================================ 400 400 401 401 test("InferUnion handles basic union", () => { 402 - const namespace = lx.namespace("test.union", { 402 + const lexicon = lx.lexicon("test.union", { 403 403 main: lx.object({ 404 404 content: lx.union(["com.example.text", "com.example.image"]), 405 405 }), 406 406 }); 407 407 408 - attest(namespace.infer).type.toString.snap(`{ 408 + attest(lexicon.infer).type.toString.snap(`{ 409 409 $type: "test.union" 410 410 content?: 411 411 | { [x: string]: unknown; $type: "com.example.text" } ··· 415 415 }); 416 416 417 417 test("InferUnion handles required union", () => { 418 - const namespace = lx.namespace("test.unionRequired", { 418 + const lexicon = lx.lexicon("test.unionRequired", { 419 419 main: lx.object({ 420 420 media: lx.union(["com.example.video", "com.example.audio"], { 421 421 required: true, ··· 423 423 }), 424 424 }); 425 425 426 - attest(namespace.infer).type.toString.snap(`{ 426 + attest(lexicon.infer).type.toString.snap(`{ 427 427 $type: "test.unionRequired" 428 428 media: 429 429 | { [x: string]: unknown; $type: "com.example.video" } ··· 432 432 }); 433 433 434 434 test("InferUnion handles union with many types", () => { 435 - const namespace = lx.namespace("test.unionMultiple", { 435 + const lexicon = lx.lexicon("test.unionMultiple", { 436 436 main: lx.object({ 437 437 attachment: lx.union([ 438 438 "com.example.image", ··· 443 443 }), 444 444 }); 445 445 446 - attest(namespace.infer).type.toString.snap(`{ 446 + attest(lexicon.infer).type.toString.snap(`{ 447 447 $type: "test.unionMultiple" 448 448 attachment?: 449 449 | { [x: string]: unknown; $type: "com.example.image" } ··· 462 462 // ============================================================================ 463 463 464 464 test("InferParams handles basic params", () => { 465 - const namespace = lx.namespace("test.params", { 465 + const lexicon = lx.lexicon("test.params", { 466 466 main: lx.params({ 467 467 limit: lx.integer(), 468 468 offset: lx.integer(), 469 469 }), 470 470 }); 471 471 472 - attest(namespace.infer).type.toString.snap(`{ 472 + attest(lexicon.infer).type.toString.snap(`{ 473 473 $type: "test.params" 474 474 limit?: number | undefined 475 475 offset?: number | undefined ··· 477 477 }); 478 478 479 479 test("InferParams handles required params", () => { 480 - const namespace = lx.namespace("test.paramsRequired", { 480 + const lexicon = lx.lexicon("test.paramsRequired", { 481 481 main: lx.params({ 482 482 query: lx.string({ required: true }), 483 483 limit: lx.integer(), 484 484 }), 485 485 }); 486 486 487 - attest(namespace.infer).type.toString.snap(`{ 487 + attest(lexicon.infer).type.toString.snap(`{ 488 488 $type: "test.paramsRequired" 489 489 limit?: number | undefined 490 490 query: string ··· 496 496 // ============================================================================ 497 497 498 498 test("InferRecord handles record with object schema", () => { 499 - const namespace = lx.namespace("test.record", { 499 + const lexicon = lx.lexicon("test.record", { 500 500 main: lx.record({ 501 501 key: "tid", 502 502 record: lx.object({ ··· 507 507 }), 508 508 }); 509 509 510 - attest(namespace.infer).type.toString.snap(`{ 510 + attest(lexicon.infer).type.toString.snap(`{ 511 511 $type: "test.record" 512 512 published?: boolean | undefined 513 513 content: string ··· 520 520 // ============================================================================ 521 521 522 522 test("InferObject handles nested objects", () => { 523 - const namespace = lx.namespace("test.nested", { 523 + const lexicon = lx.lexicon("test.nested", { 524 524 main: lx.object({ 525 525 user: lx.object({ 526 526 name: lx.string({ required: true }), ··· 529 529 }), 530 530 }); 531 531 532 - attest(namespace.infer).type.toString.snap(`{ 532 + attest(lexicon.infer).type.toString.snap(`{ 533 533 $type: "test.nested" 534 534 user?: { name: string; email: string } | undefined 535 535 }`); 536 536 }); 537 537 538 538 test("InferObject handles deeply nested objects", () => { 539 - const namespace = lx.namespace("test.deepNested", { 539 + const lexicon = lx.lexicon("test.deepNested", { 540 540 main: lx.object({ 541 541 data: lx.object({ 542 542 user: lx.object({ ··· 548 548 }), 549 549 }); 550 550 551 - attest(namespace.infer).type.toString.snap(`{ 551 + attest(lexicon.infer).type.toString.snap(`{ 552 552 $type: "test.deepNested" 553 553 data?: 554 554 | { ··· 565 565 // ============================================================================ 566 566 567 567 test("InferArray handles arrays of objects", () => { 568 - const namespace = lx.namespace("test.arrayOfObjects", { 568 + const lexicon = lx.lexicon("test.arrayOfObjects", { 569 569 main: lx.object({ 570 570 users: lx.array( 571 571 lx.object({ ··· 576 576 }), 577 577 }); 578 578 579 - attest(namespace.infer).type.toString.snap(`{ 579 + attest(lexicon.infer).type.toString.snap(`{ 580 580 $type: "test.arrayOfObjects" 581 581 users?: { id: string; name: string }[] | undefined 582 582 }`); ··· 587 587 matrix: lx.array(lx.array(lx.integer())), 588 588 }); 589 589 590 - const namespace = lx.namespace("test.nestedArrays", { 590 + const lexicon = lx.lexicon("test.nestedArrays", { 591 591 main: schema, 592 592 }); 593 593 594 - attest(namespace.infer).type.toString.snap(`{ 594 + attest(lexicon.infer).type.toString.snap(`{ 595 595 $type: "test.nestedArrays" 596 596 matrix?: number[][] | undefined 597 597 }`); 598 598 }); 599 599 600 600 test("InferArray handles arrays of refs", () => { 601 - const namespace = lx.namespace("test.arrayOfRefs", { 601 + const lexicon = lx.lexicon("test.arrayOfRefs", { 602 602 main: lx.object({ 603 603 followers: lx.array(lx.ref("com.example.user")), 604 604 }), 605 605 }); 606 606 607 - attest(namespace.infer).type.toString.snap(`{ 607 + attest(lexicon.infer).type.toString.snap(`{ 608 608 $type: "test.arrayOfRefs" 609 609 followers?: 610 610 | { [x: string]: unknown; $type: "com.example.user" }[] ··· 617 617 // ============================================================================ 618 618 619 619 test("InferObject handles complex nested structure", () => { 620 - const namespace = lx.namespace("test.complex", { 620 + const lexicon = lx.lexicon("test.complex", { 621 621 main: lx.object({ 622 622 id: lx.string({ required: true }), 623 623 author: lx.object({ ··· 635 635 }), 636 636 }); 637 637 638 - attest(namespace.infer).type.toString.snap(`{ 638 + attest(lexicon.infer).type.toString.snap(`{ 639 639 $type: "test.complex" 640 640 tags?: string[] | undefined 641 641 content?: ··· 665 665 // ============================================================================ 666 666 667 667 test("InferNS handles multiple defs in namespace", () => { 668 - const namespace = lx.namespace("com.example.app", { 668 + const lexicon = lx.lexicon("com.example.app", { 669 669 user: lx.object({ 670 670 name: lx.string({ required: true }), 671 671 email: lx.string({ required: true }), ··· 680 680 }), 681 681 }); 682 682 683 - attest(namespace.infer).type.toString.snap("never"); 683 + attest(lexicon.infer).type.toString.snap("never"); 684 684 }); 685 685 686 686 test("InferNS handles namespace with record and object defs", () => { 687 - const namespace = lx.namespace("com.example.blog", { 687 + const lexicon = lx.lexicon("com.example.blog", { 688 688 main: lx.record({ 689 689 key: "tid", 690 690 record: lx.object({ ··· 698 698 }), 699 699 }); 700 700 701 - attest(namespace.infer).type.toString.snap(`{ 701 + attest(lexicon.infer).type.toString.snap(`{ 702 702 $type: "com.example.blog" 703 703 title: string 704 704 body: string ··· 710 710 // ============================================================================ 711 711 712 712 test("Local ref resolution: resolves refs to actual types", () => { 713 - const ns = lx.namespace("test", { 713 + const ns = lx.lexicon("test", { 714 714 user: lx.object({ 715 715 name: lx.string({ required: true }), 716 716 email: lx.string({ required: true }), ··· 731 731 }); 732 732 733 733 test("Local ref resolution: refs in arrays", () => { 734 - const ns = lx.namespace("test", { 734 + const ns = lx.lexicon("test", { 735 735 user: lx.object({ 736 736 name: lx.string({ required: true }), 737 737 }), ··· 747 747 }); 748 748 749 749 test("Local ref resolution: refs in unions", () => { 750 - const ns = lx.namespace("test", { 750 + const ns = lx.lexicon("test", { 751 751 text: lx.object({ content: lx.string({ required: true }) }), 752 752 image: lx.object({ url: lx.string({ required: true }) }), 753 753 main: lx.object({ ··· 765 765 }); 766 766 767 767 test("Local ref resolution: nested refs", () => { 768 - const ns = lx.namespace("test", { 768 + const ns = lx.lexicon("test", { 769 769 profile: lx.object({ 770 770 bio: lx.string({ required: true }), 771 771 }), ··· 797 797 // ============================================================================ 798 798 799 799 test("Edge case: circular reference detection", () => { 800 - const ns = lx.namespace("test", { 800 + const ns = lx.lexicon("test", { 801 801 main: lx.object({ 802 802 value: lx.string({ required: true }), 803 803 parent: lx.ref("#main"), ··· 820 820 }); 821 821 822 822 test("Edge case: circular reference between multiple types", () => { 823 - const ns = lx.namespace("test", { 823 + const ns = lx.lexicon("test", { 824 824 user: lx.object({ 825 825 name: lx.string({ required: true }), 826 826 posts: lx.array(lx.ref("#post")), ··· 855 855 }); 856 856 857 857 test("Edge case: missing reference detection", () => { 858 - const ns = lx.namespace("test", { 858 + const ns = lx.lexicon("test", { 859 859 main: lx.object({ 860 860 author: lx.ref("#user", { required: true }), 861 861 }),
+6 -6
packages/site/src/components/Playground.tsx
··· 47 47 const timeoutId = setTimeout(async () => { 48 48 try { 49 49 const nsMatch = code.match( 50 - /const\s+ns\s*=\s*lx\.namespace\([^]*?\}\s*\);/, 50 + /const\s+ns\s*=\s*lx\.lexicon\([^]*?\}\s*\);/, 51 51 ); 52 52 if (!nsMatch) { 53 - throw new Error("No namespace definition found"); 53 + throw new Error("No lexicon definition found"); 54 54 } 55 55 56 56 const cleanedCode = nsMatch[0]; 57 - const wrappedCode = `${cleanedCode}\nreturn ns;`; 57 + const wrappedCode = `${cleanedCode}\nreturn lex;`; 58 58 const fn = new Function("lx", wrappedCode); 59 59 const result = fn(lx); 60 60 let typeInfo = "// Hover over .infer in the editor to see the type"; ··· 180 180 181 181 const DEFAULT_CODE = `import { lx, type Infer } from "prototypey"; 182 182 183 - const ns = lx.namespace("app.bsky.actor.profile", { 183 + const lex = lx.lexicon("app.bsky.actor.profile", { 184 184 main: lx.record({ 185 185 key: "self", 186 186 record: lx.object({ ··· 190 190 }), 191 191 }); 192 192 193 - type ProfileInferred = Infer<typeof ns>; 193 + type Profile = Infer<typeof lex>; 194 194 195 - const aProfile: ProfileInferred = { 195 + const aProfile: Profile = { 196 196 $type: "app.bsky.actor.profile", 197 197 displayName: "Benny Harvey" 198 198 }`;
+1 -1
packages/site/tests/components/Playground.test.tsx
··· 85 85 const inputEditor = editors[0] as HTMLTextAreaElement; 86 86 87 87 expect(inputEditor.value).toContain( 88 - 'lx.namespace("app.bsky.actor.profile"', 88 + 'lx.lexicon("app.bsky.actor.profile"', 89 89 ); 90 90 }); 91 91