Skip to content

Commit

Permalink
feat(config): accepts classes beside module id string
Browse files Browse the repository at this point in the history
  • Loading branch information
bigopon committed May 14, 2018
1 parent e8b6831 commit 80a3d39
Show file tree
Hide file tree
Showing 3 changed files with 214 additions and 64 deletions.
69 changes: 38 additions & 31 deletions config.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
System.config({
defaultJSExtensions: true,
transpiler: "babel",
babelOptions: {
"optional": [
"runtime",
"optimisation.modules.system"
]
},
paths: {
"github:*": "jspm_packages/github/*",
"aurelia-framework/*": "dist/*",
"npm:*": "jspm_packages/npm/*"
},

map: {
"aurelia-binding": "npm:aurelia-binding@1.0.0",
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0",
"aurelia-binding": "npm:aurelia-binding@1.7.1",
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.3.2",
"aurelia-loader": "npm:aurelia-loader@1.0.0",
"aurelia-logging": "npm:aurelia-logging@1.0.0",
"aurelia-metadata": "npm:aurelia-metadata@1.0.0",
"aurelia-pal": "npm:aurelia-pal@1.0.0",
"aurelia-logging": "npm:aurelia-logging@1.4.0",
"aurelia-metadata": "npm:aurelia-metadata@1.0.3",
"aurelia-pal": "npm:aurelia-pal@1.8.0",
"aurelia-pal-browser": "npm:aurelia-pal-browser@1.0.0",
"aurelia-path": "npm:aurelia-path@1.0.0",
"aurelia-task-queue": "npm:aurelia-task-queue@1.0.0",
"aurelia-templating": "npm:aurelia-templating@1.0.0",
"aurelia-path": "npm:aurelia-path@1.1.1",
"aurelia-task-queue": "npm:aurelia-task-queue@1.3.0",
"aurelia-templating": "npm:aurelia-templating@1.7.0",
"babel": "npm:babel-core@5.8.38",
"babel-runtime": "npm:babel-runtime@5.8.38",
"core-js": "npm:core-js@2.4.1",
Expand Down Expand Up @@ -44,38 +51,38 @@ System.config({
"process": "github:jspm/nodelibs-process@0.1.2",
"util": "npm:util@0.10.3"
},
"npm:aurelia-binding@1.0.0": {
"aurelia-logging": "npm:aurelia-logging@1.0.0",
"aurelia-metadata": "npm:aurelia-metadata@1.0.0",
"aurelia-pal": "npm:aurelia-pal@1.0.0",
"aurelia-task-queue": "npm:aurelia-task-queue@1.0.0"
"npm:aurelia-binding@1.7.1": {
"aurelia-logging": "npm:aurelia-logging@1.4.0",
"aurelia-metadata": "npm:aurelia-metadata@1.0.3",
"aurelia-pal": "npm:aurelia-pal@1.8.0",
"aurelia-task-queue": "npm:aurelia-task-queue@1.3.0"
},
"npm:aurelia-dependency-injection@1.0.0": {
"aurelia-metadata": "npm:aurelia-metadata@1.0.0",
"aurelia-pal": "npm:aurelia-pal@1.0.0"
"npm:aurelia-dependency-injection@1.3.2": {
"aurelia-metadata": "npm:aurelia-metadata@1.0.3",
"aurelia-pal": "npm:aurelia-pal@1.8.0"
},
"npm:aurelia-loader@1.0.0": {
"aurelia-metadata": "npm:aurelia-metadata@1.0.0",
"aurelia-path": "npm:aurelia-path@1.0.0"
"aurelia-metadata": "npm:aurelia-metadata@1.0.3",
"aurelia-path": "npm:aurelia-path@1.1.1"
},
"npm:aurelia-metadata@1.0.0": {
"aurelia-pal": "npm:aurelia-pal@1.0.0"
"npm:aurelia-metadata@1.0.3": {
"aurelia-pal": "npm:aurelia-pal@1.8.0"
},
"npm:aurelia-pal-browser@1.0.0": {
"aurelia-pal": "npm:aurelia-pal@1.0.0"
"aurelia-pal": "npm:aurelia-pal@1.8.0"
},
"npm:aurelia-task-queue@1.0.0": {
"aurelia-pal": "npm:aurelia-pal@1.0.0"
"npm:aurelia-task-queue@1.3.0": {
"aurelia-pal": "npm:aurelia-pal@1.8.0"
},
"npm:aurelia-templating@1.0.0": {
"aurelia-binding": "npm:aurelia-binding@1.0.0",
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0",
"npm:aurelia-templating@1.7.0": {
"aurelia-binding": "npm:aurelia-binding@1.7.1",
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.3.2",
"aurelia-loader": "npm:aurelia-loader@1.0.0",
"aurelia-logging": "npm:aurelia-logging@1.0.0",
"aurelia-metadata": "npm:aurelia-metadata@1.0.0",
"aurelia-pal": "npm:aurelia-pal@1.0.0",
"aurelia-path": "npm:aurelia-path@1.0.0",
"aurelia-task-queue": "npm:aurelia-task-queue@1.0.0"
"aurelia-logging": "npm:aurelia-logging@1.4.0",
"aurelia-metadata": "npm:aurelia-metadata@1.0.3",
"aurelia-pal": "npm:aurelia-pal@1.8.0",
"aurelia-path": "npm:aurelia-path@1.1.1",
"aurelia-task-queue": "npm:aurelia-task-queue@1.3.0"
},
"npm:babel-runtime@5.8.38": {
"process": "github:jspm/nodelibs-process@0.1.2"
Expand Down
123 changes: 91 additions & 32 deletions src/framework-configuration.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as TheLogManager from 'aurelia-logging';
import {ViewEngine} from 'aurelia-templating';
import {ViewEngine, HtmlBehaviorResource} from 'aurelia-templating';
import {join} from 'aurelia-path';
import {Container} from 'aurelia-dependency-injection';

const logger = TheLogManager.getLogger('aurelia');
const extPattern = /\.[^/.]+$/;

function runTasks(config, tasks) {
function runTasks(config: FrameworkConfiguration, tasks) {
let current;
let next = () => {
current = tasks.shift();
Expand All @@ -20,18 +20,30 @@ function runTasks(config, tasks) {
return next();
}

function loadPlugin(config, loader, info) {
interface FrameworkPluginInfo {
moduleId?: string;
resourcesRelativeTo?: string[];
configure?: (config: FrameworkConfiguration, pluginConfig?: any) => any;
config?: any;
}

function loadPlugin(config: FrameworkConfiguration, loader: Loader, info: FrameworkPluginInfo) {
logger.debug(`Loading plugin ${info.moduleId}.`);
config.resourcesRelativeTo = info.resourcesRelativeTo;
if (typeof info.moduleId === 'string') {
config.resourcesRelativeTo = info.resourcesRelativeTo;

let id = info.moduleId; // General plugins installed/configured by the end user.
let id = info.moduleId; // General plugins installed/configured by the end user.

if (info.resourcesRelativeTo.length > 1 ) { // In case of bootstrapper installed plugins like `aurelia-templating-resources` or `aurelia-history-browser`.
return loader.normalize(info.moduleId, info.resourcesRelativeTo[1])
.then(normalizedId => _loadPlugin(normalizedId));
}
if (info.resourcesRelativeTo.length > 1 ) { // In case of bootstrapper installed plugins like `aurelia-templating-resources` or `aurelia-history-browser`.
return loader.normalize(info.moduleId, info.resourcesRelativeTo[1])
.then(normalizedId => _loadPlugin(normalizedId));
}

return _loadPlugin(id);
return _loadPlugin(id);
} else if (typeof info.configure === 'function') {
// use info.config || {} to keep behavior consistent with loading from string
return Promise.resolve(info.configure.call(null, config, info.config || {}));
}

function _loadPlugin(moduleId) {
return loader.loadModule(moduleId).then(m => { // eslint-disable-line consistent-return
Expand Down Expand Up @@ -98,14 +110,20 @@ function loadResources(aurelia, resourcesToLoad, appResources) {
}
}

function getExt(name) { // eslint-disable-line consistent-return
function getExt(name: string) { // eslint-disable-line consistent-return
let match = name.match(extPattern);
if (match && match.length > 0) {
return (match[0].split('.'))[1];
}
}

function assertProcessed(plugins) {
function loadBehaviors(config: FrameworkConfiguration) {
return Promise.all(config.behaviorToLoad.map(m => m.load(config.container, m.target))).then(() => {
config.behaviorToLoad = null;
});
}

function assertProcessed(plugins: FrameworkConfiguration) {
if (plugins.processed) {
throw new Error('This config instance has already been applied. To load more plugins or global resources, create a new FrameworkConfiguration instance.');
}
Expand All @@ -132,13 +150,29 @@ export class FrameworkConfiguration {
constructor(aurelia: Aurelia) {
this.aurelia = aurelia;
this.container = aurelia.container;
/**
* Plugin / feature loadind instruction
* @type {FrameworkPluginInfo[]}
*/
this.info = [];
this.processed = false;
this.preTasks = [];
this.postTasks = [];
/**
* Custom element's metadata queue for loading view factory
* @type {HtmlBehaviorResource[]}
*/
this.behaviorToLoad = [];
this.resourcesToLoad = {};
this.preTask(() => aurelia.loader.normalize('aurelia-bootstrapper').then(name => this.bootstrapperName = name));
this.postTask(() => loadResources(aurelia, this.resourcesToLoad, aurelia.resources));
this.postTask(() => {
// if devs want to go all in static, and remove loader
// the following code shouldn't run
// add a check to make sure it only runs when there is something to do so
if (Object.keys(this.resourcesToLoad).length) {
return loadResources(aurelia, this.resourcesToLoad, aurelia.resources);
}
});
}

/**
Expand Down Expand Up @@ -202,19 +236,22 @@ export class FrameworkConfiguration {
* @param config The configuration for the specified plugin.
* @return Returns the current FrameworkConfiguration instance.
*/
feature(plugin: string, config?: any = {}): FrameworkConfiguration {
let hasIndex = /\/index$/i.test(plugin);
let moduleId = hasIndex || getExt(plugin) ? plugin : plugin + '/index';
let root = hasIndex ? plugin.substr(0, plugin.length - 6) : plugin;
return this.plugin({ moduleId, resourcesRelativeTo: [root, ''], config });
feature(plugin: string | ((config: FrameworkConfiguration, pluginConfig?: any) => any), config?: any = {}): FrameworkConfiguration {
if (typeof plugin === 'string') {
let hasIndex = /\/index$/i.test(plugin);
let moduleId = hasIndex || getExt(plugin) ? plugin : plugin + '/index';
let root = hasIndex ? plugin.substr(0, plugin.length - 6) : plugin;
return this.plugin({ moduleId, resourcesRelativeTo: [root, ''], config });
}
return this.plugin(plugin, config);
}
/**
* Adds globally available view resources to be imported into the Aurelia framework.
* @param resources The relative module id to the resource. (Relative to the plugin's installer.)
* @return Returns the current FrameworkConfiguration instance.
*/
globalResources(resources: string|string[]): FrameworkConfiguration {
globalResources(resources: string | Function | (string | Function)[]): FrameworkConfiguration {
assertProcessed(this);

let toAdd = Array.isArray(resources) ? resources : arguments;
Expand All @@ -223,19 +260,28 @@ export class FrameworkConfiguration {

for (let i = 0, ii = toAdd.length; i < ii; ++i) {
resource = toAdd[i];
if (typeof resource !== 'string') {
if (!resource) {
throw new Error(`Invalid resource path [${resource}]. Resources must be specified as relative module IDs.`);
}
if (typeof resource === 'string') {
let parent = resourcesRelativeTo[0];
let grandParent = resourcesRelativeTo[1];
let name = resource;

let parent = resourcesRelativeTo[0];
let grandParent = resourcesRelativeTo[1];
let name = resource;
if ((resource.startsWith('./') || resource.startsWith('../')) && parent !== '') {
name = join(parent, resource);
}

if ((resource.startsWith('./') || resource.startsWith('../')) && parent !== '') {
name = join(parent, resource);
this.resourcesToLoad[name] = { moduleId: name, relativeTo: grandParent };
} else {
let meta = this.aurelia.resources.autoRegister(this.container, resource);
if (meta instanceof HtmlBehaviorResource && meta.elementName !== null) {
this.behaviorToLoad.push(meta);
}
if (this.behaviorToLoad.length === 1) {
this.postTask(() => loadBehaviors(this));
}
}

this.resourcesToLoad[name] = { moduleId: name, relativeTo: grandParent };
}

return this;
Expand All @@ -256,17 +302,30 @@ export class FrameworkConfiguration {
/**
* Configures an external, 3rd party plugin before Aurelia starts.
* @param plugin The ID of the 3rd party plugin to configure.
* @param config The configuration for the specified plugin.
* @param pluginConfig The configuration for the specified plugin.
* @return Returns the current FrameworkConfiguration instance.
*/
plugin(plugin: string, config?: any): FrameworkConfiguration {
plugin(
plugin: string | ((frameworkConfig: FrameworkConfiguration) => any) | FrameworkPluginInfo,
pluginConfig?: any
): FrameworkConfiguration {
assertProcessed(this);

if (typeof (plugin) === 'string') {
return this.plugin({ moduleId: plugin, resourcesRelativeTo: [plugin, ''], config: config || {} });
let info: FrameworkPluginInfo;
switch (typeof plugin) {
case 'string':
info = { moduleId: plugin, resourcesRelativeTo: [plugin, ''], config: pluginConfig || {} };
break;
case 'function':
info = { configure: plugin, config: pluginConfig || {} };
break;
default:
// this is for internal use, from `feature` call
info = plugin;
break;
}

this.info.push(plugin);
this.info.push(info);
return this;
}

Expand Down
Loading

0 comments on commit 80a3d39

Please sign in to comment.