Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

baobab-router

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

baobab-router - npm Package Compare versions

Comparing version 2.0.0 to 2.1.0

188

baobab-router.dist.js

@@ -7,3 +7,3 @@ 'use strict';

function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; }
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };

@@ -43,5 +43,5 @@ /**

* This function takes a well formed URL from any BaobabRouter instance's route,
* with potentially dynamic attributes to resolve, and an object with the
* related values, and returns the URL with the values inserted instead of the
* dynamics.
* with potentially dynamic and query attributes to resolve, and an object with
* the related values, and returns the URL with the query, and with the values
* inserted instead of the dynamics.
*

@@ -62,12 +62,24 @@ * Examples:

*
* > __resolveURL('a/:b/:c', { ':c': 'C', ':d': 'D' }, { e: 'E', f: 'F' });
* > // 'a/:b/C?e=E&f=F'
*
* @param {string} url The URL to resolve.
* @param {?object} obj An optional object with the dynamic values to insert.
* @param {?object} dyn An optional object with the dynamic values to insert.
* @param {?object} qry An optional object with the query values to insert.
* @return {string} The resolved URL.
*/
function __resolveURL(url) {
var obj = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
var dyn = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
var qry = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
return url.split('/').map(function (s) {
return s in obj ? obj[s] : s;
var hash = url.split('/').map(function (s) {
return s in dyn ? escape(dyn[s]) : s;
}).join('/');
var query = Object.keys(qry).filter(function (k) {
return qry[k] !== null && qry[k] !== undefined;
}).map(function (k) {
return escape(k) + '=' + escape(qry[k]);
}).join('&');
return query ? hash + '?' + query : hash;
}

@@ -198,3 +210,3 @@

var routeArray = routeHash.split('/');
var hashArray = hash.split('/');
var hashArray = hash.replace(/\?.*$/, '').split('/');

@@ -226,16 +238,17 @@ // Check lengths:

*
* @param {object} routeState The route's state constraints.
* @param {object} hash The current state.
* @param {array} dynamicValues The array of the dynamic values.
* @return {?object} Returns an object with the dynamic values if
* the state does match the constraints, and
* null else.
* The difference between the query and the dynamic values is that null dynamic
* values are not allowed, while null query parameters are valid.
*
* @param {object} routeState The route's state constraints.
* @param {object} hash The current state.
* @param {array} dynamics The array of the dynamic values.
* @param {array} query The array of the query values.
* @return {?object} Returns an object with the dynamic values if the
* state does match the constraints, and null else.
*/
function __doesStateMatch(routeState, state) {
var dynamicValues = arguments.length <= 2 || arguments[2] === undefined ? [] : arguments[2];
function __doesStateMatch(routeState, state, dynamics, query) {
var results = {};
function searchRoutes(val, i) {
var localResults = __doesStateMatch(val, state[i], dynamicValues);
var localResults = __doesStateMatch(val, state[i], dynamics, query);
if (localResults) {

@@ -267,3 +280,3 @@ results = __deepMerge(results, localResults);

if (routeState.hasOwnProperty(k)) {
var localResults = __doesStateMatch(routeState[k], state[k], dynamicValues);
var localResults = __doesStateMatch(routeState[k], state[k], dynamics, query);
if (localResults) {

@@ -280,15 +293,20 @@ results = __deepMerge(results, localResults).value;

// Dynamics:
} else if (~dynamicValues.indexOf(routeState) && state) {
} else if (~(dynamics || []).indexOf(routeState) && state) {
results[routeState] = state;
return results;
// Null / undefined cases:
} else if ((routeState === undefined || routeState === null) && (state === undefined || state === null)) {
// Query:
} else if (~(query || []).indexOf(routeState) && ! ~(dynamics || []).indexOf(routeState)) {
results[routeState] = state;
return results;
// Other scalars:
} else if (routeState === state) {
// Null / undefined cases:
} else if ((routeState === undefined || routeState === null) && (state === undefined || state === null)) {
return results;
}
// Other scalars:
} else if (routeState === state) {
return results;
}
return null;

@@ -362,2 +380,3 @@ }

route.fullPath = __concatenatePaths(basePath, route.path);

@@ -367,4 +386,18 @@ route.fullTree = value;

route.dynamics = route.fullPath.match(solver) || [];
route.updates = __extractPaths(route.fullTree, route.dynamics);
route.queryValues = [];
for (var k in route.query || {}) {
if (route.query.hasOwnProperty(k)) {
if (typeof route.query[k] === 'string') {
route.query[k] = {
match: route.query[k]
};
}
route.queryValues.push(route.query[k].match);
}
}
route.updates = __extractPaths(route.fullTree, route.dynamics.concat(route.queryValues));
if (route.defaultRoute) {

@@ -492,33 +525,59 @@ route.fullDefaultPath = __concatenatePaths(route.fullPath, route.defaultRoute);

if (match && !route.defaultRoute) {
// Apply updates:
route.updates.map(function (obj) {
var update = {
path: obj.path,
value: obj.value
};
var _ret = function () {
var queryValues = hash.replace(/^[^\?]*\??/, '').split('&').reduce(function (res, str) {
var arr = str.split('=');
var query = (route.query || {})[arr[0]] || {};
var value = undefined;
if (obj.dynamic) {
update.value = hash.split('/')[route.fullPath.split('/').indexOf(update.value)];
}
switch (query.cast) {
case 'number':
value = +arr[1];
break;
case 'boolean':
value = arr[1] === 'true' ? true : false;
break;
default:
value = arr[1];
}
if (_routesTree.readOnly.every(function (str) {
return !__compareArrays(update.path, str);
}) && update.path.length > 1) {
if (_tree.get(update.path.slice(1)) !== update.value) {
_tree.set(update.path.slice(1), update.value);
doCommit = true;
} else {
doForceCommit = true;
res[query.match] = value;
return res;
}, {});
// Apply updates:
route.updates.map(function (obj) {
var update = {
path: obj.path,
value: obj.value
};
if (obj.dynamic) {
update.value = hash.split('/')[route.fullPath.split('/').indexOf(update.value)] || queryValues[update.value];
}
if (_routesTree.readOnly.every(function (str) {
return !__compareArrays(update.path, str);
}) && update.path.length > 1) {
if (_tree.get(update.path.slice(1)) !== update.value) {
_tree.set(update.path.slice(1), update.value);
doCommit = true;
} else {
doForceCommit = true;
}
}
});
// Commit only if something has actually been updated:
if (doCommit) {
_tree.commit();
} else if (doForceCommit) {
_checkState(); //eslint-disable-line
}
});
// Commit only if something has actually been updated:
if (doCommit) {
_tree.commit();
} else if (doForceCommit) {
_checkState(); //eslint-disable-line
}
return {
v: true
};
}();
return true;
if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
}

@@ -558,3 +617,3 @@ }

// Check if route match:
var match = baseTree ? __doesStateMatch(tree, route.fullTree, route.dynamics) : __doesStateMatch(route.fullTree, tree, route.dynamics);
var match = baseTree ? __doesStateMatch(tree, route.fullTree, route.dynamics, route.queryValues) : __doesStateMatch(route.fullTree, tree, route.dynamics, route.queryValues);

@@ -575,3 +634,3 @@ if (!match && arguments.length > 0 && !route.overrides) {

if (!arguments.length) {
var _ret = (function () {
var _ret2 = function () {
_stored = null;

@@ -603,8 +662,17 @@

}
})();
}();
if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
if ((typeof _ret2 === 'undefined' ? 'undefined' : _typeof(_ret2)) === "object") return _ret2.v;
}
if (match) {
_updateHash(__resolveURL(route.defaultRoute ? route.fullDefaultPath : route.fullPath, match),
var query = {};
for (var k in route.query) {
if (route.query.hasOwnProperty(k)) {
query[k] = match[route.query[k].match];
}
}
_updateHash(__resolveURL(route.defaultRoute ? route.fullDefaultPath : route.fullPath, match, query),
// If updating to a default route, then it might come from an invalid

@@ -649,3 +717,3 @@ // state. And if the same route is already set, then forcing the hash

if ('onhashchange' in window) {
_hashListener = function () {
_hashListener = function _hashListener() {
var hash = window.location.hash.replace(/^#/, '');

@@ -671,3 +739,3 @@ if (hash !== _stored) {

// Listen to the state changes:
_watcherListener = function () {
_watcherListener = function _watcherListener() {
return _checkState();

@@ -703,3 +771,3 @@ };

// Baobab-Router version:
BaobabRouter.version = '2.0.0';
BaobabRouter.version = '2.1.0';

@@ -706,0 +774,0 @@ // Expose private methods for unit testing:

@@ -38,5 +38,5 @@ /**

* This function takes a well formed URL from any BaobabRouter instance's route,
* with potentially dynamic attributes to resolve, and an object with the
* related values, and returns the URL with the values inserted instead of the
* dynamics.
* with potentially dynamic and query attributes to resolve, and an object with
* the related values, and returns the URL with the query, and with the values
* inserted instead of the dynamics.
*

@@ -57,12 +57,24 @@ * Examples:

*
* > __resolveURL('a/:b/:c', { ':c': 'C', ':d': 'D' }, { e: 'E', f: 'F' });
* > // 'a/:b/C?e=E&f=F'
*
* @param {string} url The URL to resolve.
* @param {?object} obj An optional object with the dynamic values to insert.
* @param {?object} dyn An optional object with the dynamic values to insert.
* @param {?object} qry An optional object with the query values to insert.
* @return {string} The resolved URL.
*/
function __resolveURL(url, obj = {}) {
function __resolveURL(url, dyn = {}, qry = {}) {
const hash = url
.split('/')
.map(s => (s in dyn) ? escape(dyn[s]) : s)
.join('/');
const query = Object.keys(qry)
.filter(k => qry[k] !== null && qry[k] !== undefined)
.map(k => escape(k) + '=' + escape(qry[k]))
.join('&');
return (
url
.split('/')
.map(s => (s in obj) ? obj[s] : s)
.join('/')
query ?
hash + '?' + query :
hash
);

@@ -192,3 +204,3 @@ }

const routeArray = routeHash.split('/');
const hashArray = hash.split('/');
const hashArray = hash.replace(/\?.*$/, '').split('/');

@@ -223,14 +235,17 @@ // Check lengths:

*
* @param {object} routeState The route's state constraints.
* @param {object} hash The current state.
* @param {array} dynamicValues The array of the dynamic values.
* @return {?object} Returns an object with the dynamic values if
* the state does match the constraints, and
* null else.
* The difference between the query and the dynamic values is that null dynamic
* values are not allowed, while null query parameters are valid.
*
* @param {object} routeState The route's state constraints.
* @param {object} hash The current state.
* @param {array} dynamics The array of the dynamic values.
* @param {array} query The array of the query values.
* @return {?object} Returns an object with the dynamic values if the
* state does match the constraints, and null else.
*/
function __doesStateMatch(routeState, state, dynamicValues = []) {
function __doesStateMatch(routeState, state, dynamics, query) {
let results = {};
function searchRoutes(val, i) {
const localResults = __doesStateMatch(val, state[i], dynamicValues);
const localResults = __doesStateMatch(val, state[i], dynamics, query);
if (localResults) {

@@ -265,3 +280,4 @@ results = __deepMerge(results, localResults);

state[k],
dynamicValues
dynamics,
query
);

@@ -279,6 +295,14 @@ if (localResults) {

// Dynamics:
} else if (~dynamicValues.indexOf(routeState) && state) {
} else if (~(dynamics || []).indexOf(routeState) && state) {
results[routeState] = state;
return results;
// Query:
} else if (
~(query || []).indexOf(routeState) &&
!~(dynamics || []).indexOf(routeState)
) {
results[routeState] = state;
return results;
// Null / undefined cases:

@@ -371,4 +395,21 @@ } else if (

route.dynamics = route.fullPath.match(solver) || [];
route.updates = __extractPaths(route.fullTree, route.dynamics);
route.queryValues = [];
for (const k in route.query || {}) {
if (route.query.hasOwnProperty(k)) {
if (typeof route.query[k] === 'string') {
route.query[k] = {
match: route.query[k],
};
}
route.queryValues.push(route.query[k].match);
}
}
route.updates = __extractPaths(
route.fullTree,
route.dynamics.concat(route.queryValues)
);
if (route.defaultRoute) {

@@ -518,2 +559,25 @@ route.fullDefaultPath =

if (match && !route.defaultRoute) {
const queryValues = hash
.replace(/^[^\?]*\??/, '')
.split('&')
.reduce((res, str) => {
const arr = str.split('=');
const query = (route.query || {})[arr[0]] || {};
let value;
switch (query.cast) {
case 'number':
value = +arr[1];
break;
case 'boolean':
value = arr[1] === 'true' ? true : false;
break;
default:
value = arr[1];
}
res[query.match] = value;
return res;
}, {});
// Apply updates:

@@ -529,3 +593,3 @@ route.updates.map(obj => {

route.fullPath.split('/').indexOf(update.value)
];
] || queryValues[update.value];
}

@@ -589,4 +653,4 @@

const match = baseTree ?
__doesStateMatch(tree, route.fullTree, route.dynamics) :
__doesStateMatch(route.fullTree, tree, route.dynamics);
__doesStateMatch(tree, route.fullTree, route.dynamics, route.queryValues) :
__doesStateMatch(route.fullTree, tree, route.dynamics, route.queryValues);

@@ -639,3 +703,12 @@ if (!match && arguments.length > 0 && !route.overrides) {

}
if (match) {
const query = {};
for (const k in route.query) {
if (route.query.hasOwnProperty(k)) {
query[k] = match[route.query[k].match];
}
}
_updateHash(

@@ -646,3 +719,4 @@ __resolveURL(

route.fullPath,
match
match,
query
),

@@ -754,3 +828,3 @@ // If updating to a default route, then it might come from an invalid

// Baobab-Router version:
BaobabRouter.version = '2.0.0';
BaobabRouter.version = '2.1.0';

@@ -757,0 +831,0 @@ // Expose private methods for unit testing:

{
"name": "baobab-router",
"version": "2.0.0",
"version": "2.1.0",
"description": "A router for Baobab",

@@ -5,0 +5,0 @@ "main": "baobab-router.dist.js",

@@ -23,43 +23,53 @@ # Baobab-router

```javascript
var Baobab = require('baobab'),
Router = require('baobab-router');
import Baobab from 'baobab';
import Router from 'baobab-router';
// Instanciate Baobab tree:
var tree = new Baobab({
view: null,
projectId: null,
projectData: null
}),
const tree = new Baobab({
view: null,
projectId: null,
projectData: null,
});
// Instanciate router:
router = new Router(tree, {
defaultRoute: '/home',
// Instanciate router:
const router = new Router(tree, {
defaultRoute: '/home',
routes: [
{
path: '/home',
state: {
view: 'home',
projectId: null,
},
},
{
path: '/settings',
state: {
view: 'settings',
projectId: null,
},
},
{
path: '/project/:pid',
defaultRoute: '/dashboard',
state: {
projectId: ':pid',
},
routes: [
{ path: '/home',
{
path: '/settings',
state: {
view: 'home',
projectId: null
} },
{ path: '/settings',
view: 'project.settings',
},
},
{
path: '/dashboard',
state: {
view: 'settings',
projectId: null
} },
{ path: '/project/:pid',
defaultRoute: '/dashboard',
state: {
projectId: ':pid'
} },
routes: [
{ path: '/settings',
state: {
view: 'project.settings'
} },
{ path: '/dashboard',
state: {
view: 'project.dashboard'
} }
] }
]
});
view: 'project.dashboard',
},
},
],
},
],
});
```

@@ -78,26 +88,24 @@

```javascript
function() {
tree.set('view', 'settings')
.set('projectId', null)
.commit();
() => {
tree.set('view', 'settings');
tree.set('projectId', null);
tree.commit();
setTimeout(function() {
console.log(window.location.hash === '#/settings');
}, 0);
setTimeout(() => console.log(window.location.hash === '#/settings'), 0);
}
function() {
tree.set('view', 'project.settings')
.set('projectId', '123456')
.commit();
() => {
tree.set('view', 'project.settings');
tree.set('projectId', '123456');
tree.commit();
setTimeout(function() {
console.log(window.location.hash === '#/project/123456/settings');
}, 0);
setTimeout(() => (
console.log(window.location.hash === '#/project/123456/settings')
), 0);
}
function() {
() => {
window.location.hash = '/settings';
setTimeout(function() {
setTimeout(() => {
console.log(tree.get('view') === 'settings');

@@ -108,6 +116,6 @@ console.log(tree.get('projectId') === null);

function() {
() => {
window.location.hash = '/project/123456/dashboard';
setTimeout(function() {
setTimeout(() => {
console.log(tree.get('view') === 'project.dashboard');

@@ -122,8 +130,8 @@ console.log(tree.get('projectId') === '123456');

```javascript
function() {
tree.set('view', 'something irrelevant')
.set('projectId', null)
.commit();
() => {
tree.set('view', 'something irrelevant');
tree.set('projectId', null);
tree.commit();
setTimeout(function() {
setTimeout(() => {
console.log(window.location.hash === '#/home');

@@ -135,8 +143,8 @@ console.log(tree.get('view') === 'home');

function() {
tree.set('view', 'something irrelevant')
.set('projectId', 123456)
.commit();
() => {
tree.set('view', 'something irrelevant');
tree.set('projectId', 123456);
tree.commit();
setTimeout(function() {
setTimeout(() => {
console.log(window.location.hash === '#/project/123456/dashboard');

@@ -148,6 +156,6 @@ console.log(tree.get('view') === 'project.dashboard');

function() {
() => {
window.location.hash = '/something/irrelevant';
setTimeout(function() {
setTimeout(() => {
console.log(window.location.hash === '#/home');

@@ -159,6 +167,6 @@ console.log(tree.get('view') === 'home');

function() {
() => {
window.location.hash = '/project/123456/irrelevant';
setTimeout(function() {
setTimeout(() => {
console.log(window.location.hash === '#/project/123456/dashboard');

@@ -176,57 +184,69 @@ console.log(tree.get('view') === 'project.dashboard');

```javascript
var Baobab = require('baobab'),
Router = require('baobab-router');
import Baobab from 'baobab';
import Router from 'baobab-router';
// Instanciate Baobab tree:
var tree = new Baobab({
logged: false,
view: null,
projectId: null,
projectData: null
}),
const tree = new Baobab({
logged: false,
view: null,
projectId: null,
projectData: null,
});
// Instanciate router:
router = new Router(tree, {
defaultRoute: '/home',
// The readOnly property is an array of paths:
readOnly: [
['logged']
],
// Instanciate router:
const router = new Router(tree, {
defaultRoute: '/home',
// The readOnly property is an array of paths:
readOnly: [
['logged'],
],
routes: [
{
path: '/login',
state: {
logged: false,
view: 'logged',
projectId: null,
},
},
{
path: '/home',
state: {
logged: true,
view: 'home',
projectId: null,
},
},
{
path: '/settings',
state: {
logged: true,
view: 'settings',
projectId: null,
},
},
{
path: '/project/:pid',
defaultRoute: '/dashboard',
state: {
logged: true,
projectId: ':pid',
},
routes: [
{ path: '/login',
{
path: '/settings',
state: {
logged: false,
view: 'logged',
projectId: null
} },
{ path: '/home',
view: 'project.settings',
},
},
{
path: '/dashboard',
state: {
logged: true,
view: 'home',
projectId: null
} },
{ path: '/settings',
state: {
logged: true,
view: 'settings',
projectId: null
} },
{ path: '/project/:pid',
defaultRoute: '/dashboard',
state: {
logged: true,
projectId: ':pid'
} },
routes: [
{ path: '/settings',
state: {
view: 'project.settings'
} },
{ path: '/dashboard',
state: {
view: 'project.dashboard'
} }
] }
]
});
view: 'project.dashboard',
},
},
],
},
],
});
```

@@ -249,9 +269,9 @@

```javascript
function() {
tree.set('logged', false)
.set('view', 'project.settings')
.set('projectId', '123456')
.commit();
() => {
tree.set('logged', false);
tree.set('view', 'project.settings');
tree.set('projectId', '123456');
tree.commit();
setTimeout(function() {
setTimeout(() => {
console.log(window.location.hash === '#/login');

@@ -263,9 +283,9 @@ console.log(tree.get('view') === 'login');

function() {
tree.set('logged', true)
.set('view', 'project.settings')
.set('projectId', '123456')
.commit();
() => {
tree.set('logged', true);
tree.set('view', 'project.settings');
tree.set('projectId', '123456');
tree.commit();
setTimeout(function() {
setTimeout(() => {
console.log(window.location.hash === '#/project/123456/settings');

@@ -277,9 +297,10 @@ console.log(tree.get('view') === 'project.settings');

function() {
tree.set('logged', false).commit();
() => {
tree.set('logged', false);
tree.commit();
setTimeout(function() {
setTimeout(() => {
window.location.hash = '/project/123456/settings';
setTimeout(function() {
setTimeout(() => {
console.log(window.location.hash === '#/login');

@@ -292,9 +313,10 @@ console.log(tree.get('view') === 'login');

function() {
tree.set('logged', true).commit();
() => {
tree.set('logged', true);
tree.commit();
setTimeout(function() {
setTimeout(() => {
window.location.hash = '/project/123456/settings';
setTimeout(function() {
setTimeout(() => {
console.log(window.location.hash === '#/project/123456/settings');

@@ -317,5 +339,7 @@ console.log(tree.get('view') === 'project.settings');

```javascript
{ routes: 'Array<Route>',
{
routes: 'Array<Route>',
defaultRoute: 'string',
readOnly: '?Array' }
readOnly: '?Array<BaobabPath>'
}
```

@@ -326,6 +350,8 @@

```javascript
{ path: '?string',
{
path: '?string',
state: 'object',
defaultRoute: '?string',
routes: '?Array<Route>' }
routes: '?Array<Route>'
}
```

@@ -362,2 +388,3 @@

- The same issue might happen if multiple read-only paths are used, and all the different values combinations are not represented in the routes.
- **Baobab v2+'s monkeys have to be declared as `readOnly` if used by the router**

@@ -364,0 +391,0 @@ ### Default routes

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