UNPKG

@litert/decorator

Version:
454 lines 20 kB
"use strict"; /* eslint-disable @typescript-eslint/no-confusing-void-expression */ /** * Copyright 2023 Angus.Fenying <fenying@litert.org> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.DecoratorUtility = void 0; class DecoratorUtility { constructor() { this._staticProperties = new Map(); this._staticMethods = new Map(); this._memberProperties = new Map(); this._memberMethods = new Map(); this._hookNativeReflectMetadata = false; } createGeneralDecorator(processors) { return (c, k, d) => { if (this.isClassConstructor(c)) { if (k === undefined) { switch (typeof d) { case 'undefined': // for class if (!processors.class) { throw new TypeError('This decorator can not apply with classes.'); } return processors.class(c); case 'number': // for class constructor parameter if (!processors.ctorParameter) { throw new TypeError('This decorator can not apply with constructor parameters.'); } return processors.ctorParameter(c, d); default: throw new TypeError('Invalid parameters for decorators.'); } } else { switch (typeof k) { case 'symbol': case 'string': break; default: throw new TypeError('Invalid parameters for decorators.'); } switch (typeof d) { case 'object': // for static method if (d.set || d.get) { if (!processors.staticAccessor) { throw new TypeError('This decorator can not apply with static accessors.'); } this._registerStaticProperty(c, k); return processors.staticAccessor(c, k, d); } else { if (!processors.staticMethod) { throw new TypeError('This decorator can not apply with static methods.'); } this._registerStaticMethod(c, k); return processors.staticMethod(c, k, d); } case 'number': // for static method parameter if (processors.staticMethodParameter) { this._registerStaticMethod(c, k); return processors.staticMethodParameter(c, k, d); } throw new TypeError('This decorator can not apply with static method parameters.'); case 'undefined': // for static property if (!processors.staticProperty) { throw new TypeError('This decorator can not apply with static properties.'); } this._registerStaticProperty(c, k); return processors.staticProperty(c, k); default: throw new TypeError('Invalid parameters for decorators.'); } } } else if (this.isClassPrototype(c)) { switch (typeof k) { case 'symbol': case 'string': break; default: throw new TypeError('Invalid parameters for decorators.'); } switch (typeof d) { case 'object': // for member method if (d.set || d.get) { if (!processors.accessor) { throw new TypeError('This decorator can not apply with member accessors.'); } this._registerMemberProperty(c, k); return processors.accessor(c, k, d); } else { if (!processors.method) { throw new TypeError('This decorator can not apply with member methods.'); } this._registerMemberMethod(c, k); return processors.method(c, k, d); } case 'number': // for member member parameter if (!processors.methodParameter) { throw new TypeError('This decorator can not apply with member method parameters.'); } this._registerMemberMethod(c, k); return processors.methodParameter(c, k, d); case 'undefined': // for member property if (!processors.property) { throw new TypeError('This decorator can not apply with member properties.'); } this._registerMemberProperty(c, k); return processors.property(c, k); default: throw new TypeError('Invalid parameters for decorators.'); } } else { throw new TypeError('Invalid parameters for decorators.'); } }; } isClassConstructor(target) { return typeof target === 'function' && target.toString().startsWith('class'); } isClassPrototype(target) { return typeof target === 'object' && this.isClassConstructor(target === null || target === void 0 ? void 0 : target.constructor); } isInsideClassDecorator(args) { return this.isClassConstructor(args[0]) && args[1] === undefined && args[2] === undefined; } isInsideConstructorParameterDecorator(args) { return this.isClassConstructor(args[0]) && args[1] === undefined && typeof args[2] === 'number'; } isInsideMethodParameterDecorator(args) { return this.isClassPrototype(args[0]) && (typeof args[1] === 'symbol' || typeof args[1] === 'string') && typeof args[2] === 'number'; } isInsideMethodDecorator(args) { return this.isClassPrototype(args[0]) && (typeof args[1] === 'symbol' || typeof args[1] === 'string') && typeof args[2] === 'object' && typeof args[2].value === 'function'; } isInsideAccessorDecorator(args) { return this.isClassPrototype(args[0]) && (typeof args[1] === 'symbol' || typeof args[1] === 'string') && typeof args[2] === 'object' && (args[2].set !== undefined || args[2].get !== undefined); } isInsidePropertyDecorator(args) { return this.isClassPrototype(args[0]) && (typeof args[1] === 'symbol' || typeof args[1] === 'string') && args[2] === undefined; } isInsideStaticMethodParameterDecorator(args) { return this.isClassConstructor(args[0]) && (typeof args[1] === 'symbol' || typeof args[1] === 'string') && typeof args[2] === 'number' && this.isStaticMethod(args[0], args[1]); } isInsideStaticMethodDecorator(args) { return this.isClassConstructor(args[0]) && (typeof args[1] === 'symbol' || typeof args[1] === 'string') && typeof args[2] === 'object' && typeof args[2].value === 'function'; } isInsideStaticAccessorDecorator(args) { return this.isClassConstructor(args[0]) && (typeof args[1] === 'symbol' || typeof args[1] === 'string') && typeof args[2] === 'object' && (args[2].set !== undefined || args[2].get !== undefined); } isInsideStaticPropertyDecorator(args) { return this.isClassConstructor(args[0]) && (typeof args[1] === 'symbol' || typeof args[1] === 'string') && args[2] === undefined; } createClassDecorator(decorator) { return (ctor, k, d) => { if (!this.isInsideClassDecorator([ctor, k, d])) { throw new TypeError('Invalid parameters for class decorator.'); } return decorator(ctor); }; } createConstructorParameterDecorator(decorator) { return (ctor, method, index) => { if (!this.isInsideConstructorParameterDecorator([ctor, method, index])) { throw new TypeError('Invalid parameters for class constructor parameter decorator.'); } return decorator(ctor, index); }; } createMethodParameterDecorator(decorator) { return (proto, method, index) => { if (!this.isInsideMethodParameterDecorator([proto, method, index])) { throw new TypeError('Invalid parameters for class method parameter decorator.'); } this._registerMemberMethod(proto, method); return decorator(proto, method, index); }; } createMethodDecorator(decorator) { return (proto, method, descriptor) => { if (!this.isInsideMethodDecorator([proto, method, descriptor])) { throw new TypeError('Invalid parameters for class method decorator.'); } this._registerMemberMethod(proto, method); return decorator(proto, method, descriptor); }; } createAccessorDecorator(decorator) { return (proto, accessor, descriptor) => { if (!this.isInsideAccessorDecorator([proto, accessor, descriptor])) { throw new TypeError('Invalid parameters for class accessor decorator.'); } this._registerMemberProperty(proto, accessor); return decorator(proto, accessor, descriptor); }; } createPropertyDecorator(decorator) { return (proto, name, descriptor) => { if (!this.isInsidePropertyDecorator([proto, name, descriptor])) { throw new TypeError('Invalid parameters for class property decorator.'); } this._registerMemberProperty(proto, name); return decorator(proto, name); }; } createStaticMethodParameterDecorator(decorator) { return (ctor, method, index) => { if (!this.isInsideStaticMethodParameterDecorator([ctor, method, index])) { throw new TypeError('Invalid parameters for class static method parameter decorator.'); } this._registerStaticMethod(ctor, method); return decorator(ctor, method, index); }; } createStaticMethodDecorator(decorator) { return (ctor, method, descriptor) => { if (!this.isInsideStaticMethodDecorator([ctor, method, descriptor])) { throw new TypeError('Invalid parameters for class static method decorator.'); } this._registerStaticMethod(ctor, method); return decorator(ctor, method, descriptor); }; } createStaticAccessorDecorator(decorator) { return (ctor, accessor, descriptor) => { if (!this.isInsideStaticAccessorDecorator([ctor, accessor, descriptor])) { throw new TypeError('Invalid parameters for class static accessor decorator.'); } this._registerStaticProperty(ctor, accessor); return decorator(ctor, accessor, descriptor); }; } createStaticPropertyDecorator(decorator) { return (ctor, name, descriptor) => { if (!this.isInsideStaticPropertyDecorator([ctor, name, descriptor])) { throw new TypeError('Invalid parameters for class static property decorator.'); } this._registerStaticProperty(ctor, name); return decorator(ctor, name); }; } getClassOfObject(obj) { if (typeof obj !== 'object' || obj === null) { throw new TypeError('Can not find the class of non-object or null.'); } return obj.constructor; } getParentClass(cls) { if (this.hasParentClass(cls)) { return cls.__proto__; } return null; } hasParentClass(cls) { return this.isClassConstructor(cls) && !!cls.__proto__.prototype; } _registerMemberProperty(proto, name) { var _a; const cls = (_a = this._memberProperties.get(proto.constructor)) !== null && _a !== void 0 ? _a : []; if (!cls.includes(name)) { cls.push(name); } this._memberProperties.set(proto.constructor, cls); } _registerMemberMethod(proto, name) { var _a; const cls = (_a = this._memberMethods.get(proto.constructor)) !== null && _a !== void 0 ? _a : []; if (!cls.includes(name)) { cls.push(name); } this._memberMethods.set(proto.constructor, cls); } _registerStaticProperty(ctor, name) { var _a; const cls = (_a = this._staticProperties.get(ctor)) !== null && _a !== void 0 ? _a : []; if (!cls.includes(name)) { cls.push(name); } this._staticProperties.set(ctor, cls); } _registerStaticMethod(ctor, name) { var _a; const cls = (_a = this._staticMethods.get(ctor)) !== null && _a !== void 0 ? _a : []; if (!cls.includes(name)) { cls.push(name); } this._staticMethods.set(ctor, cls); } isAccessor(ctor, name) { const dtr = Object.getOwnPropertyDescriptor(ctor.prototype, name); return (dtr === null || dtr === void 0 ? void 0 : dtr.get) !== undefined || (dtr === null || dtr === void 0 ? void 0 : dtr.set) !== undefined; } isStaticAccessor(ctor, name) { const dtr = Object.getOwnPropertyDescriptor(ctor, name); return (dtr === null || dtr === void 0 ? void 0 : dtr.get) !== undefined || (dtr === null || dtr === void 0 ? void 0 : dtr.set) !== undefined; } isMethod(ctor, name) { const dtr = Object.getOwnPropertyDescriptor(ctor.prototype, name); return typeof (dtr === null || dtr === void 0 ? void 0 : dtr.value) === 'function'; } isStaticMethod(ctor, name) { const dtr = Object.getOwnPropertyDescriptor(ctor, name); return typeof (dtr === null || dtr === void 0 ? void 0 : dtr.value) === 'function'; } getOwnMethodNames(target) { var _a; return (_a = this._memberMethods.get(target)) !== null && _a !== void 0 ? _a : []; } getOwnStaticMethodNames(target) { var _a; return (_a = this._staticMethods.get(target)) !== null && _a !== void 0 ? _a : []; } getOwnPropertyNames(target) { var _a; return (_a = this._memberProperties.get(target)) !== null && _a !== void 0 ? _a : []; } getOwnStaticPropertyNames(target) { var _a; return (_a = this._staticProperties.get(target)) !== null && _a !== void 0 ? _a : []; } isHookNativeReflectMetadata() { return this._hookNativeReflectMetadata; } hookNativeReflectMetadata(enabled = true) { if (this._hookNativeReflectMetadata === enabled) { return; } // eslint-disable-next-line @typescript-eslint/no-require-imports require('reflect-metadata'); const ref = Reflect; if (!enabled) { ref.metadata = this._bakOfMetadata; ref.defineMetadata = this._bakOfDefineMetadata; this._hookNativeReflectMetadata = false; return; } this._bakOfMetadata = ref.metadata; ref.metadata = (metadataKey, metadataValue) => { return (target, propertyKey, dtr) => { if (propertyKey !== undefined && typeof dtr !== 'number') { if (typeof dtr === 'object') { if (this.isClassConstructor(target)) { this._registerStaticMethod(target, propertyKey); } else { this._registerMemberMethod(target, propertyKey); } } else { if (this.isClassConstructor(target)) { this._registerStaticProperty(target, propertyKey); } else { this._registerMemberProperty(target, propertyKey); } } } if (dtr !== undefined) { this._bakOfMetadata(metadataKey, metadataValue)(target, propertyKey, dtr); } else { this._bakOfMetadata(metadataKey, metadataValue)(target, propertyKey); } }; }; this._bakOfDefineMetadata = ref.defineMetadata; ref.defineMetadata = (metadataKey, metadataValue, target, propertyKey) => { if (propertyKey !== undefined) { if (typeof target[propertyKey] === 'function') { if (this.isClassConstructor(target)) { this._registerStaticMethod(target, propertyKey); } else { this._registerMemberMethod(target, propertyKey); } } else { if (this.isClassConstructor(target)) { this._registerStaticProperty(target, propertyKey); } else { this._registerMemberProperty(target, propertyKey); } } return this._bakOfDefineMetadata(metadataKey, metadataValue, target, propertyKey); } return this._bakOfDefineMetadata(metadataKey, metadataValue, target); }; this._hookNativeReflectMetadata = true; } composite(decorators) { return function (a, b, c) { var _a, _b; for (const d of decorators) { if (typeof c === 'object') { c = (_a = d(a, b, c)) !== null && _a !== void 0 ? _a : c; } else if (b === undefined && c === undefined) { a = (_b = d(a, b, c)) !== null && _b !== void 0 ? _b : a; } else { d(a, b, c); } } if (typeof c === 'object') { return c; } else if (b === undefined && c === undefined) { return a; } }; } } exports.DecoratorUtility = DecoratorUtility; //# sourceMappingURL=DecoratorUtility.js.map