123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857 |
- 'use strict';
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- /**
- * Licensed Materials - Property of IBM
- * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2019, 2020
- * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
- *
- */
- define(['../lib/@waca/dashboard-common/dist/core/APIFactory', '../lib/@waca/core-client/js/core-client/utils/ClassFactory', './FeatureLoaderAPI', 'underscore'], function (APIFactory, ClassFactory, FeatureLoaderAPI, _) {
- 'use strict';
- /**
- * Create the feature dependency map that will be passed to a given feature in the constructor
- * We define the getter function where we check if the feature can access the feature at init time or not.
- *
- * @param {String} featureName - Feature name
- * @param {Object[]} dependencyList List of dependencies that the feature requires. The list contains a list of objects that describe a feature
- * @param {String} dependency.name dependency name
- * @param {boolean} dependency.init True if the dependency is an init time dependency
- * @param {FeatureLoader} dependency.loader The feature loader used to access the feature
- * @param {Object} [loadingState] the loading state of a given feature. Used to check we are in the init phase or not
- * @param {Bboolean} [loadingState.loaded] Indicates if the feature is done loading or not
- */
- var createFeatureDependencies = function createFeatureDependencies(featureName, dependencyList, loadingState) {
- var map = {};
- if (dependencyList) {
- var _loop = function _loop(name) {
- var dep = dependencyList[name];
- Object.defineProperty(map, name, {
- get: function get() {
- if (!dep.init && !loadingState.loaded) {
- throw new Error('The required feature "' + dep.name + '" cannot be accessed at init time by the feature"' + featureName + '". The feature "' + dep.name + '" must be added to the initDependencies of feature "' + +featureName + '" if it is needed at init time.');
- }
- return dep.loader.getFeature(dep.name);
- }
- });
- };
- for (var name in dependencyList) {
- _loop(name);
- }
- }
- return map;
- };
- var MODULE_LOADING_ERROR = {};
- var FeatureLoader = function () {
- /**
- *
- * @param {Object} options
- * @param {Object} options.dashboardAPI
- * @param {Object} options.featureParams - parameters to be passed to the feautre when it is created
- * @param {String} options.collectionName - collection name that contains the features to be loaderd
- * @param {Object[]} options.inlineFeatures - array of inline feature to be created
- * @param {Object} options.lifeCycleManager - lifecyclemanager
- */
- function FeatureLoader(options) {
- _classCallCheck(this, FeatureLoader);
- this.externalFeatureLoader = options.externalFeatures;
- this.featureNamePrefix = options.featureNamePrefix;
- this.featureParams = options.featureParams;
- this.features = {};
- this.lifeCycleManager = options.lifeCycleManager;
- this.loadingOrder = [];
- this.errors = {};
- this.logger = options.logger || console;
- this.types = options.types || [];
- this.parentAPI = options.parentAPI;
- // todo - remove the featureSet -- it is not needed
- this.featureSet = options.featureSet;
- }
- FeatureLoader.prototype.getAPI = function getAPI() {
- if (!this._api) {
- this._api = APIFactory.createAPI(this, [FeatureLoaderAPI]);
- }
- return this._api;
- };
- FeatureLoader.prototype._getFeatureListThatInitDependsOn = function _getFeatureListThatInitDependsOn(featureName) {
- var list = [];
- for (var name in this.features) {
- if (this._getInitDependencies(name).indexOf(featureName) !== -1) {
- list.push(name);
- }
- }
- return list;
- };
- FeatureLoader.prototype._getFeatureModule = function _getFeatureModule(feature) {
- return feature.module.default && _.isFunction(feature.module.default) ? feature.module.default : feature.module;
- };
- FeatureLoader.prototype._createFeature = function _createFeature(feature) {
- feature.isCreated = true;
- var params = feature.params;
- var module = this._getFeatureModule(feature);
- feature.instance = new module(params);
- return feature.instance;
- };
- /**
- * Get the feature instance. This function will create the feature if it is hasn't been created.
- * We will also create any feature that has init depenency on this feature.. These dependent features might want to register themselves with this feature
- * This is typically when we have a "provider" type feature with the purpose of only registering itself in some other feature
- * These features are not typically accessed directly, so they won't get created if we don't do this trick here
- *
- *
- * @param {String} name
- */
- FeatureLoader.prototype._getFeatureInstance = function _getFeatureInstance(name) {
- var _this = this;
- var instance = void 0;
- if (this.features[name]) {
- if (!this.features[name].instance && !this._getError(name)) {
- try {
- //delayed creation of the feature
- var _instance = this._createFeature(this.features[name]);
- this.setParentChildRelation(name, _instance);
- // Create any feature that has init depenency on this feature. See comments above
- // TODO - fix this function to also find features that depend on thi given feature when using a feature modifier/type
- // example : 3 feature: A, B , C
- // A depends on C
- // B depends on C.modifier
- // When C is created, we want to create A and B .. but the following function only finds A
- this._getFeatureListThatInitDependsOn(name).forEach(function (depName) {
- if (!_this.features[depName].isCreated) {
- _this._getFeatureInstance(depName);
- }
- });
- } catch (e) {
- this._setError(name, 'Error while creating the feature:' + name, e, this.features);
- }
- }
- instance = this.features[name].instance;
- }
- return instance;
- };
- FeatureLoader.prototype._getFeatureTags = function _getFeatureTags(name) {
- return this.features[name] && this.features[name].spec && this.features[name].spec.tags || [];
- };
- FeatureLoader.prototype._getOptions = function _getOptions(name) {
- var features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.features;
- return features[name] && features[name].spec && features[name].spec.options;
- };
- FeatureLoader.prototype._getInitDependencies = function _getInitDependencies(name) {
- var features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.features;
- var initDep = features[name] && features[name].spec && features[name].spec.dependencies || [];
- return Array.isArray(initDep) ? initDep : Object.keys(initDep);
- };
- FeatureLoader.prototype._getRuntimeDependencies = function _getRuntimeDependencies(name) {
- var features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.features;
- var runtimeDep = features[name] && features[name].spec && features[name].spec.runtimeDependencies || [];
- return Array.isArray(runtimeDep) ? runtimeDep : Object.keys(runtimeDep);
- };
- FeatureLoader.prototype._getDependencies = function _getDependencies(name) {
- var features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.features;
- return this._getInitDependencies(name, features).concat(this._getRuntimeDependencies(name, features));
- };
- // Return the feature alias name if one is defined in the dependency
- FeatureLoader.prototype._getDependenciesPreferredName = function _getDependenciesPreferredName(depName, name) {
- var features = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.features;
- var preferredName = depName;
- // check init depdendencies
- var initDep = features[name] && features[name].spec && features[name].spec.dependencies;
- var runtimeDep = features[name] && features[name].spec && features[name].spec.runtimeDependencies;
- if (initDep && !Array.isArray(initDep) && initDep[depName]) {
- preferredName = initDep[depName];
- } else if (runtimeDep && !Array.isArray(runtimeDep) && runtimeDep[depName]) {
- preferredName = runtimeDep[depName];
- }
- return preferredName;
- };
- FeatureLoader.prototype._getError = function _getError(name) {
- var features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.features;
- return features[name] && features[name].error;
- };
- FeatureLoader.prototype.setParentChildRelation = function setParentChildRelation(name, instance) {
- if (this.parentAPI) {
- APIFactory.setParentChildRelation(this.parentAPI, instance, {
- propagationInfo: {
- namespace: name.toLowerCase(),
- info: {
- featureName: name
- },
- callStack: {
- name: 'getFeature',
- params: [name]
- }
- }
- });
- }
- };
- /**
- * A function to manually register a service. Could be used by the dashboard framework to register low level features.
- * @param {String} name
- * @param {Object} instance
- * @param {Object} spec
- */
- FeatureLoader.prototype.registerFeature = function registerFeature(name, instance, spec, skipInitialization) {
- var _this2 = this;
- this.features[name] = {
- instance: instance,
- spec: spec || {},
- preparePromise: Promise.resolve(name)
- };
- if (this.featureNamePrefix) {
- this.features[this.featureNamePrefix + '.' + name] = this.features[name];
- }
- var promise = void 0;
- if (skipInitialization) {
- promise = Promise.resolve();
- } else {
- promise = this._initializeFeature(name);
- }
- return promise.then(function () {
- // Hook up API events after the feature is initialized
- _this2.setParentChildRelation(name, instance);
- });
- };
- /**
- * Load the features from a collection json
- *
- * @param {Object[]} features
- * @param {Object} [featureSpecs] Feature specfications provided as paramaters to features
- *
- */
- FeatureLoader.prototype.loadFeaturesFromArray = function loadFeaturesFromArray(collectionItems, featureSpecs) {
- var _this3 = this;
- if (featureSpecs && Object.keys(featureSpecs).length > 0) {
- this.featureParams = this.featureParams ? this.featureParams : {};
- this.featureParams.featureSpecs = Object.assign({}, this.featureParams.featureSpecs, featureSpecs);
- }
- var promises = [];
- var features = {};
- var loadingState = {
- loaded: false,
- readyPromises: []
- };
- collectionItems.forEach(function (feature) {
- var identifier = feature.name || feature.id;
- // If the feature has types make it matches the type associated with the feature loader
- var skipFeature = false;
- if (_this3.types.length > 0 && feature.types && feature.types.length > 0) {
- var matchedType = _this3.types.find(function (type) {
- return feature.types.indexOf(type) !== -1;
- });
- skipFeature = !matchedType;
- }
- if (!skipFeature && (!_this3.featureSet || _this3.featureSet.indexOf(identifier) !== -1)) {
- features[identifier] = {
- spec: feature
- };
- if (MODULE_LOADING_ERROR[feature.class]) {
- // We already failed while loading this class. don't try again. Rquire.j will not hang the second time
- _this3._setError(identifier, 'Failed to require feature', MODULE_LOADING_ERROR[feature.class].causedBy, features);
- } else {
- promises.push(ClassFactory.loadModule(feature.class).then(function (module) {
- features[identifier].module = module;
- }).catch(function (e) {
- console.log(e);
- _this3._setError(identifier, 'Failed to require feature', e.causedBy, features);
- MODULE_LOADING_ERROR[feature.class] = e;
- }));
- }
- }
- });
- // Create the features based on the dependencies list and initialize them
- return Promise.all(promises).then(function () {
- //Validate the dependencies
- _this3._validateDependencies(features);
- var name = void 0;
- for (name in features) {
- _this3._prepareFeature(name, features, loadingState);
- }
- return Promise.all(loadingState.readyPromises).then(function () {
- loadingState.loaded = true;
- });
- });
- };
- /**
- * Return the order the features were loaded in
- * Used for testing to verify the order of loading
- */
- FeatureLoader.prototype.getFeatureLoadingOrder = function getFeatureLoadingOrder() {
- return this.loadingOrder;
- };
- FeatureLoader.prototype._setError = function _setError(featureName, message) {
- var details = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
- var features = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : this.features;
- if (!features[featureName]) {
- features[featureName] = {};
- }
- if (details instanceof ErrorEvent) {
- details = {
- message: details.message,
- lineno: details.lineno,
- filename: details.filename
- };
- }
- features[featureName].error = {
- message: message,
- details: details
- };
- // move the failed feature to the main list of features
- this.features[featureName] = features[featureName];
- this.logger.log('Feature loader:' + message, featureName, details);
- };
- FeatureLoader.prototype.getFeatureErrors = function getFeatureErrors() {
- var errors = {};
- var name = void 0;
- for (name in this.features) {
- if (this.features[name].error) {
- errors[name] = this.features[name].error;
- }
- }
- return errors;
- };
- FeatureLoader.prototype._prepareFeature = function _prepareFeature(name) {
- var _this4 = this;
- var features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.features;
- var loadingState = arguments[2];
- // If the feature is not part of the features list that are being currently loaded,
- // then we check the main feature list (this.features) that contains already loaded features
- // this could happen when a feature that loaded a part of a collection is trying to load one of its dependencies that
- // was previously loaded as part of another colletion.
- if (!features[name] && this.features[name]) {
- // If not found in the local feature map, then we try to global that has the loaded features.
- // If we find the feature in the global feature, we will switch to it.
- features = this.features;
- }
- // try #2 - we could be using a feature name with modifier (e.g. state.internal)
- // let us check if we have a modifier in the feature name .
- //this could happen when a feature is attempting to create a dependency and it is using a modifier in the feature name (e.g. state.internal)
- if (!features[name]) {
- var resolved = this._resolvePartialFeatureName(name, features);
- if (resolved) {
- name = resolved.name;
- } else {
- resolved = this._resolvePartialFeatureName(name, this.features);
- if (resolved) {
- name = resolved.name;
- features = this.features;
- }
- }
- }
- if (!features[name]) {
- this._setError(name, 'Attempting to load an undefined feature:' + name, '', features);
- }
- if (this._getError(name, features)) {
- features[name].preparePromise = Promise.resolve(name);
- }
- var preparePromise = features[name].preparePromise;
- if (!preparePromise) {
- var requiredFeatures = {};
- var initDepdendents = [];
- // Go over the init dependencies and create them first
- this._getInitDependencies(name, features).forEach(function (feature) {
- // if we depend on a feature that is not is part of the feature collection,
- // then check the external feature,
- if (_this4.isFeature(feature, features) || _this4.isFeature(feature)) {
- requiredFeatures[_this4._getDependenciesPreferredName(feature, name, features)] = {
- loader: _this4,
- init: true,
- name: feature
- };
- initDepdendents.push(_this4._prepareFeature(feature, features, loadingState));
- } else if (_this4.externalFeatureLoader && _this4.externalFeatureLoader.isFeature(feature)) {
- requiredFeatures[_this4._getDependenciesPreferredName(feature, name, features)] = {
- loader: _this4.externalFeatureLoader,
- init: true,
- name: feature
- };
- } else {
- _this4._setError(name, 'Attempting to load an undefined dependency:' + feature, '', features);
- }
- });
- // Go over the runtime dependencies and create them
- this._getRuntimeDependencies(name, features).forEach(function (feature) {
- // if we depend on a feature that is not is part of the feature collection,
- // then check the external feature,
- if (_this4.isFeature(feature, features) || _this4.isFeature(feature)) {
- requiredFeatures[_this4._getDependenciesPreferredName(feature, name, features)] = {
- loader: _this4,
- init: false,
- name: feature
- };
- } else if (_this4.externalFeatureLoader && _this4.externalFeatureLoader.isFeature(feature)) {
- requiredFeatures[_this4._getDependenciesPreferredName(feature, name, features)] = {
- loader: _this4.externalFeatureLoader,
- init: false,
- name: feature
- };
- } else {
- // Could not find the runtime dependency.. let us not consider it an error yet, maybe it is not register
- requiredFeatures[_this4._getDependenciesPreferredName(feature, name, features)] = {
- loader: _this4,
- init: false,
- name: feature
- };
- }
- });
- preparePromise = Promise.all(initDepdendents).then(function () {
- // Make sure that all dependencies loaded without an error
- var depErrors = [];
- _this4._getDependencies(name, features).forEach(function (featureName) {
- var error = _this4._getError(featureName, features);
- if (error) {
- depErrors.push(error);
- }
- });
- // TODO -- improve this loop and the one above
- var canDelayCreation = true;
- // If we already created the init time dependency, then we will not delay the creation of this feature.
- // This is because the delayed creating will happen when either:
- // 1 - the feature is accessed through the getter
- // 2 - one if its init depdendencies was created
- // TODO -- Possibly at one point, we want to also check external dependencies.
- // This might be needed when we have content feature that registers itself in a dashboard level feature in the initializer.
- _this4._getInitDependencies(name, features).forEach(function (featureName) {
- if (canDelayCreation) {
- canDelayCreation = !(_this4._isCreated(featureName, features) || _this4._isCreated(featureName, _this4.features));
- }
- });
- if (depErrors.length === 0) {
- // All good, create and initialize this feature if needed, otherwise we will lazy create it when requested
- _this4.loadingOrder.push(name);
- try {
- var params = _.extend({}, _this4.featureParams);
- var options = _this4._getOptions(name, features);
- if (options) {
- params.options = options;
- }
- params.features = createFeatureDependencies(name, requiredFeatures, loadingState);
- features[name].params = params;
- if (params.featureSpecs) {
- params.spec = params.featureSpecs[name];
- }
- // Don't delay the create if the feature has an initialize
- // Or if it depends on a feature that was already created -- (in case the feature is not referenced and simply registering itself in one of the dependencies)
- var module = _this4._getFeatureModule(features[name]);
- if (!canDelayCreation || module.prototype.initialize || module.prototype.getLifeCycleHandlers) {
- // we have to create and initialize because this feature needs some async initilize
- var instance = _this4._createFeature(features[name]);
- return _this4._initializeFeature(name, features).then(function () {
- // move the feature to the main list of features once initialized
- _this4.features[name] = features[name];
- if (_this4.featureNamePrefix) {
- _this4.features[_this4.featureNamePrefix + '.' + name] = features[name];
- }
- _this4.setParentChildRelation(name, instance);
- });
- } else {
- _this4.features[name] = features[name];
- if (_this4.featureNamePrefix) {
- _this4.features[_this4.featureNamePrefix + '.' + name] = features[name];
- }
- }
- } catch (e) {
- _this4._setError(name, 'Error while creating the feature:' + name, e, features);
- }
- } else {
- _this4._setError(name, 'Dependency failed to load', depErrors, features);
- }
- });
- features[name].preparePromise = preparePromise;
- // This is uesd by the main feature loading to tell when all features are loaded
- loadingState.readyPromises.push(preparePromise);
- }
- return preparePromise;
- };
- FeatureLoader.prototype._initializeFeature = function _initializeFeature(name) {
- var _this5 = this;
- var features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.features;
- var feature = features[name];
- var promise = null;
- try {
- var instance = feature.instance;
- if (typeof instance.initialize === 'function') {
- promise = instance.initialize();
- }
- if (promise && promise.then) {
- promise = promise.then(function () {
- _this5._postFeatureInitialize(feature);
- });
- } else {
- this._postFeatureInitialize(feature);
- }
- } catch (e) {
- this._setError(name, 'Failed to initialize feature:' + name, e, features);
- }
- if (!promise) {
- promise = Promise.resolve();
- }
- return promise.catch(function (e) {
- _this5._setError(name, 'Failed to initialize feature: ' + name, e, features);
- });
- };
- FeatureLoader.prototype._deregisterLifeCycleHandlers = function _deregisterLifeCycleHandlers(feature) {
- if (feature) {
- if (feature.registeredHandlers) {
- feature.registeredHandlers.forEach(function (handler) {
- return handler.remove();
- });
- }
- feature.registeredHandlers = [];
- }
- };
- // TODO - the lifecycle handlers should not be part of the feature loader
- // The lifeCycle manager is exposed as a feature.. so features can depend on it and register handlers directly with it.
- FeatureLoader.prototype._postFeatureInitialize = function _postFeatureInitialize(feature) {
- var _this6 = this;
- var instance = feature.instance;
- this._deregisterLifeCycleHandlers(feature);
- if (this.lifeCycleManager && typeof instance.getLifeCycleHandlers === 'function') {
- var handlers = instance.getLifeCycleHandlers();
- if (!Array.isArray(handlers)) {
- throw new Error('serviceExtension getLifeCycleHandlers method is expected to return an array');
- }
- handlers.forEach(function (handler) {
- if (!handler.name || !handler.action) {
- throw new Error('serviceExtension handlers are expected to have a name and action property');
- }
- feature.registeredHandlers.push(_this6.lifeCycleManager.registerHandler(handler.name, handler.action, handler.priority));
- });
- }
- };
- FeatureLoader.prototype._validateDependencies = function _validateDependencies() {
- var features = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.features;
- // Validate the dependencies for each step
- var name = void 0;
- for (name in features) {
- this._validateFeatureDependencies(name, null, features);
- }
- };
- FeatureLoader.prototype._validateFeatureDependencies = function _validateFeatureDependencies(featureId, currentDeps) {
- var _this7 = this;
- var features = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.features;
- var dependencies = currentDeps || [];
- if (dependencies.indexOf(featureId) !== -1) {
- throw new Error('The feature with id "' + featureId + '" has a a circular dependency: ' + currentDeps);
- }
- dependencies.push(featureId);
- this._getDependencies(featureId, features).forEach(function (depItem) {
- if (!_this7._getFeatureSpec(depItem, features)) {
- throw new Error('The feature with id "' + featureId + '" has a missing dependency "' + depItem + '"');
- }
- var clonedDepArray = dependencies.concat([]);
- _this7._validateFeatureDependencies(depItem, clonedDepArray, features);
- });
- };
- FeatureLoader.prototype._getFeatureSpec = function _getFeatureSpec(name) {
- var features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.features;
- return features[name] && features[name].spec || {};
- };
- FeatureLoader.prototype.setFeatureEnabled = function setFeatureEnabled(name, isEnabled) {
- if (this.features[name]) {
- if (isEnabled) {
- this.features[name].disabled = false;
- this._postFeatureInitialize(this.features[name]);
- } else {
- this.features[name].disabled = true;
- this._deregisterLifeCycleHandlers(this.features[name]);
- }
- }
- };
- FeatureLoader.prototype.destroy = function destroy() {
- var _this8 = this;
- _.each(_.keys(this.features), function (featureName) {
- // TODO -- we should have destroyFeature
- if (_this8.featureNamePrefix && featureName.startsWith(_this8.featureNamePrefix + '.')) {
- delete _this8.features[featureName];
- } else {
- if (_this8.features[featureName].instance) {
- _this8._deregisterLifeCycleHandlers(_this8.features[featureName]);
- var instance = _this8._getFeatureInstance(featureName);
- if (instance && instance.destroy) {
- try {
- instance.destroy();
- } catch (e) {
- _this8._setError(featureName, 'Error while destroying the feature:' + featureName, e);
- }
- }
- }
- delete _this8.features[featureName];
- }
- });
- for (var prop in this) {
- // clear everything referenced by this object in case someone is still holding on to it.
- if (Object.prototype.hasOwnProperty.call(this, prop)) {
- delete this[prop];
- }
- }
- };
- /**
- * Get a feature. If a feature is disabled or does not implement the getAPI function, then null will be returned.
- *
- * If the name is of the form 'myFeature.xyz', We will first try to find a feature that matches the full name,
- * if we can't find one, then we will look for a feature with name 'myFeature',
- * and we will pass the value 'xyz' to the getAPI() when we get the API object (i.e. myFeature.getAPI('xyz'))
- *
- * @param {String} name
- */
- FeatureLoader.prototype.getFeature = function getFeature(name) {
- var api;
- var instance = this._getFeatureInstance(name);
- var apiType = void 0;
- if (!instance && name) {
- var resolved = this._resolvePartialFeatureName(name);
- if (resolved) {
- name = resolved.name;
- apiType = resolved.apiType;
- instance = this._getFeatureInstance(name);
- }
- }
- if (this.isFeatureEnabled(name) && !this._getError(name) && instance.getAPI) {
- api = instance.getAPI(apiType);
- }
- return api;
- };
- FeatureLoader.prototype.isFeature = function isFeature(name) {
- var features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.features;
- var exist = features[name];
- if (!exist) {
- var resolved = this._resolvePartialFeatureName(name, features);
- if (resolved) {
- exist = features[resolved.name];
- }
- }
- return !!exist;
- };
- FeatureLoader.prototype._isCreated = function _isCreated(name) {
- var features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.features;
- var exist = features[name];
- if (!exist) {
- var resolved = this._resolvePartialFeatureName(name, features);
- if (resolved) {
- exist = features[resolved.name];
- }
- }
- return exist && exist.instance;
- };
- FeatureLoader.prototype.getLoadedFeatures = function getLoadedFeatures() {
- var _this9 = this;
- // TODO - this is used for serialization .. it will end up creating all features even ones that were not referenced
- // WE can optimize to only use the feature that were created..
- var loadedFeatures = {};
- Object.keys(this.features).forEach(function (featureName) {
- if (!featureName.startsWith(_this9.featureNamePrefix + '.')) {
- var featureInstance = _this9._getFeatureInstance(featureName);
- if (featureInstance) {
- loadedFeatures[featureName] = featureInstance;
- }
- }
- });
- return loadedFeatures;
- };
- FeatureLoader.prototype._resolvePartialFeatureName = function _resolvePartialFeatureName(name) {
- var featuresMap = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.features;
- // We support the 2 cases:
- // "a.b.c" where "a" is the feature and "b.c" is the api type
- // or
- // "a.b.c" where "a.b" is the feature and "c" is the api type
- var parts = name.split('.');
- if (parts.length > 1) {
- var firstPart = parts[0];
- var lastPart = parts[parts.length - 1];
- var middlePart = parts.splice(1, parts.length - 2).join('.');
- name = middlePart ? firstPart + '.' + middlePart : firstPart;
- if (featuresMap[name]) {
- return {
- name: name,
- apiType: lastPart
- };
- } else {
- name = firstPart;
- if (featuresMap[name]) {
- return {
- name: name,
- apiType: lastPart ? middlePart + '.' + lastPart : middlePart
- };
- }
- }
- }
- return null;
- };
- /**
- * Indicate if the feature is enabled or not.
- * @param {boolean} name
- */
- FeatureLoader.prototype.isFeatureEnabled = function isFeatureEnabled(name) {
- var instance = this._getFeatureInstance(name);
- return instance && !this.features[name].disabled && (!instance.isEnabled || instance.isEnabled());
- };
- /**
- * @param tagToMatch - a tag that any feature must include in its getTags() api.
- * @returns any features that match the tag passed in as an array (empty array is returned if no features match).
- */
- FeatureLoader.prototype.getMatchingFeatures = function getMatchingFeatures(tagToMatch) {
- var _this10 = this;
- var matchingFeatures = [];
- _.each(_.keys(this.features), function (featureName) {
- if (_this10.isFeatureEnabled(featureName) && _this10._getFeatureTags(featureName).indexOf(tagToMatch) >= 0) {
- var featureAPI = _this10.getFeature(featureName);
- if (featureAPI) {
- matchingFeatures.push(featureAPI);
- }
- }
- });
- return matchingFeatures;
- };
- /**
- * Enable or disable a feature that matches the supplied tag
- * @param tagToMatch - a tag that any feature must include in its getTags() api.
- * @param isEnabled
- */
- FeatureLoader.prototype.setMatchingFeaturesEnabled = function setMatchingFeaturesEnabled(tagToMatch, isEnabled) {
- var _this11 = this;
- _.each(_.keys(this.features), function (featureName) {
- var feature = _this11.features[featureName];
- if (feature && _this11._getFeatureTags(featureName).indexOf(tagToMatch) >= 0) {
- _this11.setFeatureEnabled(featureName, isEnabled);
- }
- });
- };
- return FeatureLoader;
- }();
- return FeatureLoader;
- });
- //# sourceMappingURL=FeatureLoader.js.map
|