diff --git a/packages/sql/src/platform/default-platform.ts b/packages/sql/src/platform/default-platform.ts index 27b6cc65e..dba8a5271 100644 --- a/packages/sql/src/platform/default-platform.ts +++ b/packages/sql/src/platform/default-platform.ts @@ -336,7 +336,7 @@ export abstract class DefaultPlatform { column.defaultValue = dbOptions.default; } else if (dbOptions.defaultExpr) { column.defaultExpression = dbOptions.defaultExpr; - } else if (!dbOptions.noDefault && !property.hasDefaultFunctionExpression()) { + } else if (!dbOptions.noDefault && !property.hasDynamicExpression()) { column.defaultValue = property.getDefaultValue(); } } diff --git a/packages/type/src/reflection/reflection.ts b/packages/type/src/reflection/reflection.ts index a522cc16d..4a8a09473 100644 --- a/packages/type/src/reflection/reflection.ts +++ b/packages/type/src/reflection/reflection.ts @@ -7,19 +7,49 @@ * * You should have received a copy of the MIT License along with this program. */ +import { + AbstractClassType, + ClassType, + arrayRemoveItem, + getClassName, + isArray, + isClass, + isPrototypeOfBase, + stringifyValueWithType, +} from '@deepkit/core'; +import { isWithDeferredDecorators } from '../decorator.js'; +import { findCommonLiteral } from '../inheritance.js'; +import { SerializedTypes, serializeType } from '../type-serialization.js'; +import { NoTypeReceived } from '../utils.js'; +import type { ValidateFunction } from '../validator.js'; +import { Packed, resolvePacked, resolveRuntimeType } from './processor.js'; import { + BackReferenceOptionsResolved, + DatabaseFieldOptions, + EntityOptions, + IndexOptions, + ReferenceOptions, + ReflectionKind, + ReflectionVisibility, + Type, + TypeClass, + TypeFunction, + TypeMethod, + TypeMethodSignature, + TypeObjectLiteral, + TypeParameter, + TypeProperty, + TypePropertySignature, + TypeTemplateLiteral, assertType, autoIncrementAnnotation, - BackReferenceOptionsResolved, clearTypeJitContainer, copyAndSetParent, dataAnnotation, databaseAnnotation, - DatabaseFieldOptions, embeddedAnnotation, entityAnnotation, - EntityOptions, excludedAnnotation, getBackReferenceType, getClassType, @@ -28,35 +58,14 @@ import { groupAnnotation, hasMember, indexAnnotation, - IndexOptions, isBackReferenceType, isReferenceType, isType, memberNameToString, primaryKeyAnnotation, - ReferenceOptions, - ReflectionKind, - ReflectionVisibility, stringifyResolvedType, stringifyType, - Type, - TypeClass, - TypeFunction, - TypeMethod, - TypeMethodSignature, - TypeObjectLiteral, - TypeParameter, - TypeProperty, - TypePropertySignature, - TypeTemplateLiteral, } from './type.js'; -import { AbstractClassType, arrayRemoveItem, ClassType, getClassName, isArray, isClass, isPrototypeOfBase, stringifyValueWithType } from '@deepkit/core'; -import { Packed, resolvePacked, resolveRuntimeType } from './processor.js'; -import { NoTypeReceived } from '../utils.js'; -import { findCommonLiteral } from '../inheritance.js'; -import type { ValidateFunction } from '../validator.js'; -import { isWithDeferredDecorators } from '../decorator.js'; -import { SerializedTypes, serializeType } from '../type-serialization.js'; /** * Receives the runtime type of template argument. @@ -95,7 +104,11 @@ export function resolveReceiveType(type?: Packed | Type | ClassType | AbstractCl if (!('__type' in type)) { if ((type as any).__cached_type) return (type as any).__cached_type; // disabled reflection for this class, so we return empty TypeClass - return (type as any).__cached_type = { kind: ReflectionKind.class, classType: type as any, types: [] } as any; + return ((type as any).__cached_type = { + kind: ReflectionKind.class, + classType: type as any, + types: [], + } as any); } return resolveRuntimeType(type) as Type; } @@ -182,14 +195,23 @@ export function removeNominal(type: T): T { return type; } -export function getProperty(type: TypeObjectLiteral | TypeClass, memberName: number | string | symbol): TypeProperty | TypePropertySignature | undefined { +export function getProperty( + type: TypeObjectLiteral | TypeClass, + memberName: number | string | symbol, +): TypeProperty | TypePropertySignature | undefined { for (const t of type.types) { - if ((t.kind === ReflectionKind.property || t.kind === ReflectionKind.propertySignature) && t.name === memberName) return t; + if ( + (t.kind === ReflectionKind.property || t.kind === ReflectionKind.propertySignature) && + t.name === memberName + ) + return t; } return; } -export function toSignature(type: TypeProperty | TypeMethod | TypePropertySignature | TypeMethodSignature): TypePropertySignature | TypeMethodSignature { +export function toSignature( + type: TypeProperty | TypeMethod | TypePropertySignature | TypeMethodSignature, +): TypePropertySignature | TypeMethodSignature { if (type.kind === ReflectionKind.propertySignature || type.kind === ReflectionKind.methodSignature) return type; if (type.kind === ReflectionKind.property) { return { ...type, parent: type.parent as any, kind: ReflectionKind.propertySignature }; @@ -203,11 +225,15 @@ export function hasCircularReference(type: Type) { if (jit.hasCircularReference !== undefined) return jit.hasCircularReference; let hasCircular = false; - visit(type, () => undefined, () => { - hasCircular = true; - }); - - return jit.hasCircularReference = hasCircular; + visit( + type, + () => undefined, + () => { + hasCircular = true; + }, + ); + + return (jit.hasCircularReference = hasCircular); } let visitStackId: number = 0; @@ -223,7 +249,7 @@ function extendPath(path: string, member: Type): string { } export function visit(type: Type, visitor: (type: Type, path: string) => false | void, onCircular?: () => void): void { - const stack: { type: Type, depth: number, path: string }[] = []; + const stack: { type: Type; depth: number; path: string }[] = []; stack.push({ type, depth: 0, path: '' }); const stackId: number = visitStackId++; @@ -247,7 +273,8 @@ export function visit(type: Type, visitor: (type: Type, path: string) => false | case ReflectionKind.class: case ReflectionKind.intersection: case ReflectionKind.templateLiteral: - for (const member of type.types) stack.push({ type: member, depth: entry.depth + 1, path: extendPath(entry.path, member) }); + for (const member of type.types) + stack.push({ type: member, depth: entry.depth + 1, path: extendPath(entry.path, member) }); break; case ReflectionKind.string: case ReflectionKind.number: @@ -261,7 +288,8 @@ export function visit(type: Type, visitor: (type: Type, path: string) => false | case ReflectionKind.method: case ReflectionKind.methodSignature: stack.push({ type: type.return, depth: entry.depth + 1, path: entry.path }); - for (const member of type.parameters) stack.push({ type: member, depth: entry.depth + 1, path: extendPath(entry.path, member) }); + for (const member of type.parameters) + stack.push({ type: member, depth: entry.depth + 1, path: extendPath(entry.path, member) }); break; case ReflectionKind.propertySignature: case ReflectionKind.property: @@ -280,7 +308,7 @@ export function visit(type: Type, visitor: (type: Type, path: string) => false | } } -function hasFunctionExpression(fn: Function): boolean { +function isDynamicExpression(fn: Function): boolean { let code = fn.toString(); if (code.startsWith('() => ')) code = code.slice('() => '.length); if (code.startsWith('function () { return ')) { @@ -291,7 +319,8 @@ function hasFunctionExpression(fn: Function): boolean { code = code.slice('function() { return '.length); if (code.endsWith('; }')) code = code.slice(0, -3); } - if (code[0] === '\'' && code[code.length - 1] === '\'') return false; + if (code.startsWith('new ')) return true; + if (code[0] === "'" && code[code.length - 1] === "'") return false; if (code[0] === '"' && code[code.length - 1] === '"') return false; if (code[0] === '`' && code[code.length - 1] === '`') return false; return code.includes('('); @@ -342,8 +371,8 @@ export class ReflectionParameter { } } - hasDefaultFunctionExpression(): boolean { - return !!(this.parameter.default && hasFunctionExpression(this.parameter.default)); + hasDynamicExpression(): boolean { + return !!(this.parameter.default && isDynamicExpression(this.parameter.default)); } applyDecorator(t: TData) { @@ -379,9 +408,7 @@ export class ReflectionFunction { parameters: ReflectionParameter[] = []; description: string = ''; - constructor( - public readonly type: TypeMethod | TypeMethodSignature | TypeFunction, - ) { + constructor(public readonly type: TypeMethod | TypeMethodSignature | TypeFunction) { for (const p of this.type.parameters) { this.parameters.push(new ReflectionParameter(p, this)); } @@ -393,7 +420,12 @@ export class ReflectionFunction { if (!('__type' in fn)) { //functions without any types have no __type attached - return new ReflectionFunction({ kind: ReflectionKind.function, function: fn, return: { kind: ReflectionKind.any }, parameters: [] }); + return new ReflectionFunction({ + kind: ReflectionKind.function, + function: fn, + return: { kind: ReflectionKind.any }, + parameters: [], + }); } const type = reflect(fn); @@ -403,7 +435,7 @@ export class ReflectionFunction { return new ReflectionFunction(type); } - getParameterNames(): (string)[] { + getParameterNames(): string[] { return this.getParameters().map(v => v.getName()); } @@ -588,7 +620,10 @@ export class ReflectionProperty { } isDatabaseMigrationSkipped(database: string): boolean { - return this.isDatabaseSkipped(database) || databaseAnnotation.getDatabase(this.getType(), database)?.skipMigration === true; + return ( + this.isDatabaseSkipped(database) || + databaseAnnotation.getDatabase(this.getType(), database)?.skipMigration === true + ); } getBackReference(): BackReferenceOptionsResolved { @@ -650,7 +685,9 @@ export class ReflectionProperty { */ getResolvedReflectionClass(): ReflectionClass { if (this.type.kind !== ReflectionKind.class && this.type.kind !== ReflectionKind.objectLiteral) { - throw new Error(`Could not resolve reflection class since ${this.name} is not a class|object but of type ${stringifyType(this.type)}`); + throw new Error( + `Could not resolve reflection class since ${this.name} is not a class|object but of type ${stringifyType(this.type)}`, + ); } return resolveClassType(this.getType()); } @@ -681,7 +718,10 @@ export class ReflectionProperty { } clone(reflectionClass?: ReflectionClass, property?: TypeProperty | TypePropertySignature): ReflectionProperty { - const c = new ReflectionProperty(copyAndSetParent(property || this.property), reflectionClass || this.reflectionClass); + const c = new ReflectionProperty( + copyAndSetParent(property || this.property), + reflectionClass || this.reflectionClass, + ); c.jsonType = this.jsonType; c.serializer = this.serializer; c.deserializer = this.deserializer; @@ -743,7 +783,10 @@ export class ReflectionProperty { * If the property is actual optional or is an union with undefined in it. */ isOptional(): boolean { - return this.property.optional === true || (this.type.kind === ReflectionKind.union && this.type.types.some(v => v.kind === ReflectionKind.undefined)); + return ( + this.property.optional === true || + (this.type.kind === ReflectionKind.union && this.type.types.some(v => v.kind === ReflectionKind.undefined)) + ); } setOptional(v: boolean): void { @@ -751,7 +794,7 @@ export class ReflectionProperty { } isNullable(): boolean { - return (this.type.kind === ReflectionKind.union && this.type.types.some(v => v.kind === ReflectionKind.null)); + return this.type.kind === ReflectionKind.union && this.type.types.some(v => v.kind === ReflectionKind.null); } isReadonly(): boolean { @@ -776,8 +819,12 @@ export class ReflectionProperty { } } - hasDefaultFunctionExpression(): boolean { - return this.property.kind === ReflectionKind.property && !!this.property.default && hasFunctionExpression(this.property.default); + hasDynamicExpression(): boolean { + return ( + this.property.kind === ReflectionKind.property && + !!this.property.default && + isDynamicExpression(this.property.default) + ); } getDefaultValueFunction(): (() => any) | undefined { @@ -792,15 +839,21 @@ export class ReflectionProperty { } isPublic(): boolean { - return this.property.kind === ReflectionKind.property ? this.property.visibility === ReflectionVisibility.public : true; + return this.property.kind === ReflectionKind.property + ? this.property.visibility === ReflectionVisibility.public + : true; } isProtected(): boolean { - return this.property.kind === ReflectionKind.property ? this.property.visibility === ReflectionVisibility.protected : false; + return this.property.kind === ReflectionKind.property + ? this.property.visibility === ReflectionVisibility.protected + : false; } isPrivate(): boolean { - return this.property.kind === ReflectionKind.property ? this.property.visibility === ReflectionVisibility.private : false; + return this.property.kind === ReflectionKind.property + ? this.property.visibility === ReflectionVisibility.private + : false; } } @@ -825,7 +878,7 @@ export class EntityData { databaseSchemaName?: string; disableConstructor: boolean = false; data: { [name: string]: any } = {}; - indexes: { names: string[], options: IndexOptions }[] = []; + indexes: { names: string[]; options: IndexOptions }[] = []; singleTableInheritance?: true; } @@ -834,7 +887,8 @@ function applyEntityOptions(reflection: ReflectionClass, entityOptions: Ent if (entityOptions.description !== undefined) reflection.description = entityOptions.description; if (entityOptions.collection !== undefined) reflection.collectionName = entityOptions.collection; if (entityOptions.database !== undefined) reflection.databaseSchemaName = entityOptions.database; - if (entityOptions.singleTableInheritance !== undefined) reflection.singleTableInheritance = entityOptions.singleTableInheritance; + if (entityOptions.singleTableInheritance !== undefined) + reflection.singleTableInheritance = entityOptions.singleTableInheritance; if (entityOptions.indexes !== undefined) reflection.indexes = entityOptions.indexes; } @@ -902,7 +956,7 @@ export class ReflectionClass { * } * ``` */ - indexes: { names: string[], options: IndexOptions }[] = []; + indexes: { names: string[]; options: IndexOptions }[] = []; protected propertyNames: string[] = []; protected methodNames: string[] = []; @@ -928,8 +982,12 @@ export class ReflectionClass { */ public subClasses: ReflectionClass[] = []; - constructor(public readonly type: TypeClass | TypeObjectLiteral, public readonly parent?: ReflectionClass) { - if (type.kind !== ReflectionKind.class && type.kind !== ReflectionKind.objectLiteral) throw new Error('Only class, interface, or object literal type possible'); + constructor( + public readonly type: TypeClass | TypeObjectLiteral, + public readonly parent?: ReflectionClass, + ) { + if (type.kind !== ReflectionKind.class && type.kind !== ReflectionKind.objectLiteral) + throw new Error('Only class, interface, or object literal type possible'); if (parent) { this.name = parent.name; @@ -968,7 +1026,6 @@ export class ReflectionClass { const reflectionMethod = this.getMethodOrUndefined(property); if (reflectionMethod) reflectionMethod.applyDecorator(data); - } else if (parameterIndexOrDescriptor !== undefined) { const reflectionMethod = this.getMethodOrUndefined(property || 'constructor'); if (reflectionMethod) { @@ -1019,12 +1076,14 @@ export class ReflectionClass { } getClassName(): string { - return this.type.kind === ReflectionKind.class ? this.type.typeName || getClassName(this.getClassType()) : this.type.typeName || 'Object'; + return this.type.kind === ReflectionKind.class + ? this.type.typeName || getClassName(this.getClassType()) + : this.type.typeName || 'Object'; } createDefaultObject(): object { try { - return new (this.getClassType()); + return new (this.getClassType())(); } catch { return {}; } @@ -1087,7 +1146,9 @@ export class ReflectionClass { const stringName = memberNameToString(name); arrayRemoveItem(this.propertyNames, stringName); - const indexType = this.type.types.findIndex(v => (v.kind === ReflectionKind.property || v.kind === ReflectionKind.propertySignature) && v.name === name); + const indexType = this.type.types.findIndex( + v => (v.kind === ReflectionKind.property || v.kind === ReflectionKind.propertySignature) && v.name === name, + ); if (indexType !== -1) this.type.types.splice(indexType, 1); arrayRemoveItem(this.properties, property); @@ -1138,7 +1199,7 @@ export class ReflectionClass { optional?: true; readonly?: true; description?: string; - visibility?: ReflectionVisibility + visibility?: ReflectionVisibility; type: Type; }): ReflectionProperty { const type = { @@ -1187,7 +1248,8 @@ export class ReflectionClass { getAssignedSingleTableInheritanceSubClassesByIdentifier(): { [id: string]: ReflectionClass } | undefined { if (!this.subClasses.length) return; - if (this.assignedSingleTableInheritanceSubClassesByIdentifier) return this.assignedSingleTableInheritanceSubClassesByIdentifier; + if (this.assignedSingleTableInheritanceSubClassesByIdentifier) + return this.assignedSingleTableInheritanceSubClassesByIdentifier; let isBaseOfSingleTableEntity = false; for (const schema of this.subClasses) { @@ -1203,7 +1265,8 @@ export class ReflectionClass { for (const schema of this.subClasses) { if (schema.singleTableInheritance) { - if (!this.assignedSingleTableInheritanceSubClassesByIdentifier) this.assignedSingleTableInheritanceSubClassesByIdentifier = {}; + if (!this.assignedSingleTableInheritanceSubClassesByIdentifier) + this.assignedSingleTableInheritanceSubClassesByIdentifier = {}; const property = schema.getProperty(discriminant); assertType(property.type, ReflectionKind.literal); this.assignedSingleTableInheritanceSubClassesByIdentifier[property.type.literal as string] = schema; @@ -1218,14 +1281,15 @@ export class ReflectionClass { getSingleTableInheritanceDiscriminantName(): string { if (!this.data.singleTableInheritanceProperty) { - // let discriminant = findCommonDiscriminant(this.subClasses); //when no discriminator was found, find a common literal const discriminant = findCommonLiteral(this.subClasses); if (!discriminant) { - throw new Error(`Sub classes of ${this.getClassName()} single-table inheritance [${this.subClasses.map(v => v.getClassName())}] have no common discriminant or common literal. Please define one.`); + throw new Error( + `Sub classes of ${this.getClassName()} single-table inheritance [${this.subClasses.map(v => v.getClassName())}] have no common discriminant or common literal. Please define one.`, + ); } this.data.singleTableInheritanceProperty = this.getProperty(discriminant); } @@ -1251,21 +1315,32 @@ export class ReflectionClass { } } - static from(classTypeIn?: ReceiveType | AbstractClassType | TypeClass | TypeObjectLiteral | ReflectionClass, args: any[] = []): ReflectionClass { + static from( + classTypeIn?: ReceiveType | AbstractClassType | TypeClass | TypeObjectLiteral | ReflectionClass, + args: any[] = [], + ): ReflectionClass { if (!classTypeIn) throw new Error(`No type given in ReflectionClass.from`); if (isArray(classTypeIn)) classTypeIn = resolveReceiveType(classTypeIn); if (classTypeIn instanceof ReflectionClass) return classTypeIn; if (isType(classTypeIn)) { - if (classTypeIn.kind === ReflectionKind.objectLiteral || (classTypeIn.kind === ReflectionKind.class && classTypeIn.typeArguments)) { + if ( + classTypeIn.kind === ReflectionKind.objectLiteral || + (classTypeIn.kind === ReflectionKind.class && classTypeIn.typeArguments) + ) { const jit = getTypeJitContainer(classTypeIn); if (jit.reflectionClass) return jit.reflectionClass; - return jit.reflectionClass = new ReflectionClass(classTypeIn); + return (jit.reflectionClass = new ReflectionClass(classTypeIn)); } - if (classTypeIn.kind !== ReflectionKind.class) throw new Error(`TypeClass or TypeObjectLiteral expected, not ${ReflectionKind[classTypeIn.kind]}`); + if (classTypeIn.kind !== ReflectionKind.class) + throw new Error(`TypeClass or TypeObjectLiteral expected, not ${ReflectionKind[classTypeIn.kind]}`); } - const classType = isType(classTypeIn) ? (classTypeIn as TypeClass).classType : (classTypeIn as any)['prototype'] ? classTypeIn as ClassType : classTypeIn.constructor as ClassType; + const classType = isType(classTypeIn) + ? (classTypeIn as TypeClass).classType + : (classTypeIn as any)['prototype'] + ? (classTypeIn as ClassType) + : (classTypeIn.constructor as ClassType); if (!classType.prototype.hasOwnProperty(reflectionClassSymbol)) { Object.defineProperty(classType.prototype, reflectionClassSymbol, { writable: true, enumerable: false }); @@ -1275,18 +1350,27 @@ export class ReflectionClass { return classType.prototype[reflectionClassSymbol]; } - const type = isType(classTypeIn) ? classTypeIn as TypeClass : ('__type' in classType ? resolveRuntimeType(classType, args) : { - kind: ReflectionKind.class, - classType, - types: [], - } as TypeClass); + const type = isType(classTypeIn) + ? (classTypeIn as TypeClass) + : '__type' in classType + ? resolveRuntimeType(classType, args) + : ({ + kind: ReflectionKind.class, + classType, + types: [], + } as TypeClass); if (type.kind !== ReflectionKind.class) { - throw new Error(`Given class is not a class but kind ${ReflectionKind[type.kind]}. classType: ${stringifyValueWithType(classType)}`); + throw new Error( + `Given class is not a class but kind ${ReflectionKind[type.kind]}. classType: ${stringifyValueWithType(classType)}`, + ); } const parentProto = Object.getPrototypeOf(classType.prototype); - const parentReflectionClass: ReflectionClass | undefined = parentProto && parentProto.constructor !== Object ? ReflectionClass.from(parentProto, type.extendsArguments) : undefined; + const parentReflectionClass: ReflectionClass | undefined = + parentProto && parentProto.constructor !== Object + ? ReflectionClass.from(parentProto, type.extendsArguments) + : undefined; const reflectionClass = new ReflectionClass(type, parentReflectionClass); if (args.length === 0) { @@ -1407,7 +1491,11 @@ export class ReflectionClass { continue; } - if (fromReference.isBackReference() && fromReference.getBackReference().mappedBy && !fromReference.getBackReference().via) { + if ( + fromReference.isBackReference() && + fromReference.getBackReference().mappedBy && + !fromReference.getBackReference().via + ) { if (fromReference.getBackReference().mappedBy === backRef.name) { //perfect match return backRef; @@ -1416,7 +1504,12 @@ export class ReflectionClass { } //add to candidates if possible - if (fromReference.isBackReference() && fromReference.getBackReference().via && backRef.isBackReference() && backRef.getBackReference().via) { + if ( + fromReference.isBackReference() && + fromReference.getBackReference().via && + backRef.isBackReference() && + backRef.getBackReference().via + ) { if (fromReference.getBackReference().via === backRef.getBackReference().via) { candidates.push(backRef); } @@ -1432,8 +1525,10 @@ export class ReflectionClass { } if (candidates.length > 1) { - throw new Error(`Class ${this.getClassName()} has multiple potential reverse references [${candidates.map(v => v.name).join(', ')}] for ${fromReference.name} to class ${getClassName(toClassType)}. ` + - `Please specify each back reference by using 'mappedBy', e.g. @t.backReference({mappedBy: 'fieldNameOnTheOtherSide'} so its not ambiguous anymore.`); + throw new Error( + `Class ${this.getClassName()} has multiple potential reverse references [${candidates.map(v => v.name).join(', ')}] for ${fromReference.name} to class ${getClassName(toClassType)}. ` + + `Please specify each back reference by using 'mappedBy', e.g. @t.backReference({mappedBy: 'fieldNameOnTheOtherSide'} so its not ambiguous anymore.`, + ); } if (candidates.length === 1) return candidates[0]; @@ -1451,7 +1546,6 @@ export class ReflectionClass { } } - // old function to decorate an interface // export function decorate(decorate: { [P in keyof T]?: FreeDecoratorFn }, p?: ReceiveType): ReflectionClass { // const type = typeOf([], p); diff --git a/packages/type/tests/integration2.spec.ts b/packages/type/tests/integration2.spec.ts index eaecfe55f..21da26b20 100644 --- a/packages/type/tests/integration2.spec.ts +++ b/packages/type/tests/integration2.spec.ts @@ -7,39 +7,31 @@ * * You should have received a copy of the MIT License along with this program. */ +import { expect, test } from '@jest/globals'; import { ClassType } from '@deepkit/core'; -import { expect, test } from '@jest/globals'; +import { TypeNumberBrand } from '@deepkit/type-spec'; + import { entity, t } from '../src/decorator.js'; -import { propertiesOf, reflect, ReflectionClass, ReflectionFunction, ReflectionMethod, typeOf, valuesOf } from '../src/reflection/reflection.js'; +import { resolveRuntimeType } from '../src/reflection/processor.js'; +import { ReflectionClass, ReflectionFunction, ReflectionMethod, propertiesOf, reflect, typeOf, valuesOf } from '../src/reflection/reflection.js'; import { - annotateClass, - assertType, AutoIncrement, - autoIncrementAnnotation, BackReference, Data, - databaseAnnotation, - defaultAnnotation, Embedded, Entity, - entityAnnotation, Excluded, Group, Index, - integer, MapName, - metaAnnotation, MySQL, Postgres, PrimaryKey, - primaryKeyAnnotation, Reference, - referenceAnnotation, ReflectionKind, ReflectionVisibility, SQLite, - stringifyResolvedType, Type, TypeClass, TypeFunction, @@ -48,14 +40,23 @@ import { TypeNumber, TypeObjectLiteral, TypeTuple, - Unique + Unique, + annotateClass, + assertType, + autoIncrementAnnotation, + databaseAnnotation, + defaultAnnotation, + entityAnnotation, + integer, + metaAnnotation, + primaryKeyAnnotation, + referenceAnnotation, + stringifyResolvedType, } from '../src/reflection/type.js'; -import { TypeNumberBrand } from '@deepkit/type-spec'; -import { validate, ValidatorError } from '../src/validator.js'; -import { expectEqualType } from './utils.js'; -import { MyAlias } from './types.js'; -import { resolveRuntimeType } from '../src/reflection/processor.js'; import { uuid } from '../src/utils.js'; +import { ValidatorError, validate } from '../src/validator.js'; +import { MyAlias } from './types.js'; +import { expectEqualType } from './utils.js'; test('class', () => { class Entity { @@ -71,9 +72,9 @@ test('class', () => { kind: ReflectionKind.property, visibility: ReflectionVisibility.public, name: 'tags', - type: { kind: ReflectionKind.array, type: { kind: ReflectionKind.string } } - } - ] + type: { kind: ReflectionKind.array, type: { kind: ReflectionKind.string } }, + }, + ], }); }); @@ -92,9 +93,9 @@ test('class optional question mark', () => { visibility: ReflectionVisibility.public, name: 'title', optional: true, - type: { kind: ReflectionKind.string } - } - ] + type: { kind: ReflectionKind.string }, + }, + ], }); }); @@ -113,21 +114,19 @@ test('class optional union', () => { visibility: ReflectionVisibility.public, name: 'title', optional: true, - type: { kind: ReflectionKind.string } - } - ] + type: { kind: ReflectionKind.string }, + }, + ], }); }); test('class constructor', () => { class Entity1 { - constructor(title: string) { - } + constructor(title: string) {} } class Entity2 { - constructor(public title: string) { - } + constructor(public title: string) {} } expectEqualType(reflect(Entity1), { @@ -138,12 +137,10 @@ test('class constructor', () => { kind: ReflectionKind.method, visibility: ReflectionVisibility.public, name: 'constructor', - parameters: [ - { kind: ReflectionKind.parameter, name: 'title', type: { kind: ReflectionKind.string } } - ], - return: { kind: ReflectionKind.any } - } - ] + parameters: [{ kind: ReflectionKind.parameter, name: 'title', type: { kind: ReflectionKind.string } }], + return: { kind: ReflectionKind.any }, + }, + ], } as Type); expectEqualType(reflect(Entity2), { @@ -154,25 +151,22 @@ test('class constructor', () => { kind: ReflectionKind.method, visibility: ReflectionVisibility.public, name: 'constructor', - parameters: [ - { kind: ReflectionKind.parameter, name: 'title', visibility: ReflectionVisibility.public, type: { kind: ReflectionKind.string } } - ], - return: { kind: ReflectionKind.any } + parameters: [{ kind: ReflectionKind.parameter, name: 'title', visibility: ReflectionVisibility.public, type: { kind: ReflectionKind.string } }], + return: { kind: ReflectionKind.any }, }, { kind: ReflectionKind.property, visibility: ReflectionVisibility.public, name: 'title', - type: { kind: ReflectionKind.string } + type: { kind: ReflectionKind.string }, }, - ] + ], } as Type); }); test('class extends another', () => { class Class1 { - constructor(title: string) { - } + constructor(title: string) {} } class Class2 extends Class1 { @@ -189,8 +183,7 @@ test('class extends another', () => { test('class expression extends another', () => { class Class1 { - constructor(title: string) { - } + constructor(title: string) {} } const class2 = class extends Class1 { @@ -210,10 +203,8 @@ test('constructor type abstract', () => { expectEqualType(typeOf(), { kind: ReflectionKind.function, name: 'new', - parameters: [ - { kind: ReflectionKind.parameter, name: 'args', type: { kind: ReflectionKind.rest, type: { kind: ReflectionKind.any } } } - ], - return: { kind: ReflectionKind.any } + parameters: [{ kind: ReflectionKind.parameter, name: 'args', type: { kind: ReflectionKind.rest, type: { kind: ReflectionKind.any } } }], + return: { kind: ReflectionKind.any }, }); }); @@ -226,7 +217,7 @@ test('constructor type normal', () => { { kind: ReflectionKind.parameter, name: 'a', type: { kind: ReflectionKind.string } }, { kind: ReflectionKind.parameter, name: 'b', type: { kind: ReflectionKind.number } }, ], - return: { kind: ReflectionKind.void } + return: { kind: ReflectionKind.void }, } as TypeFunction); }); @@ -243,9 +234,9 @@ test('interface', () => { { kind: ReflectionKind.propertySignature, name: 'tags', - type: { kind: ReflectionKind.array, type: { kind: ReflectionKind.string } } - } - ] + type: { kind: ReflectionKind.array, type: { kind: ReflectionKind.string } }, + }, + ], }); }); @@ -254,9 +245,7 @@ test('tuple', () => { const type = typeOf<[string]>(); expectEqualType(type, { kind: ReflectionKind.tuple, - types: [ - { kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.string } } - ] + types: [{ kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.string } }], } as TypeTuple); } { @@ -265,8 +254,8 @@ test('tuple', () => { kind: ReflectionKind.tuple, types: [ { kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.string } }, - { kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.number } } - ] + { kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.number } }, + ], } as TypeTuple); } }); @@ -293,9 +282,7 @@ test('named tuple', () => { const type = typeOf<[title: string]>(); expectEqualType(type, { kind: ReflectionKind.tuple, - types: [ - { kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.string }, name: 'title' } - ] + types: [{ kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.string }, name: 'title' }], } as TypeTuple); } { @@ -304,8 +291,8 @@ test('named tuple', () => { kind: ReflectionKind.tuple, types: [ { kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.string }, name: 'title' }, - { kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.number }, name: 'prio' } - ] + { kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.number }, name: 'prio' }, + ], } as TypeTuple); } }); @@ -315,9 +302,7 @@ test('rest tuple', () => { const type = typeOf<[...string[]]>(); expectEqualType(type, { kind: ReflectionKind.tuple, - types: [ - { kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.rest, type: { kind: ReflectionKind.string } } } - ] + types: [{ kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.rest, type: { kind: ReflectionKind.string } } }], } as TypeTuple); } { @@ -326,8 +311,8 @@ test('rest tuple', () => { kind: ReflectionKind.tuple, types: [ { kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.rest, type: { kind: ReflectionKind.string } } }, - { kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.number } } - ] + { kind: ReflectionKind.tupleMember, type: { kind: ReflectionKind.number } }, + ], } as TypeTuple); } }); @@ -337,9 +322,7 @@ test('rest named tuple', () => { const type = typeOf<[...title: string[]]>(); expectEqualType(type, { kind: ReflectionKind.tuple, - types: [ - { kind: ReflectionKind.tupleMember, name: 'title', type: { kind: ReflectionKind.rest, type: { kind: ReflectionKind.string } } } - ] + types: [{ kind: ReflectionKind.tupleMember, name: 'title', type: { kind: ReflectionKind.rest, type: { kind: ReflectionKind.string } } }], } as TypeTuple); } { @@ -349,7 +332,7 @@ test('rest named tuple', () => { types: [ { kind: ReflectionKind.tupleMember, name: 'title', type: { kind: ReflectionKind.rest, type: { kind: ReflectionKind.string } } }, { kind: ReflectionKind.tupleMember, name: 'prio', type: { kind: ReflectionKind.number } }, - ] + ], } as TypeTuple); } }); @@ -368,7 +351,13 @@ test('typeof primitives', () => { test('typeof union', () => { type t = 'a' | 'b'; - expectEqualType(typeOf(), { kind: ReflectionKind.union, types: [{ kind: ReflectionKind.literal, literal: 'a' }, { kind: ReflectionKind.literal, literal: 'b' }] }); + expectEqualType(typeOf(), { + kind: ReflectionKind.union, + types: [ + { kind: ReflectionKind.literal, literal: 'a' }, + { kind: ReflectionKind.literal, literal: 'b' }, + ], + }); }); test('valuesOf union', () => { @@ -378,35 +367,35 @@ test('valuesOf union', () => { }); test('valuesOf object literal', () => { - type t = { a: string, b: number }; + type t = { a: string; b: number }; expectEqualType(valuesOf(), [{ kind: ReflectionKind.string }, { kind: ReflectionKind.number }]); }); test('propertiesOf inline', () => { - expect(propertiesOf<{ a: string, b: number }>()).toEqual(['a', 'b']); + expect(propertiesOf<{ a: string; b: number }>()).toEqual(['a', 'b']); }); test('object literal index signature', () => { - type t = { [name: string]: string | number, a: string, }; + type t = { [name: string]: string | number; a: string }; expect(typeOf()).toMatchObject({ kind: ReflectionKind.objectLiteral, types: [ { kind: ReflectionKind.indexSignature, index: { kind: ReflectionKind.string }, - type: { kind: ReflectionKind.union, types: [{ kind: ReflectionKind.string }, { kind: ReflectionKind.number }] } + type: { kind: ReflectionKind.union, types: [{ kind: ReflectionKind.string }, { kind: ReflectionKind.number }] }, } as TypeIndexSignature, { kind: ReflectionKind.propertySignature, name: 'a', - type: { kind: ReflectionKind.string } - } - ] + type: { kind: ReflectionKind.string }, + }, + ], }); }); test('propertiesOf external', () => { - type o = { a: string, b: number }; + type o = { a: string; b: number }; expect(propertiesOf()).toEqual(['a', 'b']); }); @@ -422,19 +411,21 @@ test('propertiesOf class', () => { test('typeof object literal', () => { expectEqualType(typeOf<{ a: string }>(), { kind: ReflectionKind.objectLiteral, - types: [{ kind: ReflectionKind.propertySignature, name: 'a', type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.propertySignature, name: 'a', type: { kind: ReflectionKind.string } }], } as TypeObjectLiteral); }); test('typeof object literal with function', () => { expectEqualType(typeOf<{ add(item: string): any }>(), { kind: ReflectionKind.objectLiteral, - types: [{ - kind: ReflectionKind.methodSignature, - name: 'add', - parameters: [{ kind: ReflectionKind.parameter, name: 'item', type: { kind: ReflectionKind.string } }], - return: { kind: ReflectionKind.any } - }] + types: [ + { + kind: ReflectionKind.methodSignature, + name: 'add', + parameters: [{ kind: ReflectionKind.parameter, name: 'item', type: { kind: ReflectionKind.string } }], + return: { kind: ReflectionKind.any }, + }, + ], } as TypeObjectLiteral); }); @@ -446,13 +437,13 @@ test('typeof class', () => { expectEqualType(typeOf(), { kind: ReflectionKind.class, classType: Entity, - types: [{ kind: ReflectionKind.property, name: 'a', visibility: ReflectionVisibility.public, type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.property, name: 'a', visibility: ReflectionVisibility.public, type: { kind: ReflectionKind.string } }], } as TypeClass); expectEqualType(reflect(Entity), { kind: ReflectionKind.class, classType: Entity, - types: [{ kind: ReflectionKind.property, name: 'a', visibility: ReflectionVisibility.public, type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.property, name: 'a', visibility: ReflectionVisibility.public, type: { kind: ReflectionKind.string } }], } as TypeClass); }); @@ -465,14 +456,14 @@ test('typeof generic class', () => { kind: ReflectionKind.class, classType: Entity, arguments: [typeOf()], - types: [{ kind: ReflectionKind.property, name: 'a', visibility: ReflectionVisibility.public, type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.property, name: 'a', visibility: ReflectionVisibility.public, type: { kind: ReflectionKind.string } }], } as TypeClass); expectEqualType(reflect(Entity, typeOf()), { kind: ReflectionKind.class, arguments: [typeOf()], classType: Entity, - types: [{ kind: ReflectionKind.property, name: 'a', visibility: ReflectionVisibility.public, type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.property, name: 'a', visibility: ReflectionVisibility.public, type: { kind: ReflectionKind.string } }], } as TypeClass); }); @@ -490,7 +481,7 @@ test('function', () => { { kind: ReflectionKind.parameter, name: 'text', type: { kind: ReflectionKind.string } }, { kind: ReflectionKind.parameter, name: 'size', type: { kind: ReflectionKind.number } }, ], - return: { kind: ReflectionKind.string } + return: { kind: ReflectionKind.string }, }); }); @@ -503,7 +494,7 @@ test('type function', () => { { kind: ReflectionKind.parameter, name: 'text', type: { kind: ReflectionKind.string } }, { kind: ReflectionKind.parameter, name: 'size', type: { kind: ReflectionKind.number } }, ], - return: { kind: ReflectionKind.string } + return: { kind: ReflectionKind.string }, }); }); @@ -512,10 +503,7 @@ test('query literal', () => { expectEqualType(typeOf(), { kind: ReflectionKind.union, - types: [ - { kind: ReflectionKind.string }, - { kind: ReflectionKind.number }, - ] + types: [{ kind: ReflectionKind.string }, { kind: ReflectionKind.number }], }); }); @@ -532,13 +520,16 @@ test('template literal', () => { type l771 = `${boolean}`; type l8 = `helloworld`; type hw = 'hello' | 'world'; - type l9 = `${hw | 'b'}_` - type l10 = `${`(${hw})`}_` + type l9 = `${hw | 'b'}_`; + type l10 = `${`(${hw})`}_`; const type0 = typeOf(); expectEqualType(type0, { kind: ReflectionKind.union, - types: [{ kind: ReflectionKind.literal, literal: '_aChanged' }, { kind: ReflectionKind.literal, literal: '_bChanged' }] + types: [ + { kind: ReflectionKind.literal, literal: '_aChanged' }, + { kind: ReflectionKind.literal, literal: '_bChanged' }, + ], } as Type); const type1 = typeOf(); @@ -546,22 +537,14 @@ test('template literal', () => { kind: ReflectionKind.union, types: [ { - kind: ReflectionKind.templateLiteral, types: [ - { kind: ReflectionKind.literal, literal: '_' }, - { kind: ReflectionKind.string }, - { kind: ReflectionKind.literal, literal: 'Changeda' }, - - ] + kind: ReflectionKind.templateLiteral, + types: [{ kind: ReflectionKind.literal, literal: '_' }, { kind: ReflectionKind.string }, { kind: ReflectionKind.literal, literal: 'Changeda' }], }, { - kind: ReflectionKind.templateLiteral, types: [ - { kind: ReflectionKind.literal, literal: '_' }, - { kind: ReflectionKind.string }, - { kind: ReflectionKind.literal, literal: 'Changedb' }, - - ] + kind: ReflectionKind.templateLiteral, + types: [{ kind: ReflectionKind.literal, literal: '_' }, { kind: ReflectionKind.string }, { kind: ReflectionKind.literal, literal: 'Changedb' }], }, - ] + ], } as Type); expect(stringifyResolvedType(typeOf())).toBe('`_${string}Changed2` | `_${string}Changedb`'); @@ -578,9 +561,9 @@ test('template literal', () => { }); test('mapped type key literal', () => { - type o = { a: string, b: number, c: boolean, [2]: any }; + type o = { a: string; b: number; c: boolean; [2]: any }; type Prefix = { - [P in keyof T as P extends string ? `v${P}` : never]: T[P] + [P in keyof T as P extends string ? `v${P}` : never]: T[P]; }; type o2 = Prefix; @@ -595,47 +578,36 @@ test('pick', () => { type t = Pick; expectEqualType(typeOf(), { kind: ReflectionKind.objectLiteral, - types: [ - { kind: ReflectionKind.propertySignature, name: 'debug', type: { kind: ReflectionKind.boolean } }, - ] + types: [{ kind: ReflectionKind.propertySignature, name: 'debug', type: { kind: ReflectionKind.boolean } }], }); class MyService { - constructor(public config: Pick) { - } + constructor(public config: Pick) {} } const reflection = ReflectionClass.from(MyService); const parameters = reflection.getMethodParameters('constructor'); expect(parameters[0].getType()).toMatchObject({ kind: ReflectionKind.objectLiteral, - types: [ - { kind: ReflectionKind.propertySignature, name: 'debug', type: { kind: ReflectionKind.boolean } }, - ] + types: [{ kind: ReflectionKind.propertySignature, name: 'debug', type: { kind: ReflectionKind.boolean } }], }); }); test('query union from keyof', () => { - type o = { a: string, b: string, c: number }; + type o = { a: string; b: string; c: number }; expectEqualType(typeOf(), { kind: ReflectionKind.union, - types: [ - { kind: ReflectionKind.string }, - { kind: ReflectionKind.number }, - ] + types: [{ kind: ReflectionKind.string }, { kind: ReflectionKind.number }], }); }); test('query union manual', () => { - type o = { a: string, b: string, c: number }; + type o = { a: string; b: string; c: number }; expectEqualType(typeOf(), { kind: ReflectionKind.union, - types: [ - { kind: ReflectionKind.string }, - { kind: ReflectionKind.number }, - ] + types: [{ kind: ReflectionKind.string }, { kind: ReflectionKind.number }], }); }); @@ -644,10 +616,7 @@ test('query number index', () => { expectEqualType(typeOf(), { kind: ReflectionKind.union, - types: [ - { kind: ReflectionKind.string }, - { kind: ReflectionKind.number }, - ] + types: [{ kind: ReflectionKind.string }, { kind: ReflectionKind.number }], }); expectEqualType(typeOf(), { kind: ReflectionKind.string }); @@ -658,84 +627,84 @@ test('query number index', () => { test('mapped type partial', () => { type Partial2 = { [P in keyof T]?: T[P]; - } + }; type o = { a: string }; type p = Partial2; expect(typeOf

()).toMatchObject({ kind: ReflectionKind.objectLiteral, - types: [{ kind: ReflectionKind.propertySignature, name: 'a', optional: true, type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.propertySignature, name: 'a', optional: true, type: { kind: ReflectionKind.string } }], }); }); test('mapped type required', () => { type Required2 = { [P in keyof T]-?: T[P]; - } + }; type o = { a?: string }; type p = Required2; expect(typeOf

()).toMatchObject({ kind: ReflectionKind.objectLiteral, - types: [{ kind: ReflectionKind.propertySignature, name: 'a', type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.propertySignature, name: 'a', type: { kind: ReflectionKind.string } }], }); }); test('mapped type partial readonly', () => { type Partial2 = { readonly [P in keyof T]?: T[P]; - } + }; type o = { a: string }; type p = Partial2; expect(typeOf

()).toMatchObject({ kind: ReflectionKind.objectLiteral, - types: [{ kind: ReflectionKind.propertySignature, name: 'a', readonly: true, optional: true, type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.propertySignature, name: 'a', readonly: true, optional: true, type: { kind: ReflectionKind.string } }], }); }); test('mapped type filter never', () => { type FilterB = { [P in keyof T]?: P extends 'b' ? never : T[P]; - } + }; - type o = { a?: string, b: string }; + type o = { a?: string; b: string }; type p = FilterB; expect(typeOf

()).toMatchObject({ kind: ReflectionKind.objectLiteral, - types: [{ kind: ReflectionKind.propertySignature, optional: true, name: 'a', type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.propertySignature, optional: true, name: 'a', type: { kind: ReflectionKind.string } }], }); }); test('object literal optional', () => { expectEqualType(typeOf<{ a?: string }>(), { kind: ReflectionKind.objectLiteral, - types: [{ kind: ReflectionKind.propertySignature, name: 'a', optional: true, type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.propertySignature, name: 'a', optional: true, type: { kind: ReflectionKind.string } }], }); }); test('object literal readonly', () => { expectEqualType(typeOf<{ readonly a: string }>(), { kind: ReflectionKind.objectLiteral, - types: [{ kind: ReflectionKind.propertySignature, name: 'a', readonly: true, type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.propertySignature, name: 'a', readonly: true, type: { kind: ReflectionKind.string } }], }); }); test('type alias partial remove readonly', () => { type Partial2 = { -readonly [P in keyof T]?: T[P]; - } + }; type o = { readonly a: string }; type p = Partial2; expect(typeOf

()).toMatchObject({ kind: ReflectionKind.objectLiteral, - types: [{ kind: ReflectionKind.propertySignature, name: 'a', optional: true, type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.propertySignature, name: 'a', optional: true, type: { kind: ReflectionKind.string } }], }); }); @@ -745,9 +714,8 @@ test('global partial', () => { expect(typeOf

()).toMatchObject({ kind: ReflectionKind.objectLiteral, - types: [{ kind: ReflectionKind.propertySignature, name: 'a', optional: true, type: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.propertySignature, name: 'a', optional: true, type: { kind: ReflectionKind.string } }], }); - }); test('global record', () => { @@ -757,12 +725,12 @@ test('global record', () => { expect(typeOf

()).toMatchObject({ kind: ReflectionKind.objectLiteral, - types: [{ kind: ReflectionKind.indexSignature, type: { kind: ReflectionKind.number }, index: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.indexSignature, type: { kind: ReflectionKind.number }, index: { kind: ReflectionKind.string } }], } as Type as any); expect(typeOf()).toMatchObject({ kind: ReflectionKind.objectLiteral, - types: [{ kind: ReflectionKind.indexSignature, type: { kind: ReflectionKind.number }, index: { kind: ReflectionKind.string } }] + types: [{ kind: ReflectionKind.indexSignature, type: { kind: ReflectionKind.number }, index: { kind: ReflectionKind.string } }], }); }); @@ -776,34 +744,34 @@ test('global InstanceType', () => { test('type alias all string', () => { type AllString = { [P in keyof T]: string; - } + }; - type o = { a: string, b: number }; + type o = { a: string; b: number }; type p = AllString; expect(typeOf

()).toMatchObject({ kind: ReflectionKind.objectLiteral, types: [ { kind: ReflectionKind.propertySignature, name: 'a', type: { kind: ReflectionKind.string } }, - { kind: ReflectionKind.propertySignature, name: 'b', type: { kind: ReflectionKind.string } } - ] + { kind: ReflectionKind.propertySignature, name: 'b', type: { kind: ReflectionKind.string } }, + ], }); }); test('type alias conditional type', () => { type IsString = { [P in keyof T]: T[P] extends string ? true : false; - } + }; - type o = { a: string, b: number }; + type o = { a: string; b: number }; type p = IsString; expect(typeOf

()).toMatchObject({ kind: ReflectionKind.objectLiteral, types: [ - { kind: ReflectionKind.propertySignature, name: 'a', type: { kind: ReflectionKind.literal, literal: true, } }, - { kind: ReflectionKind.propertySignature, name: 'b', type: { kind: ReflectionKind.literal, literal: false, } }, - ] + { kind: ReflectionKind.propertySignature, name: 'a', type: { kind: ReflectionKind.literal, literal: true } }, + { kind: ReflectionKind.propertySignature, name: 'b', type: { kind: ReflectionKind.literal, literal: false } }, + ], }); }); @@ -823,14 +791,14 @@ test('keep optional property', () => { expect(type.types[0].optional).toBe(undefined); expect(type.types[1].name).toBe('c'); expect(type.types[1].optional).toBe(true); -}) +}); test('type alias infer', () => { type InferTypeOfT = { - [P in keyof T]: T[P] extends { t: infer OT } ? OT : never - } + [P in keyof T]: T[P] extends { t: infer OT } ? OT : never; + }; - type o = { a: { t: string }, b: { t: number } }; + type o = { a: { t: string }; b: { t: number } }; type p = InferTypeOfT; expect(typeOf

()).toMatchObject({ @@ -838,7 +806,7 @@ test('type alias infer', () => { types: [ { kind: ReflectionKind.propertySignature, name: 'a', type: { kind: ReflectionKind.string } }, { kind: ReflectionKind.propertySignature, name: 'b', type: { kind: ReflectionKind.number } }, - ] + ], }); }); @@ -853,14 +821,16 @@ test('user interface', () => { kind: ReflectionKind.objectLiteral, types: [ { - kind: ReflectionKind.propertySignature, name: 'username', - type: { kind: ReflectionKind.string } + kind: ReflectionKind.propertySignature, + name: 'username', + type: { kind: ReflectionKind.string }, }, { - kind: ReflectionKind.propertySignature, name: 'created', - type: { kind: ReflectionKind.class, classType: Date, types: [] } + kind: ReflectionKind.propertySignature, + name: 'created', + type: { kind: ReflectionKind.class, classType: Date, types: [] }, }, - ] + ], }); }); @@ -878,24 +848,25 @@ test('generic static', () => { kind: ReflectionKind.objectLiteral, types: [ { - kind: ReflectionKind.propertySignature, name: 'body', + kind: ReflectionKind.propertySignature, + name: 'body', type: { - kind: ReflectionKind.objectLiteral, types: [ - { kind: ReflectionKind.propertySignature, name: 'title', type: { kind: ReflectionKind.string } } - ] - } + kind: ReflectionKind.objectLiteral, + types: [{ kind: ReflectionKind.propertySignature, name: 'title', type: { kind: ReflectionKind.string } }], + }, }, - ] + ], }); expect(typeOf>()).toMatchObject({ kind: ReflectionKind.objectLiteral, types: [ { - kind: ReflectionKind.propertySignature, name: 'body', - type: { kind: ReflectionKind.string } + kind: ReflectionKind.propertySignature, + name: 'body', + type: { kind: ReflectionKind.string }, }, - ] + ], }); }); @@ -923,33 +894,33 @@ test('generic dynamic', () => { kind: ReflectionKind.objectLiteral, types: [ { - kind: ReflectionKind.propertySignature, name: 'body', + kind: ReflectionKind.propertySignature, + name: 'body', type: { - kind: ReflectionKind.objectLiteral, types: [ - { kind: ReflectionKind.propertySignature, name: 'title', type: { kind: ReflectionKind.string } } - ] - } + kind: ReflectionKind.objectLiteral, + types: [{ kind: ReflectionKind.propertySignature, name: 'title', type: { kind: ReflectionKind.string } }], + }, }, - ] + ], }); expect(typeOf>([typeOf()])).toMatchObject({ kind: ReflectionKind.objectLiteral, types: [ { - kind: ReflectionKind.propertySignature, name: 'body', - type: { kind: ReflectionKind.string } + kind: ReflectionKind.propertySignature, + name: 'body', + type: { kind: ReflectionKind.string }, }, - ] + ], }); }); test('reflection class', () => { class User { - created: Date = new Date; + created: Date = new Date(); - constructor(public username: string) { - } + constructor(public username: string) {} say(text: string): void { console.log(`${this.username}: ${text}`); @@ -990,8 +961,7 @@ test('destructing params', () => { title: string; } - function say(first: string, { title }: Param, last: number): void { - } + function say(first: string, { title }: Param, last: number): void {} const reflection = ReflectionFunction.from(say); expect(reflection.getParameterNames()).toEqual(['first', 'param1', 'last']); @@ -1030,7 +1000,7 @@ test('interface extends generic', () => { }); test('interface entity', () => { - interface User extends Entity<{ name: 'user', collection: 'users' }> { + interface User extends Entity<{ name: 'user'; collection: 'users' }> { id: number & PrimaryKey; } @@ -1145,7 +1115,7 @@ test('cache same type', () => { }); test('cache with annotations class', () => { - interface User extends Entity<{ name: 'user', collection: 'users' }> { + interface User extends Entity<{ name: 'user'; collection: 'users' }> { username: string; } @@ -1214,8 +1184,7 @@ test('cache parent unset circular', () => { groups: Group[] & BackReference<{ via: UserGroup }>; } - interface Group { - } + interface Group {} interface UserGroup { user: User; @@ -1241,7 +1210,7 @@ test('cache parent unset circular', () => { }); test('circular interface', () => { - interface User extends Entity<{ name: 'user', collection: 'users' }> { + interface User extends Entity<{ name: 'user'; collection: 'users' }> { pages: Page[] & BackReference; page: Page & BackReference; } @@ -1286,8 +1255,7 @@ test('built in numeric type', () => { test('class validator', () => { class Email { - constructor(public email: string) { - } + constructor(public email: string) {} @t.validator validator(): ValidatorError | void { @@ -1304,8 +1272,7 @@ test('class validator', () => { test('value object single field', () => { class Price { - constructor(public amount: integer) { - } + constructor(public amount: integer) {} isFree() { return this.amount === 0; @@ -1315,8 +1282,10 @@ test('value object single field', () => { class Product { price2?: Price; - constructor(public title: string, public price: Embedded) { - } + constructor( + public title: string, + public price: Embedded, + ) {} } const reflection = ReflectionClass.from(Product); @@ -1426,8 +1395,7 @@ test('data decorator', () => { }); test('reference decorator', () => { - class Group { - } + class Group {} class User { group?: Group & Reference; @@ -1441,7 +1409,7 @@ test('reference decorator', () => { test('index decorator', () => { class User { - username: string & Index<{ name: 'username', unique: true }> = ''; + username: string & Index<{ name: 'username'; unique: true }> = ''; email?: string & Unique; @@ -1476,20 +1444,24 @@ test('database decorator', () => { test('enum const', () => { const enum MyEnum { - a, b, c + a, + b, + c, } const type = typeOf(); expectEqualType(type, { kind: ReflectionKind.enum, enum: { a: 0, b: 1, c: 2 }, - values: [0, 1, 2] + values: [0, 1, 2], }); }); test('enum default', () => { enum MyEnum { - a, b, c + a, + b, + c, } const type = typeOf(); @@ -1497,13 +1469,15 @@ test('enum default', () => { expectEqualType(type, { kind: ReflectionKind.enum, enum: { a: 0, b: 1, c: 2 }, - values: [0, 1, 2] + values: [0, 1, 2], }); }); test('enum initializer 1', () => { enum MyEnum { - a = 3, b, c + a = 3, + b, + c, } const type = typeOf(); @@ -1511,7 +1485,7 @@ test('enum initializer 1', () => { expectEqualType(type, { kind: ReflectionKind.enum, enum: { a: 3, b: 4, c: 5 }, - values: [3, 4, 5] + values: [3, 4, 5], }); }); @@ -1528,13 +1502,13 @@ test('enum initializer 2', () => { expectEqualType(type, { kind: ReflectionKind.enum, enum: { a: 0, b: 1, c: 2, d: 4 }, - values: [0, 1, 2, 4] + values: [0, 1, 2, 4], }); }); test('decorate class inheritance', () => { class Timestamp { - created: Date & Group<'base'> = new Date; + created: Date & Group<'base'> = new Date(); } class User extends Timestamp { @@ -1551,11 +1525,11 @@ test('decorate class inheritance', () => { test('decorate class inheritance override decorator data', () => { class Timestamp { - created: Date & Group<'base'> = new Date; + created: Date & Group<'base'> = new Date(); } class User extends Timestamp { - created: Date & Group<'a'> = new Date; + created: Date & Group<'a'> = new Date(); } const reflection = ReflectionClass.from(User); @@ -1583,13 +1557,11 @@ test('decorate class inheritance override decorator data', () => { test('set constructor parameter manually', () => { class Response { - constructor(public success: boolean) { - } + constructor(public success: boolean) {} } class StreamApiResponseClass { - constructor(public response: T) { - } + constructor(public response: T) {} } // { @@ -1714,8 +1686,8 @@ test('set constructor parameter manually', () => { test('circular type 1', () => { type Page = { title: string; - children: Page[] - } + children: Page[]; + }; const type = typeOf(); @@ -1738,11 +1710,11 @@ test('circular type 2', () => { type Document = { title: string; root: Node; - } + }; type Node = { - children: Node[] - } + children: Node[]; + }; const type = typeOf(); @@ -1859,8 +1831,7 @@ test('circular class 3', () => { }); test('typeOf returns same instance, and new one for generics', () => { - class Clazz { - } + class Clazz {} class GenericClazz { item!: T; @@ -1980,25 +1951,23 @@ test('Array', () => { expect(typeOf>()).toMatchObject({ kind: ReflectionKind.array, type: { kind: ReflectionKind.string } }); }); -test('default function expression', () => { +test('dynamic expression', () => { class post { uuid: string = uuid(); id: integer & AutoIncrement & PrimaryKey = 0; - created: Date = new Date; + created: Date = new Date(); type: string = 'asd'; } const reflection = ReflectionClass.from(post); - expect(reflection.getProperty('uuid').hasDefaultFunctionExpression()).toBe(true); - expect(reflection.getProperty('id').hasDefaultFunctionExpression()).toBe(false); - expect(reflection.getProperty('created').hasDefaultFunctionExpression()).toBe(false); - expect(reflection.getProperty('type').hasDefaultFunctionExpression()).toBe(false); - + expect(reflection.getProperty('uuid').hasDynamicExpression()).toBe(true); + expect(reflection.getProperty('id').hasDynamicExpression()).toBe(false); + expect(reflection.getProperty('created').hasDynamicExpression()).toBe(true); + expect(reflection.getProperty('type').hasDynamicExpression()).toBe(false); }); test('type annotation first position', () => { - class author { - } + class author {} class post { id: PrimaryKey & number = 0; @@ -2013,12 +1982,10 @@ test('type annotation first position', () => { expect(reflection.getProperty('author').type.kind).toBe(ReflectionKind.class); expect(reflection.getProperty('author').isPrimaryKey()).toBe(false); expect(reflection.getProperty('author').isReference()).toBe(true); - }); test('annotateClass static', () => { - class ExternalClass { - } + class ExternalClass {} interface AnnotatedClass { id: number; @@ -2030,8 +1997,7 @@ test('annotateClass static', () => { }); test('annotateClass generic', () => { - class ExternalClass { - } + class ExternalClass {} class AnnotatedClass { id!: T; @@ -2092,7 +2058,7 @@ test('template literal with never', () => { }); test('object literal with numeric index', () => { - type o = { a: string, b: number, 3: boolean }; + type o = { a: string; b: number; 3: boolean }; const type = typeOf(); assertType(type, ReflectionKind.objectLiteral); @@ -2110,7 +2076,7 @@ test('map as', () => { [Payload in keyof T as `_${Payload & string}`]: T[Payload]; }; - type o = { a: string, b: number, 3: boolean }; + type o = { a: string; b: number; 3: boolean }; type mapped = MapTuple; const type = typeOf();