-
Alexander Rose authoredAlexander Rose authored
symbol.ts 3.37 KiB
/*
* Copyright (c) 2018 Mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Type } from './type';
import { Expression } from './expression';
export type Argument<T extends Type = Type> = {
type: T,
isOptional: boolean,
isRest: boolean,
defaultValue: T['@type'] | undefined,
description: string | undefined
}
export function Argument<T extends Type>(type: T, params?: { description?: string, defaultValue?: T['@type'], isOptional?: boolean, isRest?: boolean }): Argument<T> {
const { description = void 0, isOptional = false, isRest = false, defaultValue = void 0 } = params || {};
return { type, isOptional, isRest, defaultValue, description };
}
export type Arguments<T extends { [key: string]: any } = {}> =
| Arguments.List<T>
| Arguments.Dictionary<T>
export namespace Arguments {
export const None: Arguments = Dictionary({});
export interface Dictionary<T extends { [key: string]: any } = {}, Traits = {}> {
kind: 'dictionary',
map: { [P in keyof T]: Argument<T[P]> },
'@type': T
}
export type PropTypes<Map extends { [key: string]: Argument<any> }> = { [P in keyof Map]: Map[P]['type']['@type'] }
export function Dictionary<Map extends { [key: string]: Argument<any> }>(map: Map): Arguments<PropTypes<Map>> {
return { kind: 'dictionary', map, '@type': 0 as any };
}
export interface List<T extends { [key: string]: any } = {}, Traits = {}> {
kind: 'list',
type: Type,
nonEmpty: boolean,
'@type': T
}
export function List<T extends Type>(type: T, params?: { nonEmpty?: boolean }): Arguments<{ [key: string]: T['@type'] }> {
const { nonEmpty = false } = params || { };
return { kind: 'list', type, nonEmpty, '@type': 0 as any };
}
}
export type ExpressionArguments<T> = { [P in keyof T]?: Expression } | { [index: number]: Expression }
export interface MSymbol<A extends Arguments = Arguments, T extends Type = Type> {
(args?: ExpressionArguments<A['@type']>): Expression,
info: {
namespace: string,
name: string,
description?: string
},
args: A
type: T,
id: string,
}
export function MSymbol<A extends Arguments, T extends Type>(name: string, args: A, type: T, description?: string) {
const symbol: MSymbol<A, T> = function (args: ExpressionArguments<A['@type']>) {
return Expression.Apply(Expression.Symbol(symbol.id), args as any);
} as any;
symbol.info = { namespace: '', name, description };
symbol.id = '';
symbol.args = args;
symbol.type = type;
return symbol;
}
export function CustomPropSymbol<T extends Type>(namespace: string, name: string, type: T, description?: string) {
const symbol: MSymbol<Arguments<{}>, T> = function (args: ExpressionArguments<Arguments<{}>['@type']>) {
return Expression.Apply(Expression.Symbol(symbol.id), args as any);
} as any;
symbol.info = { namespace, name, description };
symbol.id = `${namespace}.${name}`;
symbol.args = Arguments.None;
symbol.type = type;
return symbol;
}
export function isSymbol(x: any): x is MSymbol {
const s = x as MSymbol;
return typeof s === 'function' && !!s.info && !!s.args && typeof s.info.namespace === 'string' && !!s.type;
}
export type SymbolMap = { [id: string]: MSymbol | undefined }