kopia lustrzana https://github.com/c9/core
Merge remote-tracking branch 'origin/master' into merge-account-profile
Conflicts: plugins/c9.account.react/components/Footer.js plugins/c9.account.react/components/Footer.jsx plugins/c9.account.react/style-server.cli.js plugins/c9.account.react/style-server.js plugins/c9.account.react/styles/theme.lesspull/85/head
commit
0acad29850
|
@ -13,6 +13,7 @@ plugins/c9.ide.language.javascript.tern/util/sigs_ts
|
||||||
plugins/c9.account.billing/node_modules/
|
plugins/c9.account.billing/node_modules/
|
||||||
plugins/c9.account/node_modules/
|
plugins/c9.account/node_modules/
|
||||||
plugins/c9.api.project/coverage/
|
plugins/c9.api.project/coverage/
|
||||||
|
plugins/c9.proxy.apps/coverage/
|
||||||
plugins/c9.db.redis/coverage/
|
plugins/c9.db.redis/coverage/
|
||||||
scripts/build
|
scripts/build
|
||||||
build/output
|
build/output
|
||||||
|
|
|
@ -10,20 +10,21 @@ var http = require("http");
|
||||||
var frontdoor = require("../frontdoor");
|
var frontdoor = require("../frontdoor");
|
||||||
var createClient = require("./api-client");
|
var createClient = require("./api-client");
|
||||||
|
|
||||||
module.exports = {
|
require("c9/inline-mocha")(module);
|
||||||
|
require("amd-loader");
|
||||||
|
|
||||||
"test client/server integration": function(next) {
|
it("test client/server integration", function(next){
|
||||||
this.getUsers = function(params, callback) {
|
this.getUsers = function(params, callback) {
|
||||||
console.log(params)
|
|
||||||
callback(null, [{
|
callback(null, [{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: "fjakobs",
|
name: "fjakobs",
|
||||||
first: params.first
|
first: params.first
|
||||||
}]);
|
}]);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.addUser = sinon.stub();
|
this.addUser = sinon.stub();
|
||||||
|
|
||||||
this.getUser = function(params, callback) {
|
this.getUser = function(params, callback) {
|
||||||
console.log(params)
|
|
||||||
callback(null, {
|
callback(null, {
|
||||||
id: params.uid,
|
id: params.uid,
|
||||||
name: "fjakobs"
|
name: "fjakobs"
|
||||||
|
@ -73,20 +74,5 @@ module.exports = {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
|
|
||||||
// ">test real API server": function(next) {
|
|
||||||
// createClient("http://127.0.0.1:8081/api.json", function(err, client) {
|
|
||||||
// assert.equal(err, null);
|
|
||||||
// console.log(err, Object.keys(client), client.vfs);
|
|
||||||
// client.vfs.get(function(err, res) {
|
|
||||||
// console.log(err, res);
|
|
||||||
// assert.equal(err, null);
|
|
||||||
|
|
||||||
// next();
|
|
||||||
// })
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
};
|
|
||||||
|
|
||||||
!module.parent && require("asyncjs").test.testcase(module.exports).exec();
|
|
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
var assert = require("assert");
|
require("amd-loader");
|
||||||
|
|
||||||
|
|
||||||
|
var assert = require("assert-diff");
|
||||||
var sinon = require("sinon");
|
var sinon = require("sinon");
|
||||||
|
|
||||||
var Api = require("./api");
|
var Api = require("./api");
|
||||||
|
@ -284,13 +287,17 @@ module.exports = {
|
||||||
root.handle({
|
root.handle({
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
url: "/post/fab?age=34"
|
url: "/post/fab?age=34"
|
||||||
}, this.res, assert.fail);
|
}, this.res, function(err){
|
||||||
sinon.assert.calledWith(this.res.writeHead, 422);
|
|
||||||
var errors = JSON.parse(this.res.end.args[0][0]).errors;
|
assert.ok( err );
|
||||||
|
|
||||||
|
var errors = err.errors;
|
||||||
assert.equal(errors.length, 1);
|
assert.equal(errors.length, 1);
|
||||||
assert.equal(errors[0].resource, "root");
|
assert.equal(errors[0].resource, "root");
|
||||||
assert.equal(errors[0].field, "name");
|
assert.equal(errors[0].field, "name");
|
||||||
assert.equal(errors[0].code, "missing_field");
|
assert.equal(errors[0].code, "missing_field");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
this.res.writeHead.reset();
|
this.res.writeHead.reset();
|
||||||
this.res.end.reset();
|
this.res.end.reset();
|
||||||
|
@ -299,14 +306,19 @@ module.exports = {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
url: "/post/fab?age=juhu",
|
url: "/post/fab?age=juhu",
|
||||||
body: { name: "Fabian"}
|
body: { name: "Fabian"}
|
||||||
}, this.res, assert.fail);
|
}, this.res, function(err){
|
||||||
sinon.assert.calledWith(this.res.writeHead, 422);
|
|
||||||
var errors = JSON.parse(this.res.end.args[0][0]).errors;
|
assert.ok( err );
|
||||||
|
|
||||||
|
var errors = err.errors;
|
||||||
|
|
||||||
assert.equal(errors.length, 1);
|
assert.equal(errors.length, 1);
|
||||||
assert.equal(errors[0].resource, "root");
|
assert.equal(errors[0].resource, "root");
|
||||||
assert.equal(errors[0].field, "age");
|
assert.equal(errors[0].field, "age");
|
||||||
assert.equal(errors[0].type_expected, "int");
|
assert.equal(errors[0].type_expected, "int");
|
||||||
assert.equal(errors[0].code, "invalid");
|
assert.equal(errors[0].code, "invalid");
|
||||||
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"test custom type with register": function() {
|
"test custom type with register": function() {
|
||||||
|
@ -393,16 +405,19 @@ module.exports = {
|
||||||
"method": "put",
|
"method": "put",
|
||||||
"params": {
|
"params": {
|
||||||
"id": {
|
"id": {
|
||||||
|
"name": "id",
|
||||||
"type": "/\\d{4}/",
|
"type": "/\\d{4}/",
|
||||||
"source": "url",
|
"source": "url",
|
||||||
"optional": false
|
"optional": false
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
|
"name": "name",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"source": "body",
|
"source": "body",
|
||||||
"optional": false
|
"optional": false
|
||||||
},
|
},
|
||||||
"age": {
|
"age": {
|
||||||
|
"name": "age",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"source": "body",
|
"source": "body",
|
||||||
"optional": true
|
"optional": true
|
||||||
|
@ -414,6 +429,7 @@ module.exports = {
|
||||||
"method": "delete",
|
"method": "delete",
|
||||||
"params": {
|
"params": {
|
||||||
"id": {
|
"id": {
|
||||||
|
"name": "id",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"source": "url",
|
"source": "url",
|
||||||
"optional": false
|
"optional": false
|
||||||
|
@ -424,8 +440,8 @@ module.exports = {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
assert.equal(JSON.stringify(description), JSON.stringify(expected));
|
|
||||||
|
|
||||||
|
assert.equal(JSON.stringify(description), JSON.stringify(expected));
|
||||||
},
|
},
|
||||||
|
|
||||||
"test handler with two arguments should be treated as function(params, callback) {}": function() {
|
"test handler with two arguments should be treated as function(params, callback) {}": function() {
|
||||||
|
@ -457,8 +473,6 @@ module.exports = {
|
||||||
assert(called);
|
assert(called);
|
||||||
}
|
}
|
||||||
|
|
||||||
// test checks can be async
|
|
||||||
// fromString, fromJson
|
|
||||||
};
|
};
|
||||||
|
|
||||||
!module.parent && require("asyncjs").test.testcase(module.exports).exec();
|
!module.parent && require("asyncjs").test.testcase(module.exports).exec();
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
define(function(require, exports, module) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles parameter definitions. A full parameter definition is a name => value
|
||||||
|
* object, where each value is an object with a type, source, optional and name parameter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Types = require("./types").Types;
|
||||||
|
var RegExpType = require("./types").RegExp;
|
||||||
|
var BuiltinTypes = new Types();
|
||||||
|
|
||||||
|
var Params = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Batch normalize params, and creates Type Objects for each param.
|
||||||
|
*/
|
||||||
|
normalize: function(params, types, source) {
|
||||||
|
if ( ! params ) return {};
|
||||||
|
|
||||||
|
types = types || BuiltinTypes;
|
||||||
|
|
||||||
|
for (var name in params) {
|
||||||
|
var param = Params.param(params[name], name, source);
|
||||||
|
|
||||||
|
param.type = types.get(param.type);
|
||||||
|
params[name] = param;
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create/normalize a parameter definition from one of the following
|
||||||
|
* api's:
|
||||||
|
*
|
||||||
|
* 1. A URL parameter defined as part of a path definition:
|
||||||
|
* - This is a single string, defaulting to a required, *string* type url param
|
||||||
|
*
|
||||||
|
* 2. A url parameter following the { key: value } convention
|
||||||
|
* - The key is the name of the path/body/query part, value is a type
|
||||||
|
* - Values that are strings must be one of the builtin types
|
||||||
|
* - Values may be a RegExp, that will be converted to RegExpType
|
||||||
|
*
|
||||||
|
* 3. Fully defined param spec with valid values for type and source.
|
||||||
|
*
|
||||||
|
* @param String|Object def A param object or type string, or name.
|
||||||
|
* @param String name (Optional) param name.
|
||||||
|
* When omitted, the first argument will be the name
|
||||||
|
* @param String source (Optional) param source. Must be url, body or query
|
||||||
|
*
|
||||||
|
* @return Object param Full param object
|
||||||
|
*/
|
||||||
|
|
||||||
|
param: function(def, name, source) {
|
||||||
|
var param = def;
|
||||||
|
|
||||||
|
// Singe edge case for implicit param generation from the url pathparts,
|
||||||
|
// where the pathpart is not defined in params definition.
|
||||||
|
if (typeof def === 'string' && !name) {
|
||||||
|
return {
|
||||||
|
source: 'url',
|
||||||
|
optional: false,
|
||||||
|
type: BuiltinTypes.get('string'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof def === 'string' || def instanceof RegExp) {
|
||||||
|
param = {
|
||||||
|
name: name,
|
||||||
|
type: def
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
param.optional = !!param.optional;
|
||||||
|
param.source = param.source || source || "body";
|
||||||
|
param.type = param.type || "string";
|
||||||
|
|
||||||
|
// allow regular expressions as types
|
||||||
|
if (param.type instanceof RegExp)
|
||||||
|
param.type = new RegExpType(param.type);
|
||||||
|
|
||||||
|
|
||||||
|
if ( !/^body|url|query$/.test(param.source)) {
|
||||||
|
throw new Error("parameter source muste be 'url', 'query' or 'body'");
|
||||||
|
}
|
||||||
|
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Params;
|
||||||
|
});
|
|
@ -1,12 +1,25 @@
|
||||||
define(function(require, exports, module) {
|
define(function(require, exports, module) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var RegExpType = require("./types").RegExp;
|
var Params = require("./params");
|
||||||
var Types = require("./types").Types;
|
|
||||||
var flatten = require("./utils").flatten;
|
var flatten = require("./utils").flatten;
|
||||||
var error = require("http-error");
|
var error = require("http-error");
|
||||||
|
|
||||||
module.exports = function Route(route, options, handler, types) {
|
function prepareParams( options, types, parent ){
|
||||||
|
var params = Params.normalize(options.params, types );
|
||||||
|
|
||||||
|
if ( parent ){
|
||||||
|
for ( var key in parent.params ){
|
||||||
|
if ( params[key] ) continue;
|
||||||
|
params[key] = parent.params[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = function Route(route, options, handler, types, parent ) {
|
||||||
|
|
||||||
// options is optional
|
// options is optional
|
||||||
if (typeof options == "function" || Array.isArray(options)) {
|
if (typeof options == "function" || Array.isArray(options)) {
|
||||||
|
@ -15,8 +28,8 @@ module.exports = function Route(route, options, handler, types) {
|
||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
options.route = route;
|
options.route = route;
|
||||||
types = types || new Types();
|
|
||||||
|
|
||||||
this.middlewares = flatten(handler);
|
this.middlewares = flatten(handler);
|
||||||
|
|
||||||
|
@ -28,14 +41,13 @@ module.exports = function Route(route, options, handler, types) {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.middlewares.unshift(decodeParams);
|
this.middlewares.unshift(decodeParams);
|
||||||
|
|
||||||
this.method = (options.method || "GET").toLowerCase();
|
this.method = (options.method || "GET").toLowerCase();
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var keys = [];
|
var keys = [];
|
||||||
var params = options.params || {};
|
|
||||||
|
var params = prepareParams( options, types, parent );
|
||||||
var routeRe = normalizePath(options.route, keys, params);
|
var routeRe = normalizePath(options.route, keys, params);
|
||||||
params = normalizeParams(params);
|
|
||||||
|
|
||||||
function wrapHandler(handler) {
|
function wrapHandler(handler) {
|
||||||
return function(req, res, next) {
|
return function(req, res, next) {
|
||||||
|
@ -53,29 +65,22 @@ module.exports = function Route(route, options, handler, types) {
|
||||||
* the default values for url parameters.
|
* the default values for url parameters.
|
||||||
*/
|
*/
|
||||||
function normalizePath(path, keys, params) {
|
function normalizePath(path, keys, params) {
|
||||||
for (var name in params) {
|
|
||||||
var param = params[name];
|
|
||||||
if (typeof param == "string" || param instanceof RegExp)
|
|
||||||
params[name] = { type: param};
|
|
||||||
}
|
|
||||||
|
|
||||||
path = path
|
path = path
|
||||||
.concat("/?")
|
.concat("/?")
|
||||||
.replace(/\/:([\w\.\-\_]+)(\*?)/g, function(match, key, wildcard) {
|
.replace(/\/:([\w\.\-\_]+)(\*?)/g, function(match, key, wildcard) {
|
||||||
keys.push(key);
|
keys.push(key);
|
||||||
if (!params[key]) {
|
|
||||||
params[key] = {};
|
// Implicit params: part of path definition but not defined as
|
||||||
}
|
// { params }, created here on the fly.
|
||||||
// url params default to type string and optional=false
|
if (!params[key])
|
||||||
|
params[key] = Params.param( key );
|
||||||
|
|
||||||
var param = params[key];
|
var param = params[key];
|
||||||
param.type = param.type || "string";
|
|
||||||
param.optional = false;
|
|
||||||
|
|
||||||
if (!param.source)
|
// override the default source for params
|
||||||
param.source = "url";
|
// that are created by parsing the url
|
||||||
|
param.source = 'url';
|
||||||
|
|
||||||
if (param.source !== "url")
|
|
||||||
throw new Error("Url parameters must have 'url' as source but found '" + param.source + "'");
|
|
||||||
|
|
||||||
if (wildcard)
|
if (wildcard)
|
||||||
return "(/*)";
|
return "(/*)";
|
||||||
|
@ -85,43 +90,10 @@ module.exports = function Route(route, options, handler, types) {
|
||||||
.replace(/([\/.])/g, '\\$1')
|
.replace(/([\/.])/g, '\\$1')
|
||||||
.replace(/\*/g, '(.*)');
|
.replace(/\*/g, '(.*)');
|
||||||
|
|
||||||
|
|
||||||
return new RegExp('^' + path + '$');
|
return new RegExp('^' + path + '$');
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeParams(params) {
|
|
||||||
for (var name in params) {
|
|
||||||
var param = params[name];
|
|
||||||
|
|
||||||
if (param.source == "query") {
|
|
||||||
// query params default to string
|
|
||||||
param.type = param.type || "string";
|
|
||||||
}
|
|
||||||
else if (!param.source || param.source == "body") {
|
|
||||||
// body params default to json
|
|
||||||
param.type = param.type || "json";
|
|
||||||
param.source = "body";
|
|
||||||
}
|
|
||||||
else if (param.source === "url") {
|
|
||||||
param.type = param.type || "string";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error("parameter source muste be 'url', 'query' or 'body'");
|
|
||||||
}
|
|
||||||
|
|
||||||
// optional defaults to false
|
|
||||||
param.optional = !!param.optional;
|
|
||||||
|
|
||||||
// allow regular expressions as types
|
|
||||||
if (param.type instanceof RegExp)
|
|
||||||
param.type = new RegExpType(param.type);
|
|
||||||
|
|
||||||
// convert all types to type objects
|
|
||||||
param.type = types.get(param.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the given path matched the route regular expression. If
|
* Check if the given path matched the route regular expression. If
|
||||||
* the regular expression doesn't match or parsing fails `match` will
|
* the regular expression doesn't match or parsing fails `match` will
|
||||||
|
@ -129,6 +101,7 @@ module.exports = function Route(route, options, handler, types) {
|
||||||
**/
|
**/
|
||||||
this.match = function(req, path) {
|
this.match = function(req, path) {
|
||||||
var m = path.match(routeRe);
|
var m = path.match(routeRe);
|
||||||
|
|
||||||
if (!m) return false;
|
if (!m) return false;
|
||||||
|
|
||||||
var match = {};
|
var match = {};
|
||||||
|
@ -147,6 +120,7 @@ module.exports = function Route(route, options, handler, types) {
|
||||||
}
|
}
|
||||||
match[key] = value;
|
match[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
req.match = match;
|
req.match = match;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -159,6 +133,7 @@ module.exports = function Route(route, options, handler, types) {
|
||||||
*/
|
*/
|
||||||
function decodeParams(req, res, next) {
|
function decodeParams(req, res, next) {
|
||||||
var urlParams = req.match;
|
var urlParams = req.match;
|
||||||
|
|
||||||
if (!urlParams) return;
|
if (!urlParams) return;
|
||||||
|
|
||||||
var body = req.body || {};
|
var body = req.body || {};
|
||||||
|
@ -173,6 +148,10 @@ module.exports = function Route(route, options, handler, types) {
|
||||||
// 1. check if all required params are there
|
// 1. check if all required params are there
|
||||||
for (var key in params) {
|
for (var key in params) {
|
||||||
var param = params[key];
|
var param = params[key];
|
||||||
|
|
||||||
|
if ( keys.indexOf(key) === -1 && param.source == 'url' )
|
||||||
|
continue;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(!param.optional) && (
|
(!param.optional) && (
|
||||||
(param.source == "body" && !(key in body)) ||
|
(param.source == "body" && !(key in body)) ||
|
||||||
|
@ -191,7 +170,8 @@ module.exports = function Route(route, options, handler, types) {
|
||||||
var type = param.type;
|
var type = param.type;
|
||||||
var value = EMPTY;
|
var value = EMPTY;
|
||||||
var isValid = true;
|
var isValid = true;
|
||||||
switch(param.source) {
|
|
||||||
|
switch (param.source) {
|
||||||
case "body":
|
case "body":
|
||||||
if (param.optional && !(key in body))
|
if (param.optional && !(key in body))
|
||||||
break;
|
break;
|
||||||
|
@ -261,7 +241,7 @@ module.exports = function Route(route, options, handler, types) {
|
||||||
for (var name in params) {
|
for (var name in params) {
|
||||||
var param = params[name];
|
var param = params[name];
|
||||||
route.params[name] = {
|
route.params[name] = {
|
||||||
name: param.name,
|
name: name,
|
||||||
type: param.type.toString(),
|
type: param.type.toString(),
|
||||||
source: param.source,
|
source: param.source,
|
||||||
optional: param.optional
|
optional: param.optional
|
||||||
|
|
|
@ -2,13 +2,15 @@
|
||||||
|
|
||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
var assert = require("assert");
|
require("amd-loader");
|
||||||
|
require("c9/inline-mocha")(module);
|
||||||
|
|
||||||
var sinon = require("sinon");
|
var sinon = require("sinon");
|
||||||
|
var frontdoor = require('../frontdoor');
|
||||||
|
var Route = frontdoor.Route;
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
var Route = require("./route");
|
it("test router: simple route with argument", function(done) {
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
"test router: simple route with argument": function() {
|
|
||||||
var route = new Route("/user/:name", sinon.stub());
|
var route = new Route("/user/:name", sinon.stub());
|
||||||
|
|
||||||
var req = {};
|
var req = {};
|
||||||
|
@ -17,9 +19,11 @@ module.exports = {
|
||||||
|
|
||||||
assert.equal(route.match(req, "/user/fabian"), true);
|
assert.equal(route.match(req, "/user/fabian"), true);
|
||||||
assert.equal(req.match.name, "fabian");
|
assert.equal(req.match.name, "fabian");
|
||||||
},
|
|
||||||
|
|
||||||
"test router: simple route with number argument": function() {
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test router: simple route with number argument", function(done) {
|
||||||
var route = new Route("/user/:id", {
|
var route = new Route("/user/:id", {
|
||||||
params: {
|
params: {
|
||||||
id: {
|
id: {
|
||||||
|
@ -32,9 +36,11 @@ module.exports = {
|
||||||
assert.equal(route.match(req, "/user/fabian"), false);
|
assert.equal(route.match(req, "/user/fabian"), false);
|
||||||
assert.equal(route.match(req, "/user/123"), true);
|
assert.equal(route.match(req, "/user/123"), true);
|
||||||
assert.equal(req.match.id, 123);
|
assert.equal(req.match.id, 123);
|
||||||
},
|
|
||||||
|
|
||||||
"test router: for params if the value is a string it is treated as the type": function() {
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test router: for params if the value is a string it is treated as the type", function(done) {
|
||||||
var route = new Route("/user/:id", {
|
var route = new Route("/user/:id", {
|
||||||
params: {
|
params: {
|
||||||
id: "int"
|
id: "int"
|
||||||
|
@ -44,9 +50,11 @@ module.exports = {
|
||||||
var req = {};
|
var req = {};
|
||||||
assert.equal(route.match(req, "/user/123"), true);
|
assert.equal(route.match(req, "/user/123"), true);
|
||||||
assert.equal(req.match.id, 123);
|
assert.equal(req.match.id, 123);
|
||||||
},
|
|
||||||
|
|
||||||
"test router: complex route with wildcard arguments": function() {
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test router: complex route with wildcard arguments", function(done) {
|
||||||
var route = new Route("/user/:name/:rest*", {
|
var route = new Route("/user/:name/:rest*", {
|
||||||
params: {
|
params: {
|
||||||
id: {
|
id: {
|
||||||
|
@ -70,9 +78,12 @@ module.exports = {
|
||||||
assert.equal(route.match(req, "/user/fabian/abc/123"), true);
|
assert.equal(route.match(req, "/user/fabian/abc/123"), true);
|
||||||
assert.equal(req.match.name, "fabian");
|
assert.equal(req.match.name, "fabian");
|
||||||
assert.equal(req.match.rest, "/abc/123");
|
assert.equal(req.match.rest, "/abc/123");
|
||||||
},
|
|
||||||
|
|
||||||
"test router: complex route with multiple arguments": function() {
|
done();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test router: complex route with multiple arguments", function(done) {
|
||||||
var route = new Route("/user/:name/:id", {
|
var route = new Route("/user/:name/:id", {
|
||||||
params: {
|
params: {
|
||||||
id: {
|
id: {
|
||||||
|
@ -88,9 +99,12 @@ module.exports = {
|
||||||
assert.equal(route.match(req, "/user/fabian/123"), true);
|
assert.equal(route.match(req, "/user/fabian/123"), true);
|
||||||
assert.equal(req.match.id, 123);
|
assert.equal(req.match.id, 123);
|
||||||
assert.equal(req.match.name, "fabian");
|
assert.equal(req.match.name, "fabian");
|
||||||
},
|
|
||||||
|
|
||||||
"test regexp types": function() {
|
done();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test regexp types", function(done) {
|
||||||
var route = new Route("/users/:uid", {
|
var route = new Route("/users/:uid", {
|
||||||
params: {
|
params: {
|
||||||
uid: /u\d+/
|
uid: /u\d+/
|
||||||
|
@ -101,9 +115,12 @@ module.exports = {
|
||||||
|
|
||||||
assert.ok(route.match(req, "/users/u123"));
|
assert.ok(route.match(req, "/users/u123"));
|
||||||
assert.ok(!route.match(req, "/users/_u123"));
|
assert.ok(!route.match(req, "/users/_u123"));
|
||||||
},
|
|
||||||
|
|
||||||
"test custom type without register": function() {
|
done();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test custom type without register", function(done) {
|
||||||
var DateType = {
|
var DateType = {
|
||||||
parse: function(string) {
|
parse: function(string) {
|
||||||
if (!/\d{13}/.test(string))
|
if (!/\d{13}/.test(string))
|
||||||
|
@ -131,7 +148,6 @@ module.exports = {
|
||||||
|
|
||||||
assert.ok(!route.match(req, "/ts/353676299181"));
|
assert.ok(!route.match(req, "/ts/353676299181"));
|
||||||
assert.ok(!route.match(req, "/ts/abc"));
|
assert.ok(!route.match(req, "/ts/abc"));
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
!module.parent && require("asyncjs").test.testcase(module.exports).exec();
|
done();
|
||||||
|
});
|
||||||
|
|
|
@ -4,6 +4,7 @@ define(function(require, exports, module) {
|
||||||
|
|
||||||
var url = require("url");
|
var url = require("url");
|
||||||
var Types = require("./types").Types;
|
var Types = require("./types").Types;
|
||||||
|
var Params = require("./params");
|
||||||
var Route = require("./route");
|
var Route = require("./route");
|
||||||
var flatten = require("./utils").flatten;
|
var flatten = require("./utils").flatten;
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ module.exports = function Section(name, description, types) {
|
||||||
return self._route(route, options, handler);
|
return self._route(route, options, handler);
|
||||||
}).bind(self, method);
|
}).bind(self, method);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.del = this["delete"];
|
this.del = this["delete"];
|
||||||
|
|
||||||
this.registerType = types.register.bind(types);
|
this.registerType = types.register.bind(types);
|
||||||
|
@ -54,7 +56,7 @@ module.exports = function Section(name, description, types) {
|
||||||
};
|
};
|
||||||
|
|
||||||
this._route = function(route, options, handler) {
|
this._route = function(route, options, handler) {
|
||||||
route = new Route(route, options, handler, types);
|
route = new Route(route, options, handler, types, this);
|
||||||
route.parent = this;
|
route.parent = this;
|
||||||
routes[route.method].push(route);
|
routes[route.method].push(route);
|
||||||
return this;
|
return this;
|
||||||
|
@ -160,7 +162,9 @@ module.exports = function Section(name, description, types) {
|
||||||
if (section && section.length) {
|
if (section && section.length) {
|
||||||
var subPath = "/" + splitPath.slice(1).join("/");
|
var subPath = "/" + splitPath.slice(1).join("/");
|
||||||
for (var i = 0; i < section.length; i++) {
|
for (var i = 0; i < section.length; i++) {
|
||||||
|
|
||||||
var handler = section[i].match(req, subPath, method);
|
var handler = section[i].match(req, subPath, method);
|
||||||
|
|
||||||
if (handler)
|
if (handler)
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
@ -204,6 +208,21 @@ module.exports = function Section(name, description, types) {
|
||||||
|
|
||||||
return api;
|
return api;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var params;
|
||||||
|
|
||||||
|
Object.defineProperty( this, 'params', {
|
||||||
|
set: function( def, types ){
|
||||||
|
params = Params.normalize( def );
|
||||||
|
},
|
||||||
|
|
||||||
|
get: function(){
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
|
@ -0,0 +1,169 @@
|
||||||
|
"use strict";
|
||||||
|
"use server";
|
||||||
|
|
||||||
|
require("c9/inline-mocha")(module);
|
||||||
|
require("amd-loader");
|
||||||
|
|
||||||
|
var assert = require('assert-diff');
|
||||||
|
var Section = require('../frontdoor').Section;
|
||||||
|
var Url = require('url');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var mock = {
|
||||||
|
req: function( method, uri) {
|
||||||
|
var parsedUrl = Url.parse(uri||'', true);
|
||||||
|
|
||||||
|
return {
|
||||||
|
method: method || 'get',
|
||||||
|
parsedUrl: parsedUrl,
|
||||||
|
pathname: parsedUrl.pathname,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
it('Defines params on section level', function(done) {
|
||||||
|
var testParams = {
|
||||||
|
int: {
|
||||||
|
type: 'int',
|
||||||
|
source: 'url'
|
||||||
|
},
|
||||||
|
string: 'string',
|
||||||
|
alphanum: {
|
||||||
|
type: /[a-z0-9]+/,
|
||||||
|
source: 'url'
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var cases = [
|
||||||
|
{
|
||||||
|
label: 'Match a simple string param',
|
||||||
|
path: '/test/:string',
|
||||||
|
url: '/test/foo',
|
||||||
|
params: {
|
||||||
|
string: 'foo',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Match a simple number param',
|
||||||
|
path: '/test/:int',
|
||||||
|
url: '/test/123',
|
||||||
|
params: {
|
||||||
|
int: 123,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Match multiple params',
|
||||||
|
path: '/test/:int/:string',
|
||||||
|
url: '/test/123/hello',
|
||||||
|
params: {
|
||||||
|
string: 'hello',
|
||||||
|
int: 123,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Match multiple params 3x',
|
||||||
|
path: '/test/:string/:int/:alphanum',
|
||||||
|
url: '/test/hello/123/baz123',
|
||||||
|
params: {
|
||||||
|
string: 'hello',
|
||||||
|
int: 123,
|
||||||
|
alphanum: 'baz123'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Check ordered params',
|
||||||
|
path: '/test/:string/:int/:alphanum',
|
||||||
|
url: '/test/123/hello/baz123',
|
||||||
|
err: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Must match type int param',
|
||||||
|
path: '/test/:int',
|
||||||
|
url: '/test/test',
|
||||||
|
err: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Must match optinal type int',
|
||||||
|
path: '/test/:int',
|
||||||
|
url: '/test',
|
||||||
|
err: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Match an optional param',
|
||||||
|
path: '/test/:optional',
|
||||||
|
url: '/test',
|
||||||
|
err: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Match an implied url param',
|
||||||
|
path: '/test/:implied',
|
||||||
|
url: '/test/ok',
|
||||||
|
params: {
|
||||||
|
implied: 'ok',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Query params can be passed along',
|
||||||
|
path: '/test/:string/:int/:alphanum',
|
||||||
|
url: '/test/hello/123/baz123?q=123',
|
||||||
|
options: {
|
||||||
|
params: {
|
||||||
|
q: {
|
||||||
|
type: 'int',
|
||||||
|
optional: false,
|
||||||
|
source: 'query',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
string: 'hello',
|
||||||
|
int: 123,
|
||||||
|
alphanum: 'baz123',
|
||||||
|
q: 123
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Required query params must be passed',
|
||||||
|
path: '/test/:string/:int/:alphanum',
|
||||||
|
url: '/test/hello/123/baz123',
|
||||||
|
err: true,
|
||||||
|
options: {
|
||||||
|
params: {
|
||||||
|
q: {
|
||||||
|
type: 'int',
|
||||||
|
optional: false,
|
||||||
|
source: 'query',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
cases.forEach(function(testCase) {
|
||||||
|
var req = mock.req('get', testCase.url),
|
||||||
|
api = new Section('test');
|
||||||
|
|
||||||
|
api.params = testParams;
|
||||||
|
|
||||||
|
var handled = false;
|
||||||
|
|
||||||
|
api.get( testCase.path, testCase.options || {}, function(req, res, next){
|
||||||
|
handled = true;
|
||||||
|
|
||||||
|
assert.deepEqual( req.params, testCase.params, testCase.label );
|
||||||
|
});
|
||||||
|
|
||||||
|
api.handle( req.pathname, req, {}, function(err) {
|
||||||
|
if ( testCase.err ) {
|
||||||
|
assert.ok( 'OK: route not matched: ' + testCase.label );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert.ok(handled);
|
||||||
|
assert.fail( 'route not matched: ' + testCase.label );
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
|
require("amd-loader");
|
||||||
|
|
||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
|
|
||||||
var types = require("./types");
|
var types = require("./types");
|
||||||
|
|
|
@ -1,19 +1,23 @@
|
||||||
{
|
{
|
||||||
"author": "Ajax.org B.V. <info@ajax.org>",
|
"author": "Ajax.org B.V. <info@ajax.org>",
|
||||||
"contributors": [{
|
"contributors": [
|
||||||
|
{
|
||||||
"name": "Fabian Jakobs",
|
"name": "Fabian Jakobs",
|
||||||
"email": "fabian@c9.io"
|
"email": "fabian@c9.io"
|
||||||
}],
|
}
|
||||||
|
],
|
||||||
"name": "frontdoor",
|
"name": "frontdoor",
|
||||||
"description": "Frontdoor is a libarary for creating RESTful API servers.",
|
"description": "Frontdoor is a libarary for creating RESTful API servers.",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "find lib | grep '_test.js$' | xargs -n 1 node"
|
"test": "find lib | grep '_test.js$' | xargs -n 1 node"
|
||||||
},
|
},
|
||||||
"licenses": [{
|
"licenses": [
|
||||||
|
{
|
||||||
"type": "MIT",
|
"type": "MIT",
|
||||||
"url": "http://github.com/frontdoor/smith/raw/master/LICENSE"
|
"url": "http://github.com/frontdoor/smith/raw/master/LICENSE"
|
||||||
}],
|
}
|
||||||
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/c9/frontdoor.git"
|
"url": "git://github.com/c9/frontdoor.git"
|
||||||
|
@ -29,9 +33,9 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"asyncjs": "~0.0.9",
|
"asyncjs": "~0.0.9",
|
||||||
"sinon": "~1.3.0",
|
"ejs": "*",
|
||||||
|
|
||||||
"express": "3.0.3",
|
"express": "3.0.3",
|
||||||
"ejs": "*"
|
"sinon": "~1.3.0",
|
||||||
|
"tape": "^3.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
Ładowanie…
Reference in New Issue