An experimental TypeSpec syntax for Lexicon
56
fork

Configure Feed

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

wip

+2 -126
-39
packages/emitter/src/decorators.ts
··· 4 4 const formatKey = Symbol("lexFormat"); 5 5 const maxGraphemesKey = Symbol("maxGraphemes"); 6 6 const minGraphemesKey = Symbol("minGraphemes"); 7 - const blobAcceptKey = Symbol("blobAccept"); 8 - const blobMaxSizeKey = Symbol("blobMaxSize"); 9 7 const constKey = Symbol("const"); 10 8 const recordKey = Symbol("record"); 11 9 const blobKey = Symbol("blob"); ··· 66 64 67 65 export function getMinGraphemes(program: Program, target: Type): number | undefined { 68 66 return program.stateMap(minGraphemesKey).get(target); 69 - } 70 - 71 - /** 72 - * @blobAccept decorator for blob accept types 73 - */ 74 - export function $blobAccept(context: DecoratorContext, target: Type, types: Type) { 75 - const typesAny = types as any; 76 - 77 - if (Array.isArray(typesAny)) { 78 - context.program.stateMap(blobAcceptKey).set(target, typesAny); 79 - } else if (typesAny.kind === "Tuple" && typesAny.values) { 80 - const stringValues = typesAny.values.map((v: any) => v.value || v); 81 - context.program.stateMap(blobAcceptKey).set(target, stringValues); 82 - } else if (typesAny.values && Array.isArray(typesAny.values)) { 83 - const stringValues = typesAny.values.map((v: any) => { 84 - if (typeof v === 'string') return v; 85 - if (v.value) return v.value; 86 - return String(v); 87 - }); 88 - context.program.stateMap(blobAcceptKey).set(target, stringValues); 89 - } 90 - } 91 - 92 - export function getBlobAccept(program: Program, target: Type): string[] | undefined { 93 - return program.stateMap(blobAcceptKey).get(target); 94 - } 95 - 96 - /** 97 - * @blobMaxSize decorator for blob max size 98 - */ 99 - export function $blobMaxSize(context: DecoratorContext, target: Type, size: Type) { 100 - const numValue = (size as any).kind === "Number" || (size as any).kind === "Numeric" ? (size as any).value : size; 101 - context.program.stateMap(blobMaxSizeKey).set(target, Number(numValue)); 102 - } 103 - 104 - export function getBlobMaxSize(program: Program, target: Type): number | undefined { 105 - return program.stateMap(blobMaxSizeKey).get(target); 106 67 } 107 68 108 69 /**
+2 -85
packages/emitter/src/emitter.ts
··· 33 33 getLexFormat, 34 34 getMaxGraphemes, 35 35 getMinGraphemes, 36 - getBlobAccept, 37 - getBlobMaxSize, 38 36 getLexConst, 39 37 getRecordKey, 40 38 isBlob, ··· 67 65 "language", 68 66 "atIdentifier", 69 67 "bytes", 70 - "utcDateTime", 71 - "offsetDateTime", 72 - "plainDate", 73 - "plainTime", 74 68 ]); 75 69 76 70 const FORMAT_MAP: Record<string, string> = { ··· 85 79 uri: "uri", 86 80 language: "language", 87 81 atIdentifier: "at-identifier", 88 - utcDateTime: "datetime", 89 - offsetDateTime: "datetime", 90 - plainDate: "datetime", 91 - plainTime: "datetime", 92 82 }; 93 83 94 84 export class TlexEmitter { ··· 389 379 .filter((v: string | null) => v !== null) as string[]; 390 380 if (!acceptTypes.length) acceptTypes = undefined; 391 381 } 392 - } else if (acceptArg && Array.isArray(acceptArg.value)) { 393 - const values = acceptArg.value.filter( 394 - (v: any) => typeof v === "string", 395 - ); 396 - if (values.length) acceptTypes = values; 397 382 } 398 383 399 384 if (acceptTypes) blobDef.accept = acceptTypes; ··· 835 820 const propDesc = prop ? getDoc(this.program, prop) : undefined; 836 821 837 822 switch (type.kind) { 838 - case "Namespace": 839 - return this.handleNamespaceType(type as any, propDesc); 840 - case "Enum": 841 - return this.handleEnumType(type as any, propDesc); 842 - case "Boolean": 843 - return this.handleBooleanType(type as any, propDesc); 844 823 case "Scalar": 845 824 return this.handleScalarType(type as Scalar, prop, propDesc); 846 825 case "Model": ··· 855 834 } 856 835 } 857 836 858 - private handleNamespaceType( 859 - ns: any, 860 - propDesc?: string, 861 - ): LexiconDefinition | null { 862 - const mainModel = ns.models?.get("Main"); 863 - if (mainModel) { 864 - const ref = this.getModelReference(mainModel); 865 - if (ref) { 866 - return this.addDescription({ type: "ref", ref }, propDesc); 867 - } 868 - } 869 - return null; 870 - } 871 - 872 - private handleEnumType( 873 - enumType: any, 874 - propDesc?: string, 875 - ): LexiconDefinition | null { 876 - const members = Array.from(enumType.members?.values?.() || []); 877 - 878 - if (members.length === 0) { 879 - // TODO: Should we error on empty enum? 880 - return null; 881 - } 882 - 883 - const values = members.map((m: any) => m.value); 884 - const firstValue = values[0]; 885 - 886 - if (typeof firstValue === "string") { 887 - return this.addDescription({ type: "string", enum: values }, propDesc); 888 - } else if (typeof firstValue === "number" && Number.isInteger(firstValue)) { 889 - return this.addDescription({ type: "integer", enum: values }, propDesc); 890 - } 891 - 892 - // TODO: Handle mixed-type enums or float enums 893 - return null; 894 - } 895 - 896 - private handleBooleanType( 897 - boolType: any, 898 - propDesc?: string, 899 - ): LexiconDefinition { 900 - return this.addDescription( 901 - { type: "boolean", const: boolType.value }, 902 - propDesc, 903 - ); 904 - } 905 - 906 837 private handleScalarType( 907 838 scalar: Scalar, 908 839 prop?: ModelProperty, ··· 988 919 scalar: Scalar, 989 920 prop?: ModelProperty, 990 921 ): LexiconDefinition | null { 991 - // Special case: bytes type can be either blob or bytes depending on decorators 922 + // Special case: bytes type 992 923 if (scalar.name === "bytes") { 993 - return this.handleBytesScalar(prop); 924 + return { type: "bytes" }; 994 925 } 995 926 996 927 // Determine base primitive type ··· 1011 942 } 1012 943 1013 944 return primitive; 1014 - } 1015 - 1016 - private handleBytesScalar(prop?: ModelProperty): LexiconDefinition { 1017 - if (prop) { 1018 - const accept = getBlobAccept(this.program, prop); 1019 - const maxSize = getBlobMaxSize(this.program, prop); 1020 - if (accept || maxSize !== undefined) { 1021 - const blobDef: LexiconBlob = { type: "blob" }; 1022 - if (accept) blobDef.accept = accept; 1023 - if (maxSize !== undefined) blobDef.maxSize = maxSize; 1024 - return blobDef; 1025 - } 1026 - } 1027 - return { type: "bytes" }; 1028 945 } 1029 946 1030 947 private getBasePrimitiveType(scalar: Scalar): any {
-2
packages/emitter/src/index.ts
··· 21 21 $lexFormat, 22 22 $maxGraphemes, 23 23 $minGraphemes, 24 - $blobAccept, 25 - $blobMaxSize, 26 24 $lexConst, 27 25 $record, 28 26 $blob,