preserves/implementations/javascript/packages/schema/src/compiler/rendertype.ts

78 lines
2.9 KiB
TypeScript

import { SimpleType, Type } from "./type";
import { anglebrackets, braces, Item, keyvalue, opseq, seq } from "./block";
import { ModuleContext } from "./context";
export function variantInitFor(variantName: string | undefined) : Item[] {
return variantName === void 0 ? [] : [variantFor(variantName)];
}
export function variantFor(variantName: string): Item {
return keyvalue('_variant', JSON.stringify(variantName));
}
function simpleTypeFields(ctxt: ModuleContext, t: SimpleType): Item[] {
switch (t.kind) {
case 'unit':
return [];
case 'ref':
case 'set':
case 'dictionary':
case 'array':
return [keyvalue('value', renderType(ctxt, t))];
case 'record':
return Array.from(t.fields).map(([nn, tt]) => keyvalue(nn, renderType(ctxt, tt)));
default:
((_: never) => {})(t);
throw new Error("Unreachable");
}
}
export function renderVariant(
ctxt: ModuleContext,
[variantName, t]: [string, SimpleType],
): Item {
let fields = simpleTypeFields(ctxt, t);
return braces(variantFor(variantName), ... fields);
}
export function renderType(ctxt: ModuleContext, t: Type): Item {
switch (t.kind) {
case 'union': return opseq('never', ' | ', ...
Array.from(t.variants).flatMap(entry => renderVariant(ctxt, entry)));
case 'unit': return braces(... simpleTypeFields(ctxt, t));
case 'ref':
if (t.ref === null && t.typeName === '_embedded') {
return t.typeName;
} else {
return seq(t.typeName, ctxt.genericArgsFor(t));
}
case 'set': return seq('_.EncodableSet', anglebrackets(
renderType(ctxt, t.type),
'_embedded'));
case 'dictionary': return seq('_.EncodableDictionary', anglebrackets(
renderType(ctxt, t.key),
renderType(ctxt, t.value),
'_embedded'));
case 'array': return seq('Array', anglebrackets(renderType(ctxt, t.type)));
case 'record': return braces(... simpleTypeFields(ctxt, t));
default:
((_: never) => {})(t);
throw new Error("Unreachable");
}
}
export function renderTypeWithConversionMixins(ctxt: ModuleContext, t: Type): Item {
if (t.kind === 'unit' || t.kind === 'record' || t.kind === 'union') {
return opseq('any', ' & ',
renderType(ctxt, t),
seq('_.Preservable', ctxt.hasEmbedded(t) ? ctxt.genericArgs() : '<any>'),
seq('_.PreserveWritable', ctxt.hasEmbedded(t) ? ctxt.genericArgs() : '<any>'),
braces(seq('__as_preserve__',
ctxt.hasEmbedded(t) ? '' : ctxt.genericParameters(),
'()',
': _.Value', ctxt.genericArgs())));
} else {
return renderType(ctxt, t);
}
}