diff --git a/cli/domain/local.js b/cli/domain/local.js
index 5643904fb..3f484a7f3 100644
--- a/cli/domain/local.js
+++ b/cli/domain/local.js
@@ -14,7 +14,7 @@ var path = require('path');
var settings = require('../../resources/settings');
var Targz = require('tar.gz');
var uglifyJs = require('uglify-js');
-var validator = require('../../registry/domain/validator');
+var validator = require('../../registry/domain/validators');
var _ = require('underscore');
module.exports = function(){
@@ -119,11 +119,20 @@ module.exports = function(){
var components = fs.readdirSync(componentsDir).filter(function(file){
var filePath = path.resolve(componentsDir, file),
- isDir = fs.lstatSync(filePath).isDirectory();
+ isDir = fs.lstatSync(filePath).isDirectory(),
+ packagePath = path.join(filePath, 'package.json');
- return isDir ? (fs.readdirSync(filePath).filter(function(file){
- return file === 'package.json';
- }).length === 1) : false;
+ if(!isDir || !fs.existsSync(packagePath)){
+ return false;
+ }
+
+ var content = fs.readJsonSync(packagePath);
+
+ if(!content.oc || !!content.oc.packaged){
+ return false;
+ }
+
+ return true;
});
var fullPathComponents = _.map(components, function(component){
@@ -278,6 +287,7 @@ module.exports = function(){
delete component.oc.files.client;
component.oc.version = ocInfo.version;
+ component.oc.packaged = true;
if(!!component.oc.files.data){
var dataPath = path.join(componentPath, component.oc.files.data),
diff --git a/cli/facade/dev.js b/cli/facade/dev.js
index cd439b176..0d1526a1c 100644
--- a/cli/facade/dev.js
+++ b/cli/facade/dev.js
@@ -73,7 +73,7 @@ module.exports = function(dependencies){
if(!packaging){
packaging = true;
- logger.log('Packaging components...'.yellow);
+ logger.logNoNewLine('Packaging components...'.yellow);
async.eachSeries(componentsDirs, function(dir, cb){
local.package(dir, false, function(err){
@@ -85,15 +85,15 @@ module.exports = function(dependencies){
}, function(error){
if(!!error){
var errorDescription = ((error instanceof SyntaxError) || !!error.message) ? error.message : error;
- logger.log(format('An error happened while packaging {0}: {1}', componentsDirs[i], errorDescription.red));
- logger.log('retrying in 10 seconds...'.yellow);
+ logger.log(format('an error happened while packaging {0}: {1}', componentsDirs[i], errorDescription.red));
+ logger.log('Retrying in 10 seconds...'.yellow);
setTimeout(function(){
packaging = false;
packageComponents(componentsDirs);
}, 10000);
} else {
packaging = false;
- logger.log('complete'.green);
+ logger.log('OK'.green);
if(_.isFunction(callback)){
callback();
}
@@ -103,7 +103,7 @@ module.exports = function(dependencies){
};
var loadDependencies = function(components, cb){
- logger.log('Ensuring dependencies are loaded'.yellow);
+ logger.logNoNewLine('Ensuring dependencies are loaded...'.yellow);
var dependencies = getDepsFromComponents(components),
missing = [];
@@ -131,12 +131,13 @@ module.exports = function(dependencies){
});
});
} else {
+ logger.log('OK'.green);
cb(dependencies);
}
});
};
- logger.log('Looking for components...'.yellow);
+ logger.logNoNewLine('Looking for components...'.yellow);
local.getComponentsByDir(componentsDir, function(err, components){
if(err){
@@ -145,9 +146,14 @@ module.exports = function(dependencies){
return logger.log(format(errors.DEV_FAIL, errors.COMPONENTS_NOT_FOUND).red);
}
+ logger.log('OK'.green);
+ _.forEach(components, function(component){
+ logger.log('>> '.green + component);
+ });
+
loadDependencies(components, function(dependencies){
packageComponents(components, function(){
- logger.log('Starting dev registry on localhost:' + port);
+ logger.logNoNewLine(format('Starting dev registry on localhost:{0}...', port).yellow);
var conf = {
local: true,
diff --git a/cli/index.js b/cli/index.js
index fb45f2b03..d44a412a1 100644
--- a/cli/index.js
+++ b/cli/index.js
@@ -8,7 +8,12 @@ var _ = require('underscore');
var dependencies = {
local: new Local(),
- logger: console,
+ logger: {
+ log: console.log,
+ logNoNewLine: function(msg){
+ return process.stdout.write(msg.toString());
+ }
+ },
registry: new Registry()
};
diff --git a/components/oc-client/_package/package.json b/components/oc-client/_package/package.json
index 559f95ba5..0902e40d1 100644
--- a/components/oc-client/_package/package.json
+++ b/components/oc-client/_package/package.json
@@ -21,6 +21,7 @@
"src": "server.js"
}
},
- "version": "0.15.3"
+ "version": "0.15.3",
+ "packaged": true
}
}
diff --git a/components/oc-client/_package/src/head.load.js b/components/oc-client/_package/src/head.load.js
index 3f73427e2..b7a31c778 100644
--- a/components/oc-client/_package/src/head.load.js
+++ b/components/oc-client/_package/src/head.load.js
@@ -1 +1,707 @@
-!function(e,t){"use strict";function n(){}function r(e,t){if(e){"object"==typeof e&&(e=[].slice.call(e));for(var n=0,r=e.length;r>n;n++)t.call(e,e[n],n)}}function a(e,n){var r=Object.prototype.toString.call(n).slice(8,-1);return n!==t&&null!==n&&r===e}function o(e){return a("Function",e)}function u(e){return a("Array",e)}function i(e){var t=e.split("/"),n=t[t.length-1],r=n.indexOf("?");return-1!==r?n.substring(0,r):n}function c(e){e=e||n,e._done||(e(),e._done=1)}function l(e,t,r,a){var o="object"==typeof e?e:{test:e,success:t?u(t)?t:[t]:!1,failure:r?u(r)?r:[r]:!1,callback:a||n},i=!!o.test;return i&&o.success?(o.success.push(o.callback),C.load.apply(null,o.success)):!i&&o.failure?(o.failure.push(o.callback),C.load.apply(null,o.failure)):a(),C}function s(e){var t={};if("object"==typeof e)for(var n in e)e[n]&&(t={name:n,url:e[n]});else t={name:i(e),url:e};var r=O[t.name];return r&&r.url===t.url?r:(O[t.name]=t,t)}function d(e){e=e||O;for(var t in e)if(e.hasOwnProperty(t)&&e[t].state!==R)return!1;return!0}function f(e){e.state=x,r(e.onpreload,function(e){e.call()})}function m(e){e.state===t&&(e.state=_,e.onpreload=[],g({url:e.url,type:"cache"},function(){f(e)}))}function p(){var e=arguments,t=e[e.length-1],n=[].slice.call(e,1),a=n[0];return o(t)||(t=null),u(e[0])?(e[0].push(t),C.load.apply(null,e[0]),C):(a?(r(n,function(e){!o(e)&&e&&m(s(e))}),v(s(e[0]),o(a)?a:function(){C.load.apply(null,n)})):v(s(e[0])),C)}function y(){var e=arguments,t=e[e.length-1],n={};return o(t)||(t=null),u(e[0])?(e[0].push(t),C.load.apply(null,e[0]),C):(r(e,function(e){e!==t&&(e=s(e),n[e.name]=e)}),r(e,function(e){e!==t&&(e=s(e),v(e,function(){d(n)&&c(t)}))}),C)}function v(e,t){return t=t||n,e.state===R?void t():e.state===B?void C.ready(e.name,t):e.state===_?void e.onpreload.push(function(){v(e,t)}):(e.state=B,void g(e,function(){e.state=R,t(),r(M[e.name],function(e){c(e)}),S&&d()&&r(M.ALL,function(e){c(e)})}))}function h(e){e=e||"";var t=e.split("?")[0].split(".");return t[t.length-1].toLowerCase()}function g(t,r){function a(t){t=t||e.event,i.onload=i.onreadystatechange=i.onerror=null,r()}function o(n){n=n||e.event,("load"===n.type||/loaded|complete/.test(i.readyState)&&(!j.documentMode||j.documentMode<9))&&(e.clearTimeout(t.errorTimeout),e.clearTimeout(t.cssTimeout),i.onload=i.onreadystatechange=i.onerror=null,r())}function u(){if(t.state!==R&&t.cssRetries<=20){for(var n=0,r=j.styleSheets.length;r>n;n++)if(j.styleSheets[n].href===i.href)return void o({type:"load"});t.cssRetries++,t.cssTimeout=e.setTimeout(u,250)}}r=r||n;var i,c=h(t.url);"css"===c?(i=j.createElement("link"),i.type="text/"+(t.type||"css"),i.rel="stylesheet",i.href=t.url,t.cssRetries=0,t.cssTimeout=e.setTimeout(u,500)):(i=j.createElement("script"),i.type="text/"+(t.type||"javascript"),i.src=t.url),i.onload=i.onreadystatechange=o,i.onerror=a,i.async=!1,i.defer=!1,t.errorTimeout=e.setTimeout(function(){a({type:"timeout"})},7e3);var l=j.head||j.getElementsByTagName("head")[0];l.insertBefore(i,l.lastChild)}function T(){for(var e=j.getElementsByTagName("script"),t=0,n=e.length;n>t;t++){var r=e[t].getAttribute("data-headjs-load");if(r)return void C.load(r)}}function E(e,t){if(e===j)return S?c(t):A.push(t),C;if(o(e)&&(t=e,e="ALL"),u(e)){var n={};return r(e,function(e){n[e]=O[e],C.ready(e,function(){d(n)&&c(t)})}),C}if("string"!=typeof e||!o(t))return C;var a=O[e];if(a&&a.state===R||"ALL"===e&&d()&&S)return c(t),C;var i=M[e];return i?i.push(t):i=M[e]=[t],C}function L(){return j.body?void(S||(S=!0,T(),r(A,function(e){c(e)}))):(e.clearTimeout(C.readyTimeout),void(C.readyTimeout=e.setTimeout(L,50)))}function b(){j.addEventListener?(j.removeEventListener("DOMContentLoaded",b,!1),L()):"complete"===j.readyState&&(j.detachEvent("onreadystatechange",b),L())}var S,j=e.document,A=[],M={},O={},k="async"in j.createElement("script")||"MozAppearance"in j.documentElement.style||e.opera,w=e.head_conf&&e.head_conf.head||"head",C=e[w]=e[w]||function(){C.ready.apply(null,arguments)},_=1,x=2,B=3,R=4;if("complete"===j.readyState)L();else if(j.addEventListener)j.addEventListener("DOMContentLoaded",b,!1),e.addEventListener("load",L,!1);else{j.attachEvent("onreadystatechange",b),e.attachEvent("onload",L);var D=!1;try{D=!e.frameElement&&j.documentElement}catch(N){}D&&D.doScroll&&!function z(){if(!S){try{D.doScroll("left")}catch(t){return e.clearTimeout(C.readyTimeout),void(C.readyTimeout=e.setTimeout(z,50))}L()}}()}C.load=C.js=k?y:p,C.test=l,C.ready=E,C.ready(j,function(){d()&&r(M.ALL,function(e){c(e)}),C.feature&&C.feature("domloaded",!0)})}(window);
\ No newline at end of file
+///#source 1 1 /src/1.0.0/load.js
+/*! head.load - v1.0.3 */
+/*
+ * HeadJS The only script in your
+ * Author Tero Piirainen (tipiirai)
+ * Maintainer Robert Hoffmann (itechnology)
+ * License MIT / http://bit.ly/mit-license
+ * WebSite http://headjs.com
+ */
+(function (win, undefined) {
+ "use strict";
+
+ //#region variables
+ var doc = win.document,
+ domWaiters = [],
+ handlers = {}, // user functions waiting for events
+ assets = {}, // loadable items in various states
+ isAsync = "async" in doc.createElement("script") || "MozAppearance" in doc.documentElement.style || win.opera,
+ isDomReady,
+
+ /*** public API ***/
+ headVar = win.head_conf && win.head_conf.head || "head",
+ api = win[headVar] = (win[headVar] || function () { api.ready.apply(null, arguments); }),
+
+ // states
+ PRELOADING = 1,
+ PRELOADED = 2,
+ LOADING = 3,
+ LOADED = 4;
+ //#endregion
+
+ //#region PRIVATE functions
+
+ //#region Helper functions
+ function noop() {
+ // does nothing
+ }
+
+ function each(arr, callback) {
+ if (!arr) {
+ return;
+ }
+
+ // arguments special type
+ if (typeof arr === "object") {
+ arr = [].slice.call(arr);
+ }
+
+ // do the job
+ for (var i = 0, l = arr.length; i < l; i++) {
+ callback.call(arr, arr[i], i);
+ }
+ }
+
+ /* A must read: http://bonsaiden.github.com/JavaScript-Garden
+ ************************************************************/
+ function is(type, obj) {
+ var clas = Object.prototype.toString.call(obj).slice(8, -1);
+ return obj !== undefined && obj !== null && clas === type;
+ }
+
+ function isFunction(item) {
+ return is("Function", item);
+ }
+
+ function isArray(item) {
+ return is("Array", item);
+ }
+
+ function toLabel(url) {
+ ///Converts a url to a file label
+ var items = url.split("/"),
+ name = items[items.length - 1],
+ i = name.indexOf("?");
+
+ return i !== -1 ? name.substring(0, i) : name;
+ }
+
+ // INFO: this look like a "im triggering callbacks all over the place, but only wanna run it one time function" ..should try to make everything work without it if possible
+ // INFO: Even better. Look into promises/defered's like jQuery is doing
+ function one(callback) {
+ ///Execute a callback only once
+ callback = callback || noop;
+
+ if (callback._done) {
+ return;
+ }
+
+ callback();
+ callback._done = 1;
+ }
+ //#endregion
+
+ function conditional(test, success, failure, callback) {
+ ///
+ /// INFO: use cases:
+ /// head.test(condition, null , "file.NOk" , callback);
+ /// head.test(condition, "fileOk.js", null , callback);
+ /// head.test(condition, "fileOk.js", "file.NOk" , callback);
+ /// head.test(condition, "fileOk.js", ["file.NOk", "file.NOk"], callback);
+ /// head.test({
+ /// test : condition,
+ /// success : [{ label1: "file1Ok.js" }, { label2: "file2Ok.js" }],
+ /// failure : [{ label1: "file1NOk.js" }, { label2: "file2NOk.js" }],
+ /// callback: callback
+ /// );
+ /// head.test({
+ /// test : condition,
+ /// success : ["file1Ok.js" , "file2Ok.js"],
+ /// failure : ["file1NOk.js", "file2NOk.js"],
+ /// callback: callback
+ /// );
+ ///
+ var obj = (typeof test === "object") ? test : {
+ test: test,
+ success: !!success ? isArray(success) ? success : [success] : false,
+ failure: !!failure ? isArray(failure) ? failure : [failure] : false,
+ callback: callback || noop
+ };
+
+ // Test Passed ?
+ var passed = !!obj.test;
+
+ // Do we have a success case
+ if (passed && !!obj.success) {
+ obj.success.push(obj.callback);
+ api.load.apply(null, obj.success);
+ }
+ // Do we have a fail case
+ else if (!passed && !!obj.failure) {
+ obj.failure.push(obj.callback);
+ api.load.apply(null, obj.failure);
+ }
+ else {
+ callback();
+ }
+
+ return api;
+ }
+
+ function getAsset(item) {
+ ///
+ /// Assets are in the form of
+ /// {
+ /// name : label,
+ /// url : url,
+ /// state: state
+ /// }
+ ///
+ var asset = {};
+
+ if (typeof item === "object") {
+ for (var label in item) {
+ if (!!item[label]) {
+ asset = {
+ name: label,
+ url : item[label]
+ };
+ }
+ }
+ }
+ else {
+ asset = {
+ name: toLabel(item),
+ url : item
+ };
+ }
+
+ // is the item already existant
+ var existing = assets[asset.name];
+ if (existing && existing.url === asset.url) {
+ return existing;
+ }
+
+ assets[asset.name] = asset;
+ return asset;
+ }
+
+ function allLoaded(items) {
+ items = items || assets;
+
+ for (var name in items) {
+ if (items.hasOwnProperty(name) && items[name].state !== LOADED) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ function onPreload(asset) {
+ asset.state = PRELOADED;
+
+ each(asset.onpreload, function (afterPreload) {
+ afterPreload.call();
+ });
+ }
+
+ function preLoad(asset, callback) {
+ if (asset.state === undefined) {
+
+ asset.state = PRELOADING;
+ asset.onpreload = [];
+
+ loadAsset({ url: asset.url, type: "cache" }, function () {
+ onPreload(asset);
+ });
+ }
+ }
+
+ function apiLoadHack() {
+ /// preload with text/cache hack
+ ///
+ /// head.load("http://domain.com/file.js","http://domain.com/file.js", callBack)
+ /// head.load(["http://domain.com/file.js","http://domain.com/file.js"], callBack)
+ /// head.load({ label1: "http://domain.com/file.js" }, { label2: "http://domain.com/file.js" }, callBack)
+ /// head.load([{ label1: "http://domain.com/file.js" }, { label2: "http://domain.com/file.js" }], callBack)
+ ///
+ var args = arguments,
+ callback = args[args.length - 1],
+ rest = [].slice.call(args, 1),
+ next = rest[0];
+
+ if (!isFunction(callback)) {
+ callback = null;
+ }
+
+ // if array, repush as args
+ if (isArray(args[0])) {
+ args[0].push(callback);
+ api.load.apply(null, args[0]);
+
+ return api;
+ }
+
+ // multiple arguments
+ if (!!next) {
+ /* Preload with text/cache hack (not good!)
+ * http://blog.getify.com/on-script-loaders/
+ * http://www.nczonline.net/blog/2010/12/21/thoughts-on-script-loaders/
+ * If caching is not configured correctly on the server, then items could load twice !
+ *************************************************************************************/
+ each(rest, function (item) {
+ // item is not a callback or empty string
+ if (!isFunction(item) && !!item) {
+ preLoad(getAsset(item));
+ }
+ });
+
+ // execute
+ load(getAsset(args[0]), isFunction(next) ? next : function () {
+ api.load.apply(null, rest);
+ });
+ }
+ else {
+ // single item
+ load(getAsset(args[0]));
+ }
+
+ return api;
+ }
+
+ function apiLoadAsync() {
+ ///
+ /// simply load and let browser take care of ordering
+ ///
+ /// head.load("http://domain.com/file.js","http://domain.com/file.js", callBack)
+ /// head.load(["http://domain.com/file.js","http://domain.com/file.js"], callBack)
+ /// head.load({ label1: "http://domain.com/file.js" }, { label2: "http://domain.com/file.js" }, callBack)
+ /// head.load([{ label1: "http://domain.com/file.js" }, { label2: "http://domain.com/file.js" }], callBack)
+ ///
+ var args = arguments,
+ callback = args[args.length - 1],
+ items = {};
+
+ if (!isFunction(callback)) {
+ callback = null;
+ }
+
+ // if array, repush as args
+ if (isArray(args[0])) {
+ args[0].push(callback);
+ api.load.apply(null, args[0]);
+
+ return api;
+ }
+
+ // JRH 262#issuecomment-26288601
+ // First populate the items array.
+ // When allLoaded is called, all items will be populated.
+ // Issue when lazy loaded, the callback can execute early.
+ each(args, function (item, i) {
+ if (item !== callback) {
+ item = getAsset(item);
+ items[item.name] = item;
+ }
+ });
+
+ each(args, function (item, i) {
+ if (item !== callback) {
+ item = getAsset(item);
+
+ load(item, function () {
+ if (allLoaded(items)) {
+ one(callback);
+ }
+ });
+ }
+ });
+
+ return api;
+ }
+
+ function load(asset, callback) {
+ ///Used with normal loading logic
+ callback = callback || noop;
+
+ if (asset.state === LOADED) {
+ callback();
+ return;
+ }
+
+ // INFO: why would we trigger a ready event when its not really loaded yet ?
+ if (asset.state === LOADING) {
+ api.ready(asset.name, callback);
+ return;
+ }
+
+ if (asset.state === PRELOADING) {
+ asset.onpreload.push(function () {
+ load(asset, callback);
+ });
+ return;
+ }
+
+ asset.state = LOADING;
+
+ loadAsset(asset, function () {
+ asset.state = LOADED;
+
+ callback();
+
+ // handlers for this asset
+ each(handlers[asset.name], function (fn) {
+ one(fn);
+ });
+
+ // dom is ready & no assets are queued for loading
+ // INFO: shouldn't we be doing the same test above ?
+ if (isDomReady && allLoaded()) {
+ each(handlers.ALL, function (fn) {
+ one(fn);
+ });
+ }
+ });
+ }
+
+ function getExtension(url) {
+ url = url || "";
+
+ var items = url.split("?")[0].split(".");
+ return items[items.length-1].toLowerCase();
+ }
+
+ /* Parts inspired from: https://github.com/cujojs/curl
+ ******************************************************/
+ function loadAsset(asset, callback) {
+ callback = callback || noop;
+
+ function error(event) {
+ event = event || win.event;
+
+ // release event listeners
+ ele.onload = ele.onreadystatechange = ele.onerror = null;
+
+ // do callback
+ callback();
+
+ // need some more detailed error handling here
+ }
+
+ function process(event) {
+ event = event || win.event;
+
+ // IE 7/8 (2 events on 1st load)
+ // 1) event.type = readystatechange, s.readyState = loading
+ // 2) event.type = readystatechange, s.readyState = loaded
+
+ // IE 7/8 (1 event on reload)
+ // 1) event.type = readystatechange, s.readyState = complete
+
+ // event.type === 'readystatechange' && /loaded|complete/.test(s.readyState)
+
+ // IE 9 (3 events on 1st load)
+ // 1) event.type = readystatechange, s.readyState = loading
+ // 2) event.type = readystatechange, s.readyState = loaded
+ // 3) event.type = load , s.readyState = loaded
+
+ // IE 9 (2 events on reload)
+ // 1) event.type = readystatechange, s.readyState = complete
+ // 2) event.type = load , s.readyState = complete
+
+ // event.type === 'load' && /loaded|complete/.test(s.readyState)
+ // event.type === 'readystatechange' && /loaded|complete/.test(s.readyState)
+
+ // IE 10 (3 events on 1st load)
+ // 1) event.type = readystatechange, s.readyState = loading
+ // 2) event.type = load , s.readyState = complete
+ // 3) event.type = readystatechange, s.readyState = loaded
+
+ // IE 10 (3 events on reload)
+ // 1) event.type = readystatechange, s.readyState = loaded
+ // 2) event.type = load , s.readyState = complete
+ // 3) event.type = readystatechange, s.readyState = complete
+
+ // event.type === 'load' && /loaded|complete/.test(s.readyState)
+ // event.type === 'readystatechange' && /complete/.test(s.readyState)
+
+ // Other Browsers (1 event on 1st load)
+ // 1) event.type = load, s.readyState = undefined
+
+ // Other Browsers (1 event on reload)
+ // 1) event.type = load, s.readyState = undefined
+
+ // event.type == 'load' && s.readyState = undefined
+
+ // !doc.documentMode is for IE6/7, IE8+ have documentMode
+ if (event.type === "load" || (/loaded|complete/.test(ele.readyState) && (!doc.documentMode || doc.documentMode < 9))) {
+ // remove timeouts
+ win.clearTimeout(asset.errorTimeout);
+ win.clearTimeout(asset.cssTimeout);
+
+ // release event listeners
+ ele.onload = ele.onreadystatechange = ele.onerror = null;
+
+ // do callback
+ callback();
+ }
+ }
+
+ function isCssLoaded() {
+ // should we test again ? 20 retries = 5secs ..after that, the callback will be triggered by the error handler at 7secs
+ if (asset.state !== LOADED && asset.cssRetries <= 20) {
+
+ // loop through stylesheets
+ for (var i = 0, l = doc.styleSheets.length; i < l; i++) {
+ // do we have a match ?
+ // we need to tests agains ele.href and not asset.url, because a local file will be assigned the full http path on a link element
+ if (doc.styleSheets[i].href === ele.href) {
+ process({ "type": "load" });
+ return;
+ }
+ }
+
+ // increment & try again
+ asset.cssRetries++;
+ asset.cssTimeout = win.setTimeout(isCssLoaded, 250);
+ }
+ }
+
+ var ele;
+ var ext = getExtension(asset.url);
+
+ if (ext === "css") {
+ ele = doc.createElement("link");
+ ele.type = "text/" + (asset.type || "css");
+ ele.rel = "stylesheet";
+ ele.href = asset.url;
+
+ /* onload supported for CSS on unsupported browsers
+ * Safari windows 5.1.7, FF < 10
+ */
+
+ // Set counter to zero
+ asset.cssRetries = 0;
+ asset.cssTimeout = win.setTimeout(isCssLoaded, 500);
+ }
+ else {
+ ele = doc.createElement("script");
+ ele.type = "text/" + (asset.type || "javascript");
+ ele.src = asset.url;
+ }
+
+ ele.onload = ele.onreadystatechange = process;
+ ele.onerror = error;
+
+ /* Good read, but doesn't give much hope !
+ * http://blog.getify.com/on-script-loaders/
+ * http://www.nczonline.net/blog/2010/12/21/thoughts-on-script-loaders/
+ * https://hacks.mozilla.org/2009/06/defer/
+ */
+
+ // ASYNC: load in parallel and execute as soon as possible
+ ele.async = false;
+ // DEFER: load in parallel but maintain execution order
+ ele.defer = false;
+
+ // timout for asset loading
+ asset.errorTimeout = win.setTimeout(function () {
+ error({ type: "timeout" });
+ }, 7e3);
+
+ // use insertBefore to keep IE from throwing Operation Aborted (thx Bryan Forbes!)
+ var head = doc.head || doc.getElementsByTagName("head")[0];
+
+ // but insert at end of head, because otherwise if it is a stylesheet, it will not override values
+ head.insertBefore(ele, head.lastChild);
+ }
+
+ /* Parts inspired from: https://github.com/jrburke/requirejs
+ ************************************************************/
+ function init() {
+ var items = doc.getElementsByTagName("script");
+
+ // look for a script with a data-head-init attribute
+ for (var i = 0, l = items.length; i < l; i++) {
+ var dataMain = items[i].getAttribute("data-headjs-load");
+ if (!!dataMain) {
+ api.load(dataMain);
+ return;
+ }
+ }
+ }
+
+ function ready(key, callback) {
+ ///
+ /// INFO: use cases:
+ /// head.ready(callBack);
+ /// head.ready(document , callBack);
+ /// head.ready("file.js", callBack);
+ /// head.ready("label" , callBack);
+ /// head.ready(["label1", "label2"], callback);
+ ///
+
+ // DOM ready check: head.ready(document, function() { });
+ if (key === doc) {
+ if (isDomReady) {
+ one(callback);
+ }
+ else {
+ domWaiters.push(callback);
+ }
+
+ return api;
+ }
+
+ // shift arguments
+ if (isFunction(key)) {
+ callback = key;
+ key = "ALL"; // holds all callbacks that where added without labels: ready(callBack)
+ }
+
+ // queue all items from key and return. The callback will be executed if all items from key are already loaded.
+ if (isArray(key)) {
+ var items = {};
+
+ each(key, function (item) {
+ items[item] = assets[item];
+
+ api.ready(item, function() {
+ if (allLoaded(items)) {
+ one(callback);
+ }
+ });
+ });
+
+ return api;
+ }
+
+ // make sure arguments are sane
+ if (typeof key !== "string" || !isFunction(callback)) {
+ return api;
+ }
+
+ // this can also be called when we trigger events based on filenames & labels
+ var asset = assets[key];
+
+ // item already loaded --> execute and return
+ if (asset && asset.state === LOADED || key === "ALL" && allLoaded() && isDomReady) {
+ one(callback);
+ return api;
+ }
+
+ var arr = handlers[key];
+ if (!arr) {
+ arr = handlers[key] = [callback];
+ }
+ else {
+ arr.push(callback);
+ }
+
+ return api;
+ }
+
+ /* Mix of stuff from jQuery & IEContentLoaded
+ * http://dev.w3.org/html5/spec/the-end.html#the-end
+ ***************************************************/
+ function domReady() {
+ // Make sure body exists, at least, in case IE gets a little overzealous (jQuery ticket #5443).
+ if (!doc.body) {
+ // let's not get nasty by setting a timeout too small.. (loop mania guaranteed if assets are queued)
+ win.clearTimeout(api.readyTimeout);
+ api.readyTimeout = win.setTimeout(domReady, 50);
+ return;
+ }
+
+ if (!isDomReady) {
+ isDomReady = true;
+
+ init();
+ each(domWaiters, function (fn) {
+ one(fn);
+ });
+ }
+ }
+
+ function domContentLoaded() {
+ // W3C
+ if (doc.addEventListener) {
+ doc.removeEventListener("DOMContentLoaded", domContentLoaded, false);
+ domReady();
+ }
+
+ // IE
+ else if (doc.readyState === "complete") {
+ // we're here because readyState === "complete" in oldIE
+ // which is good enough for us to call the dom ready!
+ doc.detachEvent("onreadystatechange", domContentLoaded);
+ domReady();
+ }
+ }
+
+ // Catch cases where ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if (doc.readyState === "complete") {
+ domReady();
+ }
+
+ // W3C
+ else if (doc.addEventListener) {
+ doc.addEventListener("DOMContentLoaded", domContentLoaded, false);
+
+ // A fallback to window.onload, that will always work
+ win.addEventListener("load", domReady, false);
+ }
+
+ // IE
+ else {
+ // Ensure firing before onload, maybe late but safe also for iframes
+ doc.attachEvent("onreadystatechange", domContentLoaded);
+
+ // A fallback to window.onload, that will always work
+ win.attachEvent("onload", domReady);
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = !win.frameElement && doc.documentElement;
+ } catch (e) { }
+
+ if (top && top.doScroll) {
+ (function doScrollCheck() {
+ if (!isDomReady) {
+ try {
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll("left");
+ } catch (error) {
+ // let's not get nasty by setting a timeout too small.. (loop mania guaranteed if assets are queued)
+ win.clearTimeout(api.readyTimeout);
+ api.readyTimeout = win.setTimeout(doScrollCheck, 50);
+ return;
+ }
+
+ // and execute any waiting functions
+ domReady();
+ }
+ }());
+ }
+ }
+ //#endregion
+
+ //#region Public Exports
+ // INFO: determine which method to use for loading
+ api.load = api.js = isAsync ? apiLoadAsync : apiLoadHack;
+ api.test = conditional;
+ api.ready = ready;
+ //#endregion
+
+ //#region INIT
+ // perform this when DOM is ready
+ api.ready(doc, function () {
+ if (allLoaded()) {
+ each(handlers.ALL, function (callback) {
+ one(callback);
+ });
+ }
+
+ if (api.feature) {
+ api.feature("domloaded", true);
+ }
+ });
+ //#endregion
+}(window));
\ No newline at end of file
diff --git a/components/oc-client/_package/src/oc-client.js b/components/oc-client/_package/src/oc-client.js
index 5b6cd6200..e2899aa92 100644
--- a/components/oc-client/_package/src/oc-client.js
+++ b/components/oc-client/_package/src/oc-client.js
@@ -1 +1,336 @@
-"use strict";var oc=oc||{};!function(e,r,n){oc.conf=oc.conf||{},oc.cmd=oc.cmd||[];var o,t="https://cdnjs.cloudflare.com/ajax/libs/",a=t+"jquery-ajaxtransport-xdomainrequest/1.0.3/jquery.xdomainrequest.min.js",c=t+"handlebars.js/3.0.1/handlebars.runtime.js",i=t+"jade/1.9.2/runtime.min.js",d=t+"jquery/1.11.2/jquery.min.js",u=oc.conf.retryInterval||5e3,f=oc.conf.pollingInterval||500,l=oc.conf.tag||"oc-component",s="Href parameter missing",m="Error getting compiled view: {0}",p="Error rendering component: {0}, error: {1}",v="Failed to retrieve the component. Retrying in {0} seconds...".replace("{0}",u/1e3),h='Error loading component: view engine "{0}" not supported',y="Loading...",g="Component '{0}' correctly rendered",j="Unrendered component found. Trying to retrieve it...",q=oc.conf.debug||!1,b=function(){},x=n.navigator.userAgent,w=!!x.match(/MSIE 8/),C=!!x.match(/MSIE 9/),E=!1,I=!1,U={error:function(e){return console.log(e)},info:function(e){return q?console.log(e):!1}};oc.require=function(r,o,t){"function"==typeof o&&(t=o,o=r,r=void 0),"string"==typeof r&&(r=[r]);var a=function(){var e=n;if("undefined"==typeof r)return!0;for(var o=0;o'+l+">"},oc.ready=function(e){if(E)return e();if(I)oc.cmd.push(e);else{I=!0;var r=function(e){!w&&!C||o.IE_POLYFILL_LOADED?e():oc.require(a,e)},n=function(){E=!0,I=!1,e();for(var r=0;r'+y+""),oc.renderByHref(e.attr("href"),function(n,o){return!n&&o&&o.html?void M(e,o,r):U.error(n)}))})},oc.renderByHref=function(e,r){oc.ready(function(){return""===e?r(p.replace("{1}",s)):void o.ajax({url:e,headers:{Accept:"application/vnd.oc.prerendered+json"},contentType:"text/plain",crossDomain:!0,async:!0,success:function(e){if("pre-rendered"===e.renderMode)oc.render(e.template,e.data,function(n,o){return n?r(p.replace("{0}",e.href).replace("{1}",n)):(U.info(g.replace("{0}",e.template.src)),void r(null,{html:o,key:e.template.key,version:e.version}))});else if("rendered"===e.renderMode){if(U.info(g.replace("{0}",e.href)),0===e.html.indexOf("<"+l)){var n=e.html.slice(e.html.indexOf(">")+1),o=n.slice(0,n.lastIndexOf("<"));e.html=o}r(null,{html:e.html,version:e.version})}},error:function(){U.error(v),setTimeout(function(){oc.renderByHref(e,r)},u)}})})},oc.renderUnloadedComponents=function(){oc.ready(function(){var e=w?"div[data-oc-component=true]":l,r=o(e+"[data-rendered!=true]"),n=function(e,r){oc.renderNestedComponent(o(e[r]),function(){r++,r0&&n(r,0)})},oc.load=function(e,r,n){oc.ready(function(){if("function"!=typeof n&&(n=b),o(e)){o(e).html("<"+l+' href="'+r+'" />');var t=o(l,e);oc.renderNestedComponent(t,function(){n(t)})}})},oc.ready(oc.renderUnloadedComponents)}(head,document,window);
\ No newline at end of file
+'use strict';
+
+var oc = oc || {};
+
+(function(head, $document, $window){
+
+ oc.conf = oc.conf || {};
+ oc.cmd = oc.cmd || [];
+
+ // Constants
+ var CDNJS_BASEURL = 'https://cdnjs.cloudflare.com/ajax/libs/',
+ IE89_AJAX_POLYFILL_URL = CDNJS_BASEURL + 'jquery-ajaxtransport-xdomainrequest/1.0.3/jquery.xdomainrequest.min.js',
+ HANDLEBARS_URL = CDNJS_BASEURL + 'handlebars.js/3.0.1/handlebars.runtime.js',
+ JADE_URL = CDNJS_BASEURL + 'jade/1.9.2/runtime.min.js',
+ JQUERY_URL = CDNJS_BASEURL + 'jquery/1.11.2/jquery.min.js',
+ RETRY_INTERVAL = oc.conf.retryInterval || 5000,
+ POLLING_INTERVAL = oc.conf.pollingInterval || 500,
+ OC_TAG = oc.conf.tag || 'oc-component',
+ MESSAGES_ERRORS_HREF_MISSING = 'Href parameter missing',
+ MESSAGES_ERRORS_LOADING_COMPILED_VIEW = 'Error getting compiled view: {0}',
+ MESSAGES_ERRORS_RENDERING = 'Error rendering component: {0}, error: {1}',
+ MESSAGES_ERRORS_RETRIEVING = 'Failed to retrieve the component. Retrying in {0} seconds...'.replace('{0}', RETRY_INTERVAL/1000),
+ MESSAGES_ERRORS_VIEW_ENGINE_NOT_SUPPORTED = 'Error loading component: view engine "{0}" not supported',
+ MESSAGES_LOADING_COMPONENT = 'Loading...',
+ MESSAGES_RENDERED = 'Component \'{0}\' correctly rendered',
+ MESSAGES_RETRIEVING = 'Unrendered component found. Trying to retrieve it...';
+
+ // The code
+ var debug = oc.conf.debug || false,
+ headScripts = [],
+ $,
+ noop = function(){},
+ nav = $window.navigator.userAgent,
+ is8 = !!(nav.match(/MSIE 8/)),
+ is9 = !!(nav.match(/MSIE 9/)),
+ initialised = false,
+ initialising = false;
+
+ var logger = {
+ error: function(msg){
+ return console.log(msg);
+ },
+ info: function(msg){
+ return !!debug ? console.log(msg) : false;
+ }
+ };
+
+ // A minimal require.js-ish that uses head.js
+ oc.require = function(nameSpace, url, callback){
+ if(typeof(url) === 'function'){
+ callback = url;
+ url = nameSpace;
+ nameSpace = undefined;
+ }
+
+ if(typeof(nameSpace) === 'string'){
+ nameSpace = [nameSpace];
+ }
+
+ var needsToBeLoaded = function(){
+ var base = $window;
+
+ if(typeof(nameSpace) === 'undefined'){
+ return true;
+ }
+
+ for(var i = 0; i < nameSpace.length; i++){
+ base = base[nameSpace[i]];
+ if(!base){
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ var getObj = function(){
+ var base = $window;
+
+ if(typeof(nameSpace) === 'undefined'){
+ return undefined;
+ }
+
+ for(var i = 0; i < nameSpace.length; i++){
+ base = base[nameSpace[i]];
+ if(!base){
+ return undefined;
+ }
+ }
+
+ return base;
+ };
+
+ if(needsToBeLoaded()){
+ head.load(url, function(){
+ callback(getObj());
+ });
+ } else {
+ callback(getObj());
+ }
+ };
+
+
+ var processHtml = function($component, data, callback){
+
+ var newId = Math.floor(Math.random()*9999999999);
+
+ $component.html(data.html);
+ $component.attr('id', newId);
+ $component.attr('data-rendered', true);
+ $component.attr('data-rendering', false);
+ $component.attr('data-version', data.version);
+
+ if(!!data.key){
+ $component.attr('data-hash', data.key);
+ }
+
+ callback();
+ };
+
+ oc.build = function(options){
+
+ if(!options.baseUrl){
+ throw 'baseUrl parameter is required';
+ }
+
+ if(!options.name){
+ throw 'name parameter is required';
+ }
+
+ var withFinalSlash = function(s){
+ s = s || '';
+
+ if(s.slice(-1) !== '/'){
+ s += '/';
+ }
+
+ return s;
+ };
+
+ var href = withFinalSlash(options.baseUrl) + withFinalSlash(options.name);
+
+ if(!!options.version){
+ href += withFinalSlash(options.version);
+ }
+
+ if(!!options.parameters){
+ href += '?';
+ for(var parameter in options.parameters){
+ if(options.parameters.hasOwnProperty(parameter)){
+ href += parameter + '=' + options.parameters[parameter] + '&';
+ }
+ }
+ href = href.slice(0, -1);
+ }
+
+ return '<' + OC_TAG + ' href="' + href + '">' + OC_TAG + '>';
+
+ };
+
+ oc.ready = function(callback){
+
+ if(initialised){
+ return callback();
+ } else if(initialising) {
+ oc.cmd.push(callback);
+ } else {
+
+ initialising = true;
+
+ var requirePolyfills = function(cb){
+ if((is8 || is9) && !$.IE_POLYFILL_LOADED){
+ oc.require(IE89_AJAX_POLYFILL_URL, cb);
+ } else {
+ cb();
+ }
+ };
+
+ var done = function(){
+ initialised = true;
+ initialising = false;
+ callback();
+ for(var i = 0; i < oc.cmd.length; i++){
+ oc.cmd[i](oc);
+ }
+ };
+
+ oc.require('jQuery', JQUERY_URL, function(jQuery){
+ $ = jQuery;
+ requirePolyfills(done);
+ });
+ }
+ };
+
+ oc.render = function(compiledViewInfo, model, callback){
+ oc.ready(function(){
+ if(!!compiledViewInfo.type.match(/jade|handlebars/g)){
+ oc.require(['oc', 'components', compiledViewInfo.key], compiledViewInfo.src, function(compiledView){
+ if(!compiledView){
+ callback(MESSAGES_ERRORS_LOADING_COMPILED_VIEW.replace('{0}', compiledViewInfo.src));
+ } else {
+ if(compiledViewInfo.type === 'handlebars'){
+ oc.require('Handlebars', HANDLEBARS_URL, function(Handlebars){
+ var linkedComponent = Handlebars.template(compiledView, []);
+ callback(null, linkedComponent(model));
+ });
+ } else if(compiledViewInfo.type === 'jade'){
+ oc.require('jade', JADE_URL, function(jade){
+ callback(null, compiledView(model));
+ });
+ }
+ }
+ });
+ } else {
+ callback(MESSAGES_ERRORS_VIEW_ENGINE_NOT_SUPPORTED.replace('{0}', compiledViewInfo.type));
+ }
+ });
+ };
+
+ oc.renderNestedComponent = function($component, callback){
+ oc.ready(function(){
+ var dataRendering = $component.attr('data-rendering'),
+ dataRendered = $component.attr('data-rendered'),
+ isRendering = typeof(dataRendering) === 'boolean' ? dataRendering : (dataRendering === 'true'),
+ isRendered = typeof(dataRendered) === 'boolean' ? dataRendered : (dataRendered === 'true');
+
+ if(!isRendering && !isRendered){
+ logger.info(MESSAGES_RETRIEVING);
+ $component.attr('data-rendering', true);
+ $component.html('' + MESSAGES_LOADING_COMPONENT + '
');
+
+ oc.renderByHref($component.attr('href'), function(err, data){
+ if(err || !data || !data.html){
+ return logger.error(err);
+ }
+
+ processHtml($component, data, callback);
+ });
+ } else {
+ setTimeout(callback, POLLING_INTERVAL);
+ }
+ });
+ };
+
+ oc.renderByHref = function(href, callback){
+ oc.ready(function(){
+ if(href !== ''){
+ $.ajax({
+ url: href,
+ headers: { 'Accept': 'application/vnd.oc.prerendered+json' },
+ contentType: 'text/plain',
+ crossDomain: true,
+ async: true,
+ success: function(apiResponse){
+ if(apiResponse.renderMode === 'pre-rendered'){
+ oc.render(apiResponse.template, apiResponse.data, function(err, html){
+ if(err){
+ return callback(MESSAGES_ERRORS_RENDERING.replace('{0}', apiResponse.href).replace('{1}', err));
+ }
+ logger.info(MESSAGES_RENDERED.replace('{0}', apiResponse.template.src));
+ callback(null, {
+ html: html,
+ key: apiResponse.template.key,
+ version: apiResponse.version
+ });
+ });
+ } else if(apiResponse.renderMode === 'rendered'){
+ logger.info(MESSAGES_RENDERED.replace('{0}', apiResponse.href));
+
+ if(apiResponse.html.indexOf('<' + OC_TAG) === 0){
+
+ var innerHtmlPlusEnding = apiResponse.html.slice(apiResponse.html.indexOf('>') + 1),
+ innerHtml = innerHtmlPlusEnding.slice(0, innerHtmlPlusEnding.lastIndexOf('<'));
+ apiResponse.html = innerHtml;
+ }
+
+ callback(null, {
+ html: apiResponse.html,
+ version: apiResponse.version
+ });
+ }
+ },
+ error: function(){
+ logger.error(MESSAGES_ERRORS_RETRIEVING);
+ setTimeout(function() {
+ oc.renderByHref(href, callback);
+ }, RETRY_INTERVAL);
+ }
+ });
+ } else {
+ return callback(MESSAGES_ERRORS_RENDERING.replace('{1}', MESSAGES_ERRORS_HREF_MISSING));
+ }
+ });
+ };
+
+ oc.renderUnloadedComponents = function(){
+ oc.ready(function(){
+ var selector = (is8 ? 'div[data-oc-component=true]' : OC_TAG),
+ $unloadedComponents = $(selector + '[data-rendered!=true]');
+
+ var renderUnloadedComponent = function($unloadedComponents, i){
+ oc.renderNestedComponent($($unloadedComponents[i]), function(){
+ i++;
+ if(i < $unloadedComponents.length){
+ renderUnloadedComponent($unloadedComponents, i);
+ } else {
+ oc.renderUnloadedComponents();
+ }
+ });
+ };
+
+ if($unloadedComponents.length > 0){
+ renderUnloadedComponent($unloadedComponents, 0);
+ }
+ });
+ };
+
+ oc.load = function(placeholder, href, callback){
+ oc.ready(function(){
+ if(typeof(callback) !== 'function'){
+ callback = noop;
+ }
+
+ if($(placeholder)){
+ $(placeholder).html('<' + OC_TAG + ' href="' + href + '" />');
+ var newComponent = $(OC_TAG, placeholder);
+ oc.renderNestedComponent(newComponent, function(){
+ callback(newComponent);
+ });
+ }
+ });
+ };
+
+ oc.ready(oc.renderUnloadedComponents);
+
+})(head, document, window); // jshint ignore:line
\ No newline at end of file
diff --git a/registry/domain/repository.js b/registry/domain/repository.js
index 1cd29d61b..c08a404d3 100644
--- a/registry/domain/repository.js
+++ b/registry/domain/repository.js
@@ -8,7 +8,7 @@ var path = require('path');
var S3 = require('./s3');
var settings = require('../../resources/settings');
var strings = require('../../resources');
-var validator = require('./validator');
+var validator = require('./validators');
var versionHandler = require('./version-handler');
var _ = require('underscore');
diff --git a/registry/domain/validator.js b/registry/domain/validator.js
deleted file mode 100644
index 81bbb997b..000000000
--- a/registry/domain/validator.js
+++ /dev/null
@@ -1,197 +0,0 @@
-'use strict';
-
-var format = require('stringformat');
-var semver = require('semver');
-var strings = require('../../resources');
-var _ = require('underscore');
-
-var validate = {
- booleanParameter: function(booleanParameter){
- return _.isBoolean(booleanParameter);
- },
-
- numberParameter: function(numberParameter){
- return !!numberParameter && _.isNumber(numberParameter);
- },
-
- parameter: function(parameter, expectedType){
- var expected = expectedType.toLowerCase();
-
- if(_.contains(['string', 'boolean', 'number'], expected)){
- return validate[expected + 'Parameter'](parameter);
- }
-
- return false;
- },
-
- stringParameter: function(stringParameter){
- return !!stringParameter && _.isString(stringParameter) && stringParameter !== '';
- }
-};
-
-module.exports = {
- validateComponentName: function(componentName){
- return !/[^a-zA-Z0-9\-\_]/.test(componentName);
- },
- validateTemplateType: function(templateType){
- return _.contains(['handlebars', 'jade'], templateType);
- },
- validateComponentParameters: function(requestParameters, expectedParameters){
-
- var result = { isValid: true, errors: {} },
- mandatoryParameters = [];
-
- _.forEach(expectedParameters, function(expectedParameter, expectedParameterName){
- if(expectedParameter.mandatory){
- mandatoryParameters.push(expectedParameterName);
- }
- }, this);
-
- _.forEach(mandatoryParameters, function(mandatoryParameterName){
- if(!_.has(requestParameters, mandatoryParameterName)){
- if(!result.errors.mandatory){
- result.errors.mandatory = {};
- result.isValid = false;
- }
-
- result.errors.mandatory[mandatoryParameterName] = strings.errors.registry.MANDATORY_PARAMETER_MISSING_CODE;
- }
- }, this);
-
- _.forEach(requestParameters, function(requestParameter, requestParameterName){
- if(_.has(expectedParameters, requestParameterName)){
-
- var expectedType = expectedParameters[requestParameterName].type;
-
- if(!validate.parameter(requestParameter, expectedType)){
- if(!result.errors.types){
- result.errors.types = {};
- result.isValid = false;
- }
-
- result.errors.types[requestParameterName] = strings.errors.registry.PARAMETER_WRONG_FORMAT_CODE;
- }
- }
- }, this);
-
- result.errors.message = (function(){
- var errorString = '';
-
- if(_.keys(result.errors.mandatory).length > 0){
-
- var missingParams = _.map(result.errors.mandatory, function(mandatoryParameter, mandatoryParameterName){
- return mandatoryParameterName + ', ';
- }).join('').slice(0, -2);
-
- errorString += format(strings.errors.registry.MANDATORY_PARAMETER_MISSING, missingParams);
- }
-
- if(_.keys(result.errors.types).length > 0){
- if(errorString.length > 0){
- errorString += '; ';
- }
-
- var badParams = _.map(result.errors.types, function(parameter, parameterName){
- return parameterName + ', ';
- }).join('').slice(0, -2);
-
- errorString += format(strings.errors.registry.PARAMETER_WRONG_FORMAT, badParams);
- }
- return errorString;
- }());
-
- return result;
- },
- registryConfiguration: function(conf){
-
- var response = { isValid: true };
-
- var returnError = function(message){
- response.isValid = false;
- response.message = message || 'registry configuration is not valid';
- return response;
- };
-
- if(!conf || !_.isObject(conf) || _.keys(conf).length === 0){
- return returnError(strings.errors.registry.CONFIGURATION_EMPTY);
- }
-
- var prefix = conf.prefix;
-
- if(!!prefix){
- if(prefix.substr(0, 1) !== '/'){
- return returnError(strings.errors.registry.CONFIGURATION_PREFIX_DOES_NOT_START_WITH_SLASH);
- }
-
- if(prefix.substr(prefix.length - 1) !== '/'){
- return returnError(strings.errors.registry.CONFIGURATION_PREFIX_DOES_NOT_END_WITH_SLASH);
- }
- }
-
- var publishAuth = conf.publishAuth;
-
- if(!!publishAuth){
- if(publishAuth.type !== 'basic'){
- return returnError(strings.errors.registry.CONFIGURATION_PUBLISH_AUTH_NOT_SUPPORTED);
- } else {
- if(!publishAuth.username || !publishAuth.password){
- return returnError(strings.errors.registry.CONFIGURATION_PUBLISH_AUTH_CREDENTIALS_MISSING);
- }
- }
- }
-
- var dependencies = conf.dependencies;
-
- if(!!dependencies && (!_.isObject(dependencies)) || _.isArray(dependencies)){
- return returnError(strings.errors.registry.CONFIGURATION_DEPENDENCIES_MUST_BE_OBJECT);
- }
-
- var routes = conf.routes;
-
- if(!!routes && !_.isArray(routes)){
- return returnError(strings.errors.registry.CONFIGURATION_ROUTES_MUST_BE_ARRAY);
- } else {
- _.forEach(routes, function(route){
- if(!route.route || !route.handler || !route.method){
- return returnError(strings.errors.registry.CONFIGURATION_ROUTES_NOT_VALID);
- }
-
- if(!_.isFunction(route.handler)){
- return returnError(strings.errors.registry.CONFIGURATION_ROUTES_HANDLER_MUST_BE_FUNCTION);
- }
- });
- }
-
- return response;
- },
- validatePackage: function(input){
- var response = {
- isValid: true
- };
-
- var returnError = function(message){
- response.isValid = false;
- response.message = message || 'uploaded package is not valid';
- return response;
- };
-
- if(!input || !_.isObject(input) || _.keys(input).length === 0){
- return returnError('empty');
- }
-
- if(_.keys(input).length !== 1){
- return returnError('not_valid');
- }
-
- var file = input[_.keys(input)[0]];
-
- if(file.mimetype !== 'application/octet-stream' || !!file.truncated || file.extension !== 'gz' || file.path.indexOf('.tar.gz') < 0){
- return returnError('not_valid');
- }
-
- return response;
- },
- validateVersion: function(version){
- return !!semver.valid(version);
- }
-};
diff --git a/registry/domain/validators/component-parameters.js b/registry/domain/validators/component-parameters.js
new file mode 100644
index 000000000..fd76f3394
--- /dev/null
+++ b/registry/domain/validators/component-parameters.js
@@ -0,0 +1,96 @@
+'use strict';
+
+var format = require('stringformat');
+var strings = require('../../../resources');
+var _ = require('underscore');
+
+var validate = {
+ booleanParameter: function(booleanParameter){
+ return _.isBoolean(booleanParameter);
+ },
+
+ numberParameter: function(numberParameter){
+ return !!numberParameter && _.isNumber(numberParameter);
+ },
+
+ parameter: function(parameter, expectedType){
+ var expected = expectedType.toLowerCase();
+
+ if(_.contains(['string', 'boolean', 'number'], expected)){
+ return validate[expected + 'Parameter'](parameter);
+ }
+
+ return false;
+ },
+
+ stringParameter: function(stringParameter){
+ return !!stringParameter && _.isString(stringParameter) && stringParameter !== '';
+ }
+};
+
+module.exports = function(requestParameters, expectedParameters){
+
+ var result = { isValid: true, errors: {} },
+ mandatoryParameters = [];
+
+ _.forEach(expectedParameters, function(expectedParameter, expectedParameterName){
+ if(expectedParameter.mandatory){
+ mandatoryParameters.push(expectedParameterName);
+ }
+ }, this);
+
+ _.forEach(mandatoryParameters, function(mandatoryParameterName){
+ if(!_.has(requestParameters, mandatoryParameterName)){
+ if(!result.errors.mandatory){
+ result.errors.mandatory = {};
+ result.isValid = false;
+ }
+
+ result.errors.mandatory[mandatoryParameterName] = strings.errors.registry.MANDATORY_PARAMETER_MISSING_CODE;
+ }
+ }, this);
+
+ _.forEach(requestParameters, function(requestParameter, requestParameterName){
+ if(_.has(expectedParameters, requestParameterName)){
+
+ var expectedType = expectedParameters[requestParameterName].type;
+
+ if(!validate.parameter(requestParameter, expectedType)){
+ if(!result.errors.types){
+ result.errors.types = {};
+ result.isValid = false;
+ }
+
+ result.errors.types[requestParameterName] = strings.errors.registry.PARAMETER_WRONG_FORMAT_CODE;
+ }
+ }
+ }, this);
+
+ result.errors.message = (function(){
+ var errorString = '';
+
+ if(_.keys(result.errors.mandatory).length > 0){
+
+ var missingParams = _.map(result.errors.mandatory, function(mandatoryParameter, mandatoryParameterName){
+ return mandatoryParameterName + ', ';
+ }).join('').slice(0, -2);
+
+ errorString += format(strings.errors.registry.MANDATORY_PARAMETER_MISSING, missingParams);
+ }
+
+ if(_.keys(result.errors.types).length > 0){
+ if(errorString.length > 0){
+ errorString += '; ';
+ }
+
+ var badParams = _.map(result.errors.types, function(parameter, parameterName){
+ return parameterName + ', ';
+ }).join('').slice(0, -2);
+
+ errorString += format(strings.errors.registry.PARAMETER_WRONG_FORMAT, badParams);
+ }
+ return errorString;
+ }());
+
+ return result;
+};
\ No newline at end of file
diff --git a/registry/domain/validators/index.js b/registry/domain/validators/index.js
new file mode 100644
index 000000000..2f5eba185
--- /dev/null
+++ b/registry/domain/validators/index.js
@@ -0,0 +1,23 @@
+'use strict';
+
+var componentParametersValidator = require('./component-parameters');
+var registryConfigurationValidator = require('./registry-configuration');
+var uploadedPackageValidator = require('./uploaded-package');
+
+var semver = require('semver');
+var _ = require('underscore');
+
+module.exports = {
+ validateComponentName: function(componentName){
+ return !/[^a-zA-Z0-9\-\_]/.test(componentName) && componentName !== '_package';
+ },
+ validateTemplateType: function(templateType){
+ return _.contains(['handlebars', 'jade'], templateType);
+ },
+ validateComponentParameters: componentParametersValidator,
+ registryConfiguration: registryConfigurationValidator,
+ validatePackage: uploadedPackageValidator,
+ validateVersion: function(version){
+ return !!semver.valid(version);
+ }
+};
diff --git a/registry/domain/validators/registry-configuration.js b/registry/domain/validators/registry-configuration.js
new file mode 100644
index 000000000..2ed5cd02c
--- /dev/null
+++ b/registry/domain/validators/registry-configuration.js
@@ -0,0 +1,67 @@
+'use strict';
+
+var strings = require('../../../resources');
+var _ = require('underscore');
+
+module.exports = function(conf){
+
+ var response = { isValid: true };
+
+ var returnError = function(message){
+ response.isValid = false;
+ response.message = message || 'registry configuration is not valid';
+ return response;
+ };
+
+ if(!conf || !_.isObject(conf) || _.keys(conf).length === 0){
+ return returnError(strings.errors.registry.CONFIGURATION_EMPTY);
+ }
+
+ var prefix = conf.prefix;
+
+ if(!!prefix){
+ if(prefix.substr(0, 1) !== '/'){
+ return returnError(strings.errors.registry.CONFIGURATION_PREFIX_DOES_NOT_START_WITH_SLASH);
+ }
+
+ if(prefix.substr(prefix.length - 1) !== '/'){
+ return returnError(strings.errors.registry.CONFIGURATION_PREFIX_DOES_NOT_END_WITH_SLASH);
+ }
+ }
+
+ var publishAuth = conf.publishAuth;
+
+ if(!!publishAuth){
+ if(publishAuth.type !== 'basic'){
+ return returnError(strings.errors.registry.CONFIGURATION_PUBLISH_AUTH_NOT_SUPPORTED);
+ } else {
+ if(!publishAuth.username || !publishAuth.password){
+ return returnError(strings.errors.registry.CONFIGURATION_PUBLISH_AUTH_CREDENTIALS_MISSING);
+ }
+ }
+ }
+
+ var dependencies = conf.dependencies;
+
+ if(!!dependencies && (!_.isObject(dependencies)) || _.isArray(dependencies)){
+ return returnError(strings.errors.registry.CONFIGURATION_DEPENDENCIES_MUST_BE_OBJECT);
+ }
+
+ var routes = conf.routes;
+
+ if(!!routes && !_.isArray(routes)){
+ return returnError(strings.errors.registry.CONFIGURATION_ROUTES_MUST_BE_ARRAY);
+ } else {
+ _.forEach(routes, function(route){
+ if(!route.route || !route.handler || !route.method){
+ return returnError(strings.errors.registry.CONFIGURATION_ROUTES_NOT_VALID);
+ }
+
+ if(!_.isFunction(route.handler)){
+ return returnError(strings.errors.registry.CONFIGURATION_ROUTES_HANDLER_MUST_BE_FUNCTION);
+ }
+ });
+ }
+
+ return response;
+};
\ No newline at end of file
diff --git a/registry/domain/validators/uploaded-package.js b/registry/domain/validators/uploaded-package.js
new file mode 100644
index 000000000..684c56117
--- /dev/null
+++ b/registry/domain/validators/uploaded-package.js
@@ -0,0 +1,31 @@
+'use strict';
+
+var _ = require('underscore');
+
+module.exports = function(input){
+ var response = {
+ isValid: true
+ };
+
+ var returnError = function(message){
+ response.isValid = false;
+ response.message = message || 'uploaded package is not valid';
+ return response;
+ };
+
+ if(!input || !_.isObject(input) || _.keys(input).length === 0){
+ return returnError('empty');
+ }
+
+ if(_.keys(input).length !== 1){
+ return returnError('not_valid');
+ }
+
+ var file = input[_.keys(input)[0]];
+
+ if(file.mimetype !== 'application/octet-stream' || !!file.truncated || file.extension !== 'gz' || file.path.indexOf('.tar.gz') < 0){
+ return returnError('not_valid');
+ }
+
+ return response;
+};
\ No newline at end of file
diff --git a/registry/index.js b/registry/index.js
index 629e1e8d9..85459b28d 100644
--- a/registry/index.js
+++ b/registry/index.js
@@ -14,7 +14,7 @@ var Repository = require('./domain/repository');
var requestHandler = require('./middleware/request-handler');
var Router = require('./router');
var settings = require('../resources/settings');
-var validator = require('./domain/validator');
+var validator = require('./domain/validators');
var _ = require('underscore');
module.exports = function(options){
diff --git a/registry/routes/component.js b/registry/routes/component.js
index 2c434bddb..f65bd127d 100644
--- a/registry/routes/component.js
+++ b/registry/routes/component.js
@@ -7,7 +7,7 @@ var format = require('stringformat');
var RequireWrapper = require('../domain/require-wrapper');
var sanitiser = require('../domain/sanitiser');
var urlBuilder = require('../domain/url-builder');
-var validator = require('../domain/validator');
+var validator = require('../domain/validators');
var vm = require('vm');
var _ = require('underscore');
diff --git a/registry/routes/publish.js b/registry/routes/publish.js
index 6f2809899..d75053e0a 100644
--- a/registry/routes/publish.js
+++ b/registry/routes/publish.js
@@ -4,7 +4,7 @@ var format = require('stringformat');
var path = require('path');
var RequireWrapper = require('../domain/require-wrapper');
var Targz = require('tar.gz');
-var validator = require('../domain/validator');
+var validator = require('../domain/validators');
var _ = require('underscore');
module.exports = function(repository){
diff --git a/test/mocks/console.js b/test/mocks/console.js
index 3ba9837f7..2ce04fc8a 100644
--- a/test/mocks/console.js
+++ b/test/mocks/console.js
@@ -10,6 +10,10 @@ module.exports = {
logs.push(message);
return message;
},
+ logNoNewLine: function(message){
+ logs.push(message);
+ return message;
+ },
reset: function(){
logs = [];
}
diff --git a/test/unit/cli-domain-local.js b/test/unit/cli-domain-local.js
index a2a98168d..597b86828 100644
--- a/test/unit/cli-domain-local.js
+++ b/test/unit/cli-domain-local.js
@@ -2,16 +2,19 @@
var expect = require('chai').expect;
var injectr = require('injectr');
+var path = require('path');
var sinon = require('sinon');
+var _ = require('underscore');
var initialise = function(){
var fsMock = {
- readdirSync: sinon.spy(),
+ existsSync: sinon.stub(),
+ lstatSync: sinon.stub(),
mkdirSync: sinon.spy(),
- readJsonSync: sinon.stub(),
+ readdirSync: sinon.stub(),
readFileSync: sinon.stub(),
- existsSync: sinon.stub(),
+ readJsonSync: sinon.stub(),
writeFileSync: sinon.spy(),
writeJsonSync: sinon.spy()
};
@@ -24,6 +27,13 @@ var initialise = function(){
code: code
};
}
+ },
+ path: {
+ extname: path.extname,
+ join: path.join,
+ resolve: function(){
+ return _.toArray(arguments).join('/');
+ }
}
}, { __dirname: '' });
@@ -36,11 +46,15 @@ var executePackaging = function(local, callback){
return local.package('.', callback);
};
+var executeComponentsListingByDir = function(local, callback){
+ return local.getComponentsByDir('.', callback);
+};
+
describe('cli : domain : local', function(){
describe('when packaging', function(){
- describe('when component is logic-less', function(){
+ describe('when component is valid', function(){
var component;
beforeEach(function(done){
@@ -71,6 +85,10 @@ describe('cli : domain : local', function(){
it('should add version to package.json file', function(){
expect(component.oc.version).to.eql('1.2.3');
});
+
+ it('should mark the package.json as a packaged', function(){
+ expect(component.oc.packaged).to.eql(true);
+ });
});
describe('when component has a server.js logic', function(){
@@ -234,4 +252,43 @@ describe('cli : domain : local', function(){
});
});
});
+
+ describe('when getting components from dir', function(){
+
+ var error, result;
+ beforeEach(function(done){
+
+ var data = initialise();
+
+ data.fs.readdirSync.onCall(0).returns([
+ 'a-component',
+ 'a-not-component-dir',
+ 'a-file.json',
+ '_package'
+ ]);
+
+ data.fs.lstatSync.onCall(0).returns({ isDirectory: function(){ return true; }});
+ data.fs.existsSync.onCall(0).returns(true);
+ data.fs.readJsonSync.onCall(0).returns({ oc: {}});
+
+ data.fs.lstatSync.onCall(1).returns({ isDirectory: function(){ return true; }});
+ data.fs.existsSync.onCall(1).returns(false);
+
+ data.fs.lstatSync.onCall(2).returns({ isDirectory: function(){ return false; }});
+
+ data.fs.lstatSync.onCall(3).returns({ isDirectory: function(){ return true; }});
+ data.fs.existsSync.onCall(2).returns(true);
+ data.fs.readJsonSync.onCall(1).returns({ oc: { packaged: true }});
+
+ executeComponentsListingByDir(data.local, function(err, res){
+ error = err;
+ result = res;
+ done();
+ });
+ });
+
+ it('should add version to package.json file', function(){
+ expect(result).to.eql(['./a-component']);
+ });
+ });
});
diff --git a/test/unit/registry-domain-validator.js b/test/unit/registry-domain-validator.js
index ffa66bee5..7c0e183e2 100644
--- a/test/unit/registry-domain-validator.js
+++ b/test/unit/registry-domain-validator.js
@@ -4,7 +4,7 @@ var expect = require('chai').expect;
describe('registry : domain : validator', function(){
- var validator = require('../../registry/domain/validator');
+ var validator = require('../../registry/domain/validators');
describe('when validating registry configuration', function(){
@@ -486,6 +486,14 @@ describe('registry : domain : validator', function(){
});
});
+ describe('when name is reserved', function(){
+
+ var name = '_package';
+ it('should not be valid', function(){
+ expect(validate(name)).to.be.false;
+ });
+ });
+
});
describe('when validating template type for new candidate', function(){