kopia lustrzana https://github.com/c9/core
Merge remote-tracking branch 'origin/master' into mvh-frontdoor-params
rodzic
2beb3c6441
commit
f6f5e02877
|
@ -0,0 +1,98 @@
|
|||
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;
|
||||
source = source || 'url';
|
||||
|
||||
// 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 {
|
||||
name: def,
|
||||
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;
|
||||
|
||||
// allow regular expressions as types
|
||||
if (param.type instanceof RegExp)
|
||||
param.type = new RegExpType(param.type);
|
||||
|
||||
if (param.source == "body")
|
||||
param.type = param.type || "json";
|
||||
|
||||
param.type = param.type || "string";
|
||||
|
||||
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) {
|
||||
"use strict";
|
||||
|
||||
var RegExpType = require("./types").RegExp;
|
||||
var Types = require("./types").Types;
|
||||
var Params = require("./params");
|
||||
var flatten = require("./utils").flatten;
|
||||
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
|
||||
if (typeof options == "function" || Array.isArray(options)) {
|
||||
|
@ -14,9 +27,9 @@ module.exports = function Route(route, options, handler, types) {
|
|||
handler = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
|
||||
options.route = route;
|
||||
types = types || new Types();
|
||||
|
||||
this.middlewares = flatten(handler);
|
||||
|
||||
|
@ -28,14 +41,13 @@ module.exports = function Route(route, options, handler, types) {
|
|||
});
|
||||
|
||||
this.middlewares.unshift(decodeParams);
|
||||
|
||||
this.method = (options.method || "GET").toLowerCase();
|
||||
|
||||
var self = this;
|
||||
var keys = [];
|
||||
var params = options.params || {};
|
||||
|
||||
var params = prepareParams( options, types, parent );
|
||||
var routeRe = normalizePath(options.route, keys, params);
|
||||
params = normalizeParams(params);
|
||||
|
||||
function wrapHandler(handler) {
|
||||
return function(req, res, next) {
|
||||
|
@ -53,27 +65,18 @@ module.exports = function Route(route, options, handler, types) {
|
|||
* the default values for url parameters.
|
||||
*/
|
||||
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
|
||||
.concat("/?")
|
||||
.replace(/\/:([\w\.\-\_]+)(\*?)/g, function(match, key, wildcard) {
|
||||
keys.push(key);
|
||||
if (!params[key]) {
|
||||
params[key] = {};
|
||||
}
|
||||
// url params default to type string and optional=false
|
||||
|
||||
// Implicit params: part of path definition but not defined as
|
||||
// { params }, created here on the fly.
|
||||
if (!params[key])
|
||||
params[key] = Params.param( key );
|
||||
|
||||
var param = params[key];
|
||||
param.type = param.type || "string";
|
||||
param.optional = false;
|
||||
|
||||
if (!param.source)
|
||||
param.source = "url";
|
||||
|
||||
|
||||
if (param.source !== "url")
|
||||
throw new Error("Url parameters must have 'url' as source but found '" + param.source + "'");
|
||||
|
||||
|
@ -84,44 +87,11 @@ module.exports = function Route(route, options, handler, types) {
|
|||
})
|
||||
.replace(/([\/.])/g, '\\$1')
|
||||
.replace(/\*/g, '(.*)');
|
||||
|
||||
|
||||
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
|
||||
* the regular expression doesn't match or parsing fails `match` will
|
||||
|
@ -129,8 +99,9 @@ module.exports = function Route(route, options, handler, types) {
|
|||
**/
|
||||
this.match = function(req, path) {
|
||||
var m = path.match(routeRe);
|
||||
|
||||
if (!m) return false;
|
||||
|
||||
|
||||
var match = {};
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var value = m[i+1];
|
||||
|
@ -147,6 +118,7 @@ module.exports = function Route(route, options, handler, types) {
|
|||
}
|
||||
match[key] = value;
|
||||
}
|
||||
|
||||
req.match = match;
|
||||
return true;
|
||||
};
|
||||
|
@ -159,6 +131,7 @@ module.exports = function Route(route, options, handler, types) {
|
|||
*/
|
||||
function decodeParams(req, res, next) {
|
||||
var urlParams = req.match;
|
||||
|
||||
if (!urlParams) return;
|
||||
|
||||
var body = req.body || {};
|
||||
|
@ -173,6 +146,10 @@ module.exports = function Route(route, options, handler, types) {
|
|||
// 1. check if all required params are there
|
||||
for (var key in params) {
|
||||
var param = params[key];
|
||||
|
||||
if ( keys.indexOf(key) === -1 && param.source == 'url' )
|
||||
continue;
|
||||
|
||||
if (
|
||||
(!param.optional) && (
|
||||
(param.source == "body" && !(key in body)) ||
|
||||
|
@ -191,7 +168,8 @@ module.exports = function Route(route, options, handler, types) {
|
|||
var type = param.type;
|
||||
var value = EMPTY;
|
||||
var isValid = true;
|
||||
switch(param.source) {
|
||||
|
||||
switch (param.source) {
|
||||
case "body":
|
||||
if (param.optional && !(key in body))
|
||||
break;
|
||||
|
|
|
@ -4,6 +4,7 @@ define(function(require, exports, module) {
|
|||
|
||||
var url = require("url");
|
||||
var Types = require("./types").Types;
|
||||
var Params = require("./params");
|
||||
var Route = require("./route");
|
||||
var flatten = require("./utils").flatten;
|
||||
|
||||
|
@ -32,10 +33,11 @@ module.exports = function Section(name, description, types) {
|
|||
return self._route(route, options, handler);
|
||||
}).bind(self, method);
|
||||
});
|
||||
|
||||
this.del = this["delete"];
|
||||
|
||||
this.registerType = types.register.bind(types);
|
||||
|
||||
|
||||
this.all = function(method, route, options, handler) {
|
||||
var self = this;
|
||||
var args = arguments;
|
||||
|
@ -54,7 +56,7 @@ module.exports = function Section(name, description, types) {
|
|||
};
|
||||
|
||||
this._route = function(route, options, handler) {
|
||||
route = new Route(route, options, handler, types);
|
||||
route = new Route(route, options, handler, types, this);
|
||||
route.parent = this;
|
||||
routes[route.method].push(route);
|
||||
return this;
|
||||
|
@ -160,7 +162,9 @@ module.exports = function Section(name, description, types) {
|
|||
if (section && section.length) {
|
||||
var subPath = "/" + splitPath.slice(1).join("/");
|
||||
for (var i = 0; i < section.length; i++) {
|
||||
|
||||
var handler = section[i].match(req, subPath, method);
|
||||
|
||||
if (handler)
|
||||
return handler;
|
||||
}
|
||||
|
@ -204,6 +208,21 @@ module.exports = function Section(name, description, types) {
|
|||
|
||||
return api;
|
||||
};
|
||||
|
||||
var params;
|
||||
|
||||
Object.defineProperty( this, 'params', {
|
||||
set: function( def, types ){
|
||||
params = Params.normalize( def );
|
||||
},
|
||||
|
||||
get: function(){
|
||||
return params;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
});
|
|
@ -1,37 +1,41 @@
|
|||
{
|
||||
"author": "Ajax.org B.V. <info@ajax.org>",
|
||||
"contributors": [{
|
||||
"name": "Fabian Jakobs",
|
||||
"email": "fabian@c9.io"
|
||||
}],
|
||||
"name": "frontdoor",
|
||||
"description": "Frontdoor is a libarary for creating RESTful API servers.",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"test": "find lib | grep '_test.js$' | xargs -n 1 node"
|
||||
},
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/frontdoor/smith/raw/master/LICENSE"
|
||||
}],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/c9/frontdoor.git"
|
||||
},
|
||||
"main": "frontdoor.js",
|
||||
"engines": {
|
||||
"node": ">=0.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"http-error": "~0.0.1",
|
||||
"request": "~2.12.0",
|
||||
"amd-loader": "~0.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"asyncjs": "~0.0.9",
|
||||
"sinon": "~1.3.0",
|
||||
|
||||
"express": "3.0.3",
|
||||
"ejs": "*"
|
||||
"author": "Ajax.org B.V. <info@ajax.org>",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Fabian Jakobs",
|
||||
"email": "fabian@c9.io"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "frontdoor",
|
||||
"description": "Frontdoor is a libarary for creating RESTful API servers.",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"test": "find lib | grep '_test.js$' | xargs -n 1 node"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/frontdoor/smith/raw/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/c9/frontdoor.git"
|
||||
},
|
||||
"main": "frontdoor.js",
|
||||
"engines": {
|
||||
"node": ">=0.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"http-error": "~0.0.1",
|
||||
"request": "~2.12.0",
|
||||
"amd-loader": "~0.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"asyncjs": "~0.0.9",
|
||||
"ejs": "*",
|
||||
"express": "3.0.3",
|
||||
"sinon": "~1.3.0",
|
||||
"tape": "^3.5.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
"use strict";
|
||||
|
||||
var sinon = require("sinon");
|
||||
var frontdoor = require('../frontdoor');
|
||||
var Route = frontdoor.Route;
|
||||
var test = require('tape');
|
||||
|
||||
test("test router: simple route with argument", function(assert) {
|
||||
var route = new Route("/user/:name", sinon.stub());
|
||||
|
||||
var req = {};
|
||||
assert.equal(route.match(req, "/juhu"), false);
|
||||
assert.equal(route.match(req, "/juhu/12"), false);
|
||||
|
||||
assert.equal(route.match(req, "/user/fabian"), true);
|
||||
assert.equal(req.match.name, "fabian");
|
||||
|
||||
assert.end();
|
||||
});
|
||||
|
||||
test("test router: simple route with number argument", function(assert) {
|
||||
var route = new Route("/user/:id", {
|
||||
params: {
|
||||
id: {
|
||||
type: "int"
|
||||
}
|
||||
}
|
||||
}, sinon.stub());
|
||||
|
||||
var req = {};
|
||||
assert.equal(route.match(req, "/user/fabian"), false);
|
||||
assert.equal(route.match(req, "/user/123"), true);
|
||||
assert.equal(req.match.id, 123);
|
||||
|
||||
assert.end();
|
||||
});
|
||||
|
||||
test("test router: for params if the value is a string it is treated as the type", function(assert) {
|
||||
var route = new Route("/user/:id", {
|
||||
params: {
|
||||
id: "int"
|
||||
}
|
||||
}, sinon.stub());
|
||||
|
||||
var req = {};
|
||||
assert.equal(route.match(req, "/user/123"), true);
|
||||
assert.equal(req.match.id, 123);
|
||||
|
||||
assert.end();
|
||||
});
|
||||
|
||||
test("test router: complex route with wildcard arguments", function(assert) {
|
||||
var route = new Route("/user/:name/:rest*", {
|
||||
params: {
|
||||
id: {
|
||||
type: "int"
|
||||
},
|
||||
rest: {
|
||||
type: "string"
|
||||
}
|
||||
}
|
||||
}, sinon.stub());
|
||||
|
||||
var req = {};
|
||||
|
||||
assert.equal(route.match(req, "/user/fabian"), false);
|
||||
assert.equal(route.match(req, "/user/fabian/"), true);
|
||||
assert.equal(req.match.name, "fabian");
|
||||
assert.equal(req.match.rest, "/");
|
||||
assert.equal(route.match(req, "/user/fabian/abc"), true);
|
||||
assert.equal(req.match.name, "fabian");
|
||||
assert.equal(req.match.rest, "/abc");
|
||||
assert.equal(route.match(req, "/user/fabian/abc/123"), true);
|
||||
assert.equal(req.match.name, "fabian");
|
||||
assert.equal(req.match.rest, "/abc/123");
|
||||
|
||||
assert.end();
|
||||
|
||||
});
|
||||
|
||||
test("test router: complex route with multiple arguments", function(assert) {
|
||||
var route = new Route("/user/:name/:id", {
|
||||
params: {
|
||||
id: {
|
||||
type: "int"
|
||||
}
|
||||
}
|
||||
}, sinon.stub());
|
||||
|
||||
var req = {};
|
||||
|
||||
assert.equal(route.match(req, "/user/fabian"), false);
|
||||
assert.equal(route.match(req, "/user/123"), false);
|
||||
assert.equal(route.match(req, "/user/fabian/123"), true);
|
||||
assert.equal(req.match.id, 123);
|
||||
assert.equal(req.match.name, "fabian");
|
||||
|
||||
assert.end();
|
||||
|
||||
});
|
||||
|
||||
test("test regexp types", function(assert) {
|
||||
var route = new Route("/users/:uid", {
|
||||
params: {
|
||||
uid: /u\d+/
|
||||
}
|
||||
}, sinon.stub());
|
||||
|
||||
var req = {};
|
||||
|
||||
assert.ok(route.match(req, "/users/u123"));
|
||||
assert.ok(!route.match(req, "/users/_u123"));
|
||||
|
||||
assert.end();
|
||||
|
||||
});
|
||||
|
||||
test("test custom type without register", function(assert) {
|
||||
var DateType = {
|
||||
parse: function(string) {
|
||||
if (!/\d{13}/.test(string))
|
||||
throw new Error("not a timestamp");
|
||||
|
||||
return new Date(parseInt(string, 10));
|
||||
},
|
||||
check: function(value) {
|
||||
return value instanceof Date;
|
||||
}
|
||||
};
|
||||
|
||||
var route = new Route("/ts/:ts", {
|
||||
params: {
|
||||
ts: {
|
||||
type: DateType
|
||||
}
|
||||
}
|
||||
}, sinon.stub());
|
||||
|
||||
var req = {};
|
||||
|
||||
assert.ok(route.match(req, "/ts/1353676299181"));
|
||||
assert.ok(req.match.ts instanceof Date);
|
||||
|
||||
assert.ok(!route.match(req, "/ts/353676299181"));
|
||||
assert.ok(!route.match(req, "/ts/abc"));
|
||||
|
||||
|
||||
assert.end();
|
||||
});
|
|
@ -0,0 +1,166 @@
|
|||
var test = require('tape');
|
||||
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,
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
test('Defines params on section level', function(assert, things, done) {
|
||||
var testParams = {
|
||||
required: {
|
||||
type: 'int',
|
||||
optional: false,
|
||||
},
|
||||
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: 'Must match required type int',
|
||||
path: '/test/:required',
|
||||
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;
|
||||
|
||||
api.get( testCase.path, testCase.options || {}, function(req, res, next){
|
||||
assert.deepEqual( req.params, testCase.params, testCase.label );
|
||||
});
|
||||
|
||||
api.handle( req.pathname, req, {}, function(err) {
|
||||
if ( testCase.err ) {
|
||||
assert.pass( 'route not matched: ' + testCase.label );
|
||||
return;
|
||||
}
|
||||
assert.fail( 'route not matched: ' + testCase.label );
|
||||
});
|
||||
});
|
||||
|
||||
assert.end();
|
||||
});
|
20
package.json
20
package.json
|
@ -50,18 +50,18 @@
|
|||
"licenses": [],
|
||||
"c9plugins": {
|
||||
"c9.ide.language": "#afda452919",
|
||||
"c9.ide.language.css": "#eab00e0694",
|
||||
"c9.ide.language.generic": "#8a3be4533a",
|
||||
"c9.ide.language.html": "#13321c4eb3",
|
||||
"c9.ide.language.html.diff": "#0d49022da4",
|
||||
"c9.ide.language.css": "#afda1f867c",
|
||||
"c9.ide.language.generic": "#87a4a44671",
|
||||
"c9.ide.language.html": "#fa4833e117",
|
||||
"c9.ide.language.html.diff": "#a7311cfc9f",
|
||||
"c9.ide.language.javascript": "#8479d0a9c1",
|
||||
"c9.ide.language.javascript.immediate": "#99ed8f4560",
|
||||
"c9.ide.language.javascript.immediate": "#9a2cce9121",
|
||||
"c9.ide.language.javascript.eslint": "#8832423ad1",
|
||||
"c9.ide.language.javascript.tern": "#7aab8b0b6a",
|
||||
"c9.ide.language.javascript.infer": "#ded7df5136",
|
||||
"c9.ide.language.javascript.infer": "#ebb2daf81a",
|
||||
"c9.ide.language.jsonalyzer": "#efa4426f1f",
|
||||
"c9.ide.collab": "#104ec85dd1",
|
||||
"c9.ide.local": "#cf624506cc",
|
||||
"c9.ide.local": "#2bfd7ff051",
|
||||
"c9.ide.find": "#ef82bc4f0d",
|
||||
"c9.ide.find.infiles": "#1b83cf12f1",
|
||||
"c9.ide.find.replace": "#e4daf722b8",
|
||||
|
@ -70,7 +70,7 @@
|
|||
"c9.ide.ace.emmet": "#e5f1a92ac3",
|
||||
"c9.ide.ace.gotoline": "#4d1a93172c",
|
||||
"c9.ide.ace.keymaps": "#6c4bb65b1f",
|
||||
"c9.ide.ace.repl": "#ada99852fa",
|
||||
"c9.ide.ace.repl": "#8d6534a11c",
|
||||
"c9.ide.ace.split": "#0ae0151c78",
|
||||
"c9.ide.ace.statusbar": "#d7b45bb7c3",
|
||||
"c9.ide.ace.stripws": "#34426a03d1",
|
||||
|
@ -84,14 +84,14 @@
|
|||
"c9.ide.imgeditor": "#08bbc53578",
|
||||
"c9.ide.immediate": "#6845a93705",
|
||||
"c9.ide.installer": "#38f5840924",
|
||||
"c9.ide.mount": "#cb45b621f1",
|
||||
"c9.ide.mount": "#32e79866ee",
|
||||
"c9.ide.navigate": "#64156c7f4a",
|
||||
"c9.ide.newresource": "#9a7464cc47",
|
||||
"c9.ide.openfiles": "#28a4f5af16",
|
||||
"c9.ide.preview": "#dba2f4214d",
|
||||
"c9.ide.preview.browser": "#ac18aaf31d",
|
||||
"c9.ide.preview.markdown": "#ab8d30ad9f",
|
||||
"c9.ide.pubsub": "#b83cf15ade",
|
||||
"c9.ide.pubsub": "#92ec19ed3a",
|
||||
"c9.ide.readonly": "#f6f07bbe42",
|
||||
"c9.ide.recentfiles": "#7c099abf40",
|
||||
"c9.ide.remote": "#cd45e81d2f",
|
||||
|
|
Ładowanie…
Reference in New Issue