[Framework] Begin adding registration phase

Begin implementation registration phase of framework
layer initialization process. This phase is responsible
for registering resolved extensions with Angular, in a
manner than individual extensions can later request
dependencies from. WTD-518.
This commit is contained in:
Victor Woeltjen 2014-11-03 13:29:59 -08:00
parent eba3e47182
commit 650969d9c5
5 changed files with 203 additions and 0 deletions

View File

@ -8,6 +8,7 @@ define({
BUNDLE_LISTING_FILE: "bundles.json",
BUNDLE_FILE: "bundle.json",
SEPARATOR: "/",
EXTENSION_SUFFIX: "[]",
DEFAULT_BUNDLE: {
"sources": "src",
"resources": "res",

View File

@ -43,6 +43,12 @@ define(
logName += " from " + bundle.getLogName();
return {
/**
* @returns {string}
*/
getKey: function () {
return definition.key || "undefined";
},
/**
* @memberof Extension#
* @returns {Bundle}

View File

@ -0,0 +1,85 @@
/*global define,Promise*/
/**
* Module defining ExtensionRegistrar. Created by vwoeltje on 11/3/14.
*/
define(
['./Constants', './PartialConstructor'],
function (Constants, PartialConstructor) {
"use strict";
/**
*
* @constructor
*/
function ExtensionRegistrar(app, $log) {
// Track which extension categories have already been registered.
// Exceptions will be thrown if the same extension category is
// registered twice.
var registeredCategories = {};
function identify(category, extension, index) {
var name = extension.key ?
(extension.key + "-" + index) :
index;
return category + "[" + name + "]";
}
function echo() {
return arguments.slice;
}
function staticFunction(value) {
return function () { return value; }
}
// Utility function; create the second argument for Angular's
// .service service registration method (an array containing
// both dependencies and a factory method for the service.)
function makeServiceArgument(extension) {
var dependencies = extension.depends || [],
factory = (typeof extension === 'function') ?
new PartialConstructor(extension) :
staticFunction(extension);
return dependencies.concat([factory]);
}
function registerExtensionArraysForCategory(category, names) {
var name = category + Constants.EXTENSION_SUFFIX;
app.factory(name, names.concat([echo]));
}
function registerExtensions(category, extensions) {
var names = [];
function registerExtension(extension, index) {
var name = identify(category, extension, index);
// Track individual extension names as-registered
names.push(name);
app.factory(name, makeServiceArgument(extension));
}
if (registeredCategories[category]) {
$log.warn([
"Tried to register extensions for category ",
category,
" more than once. Ignoring all but first set."
].join(""));
} else {
extensions.forEach(registerExtension);
registerExtensionArraysForCategory(category, names);
registeredCategories[category] = true;
}
}
return {
registerExtensions: registerExtensions
};
}
return ExtensionRegistrar;
}
);

View File

@ -0,0 +1,65 @@
/*global define,Promise*/
/**
* Module defining FrameworkInitializer. Created by vwoeltje on 11/3/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
* @param {BundleLoader} loader
* @param {ExtensionResolver} resolver
* @param {ExtensionRegistrar} registrar
* @param {ApplicationBootstrapper} bootstrapper
*/
function FrameworkInitializer(loader, resolver, registrar, bootstrapper) {
function registerExtensions(resolvedExtensions) {
Object.keys(resolvedExtensions).forEach(function (category) {
registrar.registerExtensions(
category,
resolvedExtensions[category]
);
});
}
/**
*
* @param bundles
* @returns {Object.<string, object[]>} an object mapping
*/
function resolveExtensions(bundles) {
var resolvedExtensions = {};
function resolveExtensionsForBundle(bundle) {
}
return Promises.all(bundles.map(resolveExtensionsForBundle)).then(function () {
return resolvedExtensions;
});
}
function loadBundles(bundleList) {
return loader.loadBundles(bundleList);
}
return {
runApplication: function (bundleList) {
return loadBundles()
.then(resolveExtensions)
.then(registerExtensions)
.then(bootstrapApplication);
}
};
}
return FrameworkInitializer;
}
);

View File

@ -0,0 +1,46 @@
/*global define,Promise*/
/**
* Module defining PartialConstructor. Created by vwoeltje on 11/3/14.
*/
define(
[],
function () {
"use strict";
/**
* A partial constructor is used to instantiate objects in two
* stages:
*
* * First, dependencies injected from Angular
* * Second, arguments passed at run-time
*
* This allows extensions to accept both their Angular-injected
* dependencies and their per-instance attributes all in one
* constructor invocation. User code for these extensions then
* does not see the Angular dependency arguments; they may
* instantiate instances of these extensions by passing only
* those per-instance arguments.
*
* @constructor
*/
function PartialConstructor(Constructor) {
return function () { // Bind services
var dependencies = arguments.slice();
return function () { // Bind everything else
var other = arguments.slice(),
instance = {};
Constructor.apply(instance, dependencies.concat(other));
instance.prototype = Constructor.prototype;
return instance;
};
};
}
return PartialConstructor;
}
);