New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

swagger-router

Package Overview
Dependencies
Maintainers
1
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

swagger-router - npm Package Compare versions

Comparing version 0.0.1 to 0.0.3

TODO.md

569

index.js
"use strict";
// For Map primarily
require("es6-shim");
if (!global.Promise || !global.Promise.promisify) {
global.Promise = require('bluebird');
}
/***
* :SECTION 1:
* Private module variables and methods
***/
function robustDecodeURIComponent(uri) {
if (!/%/.test(uri)) {
return uri;
} else {
return uri.replace(/(%[0-9a-fA-F][0-9a-fA-F])+/g, function(m) {
try {
return decodeURIComponent( m );
} catch ( e ) {
return m;
}
});
}
}
// / ( {pattern} or {+pattern} )|( {/pattern}
var splitRe = /(\/)(?:\{([\+])?([^:\}\/]+)(?::([^}]+))?\}|([^\/\{]*))|(?:{([\/\+]))([^:\}\/]+)(?::([^}]+))?\}/g;
function parsePattern (pattern) {
var res = [];
splitRe.lastIndex = 0;
var m;
do {
m = splitRe.exec(pattern);
if (m) {
if (m[1] === '/') {
if (m[5] !== undefined) {
// plain path segment
res.push(robustDecodeURIComponent(m[5]));
} else if (m[3]) {
// templated path segment
res.push({
name: m[3],
modifier: m[2],
pattern: m[4]
});
}
} else if (m[7]) {
// Optional path segment:
// - {/foo} or {/foo:bar}
// - {+foo}
res.push({
name: m[7],
modifier: m[6],
pattern: m[8]
});
} else {
throw new Error('The impossible happened!');
}
}
} while (m);
return res;
}
// Parse a path or pattern
function parsePath (path, isPattern) {
if (Array.isArray(path)) {
return path;
} else if (!isPattern) {
var bits = path.replace(/^\//, '').split(/\//);
if (!/%/.test(path)) {
// fast path
return bits;
} else {
return bits.map(function(bit) {
return robustDecodeURIComponent(bit);
});
}
} else {
return parsePattern(path);
}
}
/***
* :SECTION 2:
* Module class definitions
***/
/**
* Represents a URI object which can optionally contain and
* bind optional variables encountered in the URI string
*
* @param {String|URI} uri the URI path or object to create a new URI from
* @param {Object} params the values for variables encountered in the URI path (optional)
* @param {boolean} asPattern Whether to parse the URI as a pattern (optional)
* @return {URI} URI object. Public properties:
* - `params` {object} mutable. Parameter object.
* - `path` {array} immutable.
*/
function URI(uri, params, asPattern) {
this.params = params || {};
if (uri && uri.constructor === URI) {
// this.path is considered immutable, so can be shared with other URI
// instances
this.path = uri.path;
} else if (uri && (uri.constructor === String || Array.isArray(uri))) {
this.path = parsePath(uri, asPattern);
} else if (uri !== '') {
throw new Error('Invalid path passed into URI constructor: ' + uri);
}
}
/**
* Builds and returns the full, bounded string path for this URI object
*
* @return {String} the complete path of this URI object
* @param {string} format Either 'simplePattern' or 'fullPattern'. [optional]
* @return {string} URI path
*/
URI.prototype.toString = function (format) {
var uriStr = '';
for (var i = 0; i < this.path.length; i++) {
var segment = this.path[i];
if (segment && segment.constructor === Object) {
var segmentValue = this.params[segment.name];
if (segmentValue === undefined) {
segmentValue = segment.pattern;
}
if (segmentValue !== undefined) {
if (!format || format === 'simplePattern' || !segment.name) {
// Normal mode
uriStr += '/' + encodeURIComponent(segmentValue);
} else {
uriStr += '/{' + (segment.modifier || '')
+ encodeURIComponent(segment.name) + ':'
+ encodeURIComponent(segmentValue) + '}';
}
} else if (format && !segment.modifier) {
uriStr += '/{' + encodeURIComponent(segment.name) + '}';
} else if (format) {
uriStr += '{' + (segment.modifier || '')
+ encodeURIComponent(segment.name)
+ '}';
} else {
if (segment.modifier === '+') {
// Add trailing slash
uriStr += '/';
}
// Omit optional segment & return
return uriStr;
}
} else {
uriStr += '/' + encodeURIComponent(segment);
}
}
return uriStr;
};
/**
* Expand all parameters in the URI and return a new URI.
* @return {URI}
*/
URI.prototype.expand = function() {
var res = new Array(this.path.length);
for (var i = 0; i < this.path.length; i++) {
var segment = this.path[i];
if (segment && segment.constructor === Object) {
var segmentValue = this.params[segment.name];
if (segmentValue === undefined) {
segmentValue = segment.pattern;
if (segmentValue === undefined) {
if (segment.modifier) {
// Okay to end the URI here
// Pop over-allocated entries
while (res[res.length - 1] === undefined) {
res.pop();
}
return new URI(res);
} else {
throw new Error('URI.expand: parameter ' + segment.name + ' not defined!');
}
}
}
res[i] = segmentValue;
} else {
res[i] = segment;
}
}
return new URI(res);
};
/**
* Checks if the URI starts with the given path prefix
*
* @param {String|URI} pathOrURI the prefix path to check for
* @return {Boolean} whether this URI starts with the given prefix path
*/
URI.prototype.startsWith = function (pathOrURI) {
var uri;
if (!pathOrURI) {
return true;
}
if (pathOrURI.constructor === URI) {
uri = pathOrURI;
} else {
uri = new URI(pathOrURI);
}
// if our URI is shorter than the one we are
// comparing to, it doesn't start with that prefix
if (this.path.length < uri.path.length) {
return false;
}
// check each component
for (var idx = 0; idx < uri.path.length; idx++) {
var mySeg = this.path[idx];
var otherSeg = uri.path[idx];
if (mySeg.constructor === Object && otherSeg.constructor === Object) {
// both path are named variables
// nothing to do
continue;
} else if (mySeg.constructor === Object) {
// we have a named variable, but there is a string
// given in the prefix
if (mySeg.pattern && mySeg.pattern !== otherSeg) {
// they differ
return false;
}
} else if (otherSeg.constructor === Object) {
// we have a fixed string, but a variable has been
// given in the prefix - nothing to do
continue;
} else if (mySeg !== otherSeg) {
// both are strings, but they differ
return false;
}
}
// ok, no differences found
return true;
};
// For JSON.stringify
URI.prototype.toJSON = URI.prototype.toString;
// For util.inspect, console.log & co
URI.prototype.inspect = function () {
// Quote the string
return JSON.stringify(this.toString());
};
/*

@@ -12,51 +261,65 @@ * A node in the lookup graph.

*/
function Node () {
function Node (value) {
// The value for a path ending on this node. Public property.
this.value = null;
this.value = value || null;
// Internal properties.
this._map = {};
this._name = undefined;
this._wildcard = undefined;
this._children = {};
this._paramName = null;
this._parent = null;
}
Node.prototype.set = function(key, value) {
Node.prototype._keyPrefix = '/';
Node.prototype._keyPrefixRegExp = /^\//;
Node.prototype.setChild = function(key, child) {
var self = this;
if (key.constructor === String) {
this._map['k' + key] = value;
} else if (key.name && key.pattern && key.pattern.constructor === String) {
// A named but plain key. Check if the name matches & set it normally.
if (this._name && this._name !== key.name) {
throw new Error("Captured pattern parameter " + key.name
+ " does not match existing name " + this._name);
}
this._name = key.name;
this._map['k' + key.pattern] = value;
this._children[this._keyPrefix + key] = child;
} else if (key.name && key.pattern
&& key.modifier !== '+'
&& key.pattern.constructor === String) {
// A named but plain key.
child._paramName = key.name;
this._children[this._keyPrefix + key.pattern] = child;
} else if (key.modifier === '+') {
child._paramName = key.name;
this._children['**'] = child;
} else {
// Setting up a wildcard match
// Check if there are already other non-empty keys
var longKeys = Object.keys(this._map).filter(function(key) {
return key.length > 1;
});
if (longKeys.length) {
throw new Error("Can't register \"" + key + "\" in a wildcard path segment!");
} else {
this._name = key.name;
// Could handle a modifier or regexp here as well
this._wildcard = value;
}
child._paramName = key.name;
this._children['*'] = child;
}
};
Node.prototype.get = function(segment, params) {
Node.prototype.getChild = function(segment, params) {
if (segment.constructor === String) {
// Fast path
if (segment !== '') {
var res = this._map['k' + segment] || this._wildcard;
if (this._name && res) {
params[this._name] = segment;
var res = this._children[this._keyPrefix + segment];
if (!res) {
if (segment !== '') {
// Fall back to the wildcard match, but only if the segment is
// non-empty.
res = this._children['*'];
if (!res && this._children['**']) {
res = this._children['**'];
// Build up an array for ** matches ({+foo})
if (!Array.isArray(params[res._paramName])) {
params[res._paramName] = [segment];
} else {
params[res._paramName].push(segment);
}
// We are done.
return res;
}
}
}
if (res) {
if (res._paramName) {
params[res._paramName] = segment;
}
return res;
} else {
// Don't match the wildcard with an empty segment.
return this._map['k' + segment];
return null;
}

@@ -68,6 +331,7 @@

// Unwrap the pattern
return this.get(segment.pattern, params);
} else if (segment.name === this._name) {
return this.getChild(segment.pattern, params);
} else if (this._children['*']
&& this._children['*']._paramName === segment.name) {
// XXX: also compare modifier!
return this._wildcard;
return this._children['*'] || null;
}

@@ -77,3 +341,3 @@ };

Node.prototype.hasChildren = function () {
return Object.keys(this._map).length || this._wildcard;
return Object.keys(this._children).length || this._children['*'];
};

@@ -83,11 +347,11 @@

var self = this;
if (this._wildcard) {
if (this._children['*'] || this._children['**']) {
return [];
} else {
var res = [];
Object.keys(this._map).forEach(function(key) {
Object.keys(this._children).forEach(function(key) {
// Only list '' if there are children (for paths like
// /double//slash)
if (key !== 'k' || self._map[key].hasChildren()) {
res.push(key.replace(/^k/, ''));
if (key !== self._keyPrefix || self._children[key].hasChildren()) {
res.push(key.replace(self._keyPrefixRegExp, ''));
}

@@ -99,61 +363,101 @@ });

function Router () {
this._root = new Node();
// Map for sharing of sub-trees corresponding to the same specs, using
// object identity.
this._nodes = new Map();
}
//- interface:
// - `#addSpec(spec, [prefix])`
// - `#delSpec(spec, [prefix])`
// - `#route(path)`
// - path / prefix are arrays by default
// Shallow clone, allows sharing of subtrees in DAG
Node.prototype.clone = function () {
var c = new Node();
c._children = this._children;
return c;
};
function normalizePath (path) {
if (Array.isArray(path)) {
// Nothing to be done
return path;
} else if (path.split) {
return path.replace(/^\//, '').split(/\//);
} else {
throw new Error("Invalid path: " + path);
}
}
// Call promise-returning fn for each node value, with the path to the value
Node.prototype.visitAsync = function(fn, path) {
path = path || [];
var self = this;
// First value, then each of the children (one by one)
return fn(self.value, path)
.then(function() {
return Promise.resolve(Object.keys(self._children))
.each(function(childKey) {
var segment = childKey.replace(/^\//, '');
var child = self._children[childKey];
if (child === self) {
// Don't enter an infinite loop on **
return;
} else {
return child.visitAsync(fn, path.concat([segment]));
}
});
});
};
function parsePattern (pattern) {
var bits = normalizePath(pattern);
// Re-join {/var} patterns
for (var i = 0; i < bits.length - 1; i++) {
if (bits[i] === '{' && /}$/.test(bits[i+1])) {
bits.splice(i, 2, '{/' + bits[i+1]);
}
// Work around recursive structure in ** terminal nodes
function printableValue (value) {
var res = {};
if (!value || ! (value instanceof Object)) {
return value;
}
// Parse pattern segments and convert them to objects to be consumed by
// Node.set().
return bits.map(function(bit) {
// Support named but fixed values as
// {domain:en.wikipedia.org}
var m = /^{([+\/])?([a-zA-Z0-9_]+)(?::([^}]+))?}$/.exec(bit);
if (m) {
if (m[1]) {
throw new Error("Modifiers are not yet implemented!");
}
return {
modifier: m[1],
name: m[2],
pattern: m[3]
};
Object.keys(value).forEach(function(key) {
var val = value[key];
if (key === 'methods') {
var newMethods = {};
Object.keys(val).forEach(function(method) {
newMethods[method] = '<' + val[method].name + '>';
});
res.methods = newMethods;
} else {
return bit;
res[key] = val;
}
});
return res;
}
Router.prototype._buildTree = function(segments, value) {
Node.prototype.toJSON = function () {
if (this._children['**'] === this) {
return {
value: printableValue(this.value),
_children: '<recursive>',
_paramName: this._paramName
};
} else {
return {
value: printableValue(this.value),
_children: this._children,
_paramName: this._paramName
};
}
};
/*
* The main router object
*/
function Router (options) {
// Options:
// - specHandler(spec) -> spec'
// - pathHandler(pathSpec) -> pathSpec'
this._options = options || {};
this._root = new Node();
}
// XXX modules: variant that builds a prefix tree from a path array, but pass
// in a spec instead of a value
Router.prototype._buildTree = function(path, value) {
var node = new Node();
if (segments.length) {
var segment = segments[0];
var subTree = this._buildTree(segments.slice(1), value);
node.set(segment, subTree);
if (path.length) {
var segment = path[0];
if (segment.modifier === '+') {
// Set up a recursive match and end the traversal
var recursionNode = new Node();
recursionNode.value = value;
recursionNode.setChild(segment, recursionNode);
node.setChild(segment, recursionNode);
} else {
var subTree = this._buildTree(path.slice(1), value);
node.setChild(segment, subTree);
if (segment.modifier === '/') {
// Set the value for each optional path segment ({/foo})
node.value = value;
subTree.value = value;
}
}
} else {

@@ -165,31 +469,40 @@ node.value = value;

Router.prototype.addSpec = function addSpec(spec, prefix) {
var self = this;
if (!spec || !spec.paths) {
throw new Error("No spec or no paths defined in spec!");
}
// Get the prefix
prefix = parsePattern(prefix || []);
for (var path in spec.paths) {
// Skip over the empty first element
var segments = parsePattern(path);
self._extend(prefix.concat(segments), self._root, spec.paths[path]);
Router.prototype.specToTree = function (spec) {
var root = new Node();
for (var pathPattern in spec.paths) {
var path = parsePath(pathPattern, true);
this._extend(path, root, spec.paths[pathPattern]);
}
return root;
};
Router.prototype.setTree = function(tree) {
this._root = tree;
};
Router.prototype.delSpec = function delSpec(spec, prefix) {
// Possible implementation:
// - perform a *recursive* lookup for the leaf node
// -
// - Perform a *recursive* lookup for each leaf node.
// - Walk up the tree and remove nodes as long as `.hasChildren()` is
// false.
// This will work okay in a tree, but would clash with subtree sharing in
// a graph. We should perform some benchmarks to see if subtree sharing is
// worth it. Until then we probably don't need spec deletion anyway, as we
// can always re-build the entire router from scratch.
throw new Error("Not implemented");
};
// Extend an existing route tree with a new path by walking the existing tree
// and inserting new subtrees at the desired location.
Router.prototype._extend = function route(path, node, value) {
var params = {};
var origNode = node;
for (var i = 0; i < path.length; i++) {
var nextNode = node.get(path[i], params);
if (!nextNode || !nextNode.get) {
var nextNode = node.getChild(path[i], params);
if (!nextNode || !nextNode.getChild) {
// Found our extension point
node.set(path[i], this._buildTree(path.slice(i+1), value));
node.setChild(path[i], this._buildTree(path.slice(i+1), value));
//if (path[path.length - 1].modifier === '+') {
// console.log(JSON.stringify(node, null, 2));
//}
return;

@@ -200,5 +513,8 @@ } else {

}
node.value = value;
if (value !== undefined) {
node.value = value;
}
};
// Lookup worker.
Router.prototype._lookup = function route(path, node) {

@@ -208,9 +524,9 @@ var params = {};

for (var i = 0; i < path.length; i++) {
if (!node || !node.get) {
if (!node || !node.getChild) {
return null;
}
prevNode = node;
node = node.get(path[i], params);
node = node.getChild(path[i], params);
}
if (node && node.value) {
if (node || prevNode && path[path.length - 1] === '') {
if (path[path.length - 1] === '') {

@@ -222,3 +538,3 @@ // Pass in a listing

params: params,
value: node.value
value: (node && node.value || null)
};

@@ -244,6 +560,25 @@ } else {

Router.prototype.lookup = function route(path) {
path = normalizePath(path);
return this._lookup(path, this._root);
if (!path) {
throw new Error('Path expected!');
} else if (path.constructor === String) {
path = parsePath(path);
} else if (path.constructor === URI) {
path = path.path;
}
var res = this._lookup(path, this._root);
if (res) {
return {
params: res.params,
value: res.value
};
} else {
return res;
}
};
module.exports = Router;
module.exports = {
Router: Router,
URI: URI,
Node: Node
};
{
"name": "swagger-router",
"version": "0.0.1",
"version": "0.0.3",
"description": "An efficient swagger 2 based router with support for multiple APIs. For use in RESTBase.",
"main": "index.js",
"scripts": {
"test": "mocha"
"test": "mocha",
"coverage": "istanbul cover _mocha -- -R spec",
"coveralls": "cat ./coverage/lcov.info | coveralls"
},

@@ -25,8 +27,13 @@ "repository": {

"dependencies": {
"es6-shim": "^0.22.1"
"bluebird": "^2.7.1",
"es6-shim": "^0.22.1",
"js-yaml": "~3.2.2"
},
"devDependencies": {
"mocha": "x.x.x",
"mocha-jshint": "0.0.9"
"mocha-jshint": "0.0.9",
"istanbul": "0.3.5",
"mocha-lcov-reporter": "0.0.1",
"coveralls": "2.11.2"
}
}
# Swagger 2 router
[![Build
Status](https://travis-ci.org/gwicke/swagger-router.svg?branch=master)](https://travis-ci.org/gwicke/swagger-router)

@@ -3,0 +5,0 @@ ## Features

@@ -9,3 +9,5 @@ 'use strict';

var deepEqual = require('assert').deepEqual;
var Router = require('../index');
var swaggerRouter = require('../index');
var Router = swaggerRouter.Router;
var URI = swaggerRouter.URI;

@@ -32,3 +34,8 @@ function listingHandler (list) { return list; }

'/double//': '/double//',
'/double//slash': '/double//slash'
'/double//slash': '/double//slash',
'/some/really/long/path': '/some/really/long/path',
// Modifiers: optional path segments
'/simple/{templated}{/path}': '/simple/{templated}{/path}',
'/several{/optional}{/path}{+segments}': '/several{/optional}{/path}{+segments}',
'/optional/{+path}': '/optional/{+path}'
}

@@ -120,3 +127,103 @@ }

},
'/en.wikipedia.org/v1/some/really/long/path': {
value: '/some/really/long/path',
params: {
domain: 'en.wikipedia.org'
}
},
// Optional path segments
'/en.wikipedia.org/v1/several': {
value: '/several{/optional}{/path}{+segments}',
params: {
domain: 'en.wikipedia.org'
}
},
'/en.wikipedia.org/v1/several/optional': {
value: '/several{/optional}{/path}{+segments}',
params: {
domain: 'en.wikipedia.org',
optional: 'optional'
}
},
'/en.wikipedia.org/v1/several/optional/path': {
value: '/several{/optional}{/path}{+segments}',
params: {
domain: 'en.wikipedia.org',
optional: 'optional',
path: 'path'
}
},
'/en.wikipedia.org/v1/several/optional/path/segments': {
value: '/several{/optional}{/path}{+segments}',
params: {
domain: 'en.wikipedia.org',
optional: 'optional',
path: 'path',
segments: ['segments'],
}
},
'/en.wikipedia.org/v1/several/optional/path/segments/a': {
value: '/several{/optional}{/path}{+segments}',
params: {
domain: 'en.wikipedia.org',
optional: 'optional',
path: 'path',
segments: ['segments','a'],
}
},
'/en.wikipedia.org/v1/several/optional/path/segments/a/b': {
value: '/several{/optional}{/path}{+segments}',
params: {
domain: 'en.wikipedia.org',
optional: 'optional',
path: 'path',
segments: ['segments','a','b'],
}
},
'/en.wikipedia.org/v1/simple/templated': {
value: '/simple/{templated}{/path}',
params: {
domain: 'en.wikipedia.org',
templated: 'templated'
}
},
'/en.wikipedia.org/v1/simple/templated/path': {
value: '/simple/{templated}{/path}',
params: {
domain: 'en.wikipedia.org',
templated: 'templated',
path: 'path'
}
},
'/en.wikipedia.org/v1/simple/templated/path/toolong': null,
'/en.wikipedia.org/v1/optional': {
params: {
domain: 'en.wikipedia.org'
},
value: null
},
'/en.wikipedia.org/v1/optional/': {
params: {
domain: 'en.wikipedia.org',
_ls: []
},
value: null
},
'/en.wikipedia.org/v1/optional/path': {
value: '/optional/{+path}',
params: {
domain: 'en.wikipedia.org',
path: ['path']
}
},
'/en.wikipedia.org/v1/optional/path/bits': {
value: '/optional/{+path}',
params: {
domain: 'en.wikipedia.org',
path: ['path','bits']
}
},
// A few paths that should not match

@@ -129,12 +236,42 @@ '/en.wikipedia.org/v1/pages': null,

var domains = ['en.wikipedia.org','de.wikipedia.org'];
function makeFullSpec () {
var domains = ['en.wikipedia.org', 'de.wikipedia.org', 'fr.wikipedia.org', 'es.wikipedia.org'];
function addPrefixedPaths(newPaths, prefix, paths) {
var newSpec = {};
for (var path in paths) {
newPaths[prefix + path] = paths[path];
}
}
var fullPaths = {};
specs.forEach(function(spec) {
domains.forEach(function(domain) {
addPrefixedPaths(fullPaths, '/{domain:' + domain + '}/v1', spec.paths);
});
});
return {
paths: fullPaths
};
}
var router = new Router();
specs.forEach(function(spec) {
domains.forEach(function(domain) {
router.addSpec(spec, '/{domain:' + domain + '}/v1');
var fullSpec = makeFullSpec();
var tree = router.specToTree(fullSpec);
router.setTree(tree);
describe('Set of lookups', function() {
Object.keys(expectations).forEach(function(key) {
var val = expectations[key];
it('match: ' + JSON.stringify(key), function() {
deepEqual(router.lookup(key), val);
});
});
});
describe('swagger-router', function() {
router.setTree(tree.clone());
describe('Repeat on cloned tree', function() {

@@ -149,1 +286,81 @@ Object.keys(expectations).forEach(function(key) {

describe('URI', function() {
it('to URI and back', function() {
var uri = new URI('/{domain:some}/path/to/something', {}, true);
uri = new URI(uri, {domain: 'foo/bar'});
deepEqual(uri.toString(), '/foo%2Fbar/path/to/something');
deepEqual(uri.expand().path, ['foo/bar','path','to','something']);
});
it('to URI and back, no pattern', function() {
var uri = new URI('/{domain:some}/path/to/something', {domain: 'foo'});
deepEqual(uri.toString(), '/%7Bdomain%3Asome%7D/path/to/something');
deepEqual(uri.expand().path, ['{domain:some}','path','to','something']);
});
it('{/patterns} empty', function() {
var uri = new URI('/{domain:some}/path/to{/optionalPath}', {}, true);
uri = new URI(uri, {domain: 'foo'});
deepEqual(uri.toString(), '/foo/path/to');
});
it('{/patterns} bound', function() {
var uri = new URI('/{domain:some}/path/to{/optionalPath}', {}, true);
uri.params = {optionalPath: 'foo'};
deepEqual(uri.toString(), '/some/path/to/foo');
});
it('{+patterns} empty', function() {
var uri = new URI('/{domain:some}/path/to/{+rest}', {}, true);
deepEqual(uri.toString(), '/some/path/to/');
});
it('{+patterns} bound', function() {
var uri = new URI('/{domain:some}/path/to/{+rest}',
{rest: 'foo'}, true);
deepEqual(uri.toString(), '/some/path/to/foo');
});
it('decoding / encoding', function() {
var uri = new URI('/{domain:some}/a%2Fb/to/100%/%FF', {domain: 'foo/bar'}, true);
// Note how the invalid % encoding is fixed up to %25
deepEqual(uri.toString(), '/foo%2Fbar/a%2Fb/to/100%25/%25FF');
});
it('construct from array', function() {
var uri = new URI([{
name: 'domain',
pattern: 'some'
},'a/b', 'to', '100%'], {domain: 'foo/bar'}, true);
// Note how the invalid % encoding is fixed up to %25
deepEqual(uri.toString(), '/foo%2Fbar/a%2Fb/to/100%25');
// Try once more for caching
deepEqual(uri.toString(), '/foo%2Fbar/a%2Fb/to/100%25');
});
it('append a suffix path', function() {
var baseURI = new URI('/{domain:test.com}/v1', {}, true);
var suffix = new URI('/page/{title}', {}, true);
var uri = new URI(baseURI.path.concat(suffix.path), {title: 'foo'});
deepEqual(uri.toString(), '/test.com/v1/page/foo', {}, true);
deepEqual(uri.expand().path, ['test.com', 'v1', 'page', 'foo']);
});
it('remove a suffix path', function() {
var basePath = new URI('/{domain:test.com}/v1/page/{title}', {}, true).path;
var uri = new URI(basePath.slice(0, basePath.length - 2));
deepEqual(uri.toString(), '/test.com/v1');
});
it('should serialize with "simplePattern" and "fullPattern" formats', function() {
var uri = new URI('/{domain:test.com}/v1/{title}{/foo}{+bar}', {}, true);
deepEqual(uri.toString(), '/test.com/v1');
deepEqual(uri.toString('simplePattern'), '/test.com/v1/{title}{/foo}{+bar}');
deepEqual(uri.toString('fullPattern'), '/{domain:test.com}/v1/{title}{/foo}{+bar}');
});
it('check for a prefix path', function() {
var uri = new URI('/{domain:test.com}/v1/page/{title}', {}, true);
deepEqual(uri.startsWith('/test.com/v1/page'), true);
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc