a collection of lightweight TypeScript packages for AT Protocol, the protocol powering Bluesky
atproto bluesky typescript npm
101
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(lexicons): allow referencing records inside objects

Mary 20227546 ff4b6fd2

+79 -3
+5
.changeset/purple-tires-juggle.md
··· 1 + --- 2 + '@atcute/lexicons': patch 3 + --- 4 + 5 + allow referencing records inside objects
+69
packages/lexicons/lexicons/lib/validations/index.test.ts
··· 681 681 expect(v.is(schema, { $type: 'adultContent', enabled: 123 })).toBe(false); 682 682 } 683 683 }); 684 + 685 + it(`validates variant type with record members`, () => { 686 + const recordSchema = v.record( 687 + v.tidString(), 688 + v.object({ 689 + $type: v.literal('com.example.post'), 690 + text: v.string(), 691 + createdAt: v.datetimeString(), 692 + }), 693 + ); 694 + 695 + const objectSchema = v.object({ 696 + $type: v.literal('com.example.like'), 697 + subject: v.string(), 698 + }); 699 + 700 + { 701 + const schema = v.variant([recordSchema, objectSchema], false); 702 + 703 + expect( 704 + v.is(schema, { $type: 'com.example.post', text: 'hello', createdAt: new Date().toISOString() }), 705 + ).toBe(true); 706 + expect( 707 + v.is(schema, { $type: 'com.example.like', subject: 'at://did:plc:1234/com.example.post/1' }), 708 + ).toBe(true); 709 + 710 + expect(v.is(schema, { $type: 'unknown', hello: 'world' })).toBe(true); 711 + 712 + expect(v.is(schema, 123)).toBe(false); 713 + expect(v.is(schema, {})).toBe(false); 714 + expect(v.is(schema, { $type: 'com.example.post', text: 123 })).toBe(false); 715 + } 716 + 717 + { 718 + const schema = v.variant([recordSchema, objectSchema], true); 719 + 720 + expect( 721 + v.is(schema, { $type: 'com.example.post', text: 'hello', createdAt: new Date().toISOString() }), 722 + ).toBe(true); 723 + expect( 724 + v.is(schema, { $type: 'com.example.like', subject: 'at://did:plc:1234/com.example.post/1' }), 725 + ).toBe(true); 726 + 727 + expect(v.is(schema, { $type: 'unknown', hello: 'world' })).toBe(false); 728 + 729 + expect(v.is(schema, { $type: 'com.example.post', text: 123 })).toBe(false); 730 + } 731 + }); 732 + 733 + it(`validates record referenced directly in an object`, () => { 734 + const recordSchema = v.record( 735 + v.tidString(), 736 + v.object({ 737 + $type: v.literal('com.example.post'), 738 + text: v.string(), 739 + }), 740 + ); 741 + 742 + const schema = v.object({ 743 + $type: v.optional(v.literal('com.example.wrapper')), 744 + post: recordSchema, 745 + }); 746 + 747 + expect(v.is(schema, { post: { $type: 'com.example.post', text: 'hello' } })).toBe(true); 748 + expect(v.is(schema, { post: { $type: 'com.example.post', text: 123 } })).toBe(false); 749 + expect(v.is(schema, { post: { text: 'hello' } })).toBe(false); 750 + expect(v.is(schema, { post: 'not an object' })).toBe(false); 751 + expect(v.is(schema, {})).toBe(false); 752 + }); 684 753 }); 685 754 686 755 describe(`constraints`, () => {
+5 -3
packages/lexicons/lexicons/lib/validations/index.ts
··· 1601 1601 1602 1602 // #region Variant schema 1603 1603 1604 - type VariantTuple = readonly ObjectSchema<any>[]; 1604 + type VariantMember = ObjectSchema<any> | RecordSchema<ObjectSchema<any>, RecordKeySchema>; 1605 + type VariantTuple = readonly VariantMember[]; 1605 1606 1606 1607 type InferVariantInput<TMembers extends VariantTuple> = $type.enforce<InferInput<TMembers[number]>>; 1607 1608 ··· 1629 1630 members: TMembers, 1630 1631 closed: TClosed, 1631 1632 ): VariantSchema<TMembers, TClosed>; 1632 - } = (members: ObjectSchema[], closed: boolean = false): VariantSchema<any, any> => { 1633 + } = (members: VariantMember[], closed: boolean = false): VariantSchema<any, any> => { 1633 1634 return { 1634 1635 kind: 'schema', 1635 1636 type: 'variant', ··· 1640 1641 const schemas: ObjectSchema[] = []; 1641 1642 1642 1643 for (let idx = 0, len = members.length; idx < len; idx++) { 1643 - const member = members[idx]!; 1644 + const raw = members[idx]!; 1645 + const member = raw.type === 'record' ? raw.object : raw; 1644 1646 const shape = member.shape; 1645 1647 1646 1648 let t = shape.$type as MaybeOptional<LiteralSchema<syntax.Nsid>> | undefined;