[Framework] Refactor source folder

Refactor framework source folder; move each initialization
stage into its own directory. WTD-518.
This commit is contained in:
Victor Woeltjen
2014-11-05 12:18:19 -08:00
parent dbd5b148e2
commit 73e767228f
11 changed files with 11 additions and 11 deletions

View File

@ -0,0 +1,156 @@
/*global define*/
define(
['../Constants', './Extension'],
function (Constants, Extension) {
"use strict";
/**
* A bundle's plain JSON definition.
*
* @name BundleDefinition
* @property {string} name the human-readable name of this bundle
* @property {string} sources the name of the directory which
* contains source code used by this bundle
* @property {string} resources the name of the directory which
* contains resource files used by this bundle
* @property {Object.<string,ExtensionDefinition[]>} [extensions={}]
* all extensions exposed by this bundle
*/
/**
* Instantiate a new reference to a bundle, based on its human-readable
* definition.
*
* @param {string} path the path to the directory containing
* this bundle
* @param {BundleDefinition} bundleDefinition
* @returns {{getDefinition: Function}}
* @constructor
*/
function Bundle(path, bundleDefinition) {
// Start with defaults
var definition = Object.create(Constants.DEFAULT_BUNDLE),
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
Object.keys(bundleDefinition).forEach(function (k) {
definition[k] = bundleDefinition[k];
});
// Record path to bundle in definition
definition.path = path;
// Build up the log-friendly name for this bundle
if (definition.key || definition.name) {
logName += "(";
logName += definition.key || "";
logName += (definition.key && definition.name) ? " " : "";
logName += definition.name || "";
logName += ")";
}
self = {
/**
* Get the path to this bundle.
* @memberof Bundle#
* @returns {string}
*/
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}
*/
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}
*/
getResourcePath: function (resourceFile) {
var subpath = resourceFile ?
[ definition.resources, resourceFile ] :
[ definition.resources ];
return resolvePath(subpath);
},
/**
* 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
*/
getLogName: function () {
return logName;
},
/**
* Get all extensions exposed by this bundle of a given
* category.
*
* @param category
* @memberof Bundle#
* @returns {Array}
*/
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}
*/
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
*/
getDefinition: function () {
return definition;
}
};
return self;
}
return Bundle;
}
);

View File

@ -0,0 +1,109 @@
/*global define,Promise*/
/**
* Module defining BundleLoader.js. Created by vwoeltje on 10/31/14.
*/
define(
['../Constants', './Bundle'],
function (Constants, Bundle) {
"use strict";
var INVALID_ARGUMENT_MESSAGE = "Malformed loadBundles argument; " +
"expected string or array",
BAD_CONTENTS_PREFIX = "Invalid bundle contents for ",
LOAD_ERROR_PREFIX = "Failed to load bundle ";
/**
* Loads bundle definitions and wraps them in interfaces which are
* useful to the framework. This provides the base information which
* will be used by later phases of framework layer initialization.
*
* @constructor
* @param {object} $http Angular's HTTP requester
* @param {object} $log Angular's logging service
*/
function BundleLoader($http, $log) {
// Utility function; load contents of JSON file using $http
function getJSON(file) {
return $http.get(file).then(function (response) {
return response.data;
});
}
// Remove bundles which failed to load properly.
// These should have been logged when loaded by
// loadBundleDefinition, so at this point they are safe
// to discard.
function filterBundles(array) {
return array.filter(function (x) { return x !== undefined; });
}
// Load a definition for a bundle
function loadBundleDefinition(bundlePath) {
return getJSON(bundlePath + "/" + Constants.BUNDLE_FILE).then(
function (x) {
if (x === null || typeof x !== 'object') {
$log.warn(BAD_CONTENTS_PREFIX + bundlePath);
return undefined;
}
return x;
},
function () {
$log.warn(LOAD_ERROR_PREFIX + bundlePath);
return undefined;
}
);
}
// Load an individual bundle, as a Bundle object.
// Returns undefined if the definition could not be loaded.
function loadBundle(bundlePath) {
return loadBundleDefinition(bundlePath).then(function (definition) {
return definition && (new Bundle(bundlePath, definition));
});
}
// Load all named bundles from the array, returned as an array
// of Bundle objects.
function loadBundlesFromArray(bundleArray) {
var bundlePromises = bundleArray.map(loadBundle);
return Promise.all(bundlePromises)
.then(filterBundles);
}
// Load all bundles named in the referenced file. The file is
// presumed to be a JSON file
function loadBundlesFromFile(listFile) {
return getJSON(listFile).then(loadBundlesFromArray);
}
// Load all indicated bundles. If the argument is an array,
// this is taken to be a list of all bundles to load; if it
// is a string, then it is treated as the name of a JSON
// 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[]>}
*/
loadBundles: loadBundles
};
}
return BundleLoader;
}
);

View File

@ -0,0 +1,142 @@
/*global define*/
define(
[],
function () {
"use strict";
/**
* An extension's plain JSON definition.
*
* @name ExtensionDefinition
* @property {string} [key] the machine-readable identifier for this
* extension
* @property {string} [implementation] the path to the AMD module
* which implements this extension; this path is relative
* to the containing bundle's source folder.
* @property {string[]} [depends=[]] the dependencies needed by this
* extension; these are strings as shall be passed to
* Angular's dependency resolution mechanism.
*/
/**
* Instantiate a new extension based on its definition. This serves
* primarily as a wrapper around the extension's definition to expose
* a useful interface.
*
* An extension
*
* @param {Bundle} bundle the bundle which exposed this extension
* @param {string} category the type of extension being exposed
* @param {ExtensionDefinition} definition the plain definition of
* this extension
* @constructor
*/
function Extension(bundle, category, definition) {
var logName = category,
extensionDefinition = {};
// Build up the log-friendly name for this bundle
if (definition.key || definition.name) {
logName += "(";
logName += definition.key || "";
logName += (definition.key && definition.name) ? " " : "";
logName += definition.name || "";
logName += ")";
}
logName += " from " + bundle.getLogName();
// Copy over definition. This allows us to attach the bundle
// definition without modifying the original definition object.
Object.keys(definition).forEach(function (k) {
extensionDefinition[k] = definition[k];
});
// Attach bundle metadata
extensionDefinition.bundle = bundle.getDefinition();
return {
/**
* Get the machine-readable identifier for this extension.
*
* @returns {string}
*/
getKey: function () {
return definition.key || "undefined";
},
/**
* Get the bundle which declared this extension.
*
* @memberof Extension#
* @returns {Bundle}
*/
getBundle: function () {
return bundle;
},
/**
* Get the category into which this extension falls.
* (e.g. "directives")
*
* @memberof Extension#
* @returns {string}
*/
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
*/
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
*/
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
*/
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.
*/
getDefinition: function () {
return extensionDefinition;
}
};
}
return Extension;
}
);