UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

278 lines (246 loc) 10.2 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2016 Zenesis Limited (http://www.zenesis.com) License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * John Spackman (john.spackman@zenesis.com) ************************************************************************ */ /** * This class provides static API methods that allow the annotations of a class * to be inspected at runtime. * * Annotations are added to a class when the class is defined and is an array of * zero or more objects; annotations are always seen to be an array, but the contents * of that array is not type checked and is never changed (you should not change * the array at runtime). * * Annotations in the class definition are easily recognisable by the "@" symbol, * either as a prefix to a special keyword such as "construct", or as the prefix * to the name of the member which is being annotated. The only exception to this * is that classes and properties don't need to be named, they just need a "@" * property. * * For example: * * <pre class='javascript'> * qx.Class.define("foo.MyClass", { * "@": [ "my-class-annotation" ], // Class annotations, * "@construct": [ "my-constructor-annotation" ], // Constructor annotations, * "@destruct": [ "my-destructor-annotation" ], // Destructor annotations, * * properties: { * myProperty: { * "@": [ "some-property-anno" ], * init: null, * nullable: true * } * }, * * members: { * "@myMethod": [ new foo.annotations.MyAnnotation(1, "test") ], * myMethod: function() { * // ... snip ... * } * }, * * statics: { * "@myStatic": [ "a static anno" ], * myStatic: function() { * // ... snip ... * } * } * }); * </pre> * * Note that the annotation can be anything - a string can be easy and quick, but an * instance of a class may be appropriate for sophisticated needs (see the myMethod * example above). * * The static methods in this class allow you to programmatically get the annotations * that were defined; getClass() returns the class annotations, getMethod returns the * annotions for the named method, etc. * * When classes derive from each other, the default methods get the annotations for * the class and for the super classes as well; the array will be populated so that * the class's annotations are at the start, followed by it's super class, and so * on. If you only want the annotations of the class and not those from the superclass, * use one of the getOwnXxxx methods instead. * */ qx.Bootstrap.define("qx.Annotation", { statics: { /** * Returns a list of annotations, exclusively from this class * @param clazz {Class} the class to inspect * @param name {String} the name (eg method name) to look for * @param group {String} the group to look in if applicable (eg "methods") * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ __getOwnAnnos: function(clazz, name, group, annoClass) { if (clazz.$$annotations === undefined) { return []; } var annos = group ? clazz.$$annotations[group] : clazz.$$annotations; var match = annos && annos[name]; if (!match) { return []; } if (annoClass) { match = match.filter(function(anno) { return anno instanceof annoClass; }); } return match; }, /** * Returns a list of annotations, from this class and superclasses * @param clazz {Class} the starting class to inspect * @param name {String} the name (eg method name) to look for * @param group {String} the group to look in if applicable (eg "methods") * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ __getAnnos: function(clazz, name, group, annoClass) { var result = []; for (var tmp = clazz; tmp; tmp = tmp.superclass) { if (tmp.$$annotations !== undefined) { var annos = group ? tmp.$$annotations[group] : tmp.$$annotations; var src = annos && annos[name]; if (src) { if (annoClass) { src = src.filter(function(anno) { return anno instanceof annoClass; }); } qx.lang.Array.append(result, src); } } } return result; }, /** * Returns the class annotations, exclusively from the class * @param clazz {Class} the class to inspect * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ getOwnClass: function(clazz, annoClass) { return this.__getOwnAnnos(clazz, "@", null, annoClass); }, /** * Returns the class annotations, from this class and superclasses * @param clazz {Class} the class to inspect * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ getClass: function(clazz, annoClass) { return this.__getAnnos(clazz, "@", null, annoClass); }, /** * Returns the class constructor's annotations, exclusively from the class * @param clazz {Class} the class to inspect * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ getOwnConstructor: function(clazz, annoClass) { return this.__getOwnAnnos(clazz, "@construct", null, annoClass); }, /** * Returns the class constructor's annotations, from the class and superclasses * @param clazz {Class} the class to inspect * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ getConstructor: function(clazz, annoClass) { return this.__getAnnos(clazz, "@construct", null, annoClass); }, /** * Returns the class destructor's annotations, exclusively from the class * @param clazz {Class} the class to inspect * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ getOwnDestructor: function(clazz, annoClass) { return this.__getOwnAnnos(clazz, "@destruct", null, annoClass); }, /** * Returns the class destructor's annotations, from the class and superclasses * @param clazz {Class} the class to inspect * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ getDestructor: function(clazz, annoClass) { return this.__getAnnos(clazz, "@destruct", null, annoClass); }, /** * Returns the class member's annotations, exclusively from the class * @param clazz {Class} the class to inspect * @param name {String} member name * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ getOwnMember: function(clazz, name, annoClass) { return this.__getOwnAnnos(clazz, name, "members", annoClass); }, /** * Returns the class member's annotations, from the class and superclass * @param clazz {Class} the class to inspect * @param name {String} member name * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ getMember: function(clazz, name, annoClass) { return this.__getAnnos(clazz, name, "members", annoClass); }, /** * Returns the class property's annotations, exclusively from the class * @param clazz {Class} the class to inspect * @param name {String} property name * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ getOwnProperty: function(clazz, name, annoClass) { return this.__getOwnAnnos(clazz, name, "properties", annoClass); }, /** * Returns the class property's annotations, from the class and superclasses * @param clazz {Class} the class to inspect * @param name {String} property name * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ getProperty: function(clazz, name, annoClass) { return this.__getAnnos(clazz, name, "properties", annoClass); }, /** * Returns a list of property names that implement a given annotation. * @param clazz {Class} the class to inspect * @param annotation {String|Object} annotation to look for * @return {String[]} the property names, never null */ getPropertiesByAnnotation : function(clazz, annotation) { var properties = []; qx.Class.getProperties(clazz).forEach(function(property) { if (qx.Annotation.getProperty(clazz, property).includes(annotation)) { properties.push(property); } }); return properties; }, /** * Returns the class static's annotations, exclusively from the class * @param clazz {Class} the class to inspect * @param name {String} static name * @param annoClass {Class?} optional class which the annotations being returned must implement * @return {Object[]} the annotations, never null */ getStatic: function(clazz, name, annoClass) { return this.__getOwnAnnos(clazz, name, "statics", annoClass); } } });