tinspector
Advanced tools
Comparing version 2.3.1 to 3.0.0
import "reflect-metadata"; | ||
export declare const DecoratorOption: unique symbol; | ||
export declare const DecoratorId: unique symbol; | ||
declare type Class = new (...arg: any[]) => any; | ||
export declare type DecoratorTargetType = "Method" | "Class" | "Parameter" | "Property" | "Constructor"; | ||
export interface Decorator { | ||
targetType: DecoratorTargetType; | ||
target: string; | ||
value: any; | ||
inherit: boolean; | ||
allowMultiple: boolean; | ||
} | ||
export interface ParamDecorator extends Decorator { | ||
targetType: "Parameter"; | ||
targetIndex: number; | ||
} | ||
export declare 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"; | ||
} | ||
export interface PropertyReflection extends ReflectionBase { | ||
kind: "Property"; | ||
decorators: any[]; | ||
type?: any; | ||
get: any; | ||
set: any; | ||
typeClassification?: "Class" | "Array" | "Primitive"; | ||
} | ||
export interface MethodReflection extends ReflectionBase { | ||
kind: "Method"; | ||
parameters: ParameterReflection[]; | ||
returnType: any; | ||
decorators: any[]; | ||
typeClassification?: "Class" | "Array" | "Primitive"; | ||
} | ||
export interface ConstructorReflection extends ReflectionBase { | ||
kind: "Constructor"; | ||
parameters: ParameterReflection[]; | ||
} | ||
export interface FunctionReflection extends ReflectionBase { | ||
kind: "Function"; | ||
parameters: ParameterReflection[]; | ||
returnType: any; | ||
} | ||
export interface ClassReflection extends ReflectionBase { | ||
kind: "Class"; | ||
ctor: ConstructorReflection; | ||
methods: MethodReflection[]; | ||
properties: PropertyReflection[]; | ||
decorators: any[]; | ||
type: Class; | ||
typeClassification?: "Class" | "Array" | "Primitive"; | ||
} | ||
export interface ObjectReflection extends ReflectionBase { | ||
kind: "Object"; | ||
members: Reflection[]; | ||
} | ||
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 declare type PropertyDecorator = (target: Object, propertyKey: string | symbol, ...index: any[]) => void; | ||
export declare const DECORATOR_KEY = "plumier.key:DECORATOR"; | ||
export declare const DESIGN_TYPE = "design:type"; | ||
export declare const DESIGN_PARAMETER_TYPE = "design:paramtypes"; | ||
export declare const DESIGN_RETURN_TYPE = "design:returntype"; | ||
export declare function getParameterNames(fn: Function): (string | { | ||
[key: string]: string[]; | ||
})[]; | ||
export declare function getMethodParameters(fn: Class, method: string): (string | { | ||
[key: string]: string[]; | ||
})[]; | ||
export declare function getConstructorParameters(fn: Class): (string | { | ||
[key: string]: string[]; | ||
})[]; | ||
export declare function getMembers(fun: Function): string[]; | ||
export declare function useCache<K, P extends any[], R>(cache: Map<K, R>, fn: (...args: P) => R, getKey: (...args: P) => K): (...args: P) => R; | ||
export declare function decorateParameter(callback: ((target: Class, name: string, index: number) => any), option?: DecoratorOption): ParameterDecorator; | ||
export declare function decorateParameter(data: any, option?: DecoratorOption): ParameterDecorator; | ||
export declare function decorateMethod(callback: ((target: Class, name: string) => any), option?: DecoratorOption): MethodDecorator; | ||
export declare function decorateMethod(data: any, option?: DecoratorOption): MethodDecorator; | ||
export declare function decorateProperty(callback: ((target: Class, name: string, index?: any) => any), option?: DecoratorOption): PropertyDecorator; | ||
export declare function decorateProperty(data: any, option?: DecoratorOption): PropertyDecorator; | ||
export declare function decorateClass(callback: ((target: Class) => any), option?: DecoratorOption): ClassDecorator; | ||
export declare function decorateClass(data: any, option?: DecoratorOption): ClassDecorator; | ||
export declare function decorate(data: any | ((...args: any[]) => any), targetTypes?: DecoratorTargetType[], option?: Partial<DecoratorOption>): (...args: any[]) => void; | ||
export declare function mergeDecorator(...fn: (ClassDecorator | PropertyDecorator | ParamDecorator | MethodDecorator)[]): (...args: any[]) => void; | ||
/** | ||
* Reflect module | ||
* @param path module name | ||
*/ | ||
export declare function reflect(path: string): ObjectReflection; | ||
export declare namespace reflect { | ||
var noop: () => (...args: any[]) => void; | ||
var ignore: () => (...args: any[]) => void; | ||
var type: (type: Class | Class[], info?: string | undefined) => (...args: any[]) => void; | ||
var array: (type: Class) => (...args: any[]) => void; | ||
var parameterProperties: () => ClassDecorator; | ||
} | ||
/** | ||
* Reflect class | ||
* @param classType Class | ||
*/ | ||
export declare function reflect(classType: Class): ClassReflection; | ||
export declare namespace reflect { | ||
var noop: () => (...args: any[]) => void; | ||
var ignore: () => (...args: any[]) => void; | ||
var type: (type: Class | Class[], info?: string | undefined) => (...args: any[]) => void; | ||
var array: (type: Class) => (...args: any[]) => void; | ||
var parameterProperties: () => ClassDecorator; | ||
} | ||
export * from "./types"; | ||
export * from "./decorators"; | ||
export * from "./helpers"; | ||
import { reflect } from "./reflect"; | ||
export { reflect }; | ||
export default reflect; |
498
lib/index.js
"use strict"; | ||
var __rest = (this && this.__rest) || function (s, e) { | ||
var t = {}; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) | ||
t[p] = s[p]; | ||
if (s != null && typeof Object.getOwnPropertySymbols === "function") | ||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { | ||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) | ||
t[p[i]] = s[p[i]]; | ||
} | ||
return t; | ||
}; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
require("reflect-metadata"); | ||
const acorn_1 = require("acorn"); | ||
/* ---------------------------------------------------------------- */ | ||
/* --------------------------- TYPES ------------------------------ */ | ||
/* ---------------------------------------------------------------- */ | ||
exports.DecoratorOption = Symbol("tinspector:decoratorOption"); | ||
exports.DecoratorId = Symbol("tinspector:decoratorId"); | ||
exports.DECORATOR_KEY = "plumier.key:DECORATOR"; | ||
exports.DESIGN_TYPE = "design:type"; | ||
exports.DESIGN_PARAMETER_TYPE = "design:paramtypes"; | ||
exports.DESIGN_RETURN_TYPE = "design:returntype"; | ||
const cacheStore = new Map(); | ||
/* ---------------------------------------------------------------- */ | ||
/* --------------------------- HELPERS ---------------------------- */ | ||
/* ---------------------------------------------------------------- */ | ||
function getNode(node, criteria) { | ||
if (criteria(node)) | ||
return node; | ||
if (!node.body) | ||
return; | ||
if (Array.isArray(node.body)) { | ||
for (const child of node.body) { | ||
const result = getNode(child, criteria); | ||
if (result) | ||
return result; | ||
} | ||
} | ||
return getNode(node.body, criteria); | ||
} | ||
function getNamesFromAst(nodes) { | ||
const getName = (node) => { | ||
if (node.type === "Identifier") | ||
return node.name; | ||
if (node.type === "AssignmentPattern") | ||
return node.left.name; | ||
if (node.type === "RestElement") | ||
return node.argument.name; | ||
if (node.type === "Property") { | ||
if (node.value.type === "Identifier") | ||
return node.value.name; | ||
else { | ||
const result = {}; | ||
result[node.key.name] = getName(node.value); | ||
return result; | ||
} | ||
} | ||
//if (node.type === "ObjectPattern") { | ||
return node.properties.map((x) => getName(x)); | ||
//} | ||
}; | ||
return nodes.map(x => getName(x)).filter((x) => !!x); | ||
} | ||
function getParameterNames(fn) { | ||
try { | ||
const body = fn.toString(); | ||
const ast = acorn_1.parse(body); | ||
return getNamesFromAst(ast.body[0].params); | ||
} | ||
catch (_a) { | ||
return []; | ||
} | ||
} | ||
exports.getParameterNames = getParameterNames; | ||
function getMethodParameters(fn, method) { | ||
const body = fn.toString(); | ||
const ast = acorn_1.parse(body); | ||
const ctor = getNode(ast, x => x.type === "MethodDefinition" && x.kind === "method" && x.key.name === method); | ||
return getNamesFromAst(ctor ? ctor.value.params : []); | ||
} | ||
exports.getMethodParameters = getMethodParameters; | ||
function getConstructorParameters(fn) { | ||
const body = fn.toString(); | ||
const ast = acorn_1.parse(body); | ||
const ctor = getNode(ast, x => x.type === "MethodDefinition" && x.kind === "constructor"); | ||
return getNamesFromAst(ctor ? ctor.value.params : []); | ||
} | ||
exports.getConstructorParameters = getConstructorParameters; | ||
function isConstructor(value) { | ||
return ("" + value).indexOf("class") == 0; | ||
} | ||
function getType(object) { | ||
if (typeof object === "function") { | ||
if (isConstructor(object)) | ||
return "Class"; | ||
else | ||
return "Function"; | ||
} | ||
else if (Array.isArray(object)) | ||
return "Array"; | ||
else if (typeof object === "boolean" | ||
|| typeof object === "number" | ||
|| typeof object === "bigint" | ||
|| typeof object === "string" | ||
|| typeof object === "symbol" | ||
|| typeof object === "undefined") | ||
return "Value"; | ||
else | ||
return "Object"; | ||
} | ||
function getMembers(fun) { | ||
const isGetter = (name) => Object.getOwnPropertyDescriptor(fun.prototype, name).get; | ||
const isSetter = (name) => Object.getOwnPropertyDescriptor(fun.prototype, name).set; | ||
const isFunction = (name) => typeof fun.prototype[name] === "function"; | ||
const members = Object.getOwnPropertyNames(fun.prototype) | ||
.filter(name => isGetter(name) || isSetter(name) || isFunction(name)); | ||
const properties = (Reflect.getOwnMetadata(exports.DECORATOR_KEY, fun) || []) | ||
.filter((x) => x.targetType === "Property") | ||
.map((x) => x.target); | ||
const names = members.concat(properties) | ||
.filter(name => name !== "constructor" && !~name.indexOf("__")); | ||
return [...new Set(names)]; | ||
} | ||
exports.getMembers = getMembers; | ||
function isCustomClass(type) { | ||
switch (type) { | ||
case Boolean: | ||
case String: | ||
case Array: | ||
case Number: | ||
case Object: | ||
case Date: | ||
return false; | ||
default: | ||
return true; | ||
} | ||
} | ||
function getTypeClassification(type) { | ||
if (type === undefined) | ||
return undefined; | ||
else if (Array.isArray(type)) | ||
return "Array"; | ||
else if (isCustomClass(type)) | ||
return "Class"; | ||
else | ||
return "Primitive"; | ||
} | ||
function addDecorator(target, decorator) { | ||
const decorators = Reflect.getOwnMetadata(exports.DECORATOR_KEY, target) || []; | ||
decorators.push(decorator); | ||
Reflect.defineMetadata(exports.DECORATOR_KEY, decorators, target); | ||
} | ||
function getDecorators(target) { | ||
return Reflect.getOwnMetadata(exports.DECORATOR_KEY, target) || []; | ||
} | ||
function getDecoratorIterator(fn) { | ||
return (type, target, index) => getDecorators(fn) | ||
.filter(x => { | ||
const par = x; | ||
return x.targetType === type && x.target === target | ||
&& (par.targetIndex === undefined || par.targetIndex === index); | ||
}) | ||
.map(x => { | ||
const { value, inherit, allowMultiple } = x; | ||
value[exports.DecoratorOption] = { inherit, allowMultiple }; | ||
return value; | ||
}); | ||
} | ||
function getReflectionType(decorators, type) { | ||
const array = decorators.find((x) => x.kind === "Array"); | ||
const override = decorators.find((x) => x.kind === "Override"); | ||
if (override) | ||
return override.type; | ||
else if (array) | ||
return [array.type]; | ||
else if (type === Array) | ||
return [Object]; | ||
else | ||
return type; | ||
} | ||
function useCache(cache, fn, getKey) { | ||
return (...args) => { | ||
const key = getKey(...args); | ||
const result = cache.get(key); | ||
if (!!result) | ||
return result; | ||
else { | ||
const newResult = fn(...args); | ||
cache.set(key, newResult); | ||
return newResult; | ||
} | ||
}; | ||
} | ||
exports.useCache = useCache; | ||
function printDestruct(params) { | ||
const result = []; | ||
for (const key in params) { | ||
const par = params[key]; | ||
if (typeof par === "string") | ||
result.push(par); | ||
else { | ||
const key = Object.keys(par)[0]; | ||
result.push(`${key}: ${printDestruct(par[key])}`); | ||
} | ||
} | ||
return `{ ${result.join(", ")} }`; | ||
} | ||
function isIncluded(x) { | ||
return !x.decorators.some((x) => x.kind === "Ignore"); | ||
} | ||
function decorateParameter(data, option) { | ||
return decorate(data, ["Parameter"], option); | ||
} | ||
exports.decorateParameter = decorateParameter; | ||
function decorateMethod(data, option) { | ||
return decorate(data, ["Method"], option); | ||
} | ||
exports.decorateMethod = decorateMethod; | ||
function decorateProperty(data, option) { | ||
return decorate(data, ["Property", "Parameter"], option); | ||
} | ||
exports.decorateProperty = decorateProperty; | ||
function decorateClass(data, option) { | ||
return decorate(data, ["Class"], option); | ||
} | ||
exports.decorateClass = decorateClass; | ||
function decorate(data, targetTypes = [], option) { | ||
const throwIfNotOfType = (target) => { | ||
if (targetTypes.length > 0 && !targetTypes.some(x => x === target)) | ||
throw new Error(`Reflect Error: Decorator of type ${targetTypes.join(", ")} applied into ${target}`); | ||
}; | ||
const opt = Object.assign({ allowMultiple: true, inherit: true }, option); | ||
return (...args) => { | ||
const theData = typeof data === "function" ? data(...args) : data; | ||
if (!opt.allowMultiple && !theData[exports.DecoratorId]) { | ||
const ctorName = isConstructor(args[0]) ? args[0].name : args[0].constructor.name; | ||
throw new Error(`Reflect Error: Decorator with allowMultiple set to false must have DecoratorId property in ${ctorName}`); | ||
} | ||
//class decorator | ||
if (args.length === 1) { | ||
throwIfNotOfType("Class"); | ||
return addDecorator(args[0], Object.assign({ targetType: "Class", target: args[0].name, value: typeof data === "function" ? data(args[0]) : data }, opt)); | ||
} | ||
//parameter decorator | ||
if (args.length === 3 && typeof args[2] === "number") { | ||
throwIfNotOfType("Parameter"); | ||
const isCtorParam = isConstructor(args[0]); | ||
const targetType = isCtorParam ? args[0] : args[0].constructor; | ||
const targetName = isCtorParam ? "constructor" : args[1]; | ||
return addDecorator(targetType, Object.assign({ targetType: "Parameter", target: targetName, targetIndex: args[2], value: typeof data === "function" ? data(targetType, targetName, args[2]) : data }, opt)); | ||
} | ||
//property | ||
if (args[2] === undefined || args[2].get || args[2].set) { | ||
throwIfNotOfType("Property"); | ||
return addDecorator(args[0].constructor, Object.assign({ targetType: "Property", target: args[1], value: typeof data === "function" ? data(args[0].constructor, args[1]) : data }, opt)); | ||
} | ||
throwIfNotOfType("Method"); | ||
return addDecorator(args[0].constructor, Object.assign({ targetType: "Method", target: args[1], value: typeof data === "function" ? data(args[0].constructor, args[1]) : data }, opt)); | ||
}; | ||
} | ||
exports.decorate = decorate; | ||
function mergeDecorator(...fn) { | ||
return (...args) => { | ||
fn.forEach(x => x(...args)); | ||
}; | ||
} | ||
exports.mergeDecorator = mergeDecorator; | ||
// --------------------------------------------------------------------- // | ||
// --------------------- EXTEND METADATA FUNCTIONS --------------------- // | ||
// --------------------------------------------------------------------- // | ||
function extendDecorators(child, parent) { | ||
const result = [...child]; | ||
for (const decorator of parent) { | ||
const options = decorator[exports.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[exports.DecoratorId] === decorator[exports.DecoratorId])) | ||
continue; | ||
result.push(decorator); | ||
} | ||
return result; | ||
} | ||
function extendParameter(child, parent) { | ||
const result = []; | ||
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, parent) { | ||
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, parent) { | ||
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, parent) { | ||
const { ctor, methods, properties, decorators } = child, result = __rest(child, ["ctor", "methods", "properties", "decorators"]); | ||
return Object.assign(Object.assign({}, 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, typeAnnotation, decs) { | ||
const decorators = decs || []; | ||
const type = getReflectionType(decorators, typeAnnotation); | ||
const typeClassification = getTypeClassification(type); | ||
let parName; | ||
let properties = {}; | ||
if (typeof name === "object") { | ||
parName = printDestruct(name); | ||
properties = name; | ||
} | ||
else { | ||
parName = name; | ||
} | ||
return { kind: "Parameter", name: parName, type, decorators, typeClassification, properties }; | ||
} | ||
function reflectFunction(fn) { | ||
const parameters = getParameterNames(fn).map(x => reflectParameter(x)); | ||
return { kind: "Function", name: fn.name, parameters, returnType: undefined }; | ||
} | ||
function reflectMethod(clazz, method, iterator) { | ||
const parType = Reflect.getOwnMetadata(exports.DESIGN_PARAMETER_TYPE, clazz.prototype, method) || []; | ||
const rawReturnType = Reflect.getOwnMetadata(exports.DESIGN_RETURN_TYPE, clazz.prototype, method); | ||
const parameters = getMethodParameters(clazz, method).map((x, i) => reflectParameter(x, parType[i], iterator("Parameter", method, i))); | ||
const decorators = iterator("Method", method); | ||
const returnType = getReflectionType(decorators, rawReturnType); | ||
const typeClassification = getTypeClassification(returnType); | ||
return { kind: "Method", name: method, parameters, decorators, returnType, typeClassification }; | ||
} | ||
function reflectProperty(name, typeAnnotation, des, iterator) { | ||
const decorators = iterator("Property", name); | ||
const type = getReflectionType(decorators, typeAnnotation); | ||
const typeClassification = getTypeClassification(type); | ||
return { | ||
kind: "Property", name, type, decorators, typeClassification, | ||
get: des && des.get, set: des && des.set | ||
}; | ||
} | ||
function reflectMember(clazz, name, iterator) { | ||
const type = Reflect.getOwnMetadata(exports.DESIGN_TYPE, clazz.prototype, name); | ||
const des = Reflect.getOwnPropertyDescriptor(clazz.prototype, name); | ||
if (des && typeof des.value === "function" && !des.get && !des.set) { | ||
return reflectMethod(clazz, name, iterator); | ||
} | ||
else { | ||
return reflectProperty(name, type, des, iterator); | ||
} | ||
} | ||
function reflectConstructor(fn, iterator) { | ||
const parTypes = Reflect.getOwnMetadata(exports.DESIGN_PARAMETER_TYPE, fn) || []; | ||
const params = getConstructorParameters(fn); | ||
return { | ||
kind: "Constructor", | ||
name: "constructor", | ||
parameters: params.map((x, i) => reflectParameter(x, parTypes[i], iterator("Parameter", "constructor", i))) | ||
}; | ||
} | ||
function reflectClass(fn) { | ||
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.kind === "Property" && isIncluded(x)); | ||
if (decorators.some(x => x.type === "ParameterProperties")) { | ||
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 | ||
})); | ||
properties.push(...parProps); | ||
} | ||
return { | ||
kind: "Class", ctor, name: fn.name, | ||
methods: members.filter((x) => x.kind === "Method" && isIncluded(x)), | ||
properties, decorators, type: fn, typeClassification: "Class" | ||
}; | ||
} | ||
function reflectClassRecursive(fn) { | ||
const defaultRef = { | ||
kind: "Class", type: Object, name: "Object", | ||
ctor: {}, | ||
methods: [], properties: [], decorators: [] | ||
}; | ||
const childMeta = reflectClass(fn); | ||
const parent = Object.getPrototypeOf(fn); | ||
const parentMeta = parent.prototype ? reflectClassRecursive(parent) : defaultRef; | ||
return extendClass(childMeta, parentMeta); | ||
} | ||
function reflectObject(object, name = "module") { | ||
return { | ||
kind: "Object", name, | ||
members: Object.keys(object).map(x => traverse(object[x], x)).filter((x) => !!x) | ||
}; | ||
} | ||
function traverse(fn, name) { | ||
switch (getType(fn)) { | ||
case "Function": | ||
return reflectFunction(fn); | ||
case "Class": | ||
return reflectClassRecursive(fn); | ||
case "Object": | ||
return reflectObject(fn, name); | ||
default: | ||
return; | ||
} | ||
} | ||
const reflectObjectCached = useCache(cacheStore, reflectObject, x => x); | ||
const reflectClassRecursiveCached = useCache(cacheStore, reflectClassRecursive, x => x); | ||
function reflect(option) { | ||
if (typeof option === "string") { | ||
return reflectObjectCached(require(option)); | ||
} | ||
else { | ||
return reflectClassRecursiveCached(option); | ||
} | ||
} | ||
exports.reflect = reflect; | ||
/* ---------------------------------------------------------------- */ | ||
/* ------------------------- 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({ [exports.DecoratorId]: IgnoreId, kind: "Ignore" }, ["Parameter", "Method", "Property"], { allowMultiple: false }); | ||
}; | ||
/** | ||
* Override type definition information. Useful to add type definition for some data type that is erased | ||
* after transfile such as Partial<Type> or ReadOnly<Type> | ||
* | ||
* If applied to parameter it will override the parameter type | ||
* | ||
* If applied to property it will override the property type | ||
* | ||
* if applied to method it will overrid the method return value | ||
* @param type The type overridden | ||
* @param info Additional information about type (readonly, partial etc) | ||
*/ | ||
reflect.type = function (type, info) { | ||
return decorate({ [exports.DecoratorId]: OverrideId, kind: "Override", type: type, info }, ["Parameter", "Method", "Property"], { allowMultiple: false }); | ||
}; | ||
/** | ||
* Add type information for array element | ||
* @param type Data type of array element | ||
*/ | ||
reflect.array = function (type) { | ||
return decorate({ [exports.DecoratorId]: ArrayId, kind: "Array", type: type }, ["Parameter", "Method", "Property"], { allowMultiple: false }); | ||
}; | ||
/** | ||
* Mark all constructor parameters as properties | ||
*/ | ||
reflect.parameterProperties = function () { | ||
return decorateClass({ [exports.DecoratorId]: ParamPropId, type: "ParameterProperties" }, { allowMultiple: false }); | ||
}; | ||
exports.default = reflect; | ||
__export(require("./types")); | ||
__export(require("./decorators")); | ||
__export(require("./helpers")); | ||
const reflect_1 = require("./reflect"); | ||
exports.reflect = reflect_1.reflect; | ||
exports.default = reflect_1.reflect; |
{ | ||
"name": "tinspector", | ||
"version": "2.3.1", | ||
"version": "3.0.0", | ||
"description": "TypeScript type inspector", | ||
@@ -25,6 +25,6 @@ "main": "lib/index.js", | ||
"devDependencies": { | ||
"@types/jest": "^25.1.4", | ||
"@types/node": "^13.9.1", | ||
"coveralls": "^3.0.9", | ||
"jest": "^25.1.0", | ||
"@types/jest": "^25.2.1", | ||
"@types/node": "^13.13.4", | ||
"coveralls": "^3.1.0", | ||
"jest": "^25.4.0", | ||
"tslib": "^1.11.1", | ||
@@ -31,0 +31,0 @@ "typescript": "^3.8.3" |
@@ -92,2 +92,3 @@ # tinspector | ||
- [x] (TypeScript only) Configurable decorator (inheritable / allow multiple) | ||
- [x] (TypeScript only) Generic class inheritance | ||
@@ -190,2 +191,20 @@ | ||
## Inspect Generic Class Information | ||
With above trick its possible to get generic type information in a generic class members with some extra configuration below | ||
```typescript | ||
@generic.template("T", "U") | ||
class SuperAwesome<T, U> { | ||
awesome(@reflect.type("T") par: T, @reflect.type("U") par2: U) {} | ||
} | ||
@generic.type(Number, String) | ||
class Awesome extends SuperAwesome<Number, String> { } | ||
const metadata = reflect(Awesome) | ||
``` | ||
Above code showing that we add a specialized decorator `@generic.template()` to define generic template type. We also defined data type of the generic parameters using `@reflect.type()` decorator. Next on the inherited class we specify `@generic.type()` to define types replace the generic template. Note that the order of the parameter on `@generic.template()` and `@generic.type()` is important. | ||
## Inspect Parameter Properties | ||
@@ -192,0 +211,0 @@ TypeScript has parameter properties feature, which make it possible to use constructor parameter as property. tinspector able to extract parameter properties type information by using `@reflect.parameterProperties()` decorator. |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
55569
20
949
322
1