mirror of
https://github.com/nasa/openmct.git
synced 2025-02-05 10:39:15 +00:00
[Code Style] Use prototypes in framework layer
WTD-1482
This commit is contained in:
parent
7fe866060b
commit
edca2a9f03
@ -40,24 +40,36 @@ define(
|
|||||||
*
|
*
|
||||||
* @memberof platform/framework
|
* @memberof platform/framework
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {BundleLoader} loader
|
* @param {platform/framework.BundleLoader} loader
|
||||||
* @param {BundleResolver} resolver
|
* @param {platform/framework.BundleResolver} resolver
|
||||||
* @param {ExtensionRegistrar} registrar
|
* @param {platform/framework.ExtensionRegistrar} registrar
|
||||||
* @param {ApplicationBootstrapper} bootstrapper
|
* @param {platform/framework.ApplicationBootstrapper} bootstrapper
|
||||||
*/
|
*/
|
||||||
function FrameworkInitializer(loader, resolver, registrar, bootstrapper) {
|
function FrameworkInitializer(loader, resolver, registrar, bootstrapper) {
|
||||||
|
this.loader = loader;
|
||||||
|
this.resolver = resolver;
|
||||||
|
this.registrar = registrar;
|
||||||
|
this.bootstrapper = bootstrapper;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
function bind(method, thisArg) {
|
||||||
runApplication: function (bundleList) {
|
return function () {
|
||||||
return loader.loadBundles(bundleList)
|
return method.apply(thisArg, arguments);
|
||||||
.then(resolver.resolveBundles)
|
|
||||||
.then(registrar.registerExtensions)
|
|
||||||
.then(bootstrapper.bootstrap);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the application defined by this set of bundles.
|
||||||
|
* @param bundleList
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
FrameworkInitializer.prototype.runApplication = function (bundleList) {
|
||||||
|
return this.loader.loadBundles(bundleList)
|
||||||
|
.then(bind(this.resolver.resolveBundles, this.resolver))
|
||||||
|
.then(bind(this.registrar.registerExtensions, this.registrar))
|
||||||
|
.then(bind(this.bootstrapper.bootstrap, this.bootstrapper));
|
||||||
|
};
|
||||||
|
|
||||||
return FrameworkInitializer;
|
return FrameworkInitializer;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -53,7 +53,29 @@ define(
|
|||||||
*/
|
*/
|
||||||
function LogLevel(level) {
|
function LogLevel(level) {
|
||||||
// Find the numeric level associated with the string
|
// Find the numeric level associated with the string
|
||||||
var index = LOG_LEVELS.indexOf(level);
|
this.index = LOG_LEVELS.indexOf(level);
|
||||||
|
|
||||||
|
// Default to 'warn' level if unspecified
|
||||||
|
if (this.index < 0) {
|
||||||
|
this.index = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure logging to suppress log output if it is
|
||||||
|
* not of an appropriate level. Both the Angular app
|
||||||
|
* being initialized and a reference to `$log` should be
|
||||||
|
* passed; the former is used to configure application
|
||||||
|
* logging, while the latter is needed to apply the
|
||||||
|
* same configuration during framework initialization
|
||||||
|
* (since the framework also logs.)
|
||||||
|
*
|
||||||
|
* @param app the Angular app to configure
|
||||||
|
* @param $log Angular's $log (also configured)
|
||||||
|
* @memberof platform/framework.LogLevel#
|
||||||
|
*/
|
||||||
|
LogLevel.prototype.configure = function (app, $log) {
|
||||||
|
var index = this.index;
|
||||||
|
|
||||||
// Replace logging methods with no-ops, if they are
|
// Replace logging methods with no-ops, if they are
|
||||||
// not of an appropriate level.
|
// not of an appropriate level.
|
||||||
@ -67,36 +89,14 @@ define(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to 'warn' level if unspecified
|
decorate($log);
|
||||||
if (index < 0) {
|
app.config(function ($provide) {
|
||||||
index = 1;
|
$provide.decorator('$log', function ($delegate) {
|
||||||
}
|
decorate($delegate);
|
||||||
|
return $delegate;
|
||||||
return {
|
});
|
||||||
/**
|
});
|
||||||
* Configure logging to suppress log output if it is
|
};
|
||||||
* not of an appropriate level. Both the Angular app
|
|
||||||
* being initialized and a reference to `$log` should be
|
|
||||||
* passed; the former is used to configure application
|
|
||||||
* logging, while the latter is needed to apply the
|
|
||||||
* same configuration during framework initialization
|
|
||||||
* (since the framework also logs.)
|
|
||||||
*
|
|
||||||
* @param app the Angular app to configure
|
|
||||||
* @param $log Angular's $log (also configured)
|
|
||||||
* @memberof platform/framework.LogLevel#
|
|
||||||
*/
|
|
||||||
configure: function (app, $log) {
|
|
||||||
decorate($log);
|
|
||||||
app.config(function ($provide) {
|
|
||||||
$provide.decorator('$log', function ($delegate) {
|
|
||||||
decorate($delegate);
|
|
||||||
return $delegate;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return LogLevel;
|
return LogLevel;
|
||||||
}
|
}
|
||||||
|
@ -42,25 +42,27 @@ define(
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ApplicationBootstrapper(angular, document, $log) {
|
function ApplicationBootstrapper(angular, document, $log) {
|
||||||
return {
|
this.angular = angular;
|
||||||
/**
|
this.document = document;
|
||||||
* Bootstrap the application.
|
this.$log = $log;
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @memberof ApplicationBootstrapper#
|
|
||||||
* @param {angular.Module} app the Angular application to
|
|
||||||
* bootstrap
|
|
||||||
* @memberof platform/framework.ApplicationBootstrapper#
|
|
||||||
*/
|
|
||||||
bootstrap: function (app) {
|
|
||||||
$log.info("Bootstrapping application " + (app || {}).name);
|
|
||||||
angular.element(document).ready(function () {
|
|
||||||
angular.bootstrap(document, [app.name]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap the application.
|
||||||
|
*
|
||||||
|
* @param {angular.Module} app the Angular application to
|
||||||
|
* bootstrap
|
||||||
|
*/
|
||||||
|
ApplicationBootstrapper.prototype.bootstrap = function (app) {
|
||||||
|
var angular = this.angular,
|
||||||
|
document = this.document,
|
||||||
|
$log = this.$log;
|
||||||
|
$log.info("Bootstrapping application " + (app || {}).name);
|
||||||
|
angular.element(document).ready(function () {
|
||||||
|
angular.bootstrap(document, [app.name]);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return ApplicationBootstrapper;
|
return ApplicationBootstrapper;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -56,13 +56,7 @@ define(
|
|||||||
function Bundle(path, bundleDefinition) {
|
function Bundle(path, bundleDefinition) {
|
||||||
// Start with defaults
|
// Start with defaults
|
||||||
var definition = Object.create(Constants.DEFAULT_BUNDLE),
|
var definition = Object.create(Constants.DEFAULT_BUNDLE),
|
||||||
logName = path,
|
logName = path;
|
||||||
self;
|
|
||||||
|
|
||||||
// Utility function for resolving paths in this bundle
|
|
||||||
function resolvePath(elements) {
|
|
||||||
return [path].concat(elements || []).join(Constants.SEPARATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override defaults with specifics from bundle definition
|
// Override defaults with specifics from bundle definition
|
||||||
Object.keys(bundleDefinition).forEach(function (k) {
|
Object.keys(bundleDefinition).forEach(function (k) {
|
||||||
@ -81,135 +75,138 @@ define(
|
|||||||
logName += ")";
|
logName += ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
self = {
|
this.path = path;
|
||||||
/**
|
this.definition = definition;
|
||||||
* Get the path to this bundle.
|
this.logName = logName;
|
||||||
* @memberof Bundle#
|
|
||||||
* @returns {string}
|
|
||||||
* @memberof platform/framework.Bundle#
|
|
||||||
*/
|
|
||||||
getPath: function () {
|
|
||||||
return path;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the path to this bundle's source folder. If an
|
|
||||||
* argument is provided, the path will be to the source
|
|
||||||
* file within the bundle's source file.
|
|
||||||
*
|
|
||||||
* @memberof Bundle#
|
|
||||||
* @param {string} [sourceFile] optionally, give a path to
|
|
||||||
* a specific source file in the bundle.
|
|
||||||
* @returns {string}
|
|
||||||
* @memberof platform/framework.Bundle#
|
|
||||||
*/
|
|
||||||
getSourcePath: function (sourceFile) {
|
|
||||||
var subpath = sourceFile ?
|
|
||||||
[ definition.sources, sourceFile ] :
|
|
||||||
[ definition.sources ];
|
|
||||||
|
|
||||||
return resolvePath(subpath);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the path to this bundle's resource folder. If an
|
|
||||||
* argument is provided, the path will be to the resource
|
|
||||||
* file within the bundle's resource file.
|
|
||||||
*
|
|
||||||
* @memberof Bundle#
|
|
||||||
* @param {string} [resourceFile] optionally, give a path to
|
|
||||||
* a specific resource file in the bundle.
|
|
||||||
* @returns {string}
|
|
||||||
* @memberof platform/framework.Bundle#
|
|
||||||
*/
|
|
||||||
getResourcePath: function (resourceFile) {
|
|
||||||
var subpath = resourceFile ?
|
|
||||||
[ definition.resources, resourceFile ] :
|
|
||||||
[ definition.resources ];
|
|
||||||
|
|
||||||
return resolvePath(subpath);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the path to this bundle's library folder. If an
|
|
||||||
* argument is provided, the path will be to the library
|
|
||||||
* file within the bundle's resource file.
|
|
||||||
*
|
|
||||||
* @memberof Bundle#
|
|
||||||
* @param {string} [libraryFile] optionally, give a path to
|
|
||||||
* a specific library file in the bundle.
|
|
||||||
* @returns {string}
|
|
||||||
* @memberof platform/framework.Bundle#
|
|
||||||
*/
|
|
||||||
getLibraryPath: function (libraryFile) {
|
|
||||||
var subpath = libraryFile ?
|
|
||||||
[ definition.libraries, libraryFile ] :
|
|
||||||
[ definition.libraries ];
|
|
||||||
|
|
||||||
return resolvePath(subpath);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get library configuration for this bundle. This is read
|
|
||||||
* from the bundle's definition; if the bundle is well-formed,
|
|
||||||
* it will resemble a require.config object.
|
|
||||||
* @memberof Bundle#
|
|
||||||
* @returns {object}
|
|
||||||
* @memberof platform/framework.Bundle#
|
|
||||||
*/
|
|
||||||
getConfiguration: function () {
|
|
||||||
return definition.configuration || {};
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get a log-friendly name for this bundle; this will
|
|
||||||
* include both the key (machine-readable name for this
|
|
||||||
* bundle) and the name (human-readable name for this
|
|
||||||
* bundle.)
|
|
||||||
* @returns {string} log-friendly name for this bundle
|
|
||||||
* @memberof platform/framework.Bundle#
|
|
||||||
*/
|
|
||||||
getLogName: function () {
|
|
||||||
return logName;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get all extensions exposed by this bundle of a given
|
|
||||||
* category.
|
|
||||||
*
|
|
||||||
* @param category
|
|
||||||
* @memberof Bundle#
|
|
||||||
* @returns {Array}
|
|
||||||
* @memberof platform/framework.Bundle#
|
|
||||||
*/
|
|
||||||
getExtensions: function (category) {
|
|
||||||
var extensions = definition.extensions[category] || [];
|
|
||||||
|
|
||||||
return extensions.map(function objectify(extDefinition) {
|
|
||||||
return new Extension(self, category, extDefinition);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get a list of all categories of extension exposed by
|
|
||||||
* this bundle.
|
|
||||||
*
|
|
||||||
* @memberof Bundle#
|
|
||||||
* @returns {Array}
|
|
||||||
* @memberof platform/framework.Bundle#
|
|
||||||
*/
|
|
||||||
getExtensionCategories: function () {
|
|
||||||
return Object.keys(definition.extensions);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the plain definition of this bundle, as read from
|
|
||||||
* its JSON declaration.
|
|
||||||
*
|
|
||||||
* @memberof Bundle#
|
|
||||||
* @returns {BundleDefinition} the raw definition of this bundle
|
|
||||||
* @memberof platform/framework.Bundle#
|
|
||||||
*/
|
|
||||||
getDefinition: function () {
|
|
||||||
return definition;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Utility function for resolving paths in this bundle
|
||||||
|
Bundle.prototype.resolvePath = function (elements) {
|
||||||
|
var path = this.path;
|
||||||
|
return [path].concat(elements || []).join(Constants.SEPARATOR);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path to this bundle.
|
||||||
|
* @returns {string} path to this bundle;
|
||||||
|
*/
|
||||||
|
Bundle.prototype.getPath = function () {
|
||||||
|
return this.path;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path to this bundle's source folder. If an
|
||||||
|
* argument is provided, the path will be to the source
|
||||||
|
* file within the bundle's source file.
|
||||||
|
*
|
||||||
|
* @param {string} [sourceFile] optionally, give a path to
|
||||||
|
* a specific source file in the bundle.
|
||||||
|
* @returns {string} path to the source folder (or to the
|
||||||
|
* source file within it)
|
||||||
|
*/
|
||||||
|
Bundle.prototype.getSourcePath = function (sourceFile) {
|
||||||
|
var subpath = sourceFile ?
|
||||||
|
[ this.definition.sources, sourceFile ] :
|
||||||
|
[ this.definition.sources ];
|
||||||
|
|
||||||
|
return this.resolvePath(subpath);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path to this bundle's resource folder. If an
|
||||||
|
* argument is provided, the path will be to the resource
|
||||||
|
* file within the bundle's resource file.
|
||||||
|
*
|
||||||
|
* @param {string} [resourceFile] optionally, give a path to
|
||||||
|
* a specific resource file in the bundle.
|
||||||
|
* @returns {string} path to the resource folder (or to the
|
||||||
|
* resource file within it)
|
||||||
|
*/
|
||||||
|
Bundle.prototype.getResourcePath = function (resourceFile) {
|
||||||
|
var subpath = resourceFile ?
|
||||||
|
[ this.definition.resources, resourceFile ] :
|
||||||
|
[ this.definition.resources ];
|
||||||
|
|
||||||
|
return this.resolvePath(subpath);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path to this bundle's library folder. If an
|
||||||
|
* argument is provided, the path will be to the library
|
||||||
|
* file within the bundle's resource file.
|
||||||
|
*
|
||||||
|
* @param {string} [libraryFile] optionally, give a path to
|
||||||
|
* a specific library file in the bundle.
|
||||||
|
* @returns {string} path to the resource folder (or to the
|
||||||
|
* resource file within it)
|
||||||
|
*/
|
||||||
|
Bundle.prototype.getLibraryPath = function (libraryFile) {
|
||||||
|
var subpath = libraryFile ?
|
||||||
|
[ this.definition.libraries, libraryFile ] :
|
||||||
|
[ this.definition.libraries ];
|
||||||
|
|
||||||
|
return this.resolvePath(subpath);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get library configuration for this bundle. This is read
|
||||||
|
* from the bundle's definition; if the bundle is well-formed,
|
||||||
|
* it will resemble a require.config object.
|
||||||
|
* @returns {object} library configuration
|
||||||
|
*/
|
||||||
|
Bundle.prototype.getConfiguration = function () {
|
||||||
|
return this.definition.configuration || {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a log-friendly name for this bundle; this will
|
||||||
|
* include both the key (machine-readable name for this
|
||||||
|
* bundle) and the name (human-readable name for this
|
||||||
|
* bundle.)
|
||||||
|
* @returns {string} log-friendly name for this bundle
|
||||||
|
*/
|
||||||
|
Bundle.prototype.getLogName = function () {
|
||||||
|
return this.logName;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all extensions exposed by this bundle of a given
|
||||||
|
* category.
|
||||||
|
*
|
||||||
|
* @param {string} category name of the extension category
|
||||||
|
* @returns {Array} extension definitions of that cataegory
|
||||||
|
*/
|
||||||
|
Bundle.prototype.getExtensions = function (category) {
|
||||||
|
var extensions = this.definition.extensions[category] || [],
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
return extensions.map(function objectify(extDefinition) {
|
||||||
|
return new Extension(self, category, extDefinition);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of all extension categories exposed by this bundle.
|
||||||
|
*
|
||||||
|
* @returns {string[]} the extension categories
|
||||||
|
*/
|
||||||
|
Bundle.prototype.getExtensionCategories = function () {
|
||||||
|
return Object.keys(this.definition.extensions);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the plain definition of this bundle, as read from
|
||||||
|
* its JSON declaration.
|
||||||
|
*
|
||||||
|
* @returns {platform/framework.BundleDefinition} the raw
|
||||||
|
* definition of this bundle
|
||||||
|
*/
|
||||||
|
Bundle.prototype.getDefinition = function () {
|
||||||
|
return this.definition;
|
||||||
|
};
|
||||||
|
|
||||||
return Bundle;
|
return Bundle;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -41,10 +41,26 @@ define(
|
|||||||
*
|
*
|
||||||
* @memberof platform/framework
|
* @memberof platform/framework
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {object} $http Angular's HTTP requester
|
* @param $http Angular's HTTP requester
|
||||||
* @param {object} $log Angular's logging service
|
* @param $log Angular's logging service
|
||||||
*/
|
*/
|
||||||
function BundleLoader($http, $log) {
|
function BundleLoader($http, $log) {
|
||||||
|
this.$http = $http;
|
||||||
|
this.$log = $log;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a group of bundles, to be used to constitute the
|
||||||
|
* application by later framework initialization phases.
|
||||||
|
*
|
||||||
|
* @param {string|string[]} an array of bundle names to load, or
|
||||||
|
* the name of a JSON file containing that array
|
||||||
|
* @returns {Promise.<Bundle[]>} a promise for the loaded bundles
|
||||||
|
*/
|
||||||
|
BundleLoader.prototype.loadBundles = function (bundles) {
|
||||||
|
var $http = this.$http,
|
||||||
|
$log = this.$log;
|
||||||
|
|
||||||
// Utility function; load contents of JSON file using $http
|
// Utility function; load contents of JSON file using $http
|
||||||
function getJSON(file) {
|
function getJSON(file) {
|
||||||
@ -92,7 +108,7 @@ define(
|
|||||||
var bundlePromises = bundleArray.map(loadBundle);
|
var bundlePromises = bundleArray.map(loadBundle);
|
||||||
|
|
||||||
return Promise.all(bundlePromises)
|
return Promise.all(bundlePromises)
|
||||||
.then(filterBundles);
|
.then(filterBundles);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load all bundles named in the referenced file. The file is
|
// Load all bundles named in the referenced file. The file is
|
||||||
@ -101,31 +117,10 @@ define(
|
|||||||
return getJSON(listFile).then(loadBundlesFromArray);
|
return getJSON(listFile).then(loadBundlesFromArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load all indicated bundles. If the argument is an array,
|
return Array.isArray(bundles) ? loadBundlesFromArray(bundles) :
|
||||||
// this is taken to be a list of all bundles to load; if it
|
(typeof bundles === 'string') ? loadBundlesFromFile(bundles) :
|
||||||
// is a string, then it is treated as the name of a JSON
|
Promise.reject(new Error(INVALID_ARGUMENT_MESSAGE));
|
||||||
// file containing the list of bundles to load.
|
};
|
||||||
function loadBundles(bundles) {
|
|
||||||
return Array.isArray(bundles) ? loadBundlesFromArray(bundles) :
|
|
||||||
(typeof bundles === 'string') ? loadBundlesFromFile(bundles) :
|
|
||||||
Promise.reject(new Error(INVALID_ARGUMENT_MESSAGE));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Load a group of bundles, to be used to constitute the
|
|
||||||
* application by later framework initialization phases.
|
|
||||||
*
|
|
||||||
* @memberof BundleLoader#
|
|
||||||
* @param {string|string[]} an array of bundle names to load, or
|
|
||||||
* the name of a JSON file containing that array
|
|
||||||
* @returns {Promise.<Bundle[]>}
|
|
||||||
* @memberof platform/framework.BundleLoader#
|
|
||||||
*/
|
|
||||||
loadBundles: loadBundles
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return BundleLoader;
|
return BundleLoader;
|
||||||
}
|
}
|
||||||
|
@ -78,94 +78,93 @@ define(
|
|||||||
// Attach bundle metadata
|
// Attach bundle metadata
|
||||||
extensionDefinition.bundle = bundle.getDefinition();
|
extensionDefinition.bundle = bundle.getDefinition();
|
||||||
|
|
||||||
return {
|
this.logName = logName;
|
||||||
/**
|
this.bundle = bundle;
|
||||||
* Get the machine-readable identifier for this extension.
|
this.category = category;
|
||||||
*
|
this.definition = definition;
|
||||||
* @returns {string}
|
this.extensionDefinition = extensionDefinition;
|
||||||
* @memberof platform/framework.Extension#
|
|
||||||
*/
|
|
||||||
getKey: function () {
|
|
||||||
return definition.key || "undefined";
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the bundle which declared this extension.
|
|
||||||
*
|
|
||||||
* @memberof Extension#
|
|
||||||
* @returns {Bundle}
|
|
||||||
* @memberof platform/framework.Extension#
|
|
||||||
*/
|
|
||||||
getBundle: function () {
|
|
||||||
return bundle;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the category into which this extension falls.
|
|
||||||
* (e.g. "directives")
|
|
||||||
*
|
|
||||||
* @memberof Extension#
|
|
||||||
* @returns {string}
|
|
||||||
* @memberof platform/framework.Extension#
|
|
||||||
*/
|
|
||||||
getCategory: function () {
|
|
||||||
return category;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Check whether or not this extension should have an
|
|
||||||
* associated implementation module which may need to
|
|
||||||
* be loaded.
|
|
||||||
*
|
|
||||||
* @returns {boolean} true if an implementation separate
|
|
||||||
* from this definition should also be loaded
|
|
||||||
* @memberof platform/framework.Extension#
|
|
||||||
*/
|
|
||||||
hasImplementation: function () {
|
|
||||||
return definition.implementation !== undefined;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the path to the AMD module which implements this
|
|
||||||
* extension. Will return undefined if there is no
|
|
||||||
* implementation associated with this extension.
|
|
||||||
*
|
|
||||||
* @memberof Extension#
|
|
||||||
* @returns {string} path to implementation, or undefined
|
|
||||||
* @memberof platform/framework.Extension#
|
|
||||||
*/
|
|
||||||
getImplementationPath: function () {
|
|
||||||
return definition.implementation ?
|
|
||||||
bundle.getSourcePath(definition.implementation) :
|
|
||||||
undefined;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get a log-friendly name for this extension; this will
|
|
||||||
* include both the key (machine-readable name for this
|
|
||||||
* extension) and the name (human-readable name for this
|
|
||||||
* extension.)
|
|
||||||
* @returns {string} log-friendly name for this extension
|
|
||||||
* @memberof platform/framework.Extension#
|
|
||||||
*/
|
|
||||||
getLogName: function () {
|
|
||||||
return logName;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the plain definition of the extension.
|
|
||||||
*
|
|
||||||
* Note that this definition will have an additional "bundle"
|
|
||||||
* field which points back to the bundle which defined the
|
|
||||||
* extension, as a convenience.
|
|
||||||
*
|
|
||||||
* @memberof Extension#
|
|
||||||
* @returns {ExtensionDefinition} the plain definition of
|
|
||||||
* this extension, as read from the bundle
|
|
||||||
* declaration.
|
|
||||||
* @memberof platform/framework.Extension#
|
|
||||||
*/
|
|
||||||
getDefinition: function () {
|
|
||||||
return extensionDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the machine-readable identifier for this extension.
|
||||||
|
*
|
||||||
|
* @returns {string} the identifier for this extension
|
||||||
|
*/
|
||||||
|
Extension.prototype.getKey = function () {
|
||||||
|
return this.definition.key || "undefined";
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the bundle which declared this extension.
|
||||||
|
*
|
||||||
|
* @returns {Bundle} the declaring bundle
|
||||||
|
*/
|
||||||
|
Extension.prototype.getBundle = function () {
|
||||||
|
return this.bundle;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the category into which this extension falls.
|
||||||
|
* (e.g. "directives")
|
||||||
|
*
|
||||||
|
* @returns {string} the extension category
|
||||||
|
*/
|
||||||
|
Extension.prototype.getCategory = function () {
|
||||||
|
return this.category;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether or not this extension should have an
|
||||||
|
* associated implementation module which may need to
|
||||||
|
* be loaded.
|
||||||
|
*
|
||||||
|
* @returns {boolean} true if an implementation separate
|
||||||
|
* from this definition should also be loaded
|
||||||
|
*/
|
||||||
|
Extension.prototype.hasImplementation = function () {
|
||||||
|
return this.definition.implementation !== undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path to the AMD module which implements this
|
||||||
|
* extension. Will return undefined if there is no
|
||||||
|
* implementation associated with this extension.
|
||||||
|
*
|
||||||
|
* @returns {string} path to implementation, or undefined
|
||||||
|
*/
|
||||||
|
Extension.prototype.getImplementationPath = function () {
|
||||||
|
return this.definition.implementation ?
|
||||||
|
this.bundle.getSourcePath(this.definition.implementation) :
|
||||||
|
undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a log-friendly name for this extension; this will
|
||||||
|
* include both the key (machine-readable name for this
|
||||||
|
* extension) and the name (human-readable name for this
|
||||||
|
* extension.)
|
||||||
|
*
|
||||||
|
* @returns {string} log-friendly name for this extension
|
||||||
|
*/
|
||||||
|
Extension.prototype.getLogName = function () {
|
||||||
|
return this.logName;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the plain definition of the extension.
|
||||||
|
*
|
||||||
|
* Note that this definition will have an additional "bundle"
|
||||||
|
* field which points back to the bundle which defined the
|
||||||
|
* extension, as a convenience.
|
||||||
|
*
|
||||||
|
* @returns {ExtensionDefinition} the plain definition of
|
||||||
|
* this extension, as read from the bundle
|
||||||
|
* declaration.
|
||||||
|
*/
|
||||||
|
Extension.prototype.getDefinition = function () {
|
||||||
|
return this.extensionDefinition;
|
||||||
|
};
|
||||||
|
|
||||||
return Extension;
|
return Extension;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,131 +37,191 @@ define(
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function CustomRegistrars(app, $log) {
|
function CustomRegistrars(app, $log) {
|
||||||
|
this.app = app;
|
||||||
|
this.$log = $log;
|
||||||
|
}
|
||||||
|
|
||||||
// Used to create custom registration functions which map to
|
// Utility; bind a function to a "this" pointer
|
||||||
// named methods on Angular modules, which follow the normal
|
function bind(fn, thisArg) {
|
||||||
// app.method(key, [ deps..., function ]) pattern.
|
return function () {
|
||||||
function CustomRegistrar(angularFunction) {
|
return fn.apply(thisArg, arguments);
|
||||||
return function (extension, index) {
|
|
||||||
var key = extension.key,
|
|
||||||
dependencies = extension.depends || [];
|
|
||||||
|
|
||||||
if (!key) {
|
|
||||||
$log.warn([
|
|
||||||
"Cannot register ",
|
|
||||||
angularFunction,
|
|
||||||
" ",
|
|
||||||
index,
|
|
||||||
", no key specified. ",
|
|
||||||
JSON.stringify(extension)
|
|
||||||
].join(""));
|
|
||||||
} else {
|
|
||||||
$log.info([
|
|
||||||
"Registering ",
|
|
||||||
angularFunction,
|
|
||||||
": ",
|
|
||||||
key
|
|
||||||
].join(""));
|
|
||||||
app[angularFunction](
|
|
||||||
key,
|
|
||||||
dependencies.concat([extension])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerConstant(extension) {
|
|
||||||
var key = extension.key,
|
|
||||||
value = extension.value;
|
|
||||||
|
|
||||||
if (typeof key === "string" && value !== undefined) {
|
|
||||||
$log.info([
|
|
||||||
"Registering constant: ",
|
|
||||||
key,
|
|
||||||
" with value ",
|
|
||||||
value
|
|
||||||
].join(""));
|
|
||||||
app.constant(key, value);
|
|
||||||
} else {
|
|
||||||
$log.warn([
|
|
||||||
"Cannot register constant ",
|
|
||||||
key,
|
|
||||||
" with value ",
|
|
||||||
value
|
|
||||||
].join(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Custom registration function for extensions of category "runs"
|
|
||||||
function registerRun(extension) {
|
|
||||||
if (typeof extension === 'function') {
|
|
||||||
// Prepend dependencies, and schedule to run
|
|
||||||
app.run((extension.depends || []).concat([extension]));
|
|
||||||
} else {
|
|
||||||
// If it's not a function, no implementation was given
|
|
||||||
$log.warn([
|
|
||||||
"Cannot register run extension from ",
|
|
||||||
(extension.bundle || {}).path,
|
|
||||||
"; no implementation."
|
|
||||||
].join(""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Custom registration function for extensions of category "route"
|
|
||||||
function registerRoute(extension) {
|
|
||||||
var route = Object.create(extension);
|
|
||||||
|
|
||||||
// Adjust path for bundle
|
|
||||||
if (route.templateUrl) {
|
|
||||||
route.templateUrl = [
|
|
||||||
route.bundle.path,
|
|
||||||
route.bundle.resources,
|
|
||||||
route.templateUrl
|
|
||||||
].join(Constants.SEPARATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log the registration
|
|
||||||
$log.info("Registering route: " + (route.key || route.when));
|
|
||||||
|
|
||||||
// Register the route with Angular
|
|
||||||
app.config(['$routeProvider', function ($routeProvider) {
|
|
||||||
if (route.when) {
|
|
||||||
$routeProvider.when(route.when, route);
|
|
||||||
} else {
|
|
||||||
$routeProvider.otherwise(route);
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle service compositing
|
|
||||||
function registerComponents(components) {
|
|
||||||
return new ServiceCompositor(app, $log)
|
|
||||||
.registerCompositeServices(components);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utility; create a function which converts another function
|
|
||||||
// (which acts on single objects) to one which acts upon arrays.
|
|
||||||
function mapUpon(func) {
|
|
||||||
return function (array) {
|
|
||||||
return array.map(func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// More like key-value pairs than methods; key is the
|
|
||||||
// name of the extension category to be handled, and the value
|
|
||||||
// is the function which handles it.
|
|
||||||
return {
|
|
||||||
constants: mapUpon(registerConstant),
|
|
||||||
routes: mapUpon(registerRoute),
|
|
||||||
directives: mapUpon(new CustomRegistrar("directive")),
|
|
||||||
controllers: mapUpon(new CustomRegistrar("controller")),
|
|
||||||
services: mapUpon(new CustomRegistrar("service")),
|
|
||||||
runs: mapUpon(registerRun),
|
|
||||||
components: registerComponents
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used to create custom registration functions which map to
|
||||||
|
// named methods on Angular modules, which follow the normal
|
||||||
|
// app.method(key, [ deps..., function ]) pattern.
|
||||||
|
function customRegistrar(angularFunction) {
|
||||||
|
return function (extension, index) {
|
||||||
|
var app = this.app,
|
||||||
|
$log = this.$log,
|
||||||
|
key = extension.key,
|
||||||
|
dependencies = extension.depends || [];
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
$log.warn([
|
||||||
|
"Cannot register ",
|
||||||
|
angularFunction,
|
||||||
|
" ",
|
||||||
|
index,
|
||||||
|
", no key specified. ",
|
||||||
|
JSON.stringify(extension)
|
||||||
|
].join(""));
|
||||||
|
} else {
|
||||||
|
$log.info([
|
||||||
|
"Registering ",
|
||||||
|
angularFunction,
|
||||||
|
": ",
|
||||||
|
key
|
||||||
|
].join(""));
|
||||||
|
app[angularFunction](
|
||||||
|
key,
|
||||||
|
dependencies.concat([extension])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerConstant(extension) {
|
||||||
|
var app = this.app,
|
||||||
|
$log = this.$log,
|
||||||
|
key = extension.key,
|
||||||
|
value = extension.value;
|
||||||
|
|
||||||
|
if (typeof key === "string" && value !== undefined) {
|
||||||
|
$log.info([
|
||||||
|
"Registering constant: ",
|
||||||
|
key,
|
||||||
|
" with value ",
|
||||||
|
value
|
||||||
|
].join(""));
|
||||||
|
app.constant(key, value);
|
||||||
|
} else {
|
||||||
|
$log.warn([
|
||||||
|
"Cannot register constant ",
|
||||||
|
key,
|
||||||
|
" with value ",
|
||||||
|
value
|
||||||
|
].join(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom registration function for extensions of category "runs"
|
||||||
|
function registerRun(extension) {
|
||||||
|
var app = this.app,
|
||||||
|
$log = this.$log;
|
||||||
|
|
||||||
|
if (typeof extension === 'function') {
|
||||||
|
// Prepend dependencies, and schedule to run
|
||||||
|
app.run((extension.depends || []).concat([extension]));
|
||||||
|
} else {
|
||||||
|
// If it's not a function, no implementation was given
|
||||||
|
$log.warn([
|
||||||
|
"Cannot register run extension from ",
|
||||||
|
(extension.bundle || {}).path,
|
||||||
|
"; no implementation."
|
||||||
|
].join(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom registration function for extensions of category "route"
|
||||||
|
function registerRoute(extension) {
|
||||||
|
var app = this.app,
|
||||||
|
$log = this.$log,
|
||||||
|
route = Object.create(extension);
|
||||||
|
|
||||||
|
// Adjust path for bundle
|
||||||
|
if (route.templateUrl) {
|
||||||
|
route.templateUrl = [
|
||||||
|
route.bundle.path,
|
||||||
|
route.bundle.resources,
|
||||||
|
route.templateUrl
|
||||||
|
].join(Constants.SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the registration
|
||||||
|
$log.info("Registering route: " + (route.key || route.when));
|
||||||
|
|
||||||
|
// Register the route with Angular
|
||||||
|
app.config(['$routeProvider', function ($routeProvider) {
|
||||||
|
if (route.when) {
|
||||||
|
$routeProvider.when(route.when, route);
|
||||||
|
} else {
|
||||||
|
$routeProvider.otherwise(route);
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle service compositing
|
||||||
|
function registerComponents(components) {
|
||||||
|
var app = this.app,
|
||||||
|
$log = this.$log;
|
||||||
|
return new ServiceCompositor(app, $log)
|
||||||
|
.registerCompositeServices(components);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility; create a function which converts another function
|
||||||
|
// (which acts on single objects) to one which acts upon arrays.
|
||||||
|
function mapUpon(func) {
|
||||||
|
return function (array) {
|
||||||
|
return array.map(bind(func, this));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// More like key-value pairs than methods; key is the
|
||||||
|
// name of the extension category to be handled, and the value
|
||||||
|
// is the function which handles it.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register constant values.
|
||||||
|
* @param {Array} extensions the resolved extensions
|
||||||
|
*/
|
||||||
|
CustomRegistrars.prototype.constants =
|
||||||
|
mapUpon(registerConstant);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register Angular routes.
|
||||||
|
* @param {Array} extensions the resolved extensions
|
||||||
|
*/
|
||||||
|
CustomRegistrars.prototype.routes =
|
||||||
|
mapUpon(registerRoute);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register Angular directives.
|
||||||
|
* @param {Array} extensions the resolved extensions
|
||||||
|
*/
|
||||||
|
CustomRegistrars.prototype.directives =
|
||||||
|
mapUpon(customRegistrar("directive"));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register Angular controllers.
|
||||||
|
* @param {Array} extensions the resolved extensions
|
||||||
|
*/
|
||||||
|
CustomRegistrars.prototype.controllers =
|
||||||
|
mapUpon(customRegistrar("controller"));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register Angular services.
|
||||||
|
* @param {Array} extensions the resolved extensions
|
||||||
|
*/
|
||||||
|
CustomRegistrars.prototype.services =
|
||||||
|
mapUpon(customRegistrar("service"));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register functions which will run after bootstrapping.
|
||||||
|
* @param {Array} extensions the resolved extensions
|
||||||
|
*/
|
||||||
|
CustomRegistrars.prototype.runs =
|
||||||
|
mapUpon(registerRun);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register components of composite services.
|
||||||
|
* @param {Array} extensions the resolved extensions
|
||||||
|
*/
|
||||||
|
CustomRegistrars.prototype.components =
|
||||||
|
registerComponents;
|
||||||
|
|
||||||
return CustomRegistrars;
|
return CustomRegistrars;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -47,14 +47,41 @@ define(
|
|||||||
// Track which extension categories have already been registered.
|
// Track which extension categories have already been registered.
|
||||||
// Exceptions will be thrown if the same extension category is
|
// Exceptions will be thrown if the same extension category is
|
||||||
// registered twice.
|
// registered twice.
|
||||||
var registeredCategories = {};
|
this.registeredCategories = {};
|
||||||
|
this.customRegistrars = customRegistrars || {};
|
||||||
|
this.app = app;
|
||||||
|
this.sorter = sorter;
|
||||||
|
this.$log = $log;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a group of resolved extensions with the Angular
|
||||||
|
* module managed by this registrar.
|
||||||
|
*
|
||||||
|
* For convenient chaining (particularly from the framework
|
||||||
|
* initializer's perspective), this returns the Angular
|
||||||
|
* module with which extensions were registered.
|
||||||
|
*
|
||||||
|
* @param {Object.<string, object[]>} extensionGroup an object
|
||||||
|
* containing key-value pairs, where keys are extension
|
||||||
|
* categories and values are arrays of resolved
|
||||||
|
* extensions
|
||||||
|
* @returns {angular.Module} the application module with
|
||||||
|
* which extensions were registered
|
||||||
|
*/
|
||||||
|
ExtensionRegistrar.prototype.registerExtensions = function (extensionGroup) {
|
||||||
|
var registeredCategories = this.registeredCategories,
|
||||||
|
customRegistrars = this.customRegistrars,
|
||||||
|
app = this.app,
|
||||||
|
sorter = this.sorter,
|
||||||
|
$log = this.$log;
|
||||||
|
|
||||||
// Used to build unique identifiers for individual extensions,
|
// Used to build unique identifiers for individual extensions,
|
||||||
// so that these can be registered separately with Angular
|
// so that these can be registered separately with Angular
|
||||||
function identify(category, extension, index) {
|
function identify(category, extension, index) {
|
||||||
var name = extension.key ?
|
var name = extension.key ?
|
||||||
("extension-" + extension.key + "#" + index) :
|
("extension-" + extension.key + "#" + index) :
|
||||||
("extension#" + index);
|
("extension#" + index);
|
||||||
return category + "[" + name + "]";
|
return category + "[" + name + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,8 +103,8 @@ define(
|
|||||||
function makeServiceArgument(category, extension) {
|
function makeServiceArgument(category, extension) {
|
||||||
var dependencies = extension.depends || [],
|
var dependencies = extension.depends || [],
|
||||||
factory = (typeof extension === 'function') ?
|
factory = (typeof extension === 'function') ?
|
||||||
new PartialConstructor(extension) :
|
new PartialConstructor(extension) :
|
||||||
staticFunction(extension);
|
staticFunction(extension);
|
||||||
|
|
||||||
return dependencies.concat([factory]);
|
return dependencies.concat([factory]);
|
||||||
}
|
}
|
||||||
@ -129,9 +156,9 @@ define(
|
|||||||
// an extension category (e.g. is suffixed by [])
|
// an extension category (e.g. is suffixed by [])
|
||||||
function isExtensionDependency(dependency) {
|
function isExtensionDependency(dependency) {
|
||||||
var index = dependency.indexOf(
|
var index = dependency.indexOf(
|
||||||
Constants.EXTENSION_SUFFIX,
|
Constants.EXTENSION_SUFFIX,
|
||||||
dependency.length - Constants.EXTENSION_SUFFIX.length
|
dependency.length - Constants.EXTENSION_SUFFIX.length
|
||||||
);
|
);
|
||||||
return index !== -1;
|
return index !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,8 +180,8 @@ define(
|
|||||||
(extension.depends || []).filter(
|
(extension.depends || []).filter(
|
||||||
isExtensionDependency
|
isExtensionDependency
|
||||||
).forEach(function (dependency) {
|
).forEach(function (dependency) {
|
||||||
needed[dependency] = true;
|
needed[dependency] = true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove categories which have been provided
|
// Remove categories which have been provided
|
||||||
@ -174,53 +201,29 @@ define(
|
|||||||
findEmptyExtensionDependencies(
|
findEmptyExtensionDependencies(
|
||||||
extensionGroup
|
extensionGroup
|
||||||
).forEach(function (name) {
|
).forEach(function (name) {
|
||||||
$log.info("Registering empty extension category " + name);
|
$log.info("Registering empty extension category " + name);
|
||||||
app.factory(name, [staticFunction([])]);
|
app.factory(name, [staticFunction([])]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerExtensionGroup(extensionGroup) {
|
// Announce we're entering a new phase
|
||||||
// Announce we're entering a new phase
|
$log.info("Registering extensions...");
|
||||||
$log.info("Registering extensions...");
|
|
||||||
|
|
||||||
// Register all declared extensions by category
|
// Register all declared extensions by category
|
||||||
Object.keys(extensionGroup).forEach(function (category) {
|
Object.keys(extensionGroup).forEach(function (category) {
|
||||||
registerExtensionsForCategory(
|
registerExtensionsForCategory(
|
||||||
category,
|
category,
|
||||||
sorter.sort(extensionGroup[category])
|
sorter.sort(extensionGroup[category])
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Also handle categories which are needed but not declared
|
// Also handle categories which are needed but not declared
|
||||||
registerEmptyDependencies(extensionGroup);
|
registerEmptyDependencies(extensionGroup);
|
||||||
|
|
||||||
// Return the application to which these extensions
|
// Return the application to which these extensions
|
||||||
// have been registered
|
// have been registered
|
||||||
return app;
|
return app;
|
||||||
}
|
};
|
||||||
|
|
||||||
customRegistrars = customRegistrars || {};
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Register a group of resolved extensions with the Angular
|
|
||||||
* module managed by this registrar.
|
|
||||||
*
|
|
||||||
* For convenient chaining (particularly from the framework
|
|
||||||
* initializer's perspective), this returns the Angular
|
|
||||||
* module with which extensions were registered.
|
|
||||||
*
|
|
||||||
* @param {Object.<string, object[]>} extensionGroup an object
|
|
||||||
* containing key-value pairs, where keys are extension
|
|
||||||
* categories and values are arrays of resolved
|
|
||||||
* extensions
|
|
||||||
* @returns {angular.Module} the application module with
|
|
||||||
* which extensions were registered
|
|
||||||
* @memberof platform/framework.ExtensionRegistrar#
|
|
||||||
*/
|
|
||||||
registerExtensions: registerExtensionGroup
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return ExtensionRegistrar;
|
return ExtensionRegistrar;
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,17 @@ define(
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ExtensionSorter($log) {
|
function ExtensionSorter($log) {
|
||||||
|
this.$log = $log;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort extensions according to priority.
|
||||||
|
*
|
||||||
|
* @param {object[]} extensions array of resolved extensions
|
||||||
|
* @returns {object[]} the same extensions, in priority order
|
||||||
|
*/
|
||||||
|
ExtensionSorter.prototype.sort = function (extensions) {
|
||||||
|
var $log = this.$log;
|
||||||
|
|
||||||
// Handle unknown or malformed priorities specified by extensions
|
// Handle unknown or malformed priorities specified by extensions
|
||||||
function unrecognizedPriority(extension) {
|
function unrecognizedPriority(extension) {
|
||||||
@ -68,7 +79,7 @@ define(
|
|||||||
// Should be a number; otherwise, issue a warning and
|
// Should be a number; otherwise, issue a warning and
|
||||||
// fall back to default priority level.
|
// fall back to default priority level.
|
||||||
return (typeof priority === 'number') ?
|
return (typeof priority === 'number') ?
|
||||||
priority : unrecognizedPriority(extension);
|
priority : unrecognizedPriority(extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach a numeric priority to an extension; this is done in
|
// Attach a numeric priority to an extension; this is done in
|
||||||
@ -98,22 +109,11 @@ define(
|
|||||||
return (b.priority - a.priority) || (a.index - b.index);
|
return (b.priority - a.priority) || (a.index - b.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return (extensions || [])
|
||||||
/**
|
.map(prioritize)
|
||||||
* Sort extensions according to priority.
|
.sort(compare)
|
||||||
*
|
.map(deprioritize);
|
||||||
* @param {object[]} extensions array of resolved extensions
|
};
|
||||||
* @returns {object[]} the same extensions, in priority order
|
|
||||||
* @memberof platform/framework.ExtensionSorter#
|
|
||||||
*/
|
|
||||||
sort: function (extensions) {
|
|
||||||
return (extensions || [])
|
|
||||||
.map(prioritize)
|
|
||||||
.sort(compare)
|
|
||||||
.map(deprioritize);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return ExtensionSorter;
|
return ExtensionSorter;
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,30 @@ define(
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ServiceCompositor(app, $log) {
|
function ServiceCompositor(app, $log) {
|
||||||
var latest = {},
|
this.latest = {};
|
||||||
providerLists = {}; // Track latest services registered
|
this.providerLists = {}; // Track latest services registered
|
||||||
|
this.app = app;
|
||||||
|
this.$log = $log;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register composite services with Angular. This will build
|
||||||
|
* up a dependency hierarchy between providers, aggregators,
|
||||||
|
* and/or decorators, such that a dependency upon the service
|
||||||
|
* type they expose shall be satisfied by their fully-wired
|
||||||
|
* whole.
|
||||||
|
*
|
||||||
|
* Note that this method assumes that a complete set of
|
||||||
|
* components shall be provided. Multiple calls to this
|
||||||
|
* method may not behave as expected.
|
||||||
|
*
|
||||||
|
* @param {Array} components extensions of category component
|
||||||
|
*/
|
||||||
|
ServiceCompositor.prototype.registerCompositeServices = function (components) {
|
||||||
|
var latest = this.latest,
|
||||||
|
providerLists = this.providerLists,
|
||||||
|
app = this.app,
|
||||||
|
$log = this.$log;
|
||||||
|
|
||||||
// Log a warning; defaults to "no service provided by"
|
// Log a warning; defaults to "no service provided by"
|
||||||
function warn(extension, category, message) {
|
function warn(extension, category, message) {
|
||||||
@ -200,33 +222,13 @@ define(
|
|||||||
registerLatest();
|
registerLatest();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial point of entry; just separate components by type
|
// Initial point of entry; split into three component types.
|
||||||
function registerCompositeServices(components) {
|
registerComposites(
|
||||||
registerComposites(
|
components.filter(hasType("provider")),
|
||||||
components.filter(hasType("provider")),
|
components.filter(hasType("aggregator")),
|
||||||
components.filter(hasType("aggregator")),
|
components.filter(hasType("decorator"))
|
||||||
components.filter(hasType("decorator"))
|
);
|
||||||
);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Register composite services with Angular. This will build
|
|
||||||
* up a dependency hierarchy between providers, aggregators,
|
|
||||||
* and/or decorators, such that a dependency upon the service
|
|
||||||
* type they expose shall be satisfied by their fully-wired
|
|
||||||
* whole.
|
|
||||||
*
|
|
||||||
* Note that this method assumes that a complete set of
|
|
||||||
* components shall be provided. Multiple calls to this
|
|
||||||
* method may not behave as expected.
|
|
||||||
*
|
|
||||||
* @param {Array} components extensions of category component
|
|
||||||
* @memberof platform/framework.ServiceCompositor#
|
|
||||||
*/
|
|
||||||
registerCompositeServices: registerCompositeServices
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return ServiceCompositor;
|
return ServiceCompositor;
|
||||||
}
|
}
|
||||||
|
@ -38,8 +38,27 @@ define(
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function BundleResolver(extensionResolver, requireConfigurator, $log) {
|
function BundleResolver(extensionResolver, requireConfigurator, $log) {
|
||||||
|
this.extensionResolver = extensionResolver;
|
||||||
|
this.requireConfigurator = requireConfigurator;
|
||||||
|
this.$log = $log;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Resolve all extensions exposed by these bundles.
|
||||||
|
*
|
||||||
|
* @param {Bundle[]} bundles the bundles to resolve
|
||||||
|
* @returns {Promise.<Object.<string, object[]>>} an promise
|
||||||
|
* for an object containing
|
||||||
|
* key-value pairs, where keys are extension
|
||||||
|
* categories and values are arrays of resolved
|
||||||
|
* extensions belonging to those categories
|
||||||
|
*/
|
||||||
|
BundleResolver.prototype.resolveBundles = function (bundles) {
|
||||||
|
var extensionResolver = this.extensionResolver,
|
||||||
|
requireConfigurator = this.requireConfigurator,
|
||||||
|
$log = this.$log;
|
||||||
|
|
||||||
|
/*
|
||||||
* Merge resolved bundles (where each is expressed as an
|
* Merge resolved bundles (where each is expressed as an
|
||||||
* object containing key-value pairs, where keys are extension
|
* object containing key-value pairs, where keys are extension
|
||||||
* categories and values are arrays of resolved extensions)
|
* categories and values are arrays of resolved extensions)
|
||||||
@ -99,28 +118,13 @@ define(
|
|||||||
.then(giveResult);
|
.then(giveResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
// First, make sure Require is suitably configured
|
||||||
/**
|
requireConfigurator.configure(bundles);
|
||||||
* Resolve all extensions exposed by these bundles.
|
|
||||||
*
|
|
||||||
* @param {Bundle[]} bundles the bundles to resolve
|
|
||||||
* @returns {Promise.<Object.<string, object[]>>} an promise
|
|
||||||
* for an object containing
|
|
||||||
* key-value pairs, where keys are extension
|
|
||||||
* categories and values are arrays of resolved
|
|
||||||
* extensions belonging to those categories
|
|
||||||
* @memberof platform/framework.BundleResolver#
|
|
||||||
*/
|
|
||||||
resolveBundles: function (bundles) {
|
|
||||||
// First, make sure Require is suitably configured
|
|
||||||
requireConfigurator.configure(bundles);
|
|
||||||
|
|
||||||
// Then, resolve all extension implementations.
|
// Then, resolve all extension implementations.
|
||||||
return Promise.all(bundles.map(resolveBundle))
|
return Promise.all(bundles.map(resolveBundle))
|
||||||
.then(mergeResolvedBundles);
|
.then(mergeResolvedBundles);
|
||||||
}
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return BundleResolver;
|
return BundleResolver;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,27 @@ define(
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ExtensionResolver(loader, $log) {
|
function ExtensionResolver(loader, $log) {
|
||||||
|
this.loader = loader;
|
||||||
|
this.$log = $log;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the provided extension; this will give a promise
|
||||||
|
* for the extension's implementation, if one has been
|
||||||
|
* specified, or for the plain definition of the extension
|
||||||
|
* otherwise. The plain definition will also be given
|
||||||
|
* if the implementation fails to load for some reason.
|
||||||
|
*
|
||||||
|
* All key-value pairs from the extension definition
|
||||||
|
* will additionally be attached to any loaded implementation.
|
||||||
|
*
|
||||||
|
* @param {Extension} extension the extension to resolve
|
||||||
|
* @returns {Promise} a promise for the resolved extension
|
||||||
|
*/
|
||||||
|
ExtensionResolver.prototype.resolve = function (extension) {
|
||||||
|
var loader = this.loader,
|
||||||
|
$log = this.$log;
|
||||||
|
|
||||||
function loadImplementation(extension) {
|
function loadImplementation(extension) {
|
||||||
var implPath = extension.getImplementationPath(),
|
var implPath = extension.getImplementationPath(),
|
||||||
implPromise = loader.load(implPath),
|
implPromise = loader.load(implPath),
|
||||||
@ -57,8 +78,8 @@ define(
|
|||||||
// loaded implementation.
|
// loaded implementation.
|
||||||
function attachDefinition(impl) {
|
function attachDefinition(impl) {
|
||||||
var result = (typeof impl === 'function') ?
|
var result = (typeof impl === 'function') ?
|
||||||
constructorFor(impl) :
|
constructorFor(impl) :
|
||||||
Object.create(impl);
|
Object.create(impl);
|
||||||
|
|
||||||
// Copy over static properties
|
// Copy over static properties
|
||||||
Object.keys(impl).forEach(function (k) {
|
Object.keys(impl).forEach(function (k) {
|
||||||
@ -84,11 +105,11 @@ define(
|
|||||||
function handleError(err) {
|
function handleError(err) {
|
||||||
// Build up a log message from parts
|
// Build up a log message from parts
|
||||||
var message = [
|
var message = [
|
||||||
"Could not load implementation for extension ",
|
"Could not load implementation for extension ",
|
||||||
extension.getLogName(),
|
extension.getLogName(),
|
||||||
" due to ",
|
" due to ",
|
||||||
err.message
|
err.message
|
||||||
].join("");
|
].join("");
|
||||||
|
|
||||||
// Log that the extension was not loaded
|
// Log that the extension was not loaded
|
||||||
$log.warn(message);
|
$log.warn(message);
|
||||||
@ -107,33 +128,16 @@ define(
|
|||||||
return implPromise.then(attachDefinition, handleError);
|
return implPromise.then(attachDefinition, handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
// Log that loading has begun
|
||||||
/**
|
$log.info([
|
||||||
* Resolve the provided extension; this will give a promise
|
"Resolving extension ",
|
||||||
* for the extension's implementation, if one has been
|
extension.getLogName()
|
||||||
* specified, or for the plain definition of the extension
|
].join(""));
|
||||||
* otherwise. The plain definition will also be given
|
|
||||||
* if the implementation fails to load for some reason.
|
|
||||||
*
|
|
||||||
* All key-value pairs from the extension definition
|
|
||||||
* will additionally be attached to any loaded implementation.
|
|
||||||
*
|
|
||||||
* @param {Extension} extension
|
|
||||||
* @memberof platform/framework.ExtensionResolver#
|
|
||||||
*/
|
|
||||||
resolve: function (extension) {
|
|
||||||
// Log that loading has begun
|
|
||||||
$log.info([
|
|
||||||
"Resolving extension ",
|
|
||||||
extension.getLogName()
|
|
||||||
].join(""));
|
|
||||||
|
|
||||||
return extension.hasImplementation() ?
|
return extension.hasImplementation() ?
|
||||||
loadImplementation(extension) :
|
loadImplementation(extension) :
|
||||||
Promise.resolve(extension.getDefinition());
|
Promise.resolve(extension.getDefinition());
|
||||||
}
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return ExtensionResolver;
|
return ExtensionResolver;
|
||||||
}
|
}
|
||||||
|
@ -39,31 +39,27 @@ define(
|
|||||||
* @param {*} $log Angular's logging service
|
* @param {*} $log Angular's logging service
|
||||||
*/
|
*/
|
||||||
function ImplementationLoader(require) {
|
function ImplementationLoader(require) {
|
||||||
function loadModule(path) {
|
this.require = require;
|
||||||
return new Promise(function (fulfill, reject) {
|
|
||||||
require([path], fulfill, reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Load an extension's implementation; or, equivalently,
|
|
||||||
* load an AMD module. This is fundamentally similar
|
|
||||||
* to a call to RequireJS, except that the result is
|
|
||||||
* wrapped in a promise. The promise will be fulfilled
|
|
||||||
* with the loaded module, or rejected with the error
|
|
||||||
* reported by Require.
|
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @memberof ImplementationLoader#
|
|
||||||
* @param {string} path the path to the module to load
|
|
||||||
* @returns {Promise} a promise for the specified module.
|
|
||||||
* @memberof platform/framework.ImplementationLoader#
|
|
||||||
*/
|
|
||||||
load: loadModule
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an extension's implementation; or, equivalently,
|
||||||
|
* load an AMD module. This is fundamentally similar
|
||||||
|
* to a call to RequireJS, except that the result is
|
||||||
|
* wrapped in a promise. The promise will be fulfilled
|
||||||
|
* with the loaded module, or rejected with the error
|
||||||
|
* reported by Require.
|
||||||
|
*
|
||||||
|
* @param {string} path the path to the module to load
|
||||||
|
* @returns {Promise} a promise for the specified module.
|
||||||
|
*/
|
||||||
|
ImplementationLoader.prototype.load = function loadModule(path) {
|
||||||
|
var require = this.require;
|
||||||
|
return new Promise(function (fulfill, reject) {
|
||||||
|
require([path], fulfill, reject);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return ImplementationLoader;
|
return ImplementationLoader;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -35,79 +35,79 @@ define(
|
|||||||
* @param requirejs an instance of RequireJS
|
* @param requirejs an instance of RequireJS
|
||||||
*/
|
*/
|
||||||
function RequireConfigurator(requirejs) {
|
function RequireConfigurator(requirejs) {
|
||||||
// Utility function to clone part of a bundle definition
|
this.requirejs = requirejs;
|
||||||
function clone(obj) {
|
|
||||||
return JSON.parse(JSON.stringify(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look up module configuration from the bundle definition.
|
|
||||||
// This will adjust paths to libraries as-needed.
|
|
||||||
function getConfiguration(bundle) {
|
|
||||||
var configuration = bundle.getConfiguration();
|
|
||||||
|
|
||||||
// Adjust paths to point to libraries
|
|
||||||
if (configuration.paths) {
|
|
||||||
// Don't modify the actual bundle definition...
|
|
||||||
configuration = clone(configuration);
|
|
||||||
// ...replace values in a clone instead.
|
|
||||||
Object.keys(configuration.paths).forEach(function (path) {
|
|
||||||
configuration.paths[path] =
|
|
||||||
bundle.getLibraryPath(configuration.paths[path]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build up paths and shim values from multiple bundles;
|
|
||||||
// this is sensitive to the value from baseConfiguration
|
|
||||||
// passed via reduce in buildConfiguration below, insofar
|
|
||||||
// as it assumes paths and shim will have initial empty values.
|
|
||||||
function mergeConfigurations(base, next) {
|
|
||||||
["paths", "shim"].forEach(function (k) {
|
|
||||||
Object.keys(next[k] || {}).forEach(function (p) {
|
|
||||||
base[k][p] = next[k][p];
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build a configuration object, to pass to requirejs.config,
|
|
||||||
// based on the defined configurations for all bundles.
|
|
||||||
// The paths and shim properties from all bundles will be
|
|
||||||
// merged to allow one requirejs.config call.
|
|
||||||
function buildConfiguration(bundles) {
|
|
||||||
// Provide an initial requirejs configuration...
|
|
||||||
var baseConfiguration = {
|
|
||||||
baseUrl: "",
|
|
||||||
paths: {},
|
|
||||||
shim: {}
|
|
||||||
},
|
|
||||||
// ...and pull out all bundle-specific parts
|
|
||||||
bundleConfigurations = bundles.map(getConfiguration);
|
|
||||||
|
|
||||||
// Reduce this into one configuration object.
|
|
||||||
return bundleConfigurations.reduce(
|
|
||||||
mergeConfigurations,
|
|
||||||
baseConfiguration
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Configure RequireJS to utilize any path/shim definitions
|
|
||||||
* provided by these bundles.
|
|
||||||
*
|
|
||||||
* @param {Bundle[]} the bundles to include in this
|
|
||||||
* configuration
|
|
||||||
* @memberof platform/framework.RequireConfigurator#
|
|
||||||
*/
|
|
||||||
configure: function (bundles) {
|
|
||||||
return requirejs.config(buildConfiguration(bundles));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Utility function to clone part of a bundle definition
|
||||||
|
function clone(obj) {
|
||||||
|
return JSON.parse(JSON.stringify(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up module configuration from the bundle definition.
|
||||||
|
// This will adjust paths to libraries as-needed.
|
||||||
|
function getConfiguration(bundle) {
|
||||||
|
var configuration = bundle.getConfiguration();
|
||||||
|
|
||||||
|
// Adjust paths to point to libraries
|
||||||
|
if (configuration.paths) {
|
||||||
|
// Don't modify the actual bundle definition...
|
||||||
|
configuration = clone(configuration);
|
||||||
|
// ...replace values in a clone instead.
|
||||||
|
Object.keys(configuration.paths).forEach(function (path) {
|
||||||
|
configuration.paths[path] =
|
||||||
|
bundle.getLibraryPath(configuration.paths[path]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build up paths and shim values from multiple bundles;
|
||||||
|
// this is sensitive to the value from baseConfiguration
|
||||||
|
// passed via reduce in buildConfiguration below, insofar
|
||||||
|
// as it assumes paths and shim will have initial empty values.
|
||||||
|
function mergeConfigurations(base, next) {
|
||||||
|
["paths", "shim"].forEach(function (k) {
|
||||||
|
Object.keys(next[k] || {}).forEach(function (p) {
|
||||||
|
base[k][p] = next[k][p];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a configuration object, to pass to requirejs.config,
|
||||||
|
// based on the defined configurations for all bundles.
|
||||||
|
// The paths and shim properties from all bundles will be
|
||||||
|
// merged to allow one requirejs.config call.
|
||||||
|
function buildConfiguration(bundles) {
|
||||||
|
// Provide an initial requirejs configuration...
|
||||||
|
var baseConfiguration = {
|
||||||
|
baseUrl: "",
|
||||||
|
paths: {},
|
||||||
|
shim: {}
|
||||||
|
},
|
||||||
|
// ...and pull out all bundle-specific parts
|
||||||
|
bundleConfigurations = bundles.map(getConfiguration);
|
||||||
|
|
||||||
|
// Reduce this into one configuration object.
|
||||||
|
return bundleConfigurations.reduce(
|
||||||
|
mergeConfigurations,
|
||||||
|
baseConfiguration
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure RequireJS to utilize any path/shim definitions
|
||||||
|
* provided by these bundles.
|
||||||
|
*
|
||||||
|
* @param {Bundle[]} the bundles to include in this
|
||||||
|
* configuration
|
||||||
|
* @memberof platform/framework.RequireConfigurator#
|
||||||
|
*/
|
||||||
|
RequireConfigurator.prototype.configure = function (bundles) {
|
||||||
|
return this.requirejs.config(buildConfiguration(bundles));
|
||||||
|
};
|
||||||
|
|
||||||
return RequireConfigurator;
|
return RequireConfigurator;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user