src/utils/di/Decorators.js
/* */
import {isFunction} from './Util.js';
// This module contains:
// - built-in annotation classes
// - helpers to read/write annotations
// ANNOTATIONS
// A built-in token.
// Used to ask for pre-injected parent constructor.
// A class constructor can ask for this.
class SuperConstructor {
}
// A built-in scope.
// Never cache.
class TransientScope {
}
class Inject {
constructor(...tokens) {
this.tokens = tokens;
}
}
class Provide {
constructor(token) {
this.token = token;
}
}
class ClassProvider {
}
class FactoryProvider {
}
// HELPERS
// Append annotation on a function or class.
// This can be helpful when not using ES6+.
function annotate(fn, annotation) {
fn.annotations = fn.annotations || [];
fn.annotations.push(annotation);
}
// Read annotations on a function or class and return whether given annotation is present.
function hasAnnotation(fn, annotationClass) {
if (!fn.annotations || fn.annotations.length === 0) {
return false;
}
for (var annotation of fn.annotations) {
if (annotation instanceof annotationClass) {
return true;
}
}
return false;
}
// Read annotations on a function or class and collect "interesting" metadata:
function readAnnotations(fn) {
var collectedAnnotations = {
// Description of the provided value.
provide: {
token: null
},
// List of parameter descriptions.
// A parameter description is an object with properties:
// - token (anything)
params: []
};
if (fn.annotations && fn.annotations.length) {
for (var annotation of fn.annotations) {
if (annotation instanceof Inject) {
annotation.tokens.forEach((token) => {
collectedAnnotations.params.push({
token: token
});
});
}
if (annotation instanceof Provide) {
collectedAnnotations.provide.token = annotation.token;
}
}
}
// Read annotations for individual parameters.
if (fn.parameters) {
fn.parameters.forEach((param, idx) => {
for (var paramAnnotation of param) {
// Type annotation.
if (isFunction(paramAnnotation) && !collectedAnnotations.params[idx]) {
collectedAnnotations.params[idx] = {
token: paramAnnotation
};
} else if (paramAnnotation instanceof Inject) {
collectedAnnotations.params[idx] = {
token: paramAnnotation.tokens[0]
};
}
}
});
}
return collectedAnnotations;
}
// Decorator versions of annotation classes
function inject(...tokens) {
return function (fn) {
annotate(fn, new Inject(...tokens));
};
}
function inject(...tokens) {
return function (fn) {
annotate(fn, new Inject(...tokens));
};
}
function provide(...tokens) {
return function (fn) {
annotate(fn, new Provide(...tokens));
};
}
export {
annotate,
hasAnnotation,
readAnnotations,
SuperConstructor,
TransientScope,
Inject,
Provide,
ClassProvider,
FactoryProvider,
inject,
provide,
};