diff --git a/src/index.ts b/src/index.ts index 139104b..470b073 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,14 +1,19 @@ import "reflect-metadata" import { parse, Node } from "acorn" + /* ---------------------------------------------------------------- */ /* --------------------------- TYPES ------------------------------ */ /* ---------------------------------------------------------------- */ + +export const DecoratorOption = Symbol("tinspector:decoratorOption") +export const DecoratorId = Symbol("tinspector:decoratorId") + type Class = new (...arg: any[]) => any type DecoratorIterator = (type: DecoratorTargetType, target: string, index?: number) => any[] export type DecoratorTargetType = "Method" | "Class" | "Parameter" | "Property" | "Constructor" -export interface Decorator { targetType: DecoratorTargetType, target: string, value: any } -export interface ParameterDecorator extends Decorator { targetType: "Parameter", targetIndex: number } +export interface Decorator { targetType: DecoratorTargetType, target: string, value: any, inherit: boolean, allowMultiple: boolean } +export interface ParamDecorator extends Decorator { targetType: "Parameter", targetIndex: number } export type Reflection = ParameterReflection | FunctionReflection | PropertyReflection | MethodReflection | ClassReflection | ObjectReflection export interface ReflectionBase { kind: string, name: string } export interface ParameterReflection extends ReflectionBase { kind: "Parameter", properties: string | { [key: string]: string[] }, decorators: any[], type?: any, typeClassification?: "Class" | "Array" | "Primitive" } @@ -21,6 +26,12 @@ export interface ObjectReflection extends ReflectionBase { kind: "Object", membe export interface ArrayDecorator { kind: "Array", type: Class } export interface TypeDecorator { kind: "Override", type: Class, info?: string } export interface PrivateDecorator { kind: "Ignore" } +export interface DecoratorOption { + inherit?: boolean, + allowMultiple?: boolean +} + +export type PropertyDecorator = (target: Object, propertyKey: string | symbol, ...index: any[]) => void; export const DECORATOR_KEY = "plumier.key:DECORATOR" export const DESIGN_TYPE = "design:type" @@ -114,14 +125,16 @@ function getType(object: any) { export function getMembers(fun: Function) { const isGetter = (name: string) => Object.getOwnPropertyDescriptor(fun.prototype, name)!.get + const isSetter = (name: string) => Object.getOwnPropertyDescriptor(fun.prototype, name)!.set const isFunction = (name: string) => typeof fun.prototype[name] === "function"; const members = Object.getOwnPropertyNames(fun.prototype) - .filter(name => isGetter(name) || isFunction(name)) + .filter(name => isGetter(name) || isSetter(name) || isFunction(name)) const properties = (Reflect.getOwnMetadata(DECORATOR_KEY, fun) || []) .filter((x: Decorator) => x.targetType === "Property") .map((x: Decorator) => x.target) - return members.concat(properties) + const names = members.concat(properties) .filter(name => name !== "constructor" && !~name.indexOf("__")) + return [...new Set(names)] } function isCustomClass(type: Function | Function[]) { @@ -159,11 +172,15 @@ function getDecorators(target: any): Decorator[] { function getDecoratorIterator(fn: any): DecoratorIterator { return (type: DecoratorTargetType, target: string, index?: number) => getDecorators(fn) .filter(x => { - const par = x as ParameterDecorator + const par = x as ParamDecorator return x.targetType === type && x.target === target && (par.targetIndex === undefined || par.targetIndex === index) }) - .map(x => x.value) + .map(x => { + const { value, inherit, allowMultiple } = x + value[DecoratorOption] = { inherit, allowMultiple } + return value + }) } function getReflectionType(decorators: any[], type: any) { @@ -179,34 +196,6 @@ function getReflectionType(decorators: any[], type: any) { return type } -function removeDuplicate(reflections: T[]): T[] { - const seen: { [key: string]: boolean } = {} - const result: T[] = [] - for (let i = 0; i < reflections.length; i++) { - const element = reflections[i]; - if (!seen[element.name]) { - result.push(element) - seen[element.name] = true - } - } - return result; -} - -/* -Decorator is not inherited by design due to TypeScript behavior that use decorator to provide type information, -except on inherited method/properties that is not overridden in the child class. -*/ -function extendsClass(child: ClassReflection, parent: ClassReflection): ClassReflection { - return { - kind: "Class", type: child.type, name: child.name, - ctor: child.ctor, typeClassification: child.typeClassification, - decorators: child.decorators, - //merge only methods, properties and decorators - methods: removeDuplicate(child.methods.concat(parent.methods)), - properties: removeDuplicate(child.properties.concat(parent.properties)) - } -} - export function useCache(cache: Map, fn: (...args: P) => R, getKey: (...args: P) => K) { return (...args: P) => { @@ -235,40 +224,45 @@ function printDestruct(params: any[]) { return `{ ${result.join(", ")} }` } +function isIncluded(x: { decorators: any[] }) { + return !x.decorators.some((x: PrivateDecorator) => x.kind === "Ignore") +} + /* ---------------------------------------------------------------- */ /* --------------------------- DECORATORS ------------------------- */ /* ---------------------------------------------------------------- */ -export function decorateParameter(callback: ((target: Class, name: string, index: number) => object)): (target: any, name: string, index: number) => void -export function decorateParameter(data: {}): (target: any, name: string, index: number) => void -export function decorateParameter(data: any) { - return decorate(data, ["Parameter"]) + +export function decorateParameter(callback: ((target: Class, name: string, index: number) => any), option?: DecoratorOption): ParameterDecorator +export function decorateParameter(data: any, option?: DecoratorOption): ParameterDecorator +export function decorateParameter(data: any, option?: DecoratorOption): ParameterDecorator { + return decorate(data, ["Parameter"], option) as any } -export function decorateMethod(callback: ((target: Class, name: string) => object)): (target: any, name: string) => void -export function decorateMethod(data: {}): (target: any, name: string) => void -export function decorateMethod(data: any) { - return decorate(data, ["Method"]) +export function decorateMethod(callback: ((target: Class, name: string) => any), option?: DecoratorOption): MethodDecorator +export function decorateMethod(data: any, option?: DecoratorOption): MethodDecorator +export function decorateMethod(data: any, option?: DecoratorOption) { + return decorate(data, ["Method"], option) } -export function decorateProperty(callback: ((target: Class, name: string, index?: any) => object)): (target: any, name: string, index?: any) => void -export function decorateProperty(data: {}): (target: any, name: string, index?: any) => void -export function decorateProperty(data: any) { - return decorate(data, ["Property", "Parameter"]) +export function decorateProperty(callback: ((target: Class, name: string, index?: any) => any), option?: DecoratorOption): PropertyDecorator +export function decorateProperty(data: any, option?: DecoratorOption): PropertyDecorator +export function decorateProperty(data: any, option?: DecoratorOption) { + return decorate(data, ["Property", "Parameter"], option) } -export function decorateClass(callback: ((target: Class) => object)): (target: any) => void -export function decorateClass(data: {}): (target: any) => void -export function decorateClass(data: any) { - return decorate(data, ["Class"]) +export function decorateClass(callback: ((target: Class) => any), option?: DecoratorOption): ClassDecorator +export function decorateClass(data: any, option?: DecoratorOption): ClassDecorator +export function decorateClass(data: any, option?: DecoratorOption) { + return decorate(data, ["Class"], option) } -export function decorate(data: any, targetTypes: DecoratorTargetType[] = []) { +export function decorate(data: any | ((...args: any[]) => any), targetTypes: DecoratorTargetType[] = [], option?: Partial) { const throwIfNotOfType = (target: DecoratorTargetType) => { if (targetTypes.length > 0 && !targetTypes.some(x => x === target)) throw new Error(`Reflect Error: Decorator of type ${targetTypes.join(", ")} applied into ${target}`) } - + const opt: Required = { allowMultiple: true, inherit: true, ...option } return (...args: any[]) => { //class decorator if (args.length === 1) { @@ -276,7 +270,8 @@ export function decorate(data: any, targetTypes: DecoratorTargetType[] = []) { return addDecorator(args[0], { targetType: "Class", target: args[0].name, - value: typeof data === "function" ? data(args[0]) : data + value: typeof data === "function" ? data(args[0]) : data, + ...opt }) } //parameter decorator @@ -285,11 +280,12 @@ export function decorate(data: any, targetTypes: DecoratorTargetType[] = []) { const isCtorParam = isConstructor(args[0]) const targetType = isCtorParam ? args[0] : args[0].constructor const targetName = isCtorParam ? "constructor" : args[1] - return addDecorator(targetType, { + return addDecorator(targetType, { targetType: "Parameter", target: targetName, targetIndex: args[2], - value: typeof data === "function" ? data(targetType, targetName, args[2]) : data + value: typeof data === "function" ? data(targetType, targetName, args[2]) : data, + ...opt }) } //property @@ -298,27 +294,96 @@ export function decorate(data: any, targetTypes: DecoratorTargetType[] = []) { return addDecorator(args[0].constructor, { targetType: "Property", target: args[1], - value: typeof data === "function" ? data(args[0].constructor, args[1]) : data + value: typeof data === "function" ? data(args[0].constructor, args[1]) : data, + ...opt }) } throwIfNotOfType("Method") return addDecorator(args[0].constructor, { targetType: "Method", target: args[1], - value: typeof data === "function" ? data(args[0].constructor, args[1]) : data + value: typeof data === "function" ? data(args[0].constructor, args[1]) : data, + ...opt }) } } -export function mergeDecorator(...fn: Function[]) { +export function mergeDecorator(...fn: (ClassDecorator | PropertyDecorator | ParamDecorator | MethodDecorator)[]) { return (...args: any[]) => { - fn.forEach(x => x(...args)) + fn.forEach(x => (x as Function)(...args)) } } -/* ---------------------------------------------------------------- */ -/* ------------------------- MAIN FUNCTIONS ----------------------- */ -/* ---------------------------------------------------------------- */ +// --------------------------------------------------------------------- // +// --------------------- EXTEND METADATA FUNCTIONS --------------------- // +// --------------------------------------------------------------------- // + +function extendDecorators(child: any[], parent: any[]) { + const result = [...child] + for (const decorator of parent) { + const options: DecoratorOption = decorator[DecoratorOption]! + // continue, if the decorator is not inheritable + if (!options.inherit) continue + // continue, if allow multiple and already has decorator with the same ID + if (!options.allowMultiple && child.some(x => x[DecoratorId] === decorator[DecoratorId])) continue + result.push(decorator) + } + return result +} + +function extendParameter(child: ParameterReflection[], parent: ParameterReflection[]) { + const result: ParameterReflection[] = [] + for (const member of child) { + const exists = parent.find(x => x.name === member.name)! + member.decorators = extendDecorators(member.decorators, exists.decorators) + result.push(member) + } + return result +} + +function extendProperty(child: PropertyReflection[], parent: PropertyReflection[]) { + const result = [...child] + for (const member of parent) { + const exists = result.find(x => x.name === member.name) + if (exists) { + exists.decorators = extendDecorators(exists.decorators, member.decorators) + continue + } + member.decorators = extendDecorators([], member.decorators) + result.push(member) + } + return result +} + +function extendMethod(child: MethodReflection[], parent: MethodReflection[]) { + const result = [...child] + for (const member of parent) { + const exists = result.find(x => x.name === member.name) + if (exists) { + exists.parameters = extendParameter(exists.parameters, member.parameters) + exists.decorators = extendDecorators(exists.decorators, member.decorators) + continue + } + member.decorators = extendDecorators([], member.decorators) + result.push(member) + } + return result +} + +function extendClass(child: ClassReflection, parent: ClassReflection): ClassReflection { + const { ctor, methods, properties, decorators, ...result } = child; + return { + ...result, + ctor, + decorators: extendDecorators(child.decorators, parent.decorators), + methods: extendMethod(child.methods, parent.methods), + properties: extendProperty(child.properties, parent.properties) + } +} + +// --------------------------------------------------------------------- // +// -------------------------- REFLECT FUNCTION ------------------------- // +// --------------------------------------------------------------------- // function reflectParameter(name: string | { [key: string]: string[] }, typeAnnotation?: any, decs?: any[]): ParameterReflection { const decorators = decs || [] @@ -383,14 +448,13 @@ function reflectConstructor(fn: Class, iterator: DecoratorIterator): Constructor } function reflectClass(fn: Class): ClassReflection { - const notPrivate = (x: { decorators: any[] }) => !x.decorators.some((x: PrivateDecorator) => x.kind === "Ignore") const iterator = getDecoratorIterator(fn) const members = getMembers(fn).map(x => reflectMember(fn, x, iterator)) const ctor = reflectConstructor(fn, iterator) const decorators = iterator("Class", fn.name) - const properties = members.filter((x): x is PropertyReflection => x.kind === "Property" && notPrivate(x)) + const properties = members.filter((x): x is PropertyReflection => x.kind === "Property" && isIncluded(x)) if (decorators.some(x => x.type === "ParameterProperties")) { - const parProps = ctor.parameters.filter(x => notPrivate(x)).map(x => ({ + const parProps = ctor.parameters.filter(x => isIncluded(x)).map(x => ({ decorators: x.decorators, type: x.type, name: x.name, kind: "Property", get: undefined, set: undefined })) @@ -398,7 +462,7 @@ function reflectClass(fn: Class): ClassReflection { } return { kind: "Class", ctor, name: fn.name, - methods: members.filter((x): x is MethodReflection => x.kind === "Method" && notPrivate(x)), + methods: members.filter((x): x is MethodReflection => x.kind === "Method" && isIncluded(x)), properties, decorators, type: fn, typeClassification: "Class" } } @@ -412,7 +476,7 @@ function reflectClassRecursive(fn: Class): ClassReflection { const childMeta = reflectClass(fn) const parent = Object.getPrototypeOf(fn) const parentMeta = parent.prototype ? reflectClassRecursive(parent) : defaultRef - return extendsClass(childMeta, parentMeta) + return extendClass(childMeta, parentMeta) } function reflectObject(object: any, name: string = "module"): ObjectReflection { @@ -462,11 +526,23 @@ export function reflect(option: string | Class) { /* ------------------------- DECORATORS --------------------------- */ /* ---------------------------------------------------------------- */ +const IgnoreId = Symbol("ignore") +const OverrideId = Symbol("override") +const ArrayId = Symbol("array") +const ParamPropId = Symbol("paramProp") + +/** + * Decorator that do nothing, intended to be able to inspect data type + */ +reflect.noop = function () { + return decorate({}) +} + /** * Ignore member from metadata generated */ reflect.ignore = function () { - return decorate({ kind: "Ignore" }, ["Parameter", "Method", "Property"]) + return decorate({ [DecoratorId]: IgnoreId, kind: "Ignore" }, ["Parameter", "Method", "Property"], { allowMultiple: false }) } /** @@ -482,7 +558,7 @@ reflect.ignore = function () { * @param info Additional information about type (readonly, partial etc) */ reflect.type = function (type: Class | Class[], info?: string) { - return decorate({ kind: "Override", type: type, info }, ["Parameter", "Method", "Property"]) + return decorate({ [DecoratorId]: OverrideId, kind: "Override", type: type, info }, ["Parameter", "Method", "Property"], { allowMultiple: false }) } /** @@ -490,15 +566,14 @@ reflect.type = function (type: Class | Class[], info?: string) { * @param type Data type of array element */ reflect.array = function (type: Class) { - return decorate({ kind: "Array", type: type }, ["Parameter", "Method", "Property"]) + return decorate({ [DecoratorId]: ArrayId, kind: "Array", type: type }, ["Parameter", "Method", "Property"], { allowMultiple: false }) } /** * Mark all constructor parameters as properties */ reflect.parameterProperties = function () { - return decorateClass({ type: "ParameterProperties" }) + return decorateClass({ [DecoratorId]: ParamPropId, type: "ParameterProperties" }, { allowMultiple: false }) } - export default reflect \ No newline at end of file diff --git a/test/__snapshots__/cache.spec.js.snap b/test/__snapshots__/cache.spec.js.snap index 8fdda08..af2219d 100644 --- a/test/__snapshots__/cache.spec.js.snap +++ b/test/__snapshots__/cache.spec.js.snap @@ -10,6 +10,10 @@ Object { "decorators": Array [ Object { "name": "first", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Class", @@ -49,6 +53,10 @@ Object { "decorators": Array [ Object { "name": "second", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Class", diff --git a/test/__snapshots__/class.spec.js.snap b/test/__snapshots__/class.spec.js.snap index 779e6f1..63f15e3 100644 --- a/test/__snapshots__/class.spec.js.snap +++ b/test/__snapshots__/class.spec.js.snap @@ -18,6 +18,11 @@ Object { "type": Array [ Number, ], + Symbol(tinspector:decoratorId): Symbol(override), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Method", @@ -57,6 +62,11 @@ Object { "info": "Readonly", "kind": "Override", "type": OtherDummyClass, + Symbol(tinspector:decoratorId): Symbol(override), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -88,6 +98,11 @@ Object { Object { "kind": "Array", "type": EmptyClass, + Symbol(tinspector:decoratorId): Symbol(array), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -101,7 +116,12 @@ Object { ], }, "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Class", "methods": Array [], @@ -124,7 +144,12 @@ Object { "methods": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Method", "name": "dummyMethod", @@ -134,6 +159,11 @@ Object { Object { "kind": "Array", "type": EmptyClass, + Symbol(tinspector:decoratorId): Symbol(array), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -168,7 +198,12 @@ Object { "methods": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Method", "name": "dummyMethod", @@ -207,7 +242,12 @@ Object { "methods": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Method", "name": "dummyMethod", @@ -220,6 +260,11 @@ Object { "type": Array [ EmptyClass, ], + Symbol(tinspector:decoratorId): Symbol(override), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -254,7 +299,12 @@ Object { "methods": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Method", "name": "dummyMethod", @@ -415,7 +465,12 @@ Object { ], }, "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Class", "methods": Array [], @@ -438,7 +493,12 @@ Object { "methods": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Method", "name": "dummyMethod", @@ -449,6 +509,11 @@ Object { "info": undefined, "kind": "Override", "type": Domain, + Symbol(tinspector:decoratorId): Symbol(override), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -496,7 +561,12 @@ Object { "methods": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Method", "name": "dummyMethod", @@ -507,6 +577,11 @@ Object { "info": undefined, "kind": "Override", "type": Domain, + Symbol(tinspector:decoratorId): Symbol(override), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -542,7 +617,12 @@ Object { "methods": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Method", "name": "dummyMethod", @@ -578,6 +658,127 @@ Object { } `; +exports[`Class Introspection Should inspect getter and setter 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [], + "name": "DummyClass", + "properties": Array [ + Object { + "decorators": Array [], + "get": get myProp, + "kind": "Property", + "name": "myProp", + "set": set myProp, + "type": undefined, + "typeClassification": undefined, + }, + ], + "type": DummyClass, + "typeClassification": "Class", +} +`; + +exports[`Class Introspection Should inspect getter and setter with decorator 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [], + "name": "DummyClass", + "properties": Array [ + Object { + "decorators": Array [ + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "get": get myProp, + "kind": "Property", + "name": "myProp", + "set": set myProp, + "type": Number, + "typeClassification": "Primitive", + }, + ], + "type": DummyClass, + "typeClassification": "Class", +} +`; + +exports[`Class Introspection Should inspect parameter properties 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [ + Object { + "decorators": Array [], + "kind": "Parameter", + "name": "myProp", + "properties": Object {}, + "type": Number, + "typeClassification": "Primitive", + }, + Object { + "decorators": Array [], + "kind": "Parameter", + "name": "myOtherProp", + "properties": Object {}, + "type": String, + "typeClassification": "Primitive", + }, + ], + }, + "decorators": Array [ + Object { + "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, + }, + ], + "kind": "Class", + "methods": Array [], + "name": "DummyClass", + "properties": Array [ + Object { + "decorators": Array [], + "get": undefined, + "kind": "Property", + "name": "myProp", + "set": undefined, + "type": Number, + }, + Object { + "decorators": Array [], + "get": undefined, + "kind": "Property", + "name": "myOtherProp", + "set": undefined, + "type": String, + }, + ], + "type": DummyClass, + "typeClassification": "Class", +} +`; + exports[`Class Introspection Should inspect parameters type with method decorator 1`] = ` Object { "ctor": Object { @@ -590,7 +791,12 @@ Object { "methods": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Method", "name": "dummyMethod", @@ -622,3 +828,80 @@ Object { "typeClassification": "Class", } `; + +exports[`Class Introspection Should inspect property 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [], + "name": "DummyClass", + "properties": Array [ + Object { + "decorators": Array [ + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "get": undefined, + "kind": "Property", + "name": "myProp", + "set": undefined, + "type": Number, + "typeClassification": "Primitive", + }, + Object { + "decorators": Array [ + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "get": undefined, + "kind": "Property", + "name": "myOtherProp", + "set": undefined, + "type": String, + "typeClassification": "Primitive", + }, + ], + "type": DummyClass, + "typeClassification": "Class", +} +`; + +exports[`Class Introspection Should inspect setter only 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [], + "name": "DummyClass", + "properties": Array [ + Object { + "decorators": Array [], + "get": undefined, + "kind": "Property", + "name": "myProp", + "set": set myProp, + "type": undefined, + "typeClassification": undefined, + }, + ], + "type": DummyClass, + "typeClassification": "Class", +} +`; diff --git a/test/__snapshots__/decorator.spec.js.snap b/test/__snapshots__/decorator.spec.js.snap index 05f9078..c27704b 100644 --- a/test/__snapshots__/decorator.spec.js.snap +++ b/test/__snapshots__/decorator.spec.js.snap @@ -10,9 +10,17 @@ Object { "decorators": Array [ Object { "info": "Some Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, Object { "otherInfo": "Some Other Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Class", @@ -34,6 +42,10 @@ Object { "decorators": Array [ Object { "name": "DummyClass", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Class", @@ -55,6 +67,10 @@ Object { "decorators": Array [ Object { "info": "Some Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -87,6 +103,10 @@ Object { "index": 0, "name": "constructor", "target": "DummyClass", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -117,9 +137,17 @@ Object { "decorators": Array [ Object { "info": "Some Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, Object { "otherInfo": "Some Other Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -154,9 +182,17 @@ Object { "decorators": Array [ Object { "info": "Some Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, Object { "otherInfo": "Some Other Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Method", @@ -187,9 +223,17 @@ Object { "decorators": Array [ Object { "info": "Some Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, Object { "otherInfo": "Some Other Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Method", @@ -225,6 +269,10 @@ Object { "decorators": Array [ Object { "info": "Some Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -264,9 +312,17 @@ Object { "decorators": Array [ Object { "info": "Some Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, Object { "otherInfo": "Some Other Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -308,6 +364,10 @@ Object { "index": 0, "name": "method", "target": "DummyClass", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -347,9 +407,18 @@ Object { "decorators": Array [ Object { "type": "Cache", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, Object { "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Class", @@ -380,6 +449,10 @@ Object { "decorators": Array [ Object { "info": "Some Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Class", @@ -399,20 +472,35 @@ Object { "parameters": Array [], }, "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Class", "methods": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Method", "name": "myFunction", "parameters": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Parameter", "name": "par", @@ -429,7 +517,12 @@ Object { "properties": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "get": undefined, "kind": "Property", @@ -458,6 +551,10 @@ Object { "decorators": Array [ Object { "info": "Some Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Method", @@ -488,6 +585,10 @@ Object { "decorators": Array [ Object { "info": "Some Info", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Method", @@ -519,6 +620,10 @@ Object { Object { "method": "method", "target": "DummyClass", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Method", @@ -550,6 +655,10 @@ Object { Object { "method": "method", "target": "DummyClass", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Method", @@ -607,7 +716,12 @@ Object { "properties": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "get": get data, "kind": "Property", @@ -639,6 +753,10 @@ Object { Object { "name": "data", "target": DummyClass, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": get data, @@ -670,9 +788,17 @@ Object { "decorators": Array [ Object { "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, Object { "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": get data, @@ -702,7 +828,12 @@ Object { "properties": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "get": undefined, "kind": "Property", @@ -733,9 +864,17 @@ Object { "decorators": Array [ Object { "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, Object { "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": undefined, @@ -769,6 +908,10 @@ Object { "index": undefined, "name": "dummyProp", "target": DummyClass, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": undefined, @@ -796,6 +939,10 @@ Object { "index": 0, "name": "constructor", "target": DummyClass, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -809,6 +956,11 @@ Object { "decorators": Array [ Object { "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Class", @@ -821,6 +973,10 @@ Object { "index": 0, "name": "constructor", "target": DummyClass, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": undefined, @@ -854,6 +1010,11 @@ Object { "decorators": Array [ Object { "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Class", @@ -882,7 +1043,12 @@ Object { "parameters": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "kind": "Parameter", "name": "data", @@ -895,6 +1061,11 @@ Object { "decorators": Array [ Object { "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Class", @@ -903,7 +1074,12 @@ Object { "properties": Array [ Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "get": undefined, "kind": "Property", @@ -928,6 +1104,10 @@ Object { Object { "name": "constructor", "target": DummyClass, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -941,6 +1121,11 @@ Object { "decorators": Array [ Object { "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Class", @@ -952,6 +1137,10 @@ Object { Object { "name": "constructor", "target": DummyClass, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": undefined, @@ -976,9 +1165,17 @@ Object { "decorators": Array [ Object { "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, Object { "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -992,6 +1189,11 @@ Object { "decorators": Array [ Object { "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Class", @@ -1002,9 +1204,17 @@ Object { "decorators": Array [ Object { "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, Object { "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": undefined, @@ -1037,6 +1247,11 @@ Object { "decorators": Array [ Object { "kind": "Ignore", + Symbol(tinspector:decoratorId): Symbol(ignore), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -1050,6 +1265,11 @@ Object { "decorators": Array [ Object { "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Class", diff --git a/test/__snapshots__/inheritance.spec.js.snap b/test/__snapshots__/inheritance.spec.js.snap index 9397e3c..7f0e5ec 100644 --- a/test/__snapshots__/inheritance.spec.js.snap +++ b/test/__snapshots__/inheritance.spec.js.snap @@ -1,5 +1,929 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Inheritance Decorators Decorator On Class Should get base class decorators 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [ + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + Object { + "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Class", + "methods": Array [], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator On Class Should merge base class decorators and child decorators 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [ + Object { + "value": 4, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + Object { + "value": 3, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + Object { + "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Class", + "methods": Array [], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator On Class Should not inherit decorator if specified 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [ + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + Object { + "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": false, + }, + }, + ], + "kind": "Class", + "methods": Array [], + "name": "BaseClass", + "properties": Array [], + "type": BaseClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator On Class Should not inherit decorator if specified 2`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [ + Object { + "value": 3, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Class", + "methods": Array [], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator On Class Should not merge decorator if not allowMultiple 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [ + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + Object { + "value": 1, + Symbol(tinspector:decoratorId): "the-id", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, + }, + ], + "kind": "Class", + "methods": Array [], + "name": "BaseClass", + "properties": Array [], + "type": BaseClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator On Class Should not merge decorator if not allowMultiple 2`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [ + Object { + "value": 3, + Symbol(tinspector:decoratorId): "the-id", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Class", + "methods": Array [], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on Constructor Parameter Should not get base class parameter 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on Constructor Parameter Should not merge decorator if the same name 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [ + Object { + "decorators": Array [ + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Parameter", + "name": "a", + "properties": Object {}, + "type": String, + "typeClassification": "Primitive", + }, + ], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on Method Parameter Should get base class parameter decorator 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [ + Object { + "decorators": Array [], + "kind": "Method", + "name": "myMethod", + "parameters": Array [ + Object { + "decorators": Array [ + Object { + "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Parameter", + "name": "a", + "properties": Object {}, + "type": String, + "typeClassification": "Primitive", + }, + ], + "returnType": String, + "typeClassification": "Primitive", + }, + ], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on Method Parameter Should merge decorators by default 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [ + Object { + "decorators": Array [], + "kind": "Method", + "name": "myMethod", + "parameters": Array [ + Object { + "decorators": Array [ + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + Object { + "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Parameter", + "name": "a", + "properties": Object {}, + "type": String, + "typeClassification": "Primitive", + }, + ], + "returnType": String, + "typeClassification": "Primitive", + }, + ], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on Method Parameter Should not include decorators if parameter not included on derived method 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [ + Object { + "decorators": Array [], + "kind": "Method", + "name": "myMethod", + "parameters": Array [ + Object { + "decorators": Array [ + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + Object { + "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Parameter", + "name": "a", + "properties": Object {}, + "type": String, + "typeClassification": "Primitive", + }, + ], + "returnType": String, + "typeClassification": "Primitive", + }, + ], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on Method Parameter Should not inherit decorator if specified 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [ + Object { + "decorators": Array [], + "kind": "Method", + "name": "myMethod", + "parameters": Array [ + Object { + "decorators": Array [ + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Parameter", + "name": "a", + "properties": Object {}, + "type": String, + "typeClassification": "Primitive", + }, + ], + "returnType": String, + "typeClassification": "Primitive", + }, + ], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on Method Parameter Should not merge decorators if not allowMultiple 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [ + Object { + "decorators": Array [], + "kind": "Method", + "name": "myMethod", + "parameters": Array [ + Object { + "decorators": Array [ + Object { + "value": 2, + Symbol(tinspector:decoratorId): "id", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Parameter", + "name": "a", + "properties": Object {}, + "type": String, + "typeClassification": "Primitive", + }, + ], + "returnType": String, + "typeClassification": "Primitive", + }, + ], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on Method Should get base class method decorator 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [ + Object { + "decorators": Array [ + Object { + "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Method", + "name": "myMethod", + "parameters": Array [ + Object { + "decorators": Array [], + "kind": "Parameter", + "name": "a", + "properties": Object {}, + "type": String, + "typeClassification": "Primitive", + }, + ], + "returnType": String, + "typeClassification": "Primitive", + }, + ], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on Method Should merge decorators by default 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [ + Object { + "decorators": Array [ + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + Object { + "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Method", + "name": "myMethod", + "parameters": Array [ + Object { + "decorators": Array [], + "kind": "Parameter", + "name": "a", + "properties": Object {}, + "type": String, + "typeClassification": "Primitive", + }, + ], + "returnType": String, + "typeClassification": "Primitive", + }, + ], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on Method Should not inherit decorator if specified 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [ + Object { + "decorators": Array [ + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "kind": "Method", + "name": "myMethod", + "parameters": Array [ + Object { + "decorators": Array [], + "kind": "Parameter", + "name": "a", + "properties": Object {}, + "type": String, + "typeClassification": "Primitive", + }, + ], + "returnType": String, + "typeClassification": "Primitive", + }, + ], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on Method Should not inherit decorator on non overridden method 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [ + Object { + "decorators": Array [], + "kind": "Method", + "name": "myMethod", + "parameters": Array [ + Object { + "decorators": Array [], + "kind": "Parameter", + "name": "a", + "properties": Object {}, + "type": String, + "typeClassification": "Primitive", + }, + ], + "returnType": String, + "typeClassification": "Primitive", + }, + ], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on Method Should not merge decorators if not allowMultiple 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [ + Object { + "decorators": Array [ + Object { + "value": 1, + Symbol(tinspector:decoratorId): "id", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, + }, + ], + "kind": "Method", + "name": "myMethod", + "parameters": Array [ + Object { + "decorators": Array [], + "kind": "Parameter", + "name": "a", + "properties": Object {}, + "type": String, + "typeClassification": "Primitive", + }, + ], + "returnType": String, + "typeClassification": "Primitive", + }, + ], + "name": "ChildClass", + "properties": Array [], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on property Should get base class getter decorator 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [], + "name": "ChildClass", + "properties": Array [ + Object { + "decorators": Array [ + Object { + "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "get": get parentProp, + "kind": "Property", + "name": "parentProp", + "set": undefined, + "type": undefined, + "typeClassification": undefined, + }, + ], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on property Should get decorator on parameter property 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [ + Object { + "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, + }, + ], + "kind": "Class", + "methods": Array [], + "name": "ChildClass", + "properties": Array [ + Object { + "decorators": Array [ + Object { + "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "get": undefined, + "kind": "Property", + "name": "parentProp", + "set": undefined, + "type": Number, + }, + ], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on property Should get decorator on property 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [], + "name": "ChildClass", + "properties": Array [ + Object { + "decorators": Array [ + Object { + "value": 2, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "get": undefined, + "kind": "Property", + "name": "childProp", + "set": undefined, + "type": Number, + "typeClassification": "Primitive", + }, + Object { + "decorators": Array [ + Object { + "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, + ], + "get": undefined, + "kind": "Property", + "name": "parentProp", + "set": undefined, + "type": Number, + "typeClassification": "Primitive", + }, + ], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on property Should not inherit if specified 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [], + "name": "ChildClass", + "properties": Array [ + Object { + "decorators": Array [], + "get": get parentProp, + "kind": "Property", + "name": "parentProp", + "set": undefined, + "type": undefined, + "typeClassification": undefined, + }, + ], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on property Should not inherit on non overridden property 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [], + "name": "ChildClass", + "properties": Array [ + Object { + "decorators": Array [], + "get": get parentProp, + "kind": "Property", + "name": "parentProp", + "set": undefined, + "type": Object, + "typeClassification": "Primitive", + }, + ], + "type": ChildClass, + "typeClassification": "Class", +} +`; + +exports[`Inheritance Decorators Decorator on property Should not merge decorator if not allowMultiple 1`] = ` +Object { + "ctor": Object { + "kind": "Constructor", + "name": "constructor", + "parameters": Array [], + }, + "decorators": Array [], + "kind": "Class", + "methods": Array [], + "name": "ChildClass", + "properties": Array [ + Object { + "decorators": Array [ + Object { + "value": 1, + Symbol(tinspector:decoratorId): "id", + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, + }, + ], + "get": get parentProp, + "kind": "Property", + "name": "parentProp", + "set": undefined, + "type": Object, + "typeClassification": "Primitive", + }, + ], + "type": ChildClass, + "typeClassification": "Class", +} +`; + exports[`Inheritance Overridden method should not duplicated 1`] = ` Object { "ctor": Object { @@ -62,6 +986,11 @@ Object { "decorators": Array [ Object { "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Class", @@ -106,6 +1035,10 @@ Object { "decorators": Array [ Object { "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": undefined, @@ -119,6 +1052,10 @@ Object { "decorators": Array [ Object { "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": undefined, @@ -132,6 +1069,10 @@ Object { "decorators": Array [ Object { "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": undefined, @@ -145,6 +1086,10 @@ Object { "decorators": Array [ Object { "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": undefined, @@ -196,46 +1141,6 @@ Object { } `; -exports[`Inheritance Should get base class getter with decorator 1`] = ` -Object { - "ctor": Object { - "kind": "Constructor", - "name": "constructor", - "parameters": Array [], - }, - "decorators": Array [], - "kind": "Class", - "methods": Array [], - "name": "ChildClass", - "properties": Array [ - Object { - "decorators": Array [], - "get": get childProp, - "kind": "Property", - "name": "childProp", - "set": undefined, - "type": undefined, - "typeClassification": undefined, - }, - Object { - "decorators": Array [ - Object { - "value": 1, - }, - ], - "get": get parentProp, - "kind": "Property", - "name": "parentProp", - "set": undefined, - "type": Object, - "typeClassification": "Primitive", - }, - ], - "type": ChildClass, - "typeClassification": "Class", -} -`; - exports[`Inheritance Should get base class method 1`] = ` Object { "ctor": Object { @@ -262,45 +1167,6 @@ Object { } `; -exports[`Inheritance Should get base class method with decorator 1`] = ` -Object { - "ctor": Object { - "kind": "Constructor", - "name": "constructor", - "parameters": Array [], - }, - "decorators": Array [], - "kind": "Class", - "methods": Array [ - Object { - "decorators": Array [ - Object { - "value": 1, - }, - ], - "kind": "Method", - "name": "myMethod", - "parameters": Array [ - Object { - "decorators": Array [], - "kind": "Parameter", - "name": "a", - "properties": Object {}, - "type": String, - "typeClassification": "Primitive", - }, - ], - "returnType": String, - "typeClassification": "Primitive", - }, - ], - "name": "ChildClass", - "properties": Array [], - "type": ChildClass, - "typeClassification": "Class", -} -`; - exports[`Inheritance Should get base class properties 1`] = ` Object { "ctor": Object { @@ -317,6 +1183,10 @@ Object { "decorators": Array [ Object { "value": 1, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": undefined, @@ -375,6 +1245,11 @@ Object { "decorators": Array [ Object { "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Class", @@ -478,6 +1353,11 @@ Object { "decorators": Array [ Object { "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Class", @@ -518,7 +1398,12 @@ Object { }, Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "get": undefined, "kind": "Property", @@ -529,7 +1414,12 @@ Object { }, Object { "decorators": Array [ - Object {}, + Object { + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, + }, ], "get": undefined, "kind": "Property", @@ -571,6 +1461,11 @@ Object { "decorators": Array [ Object { "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Class", @@ -597,6 +1492,10 @@ Object { "decorators": Array [ Object { "cache": 10, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": undefined, @@ -609,6 +1508,10 @@ Object { "decorators": Array [ Object { "cache": 20, + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": true, + "inherit": true, + }, }, ], "get": undefined, diff --git a/test/__snapshots__/private.spec.js.snap b/test/__snapshots__/private.spec.js.snap index a850dfe..f1b20e9 100644 --- a/test/__snapshots__/private.spec.js.snap +++ b/test/__snapshots__/private.spec.js.snap @@ -52,6 +52,11 @@ Object { "decorators": Array [ Object { "kind": "Ignore", + Symbol(tinspector:decoratorId): Symbol(ignore), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Parameter", @@ -65,6 +70,11 @@ Object { "decorators": Array [ Object { "type": "ParameterProperties", + Symbol(tinspector:decoratorId): Symbol(paramProp), + Symbol(tinspector:decoratorOption): Object { + "allowMultiple": false, + "inherit": true, + }, }, ], "kind": "Class", diff --git a/test/class.spec.ts b/test/class.spec.ts index 7c12391..cd5f704 100644 --- a/test/class.spec.ts +++ b/test/class.spec.ts @@ -17,9 +17,11 @@ describe("Class Introspection", () => { expect(meta).toMatchSnapshot() }) - it("Should inspect class with method parameters", () => { + it("Should inspect array on constructor parameters", () => { + class EmptyClass { } + @decorateClass({}) class DummyClass { - dummyMethod(dummy: string, other: any) { } + constructor(@reflect.array(EmptyClass) empty: EmptyClass[]) { } } const meta = reflect(DummyClass) expect(meta).toMatchSnapshot() @@ -34,6 +36,14 @@ describe("Class Introspection", () => { expect(meta).toMatchSnapshot() }) + it("Should inspect class with method parameters", () => { + class DummyClass { + dummyMethod(dummy: string, other: any) { } + } + const meta = reflect(DummyClass) + expect(meta).toMatchSnapshot() + }) + it("Should inspect parameters type with method decorator", () => { class DummyClass { @decorateMethod({}) @@ -43,6 +53,18 @@ describe("Class Introspection", () => { expect(meta).toMatchSnapshot() }) + it("Should able to define return type of method", () => { + class DummyClass { + @reflect.type([Number]) + method() { + return [1, 2, 3] + } + } + const meta = reflect(DummyClass) + expect(meta.methods[0].returnType).toEqual([Number]) + expect(meta).toMatchSnapshot() + }) + it("Should inspect async method with parameters", () => { class DummyClass { @decorateMethod({}) @@ -67,16 +89,6 @@ describe("Class Introspection", () => { expect(meta).toMatchSnapshot() }) - it("Should inspect array on constructor parameters", () => { - class EmptyClass { } - @decorateClass({}) - class DummyClass { - constructor(@reflect.array(EmptyClass) empty: EmptyClass[]) { } - } - const meta = reflect(DummyClass) - expect(meta).toMatchSnapshot() - }) - it("Should inspect array on method parameter but without type override", () => { class EmptyClass { } class DummyClass { @@ -165,15 +177,58 @@ describe("Class Introspection", () => { expect(meta).toMatchSnapshot() }) - it("Should able to define return type of method", () => { + it("Should inspect property", () => { class DummyClass { - @reflect.type([Number]) - method() { - return [1, 2, 3] - } + @reflect.noop() + myProp: number = 10 + @reflect.noop() + myOtherProp: string = "hello" } + + const meta = reflect(DummyClass) + expect(meta).toMatchSnapshot() + }) + + it("Should inspect getter and setter", () => { + class DummyClass { + get myProp() { return 1 } + set myProp(val: number) { } + } + + const meta = reflect(DummyClass) + expect(meta).toMatchSnapshot() + }) + + it("Should inspect setter only", () => { + class DummyClass { + set myProp(val: number) { } + } + + const meta = reflect(DummyClass) + expect(meta).toMatchSnapshot() + }) + + it("Should inspect getter and setter with decorator", () => { + class DummyClass { + @reflect.noop() + get myProp() { return 1 } + set myProp(val: number) { } + } + + const meta = reflect(DummyClass) + expect(meta).toMatchSnapshot() + }) + + it("Should inspect parameter properties", () => { + @reflect.parameterProperties() + class DummyClass { + constructor( + public myProp:number, + public myOtherProp:string, + ){} + } + const meta = reflect(DummyClass) - expect(meta.methods[0].returnType).toEqual([Number]) expect(meta).toMatchSnapshot() }) }) \ No newline at end of file diff --git a/test/durability.spec.ts b/test/durability.spec.ts index d0be811..5839d5f 100644 --- a/test/durability.spec.ts +++ b/test/durability.spec.ts @@ -3,7 +3,7 @@ import { join } from "path" describe("Durability", () => { - it("Should not error parsing index", () => { - reflect(join(__dirname, "../src/index.js")) + it("Should not error parsing typescript", () => { + reflect("typescript") }) }) \ No newline at end of file diff --git a/test/inheritance.spec.ts b/test/inheritance.spec.ts index 479bb07..65c5c9c 100644 --- a/test/inheritance.spec.ts +++ b/test/inheritance.spec.ts @@ -1,4 +1,4 @@ -import { reflect, getMembers, decorateProperty, DECORATOR_KEY, decorateMethod, DESIGN_PARAMETER_TYPE } from "../src"; +import { reflect, getMembers, decorateProperty, DECORATOR_KEY, decorateMethod, DESIGN_PARAMETER_TYPE, decorateClass, DecoratorId, decorateParameter } from "../src"; import { inspect } from "util"; describe("getDeepMember", () => { @@ -47,11 +47,11 @@ describe("Inheritance", () => { @decorateProperty({ value: 1 }) childProp = 1 } - class GrandChildClass extends ChildClass { + class GrandChildClass extends ChildClass { @decorateProperty({ value: 1 }) grandChildProp = 1 } - class GreatGrandChildClass extends GrandChildClass { + class GreatGrandChildClass extends GrandChildClass { @decorateProperty({ value: 1 }) greatGrandChildProp = 1 } @@ -70,18 +70,6 @@ describe("Inheritance", () => { expect(meta).toMatchSnapshot() }) - it("Should get base class getter with decorator", () => { - class BaseClass { - @decorateProperty({ value: 1 }) - get parentProp() { return 1 } - } - class ChildClass extends BaseClass { - get childProp() { return 1 } - } - const meta = reflect(ChildClass) - expect(meta).toMatchSnapshot() - }) - it("Should get base class method", () => { class BaseClass { myMethod() { } @@ -91,17 +79,6 @@ describe("Inheritance", () => { expect(meta).toMatchSnapshot() }) - it("Should get base class method with decorator", () => { - class BaseClass { - @decorateMethod({ value: 1 }) - myMethod(a: string): string { return "" } - } - class ChildClass extends BaseClass { } - const meta = reflect(ChildClass) - expect(meta).toMatchSnapshot() - }) - - it("Should inspect domain with inheritance using constructor property", () => { @reflect.parameterProperties() class DomainBase { @@ -144,7 +121,6 @@ describe("Inheritance", () => { expect(meta).toMatchSnapshot() }) - it("Overridden method should not duplicated", () => { class BaseClass { myMethod(a: string): string { return "" } @@ -156,6 +132,31 @@ describe("Inheritance", () => { expect(meta).toMatchSnapshot() }) + // it("Should not override private method", () => { + // class BaseClass { + // @reflect.ignore() + // privateMethod(a: string): string { return "" } + // } + // class ChildClass extends BaseClass { + // myMethod(a: string): string { return "Hello" } + // } + // const meta = reflect(ChildClass) + // expect(meta).toMatchSnapshot() + // }) + + // it("Should not override private property", () => { + // class BaseClass { + // @reflect.ignore() + // baseProp:number = 1 + // } + // class ChildClass extends BaseClass { + // @reflect.noop() + // childProp:number = 2 + // } + // const meta = reflect(ChildClass) + // expect(meta).toMatchSnapshot() + // }) + it("Overridden parameter property should not duplicated", () => { @reflect.parameterProperties() class BaseClass { @@ -191,4 +192,279 @@ describe("Inheritance", () => { const meta = reflect(ChildClass) expect(meta).toMatchSnapshot() }) + + describe("Decorators", () => { + describe("Decorator On Class", () => { + it("Should get base class decorators", () => { + @decorateClass({ value: 1 }) + @decorateClass({ value: 2 }) + class BaseClass { + } + class ChildClass extends BaseClass { } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should merge base class decorators and child decorators", () => { + @decorateClass({ value: 1 }) + @decorateClass({ value: 2 }) + class BaseClass { + } + @decorateClass({ value: 3 }) + @decorateClass({ value: 4 }) + class ChildClass extends BaseClass { } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should not inherit decorator if specified", () => { + @decorateClass({ value: 1 }, { inherit: false }) + @decorateClass({ value: 2 }) + class BaseClass { + } + @decorateClass({ value: 3 }) + class ChildClass extends BaseClass { } + const parMeta = reflect(BaseClass) + const meta = reflect(ChildClass) + expect(parMeta).toMatchSnapshot() + expect(meta).toMatchSnapshot() + }) + + it("Should not merge decorator if not allowMultiple", () => { + @decorateClass({ [DecoratorId]: "the-id", value: 1 }, { allowMultiple: false }) + @decorateClass({ value: 2 }) + class BaseClass { + } + @decorateClass({ [DecoratorId]: "the-id", value: 3 }) + class ChildClass extends BaseClass { } + const parMeta = reflect(BaseClass) + const meta = reflect(ChildClass) + expect(parMeta).toMatchSnapshot() + expect(meta).toMatchSnapshot() + }) + }) + + describe("Decorator on property", () => { + it("Should get decorator on property", () => { + class BaseClass { + @decorateProperty({ value: 1 }) + parentProp: number = 2 + } + class ChildClass extends BaseClass { + @decorateProperty({ value: 2 }) + childProp: number = 2 + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should get decorator on parameter property", () => { + @reflect.parameterProperties() + class BaseClass { + constructor( + @decorateProperty({ value: 1 }) + public parentProp: number = 2 + ) { } + } + class ChildClass extends BaseClass { + + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should get base class getter decorator", () => { + class BaseClass { + @decorateProperty({ value: 1 }) + get parentProp() { return 1 } + } + class ChildClass extends BaseClass { + //override + get parentProp() { return 3 } + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should not inherit if specified", () => { + class BaseClass { + @decorateProperty({ value: 1 }, { inherit: false }) + get parentProp() { return 1 } + } + class ChildClass extends BaseClass { + //override + get parentProp() { return 3 } + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should not inherit on non overridden property", () => { + class BaseClass { + @decorateProperty({ value: 1 }, { inherit: false }) + get parentProp() { return 1 } + } + class ChildClass extends BaseClass { + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should not merge decorator if not allowMultiple", () => { + class BaseClass { + @decorateProperty({ [DecoratorId]: "id", value: 1 }, { allowMultiple: false }) + get parentProp() { return 1 } + } + class ChildClass extends BaseClass { + //override + @decorateProperty({ [DecoratorId]: "id", value: 1 }, { allowMultiple: false }) + get parentProp() { return 3 } + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + }) + + describe("Decorator on Method", () => { + it("Should get base class method decorator", () => { + class BaseClass { + @decorateMethod({ value: 1 }) + myMethod(a: string): string { return "" } + } + class ChildClass extends BaseClass { } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should merge decorators by default", () => { + class BaseClass { + @decorateMethod({ value: 1 }) + myMethod(a: string): string { return "" } + } + class ChildClass extends BaseClass { + @decorateMethod({ value: 2 }) + myMethod(a: string): string { return "" } + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should not inherit decorator if specified", () => { + class BaseClass { + @decorateMethod({ value: 1 }, { inherit: false }) + myMethod(a: string): string { return "" } + } + class ChildClass extends BaseClass { + @decorateMethod({ value: 2 }) + myMethod(a: string): string { return "" } + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should not inherit decorator on non overridden method", () => { + class BaseClass { + @decorateMethod({ value: 1 }, { inherit: false }) + myMethod(a: string): string { return "" } + } + class ChildClass extends BaseClass { + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should not merge decorators if not allowMultiple", () => { + class BaseClass { + @decorateMethod({ [DecoratorId]: "id", value: 1 }, { allowMultiple: false }) + myMethod(a: string): string { return "" } + } + class ChildClass extends BaseClass { + @decorateMethod({ [DecoratorId]: "id", value: 1 }, { allowMultiple: false }) + myMethod(a: string): string { return "" } + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + }) + + describe("Decorator on Method Parameter", () => { + it("Should get base class parameter decorator", () => { + class BaseClass { + myMethod(@decorateParameter({ value: 1 }) a: string): string { return "" } + } + class ChildClass extends BaseClass { } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should merge decorators by default", () => { + class BaseClass { + myMethod(@decorateParameter({ value: 1 }) a: string): string { return "" } + } + class ChildClass extends BaseClass { + myMethod(@decorateParameter({ value: 2 }) a: string): string { return "" } + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should not include decorators if parameter not included on derived method", () => { + class BaseClass { + myMethod(@decorateParameter({ value: 1 }) a: string, @decorateParameter({ value: 3 }) c:number): string { return "" } + } + class ChildClass extends BaseClass { + myMethod(@decorateParameter({ value: 2 }) a: string): string { return "" } + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should not inherit decorator if specified", () => { + class BaseClass { + myMethod(@decorateParameter({ value: 1 }, {inherit: false}) a: string): string { return "" } + } + class ChildClass extends BaseClass { + myMethod(@decorateParameter({ value: 2 }) a: string): string { return "" } + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should not merge decorators if not allowMultiple", () => { + class BaseClass { + myMethod(@decorateParameter({ [DecoratorId]: "id", value: 1 }, {allowMultiple: false}) a: string): string { return "" } + } + class ChildClass extends BaseClass { + myMethod(@decorateParameter({ [DecoratorId]: "id", value: 2 }) a: string): string { return "" } + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + }) + + describe("Decorator on Constructor Parameter", () => { + it("Should not get base class parameter", () => { + class BaseClass { + constructor(a: string){} + } + class ChildClass extends BaseClass { } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + it("Should not merge decorator if the same name", () => { + class BaseClass { + constructor(@decorateParameter({ value: 1 }) a: string){} + } + class ChildClass extends BaseClass { + constructor(@decorateParameter({ value: 2 }) a: string){ + super(a) + } + } + const meta = reflect(ChildClass) + expect(meta).toMatchSnapshot() + }) + + }) + }) })