An experimental TypeSpec syntax for Lexicon
56
fork

Configure Feed

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

kay

+28 -114
+21 -16
typelex-emitter/lib/decorators.tsp
··· 1 1 import "../dist/decorators.js"; 2 2 3 3 /** 4 - * Specifies the lexicon format of a string field (e.g., "at-uri", "cid", "did", "datetime") 4 + * Specifies the lexicon format of a string field. 5 + * 6 + * Common formats: 7 + * - "at-uri": AT Protocol URI 8 + * - "cid": Content identifier 9 + * - "did": Decentralized identifier 10 + * - "datetime": ISO 8601 datetime 11 + * - "handle": AT Protocol handle 12 + * - "uri": Generic URI 13 + * - "language": ISO language code 14 + * 15 + * @example 16 + * ```typespec 17 + * model Post { 18 + * @lexFormat("at-uri") 19 + * uri: string; 20 + * 21 + * @lexFormat("cid") 22 + * cid: string; 23 + * } 24 + * ``` 5 25 */ 6 26 extern dec lexFormat(target: unknown, format: valueof string); 7 - 8 - /** 9 - * Specifies a reference to another type 10 - */ 11 - extern dec ref(target: unknown, ref: valueof string); 12 - 13 - /** 14 - * Specifies a union of referenced types (comma-separated string) 15 - */ 16 - extern dec unionRefs(target: unknown, refs: valueof string); 17 - 18 - /** 19 - * Specifies the ref for array items 20 - */ 21 - extern dec arrayItems(target: unknown, itemRef: valueof string);
-2
typelex-emitter/lib/main.tsp
··· 1 1 import "./decorators.tsp"; 2 - 3 - namespace ATProto;
+5 -45
typelex-emitter/src/decorators.ts
··· 1 - import { DecoratorContext, Program, Type, getNamespaceFullName } from "@typespec/compiler"; 1 + import { DecoratorContext, Program, Type } from "@typespec/compiler"; 2 2 3 3 const formatKey = Symbol("lexFormat"); 4 4 5 - // LexFormat decorator for string formats like "at-uri", "cid", "did", "datetime" 5 + /** 6 + * @lexFormat decorator for lexicon-specific string formats 7 + * Used for formats like "at-uri", "cid", "did", "datetime", etc. 8 + */ 6 9 export function $lexFormat(context: DecoratorContext, target: Type, format: Type) { 7 - decoratorProgram = context.program; 8 10 // Extract the value from the Type if it's a string literal 9 11 const formatValue = (format as any).kind === "String" ? (format as any).value : format; 10 12 context.program.stateMap(formatKey).set(target, formatValue); ··· 13 15 export function getLexFormat(program: Program, target: Type): string | undefined { 14 16 return program.stateMap(formatKey).get(target); 15 17 } 16 - 17 - // Ref decorator for references to other types 18 - export let decoratorProgram: any = null; 19 - export function $ref(context: DecoratorContext, target: Type, ref: Type) { 20 - decoratorProgram = context.program; 21 - const refValue = (ref as any).kind === "String" ? (ref as any).value : ref; 22 - context.program.stateMap(refKey).set(target, refValue); 23 - } 24 - 25 - export function getRef(program: Program, target: Type): string | undefined { 26 - return program.stateMap(refKey).get(target); 27 - } 28 - 29 - const refKey = Symbol("ref"); 30 - 31 - // UnionRefs decorator for union types 32 - export function $unionRefs(context: DecoratorContext, target: Type, refs: Type) { 33 - decoratorProgram = context.program; 34 - const refsValue = (refs as any).kind === "String" ? (refs as any).value : refs; 35 - // Parse comma-separated string into array 36 - const refsArray = refsValue.split(',').map((r: string) => r.trim()); 37 - context.program.stateMap(unionKey).set(target, refsArray); 38 - } 39 - 40 - export function getUnionRefs(program: Program, target: Type): string[] | undefined { 41 - return program.stateMap(unionKey).get(target); 42 - } 43 - 44 - const unionKey = Symbol("unionRefs"); 45 - 46 - // ArrayItems decorator for array item refs 47 - export function $arrayItems(context: DecoratorContext, target: Type, itemRef: Type) { 48 - decoratorProgram = context.program; 49 - const itemRefValue = (itemRef as any).kind === "String" ? (itemRef as any).value : itemRef; 50 - context.program.stateMap(arrayItemsKey).set(target, itemRefValue); 51 - } 52 - 53 - export function getArrayItems(program: Program, target: Type): string | undefined { 54 - return program.stateMap(arrayItemsKey).get(target); 55 - } 56 - 57 - const arrayItemsKey = Symbol("arrayItems");
+1 -49
typelex-emitter/src/emitter.ts
··· 21 21 LexiconRef, 22 22 LexiconUnion, 23 23 } from "./types.js"; 24 - import { getLexFormat, getRef, getUnionRefs, getArrayItems } from "./decorators.js"; 24 + import { getLexFormat } from "./decorators.js"; 25 25 26 26 export interface EmitterOptions { 27 27 outputDir: string; ··· 203 203 } 204 204 205 205 private typeToLexiconDefinition(type: Type, prop?: ModelProperty): LexiconDefinition | null { 206 - // Check for decorators on the property first 207 - if (prop) { 208 - // Check for @ref decorator 209 - const ref = getRef(this.program, prop); 210 - if (ref) { 211 - const refDef: LexiconRef = { 212 - type: "ref", 213 - ref: ref, 214 - }; 215 - const propDesc = getDoc(this.program, prop); 216 - if (propDesc) { 217 - refDef.description = propDesc; 218 - } 219 - return refDef; 220 - } 221 - 222 - // Check for @unionRefs decorator 223 - const unionRefs = getUnionRefs(this.program, prop); 224 - if (unionRefs) { 225 - const unionDef: LexiconUnion = { 226 - type: "union", 227 - refs: unionRefs, 228 - }; 229 - const propDesc = getDoc(this.program, prop); 230 - if (propDesc) { 231 - unionDef.description = propDesc; 232 - } 233 - return unionDef; 234 - } 235 - 236 - // Check for @arrayItems decorator 237 - const arrayItemRef = getArrayItems(this.program, prop); 238 - if (arrayItemRef) { 239 - const arrayDef: LexiconArray = { 240 - type: "array", 241 - items: { 242 - type: "ref", 243 - ref: arrayItemRef, 244 - }, 245 - }; 246 - const propDesc = getDoc(this.program, prop); 247 - if (propDesc) { 248 - arrayDef.description = propDesc; 249 - } 250 - return arrayDef; 251 - } 252 - } 253 - 254 206 switch (type.kind) { 255 207 case "Boolean": { 256 208 // Handle boolean literal types (e.g., `true` or `false`)
+1 -2
typelex-emitter/src/index.ts
··· 1 - import { resolvePath } from "@typespec/compiler"; 2 1 import type { EmitContext } from "@typespec/compiler"; 3 2 import { TypeLexEmitter } from "./emitter.js"; 4 3 ··· 15 14 } 16 15 17 16 // Export decorators 18 - export { $lexFormat, $ref, $unionRefs, $arrayItems } from "./decorators.js"; 17 + export { $lexFormat } from "./decorators.js";