A calm place to write long-form, and publish it to the open social web. skypress.blog/
0

Configure Feed

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

Add pure schema-doc helper single-sourcing the content lexicon

+85
+32
src/lib/lexicon/schema-doc.test.ts
··· 1 + import { describe, expect, it } from 'vitest'; 2 + import { 3 + CONTENT_LEXICON_ID, 4 + CONTENT_LEXICON_DESCRIPTION, 5 + contentSchemaFields, 6 + } from './schema-doc'; 7 + 8 + describe( 'content lexicon doc', () => { 9 + it( 'exposes the owned lexicon NSID and description from the schema file', () => { 10 + expect( CONTENT_LEXICON_ID ).toBe( 'blog.skypress.content.gutenberg' ); 11 + expect( CONTENT_LEXICON_DESCRIPTION ).toContain( 'block tree' ); 12 + } ); 13 + 14 + it( 'derives ordered field rows from the schema, with required flags', () => { 15 + const fields = contentSchemaFields(); 16 + expect( fields.map( ( f ) => f.name ) ).toEqual( [ 'version', 'blocks' ] ); 17 + 18 + expect( fields[ 0 ] ).toMatchObject( { 19 + name: 'version', 20 + type: 'integer', 21 + required: true, 22 + } ); 23 + expect( fields[ 0 ].description.length ).toBeGreaterThan( 0 ); 24 + 25 + expect( fields[ 1 ] ).toMatchObject( { 26 + name: 'blocks', 27 + type: 'array', 28 + required: true, 29 + } ); 30 + expect( fields[ 1 ].description ).toContain( 'block tree' ); 31 + } ); 32 + } );
+53
src/lib/lexicon/schema-doc.ts
··· 1 + /** 2 + * Single-sources the one SkyPress-owned lexicon for the public /lexicon page. 3 + * 4 + * The owned schema is imported from its canonical JSON (not retyped), so the page's 5 + * "the format we own" section cannot silently drift from the lexicon. The interop 6 + * `site.standard.*` tables on the page are hand-authored — those lexicons are 7 + * community-owned (Decision 0005). 8 + */ 9 + import schema from '../../../lexicons/blog.skypress.content.gutenberg.json'; 10 + 11 + interface LexiconObjectDef { 12 + type: string; 13 + description: string; 14 + required?: string[]; 15 + properties: Record< string, { type: string; description: string } >; 16 + } 17 + 18 + interface LexiconDoc { 19 + lexicon: number; 20 + id: string; 21 + defs: { main: LexiconObjectDef }; 22 + } 23 + 24 + const doc = schema as LexiconDoc; 25 + 26 + /** A documented field of the owned content lexicon's `main` object. */ 27 + export interface SchemaField { 28 + name: string; 29 + type: string; 30 + required: boolean; 31 + description: string; 32 + } 33 + 34 + /** The owned lexicon's NSID, e.g. `blog.skypress.content.gutenberg`. */ 35 + export const CONTENT_LEXICON_ID = doc.id; 36 + 37 + /** The `defs.main` description straight from the schema. */ 38 + export const CONTENT_LEXICON_DESCRIPTION = doc.defs.main.description; 39 + 40 + /** The raw schema object, for rendering the actual JSON on the page. */ 41 + export const CONTENT_LEXICON = doc; 42 + 43 + /** Ordered field rows for the owned lexicon's `main` object (insertion order). */ 44 + export function contentSchemaFields(): SchemaField[] { 45 + const main = doc.defs.main; 46 + const required = new Set( main.required ?? [] ); 47 + return Object.entries( main.properties ).map( ( [ name, def ] ) => ( { 48 + name, 49 + type: def.type, 50 + required: required.has( name ), 51 + description: def.description, 52 + } ) ); 53 + }