import { isVmConst, VmError, type VmTypeName, type VmAny, type VmValue, type VmValueMap } from '@mirascript/mirascript'; import { convert, serializeForDisplay } from '@mirascript/mirascript/subtle'; import type { ArgumentValue } from './definitions.js'; /** 类型信息 */ export type TypeInfo = 'string' | 'number' | 'boolean'; const x: TypeInfo = 'boolean'; x satisfies VmTypeName; /** 类型映射 */ type TypeMap = VmValueMap & { s: string; f: number; b: boolean; '': VmValue; }; /** Ts 类型 */ export type TsTypeOf = T extends '' ? I : TypeMap[T]; /** 兼容的旧类型 */ export type LegacyType = 's' | 'f' | 'b'; /** 类型信息 */ export namespace TypeInfo { /** 解析类型 */ export function parse(type: TypeInfo | LegacyType): TypeInfo { if (type === 's' || type === 'string') return 'string'; if (type === 'f' || type === 'number') return 'number'; if (type === 'b' || type === 'boolean') return 'boolean'; throw new TypeError(`Invalid type '${String(type)}'`); } /** 判断类型 */ export function is(value: VmValue | undefined, type: T): value is TsTypeOf { switch (type) { case 'b': case 'boolean': return typeof value === 'boolean'; case 'f': case 'number': return typeof value === 'number'; case 's': case 'string': return typeof value === 'string'; default: (type) satisfies never; return false; } } /** 转换类型 */ export function to( value: I | undefined, type: T, fallback?: F, ): TsTypeOf | Exclude { const c = converter(type); return (c as typeof convert.toNumber)(value, fallback) as TsTypeOf; } /** 检查是否为 ArgumentValue */ function assertArgumentValue(value: VmAny, fallback?: F): ArgumentValue | Exclude { if (value != null && isVmConst(value)) return value; if (fallback === undefined) { throw new VmError(`Value is not ArgumentValue: ${serializeForDisplay(value)}`, undefined); } return fallback as Exclude; } /** 获取转换器 */ type Converters = { string: typeof convert.toString; s: typeof convert.toString; number: typeof convert.toNumber; f: typeof convert.toNumber; boolean: typeof convert.toBoolean; b: typeof convert.toBoolean; '': typeof assertArgumentValue; }; /** 获取转换器 */ export function converter(type: T): Converters[T] { // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check switch (type) { case 'b': case 'boolean': return toBoolean as Converters[T]; case 'f': case 'number': return toNumber as Converters[T]; case 's': case 'string': return toString as Converters[T]; default: (type) satisfies ''; return assertArgumentValue as Converters[T]; } } export const { toBoolean, toFormat, toNumber, toString } = convert; }