Socket
Socket
Sign inDemoInstall

catberry

Package Overview
Dependencies
356
Maintainers
1
Versions
41
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 8.2.0 to 8.3.0

browser/providers/StateProvider.js

4

browser/Bootstrapper.js

@@ -21,2 +21,3 @@ /**

const routeDefinitions = '__routeDefinitions' || [];
const routeDescriptors = '__routes' || [];

@@ -55,2 +56,5 @@ const Catberry = require('./node_modules/catberry/browser/Catberry.js');

routeDescriptors.forEach(routeDescriptor =>
locator.registerInstance('routeDescriptor', routeDescriptor));
stores.forEach(store => locator.registerInstance('store', store));

@@ -57,0 +61,0 @@

2

lib/base/CatberryBase.js

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

*/
this.version = '8.2.0';
this.version = '8.3.0';

@@ -27,0 +27,0 @@ /**

@@ -81,2 +81,13 @@ 'use strict';

}
/**
* Gets URI for the named route and specified parameters.
* @param {string} name Name of the route.
* @param {Object} values Set of route parameter values.
* @returns {string} URI string.
*/
getRouteURI(name, values) {
const stateProvider = this.locator.resolve('stateProvider');
return stateProvider.getRouteURI(name, values);
}
}

@@ -83,0 +94,0 @@

@@ -8,2 +8,3 @@ 'use strict';

const requireHelper = require('../helpers/requireHelper');
const RouteParser = require('../tokenizers/RouteParser');

@@ -14,2 +15,3 @@ const BOOTSTRAPPER_FILENAME = 'Bootstrapper.js';

const COMPONENTS_REPLACE = '/** __components **/';
const ROUTE_DESCRIPTORS_REPLACE = '\'__routes\'';
const ROUTE_DEFINITIONS_REPLACE = '\'__routeDefinitions\'';

@@ -42,2 +44,9 @@ const ROUTE_DEFINITIONS_FILENAME = 'routes.js';

this._templateProvider = locator.resolve('templateProvider');
/**
* Current route parser.
* @type {RouteParser}
* @private
*/
this._routeParser = new RouteParser();
}

@@ -85,7 +94,24 @@

const requireString = isExists ? `require('./${filePath}')` : 'null';
const routeDescriptors = [];
if (isExists) {
const routeDefinitions = require(routeDefinitionsPath);
/* eslint max-nested-callbacks: 0 */
routeDefinitions.forEach(definition => {
if (typeof (definition) === 'string') {
routeDescriptors.push(this._routeParser.parseRouteExpression(definition));
}
if (typeof (definition) === 'object' &&
typeof (definition.expression) === 'string') {
routeDescriptors.push(this._routeParser.parseRouteExpression(definition.expression));
}
});
}
return context.file
.replace(COMPONENTS_REPLACE, context.components)
.replace(STORES_REPLACE, context.stores)
.replace(ROUTE_DEFINITIONS_REPLACE, requireString);
.replace(ROUTE_DEFINITIONS_REPLACE, requireString)
.replace(ROUTE_DESCRIPTORS_REPLACE, JSON.stringify(routeDescriptors));
})

@@ -92,0 +118,0 @@ )

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

${userAgent || 'Unknown browser'};<br/>
Catberry@8.2.0 (
Catberry@8.3.0 (
<a href="https://github.com/catberry/catberry/issues" target="_blank">

@@ -24,0 +24,0 @@ report an issue

'use strict';
const routeHelper = require('./../helpers/routeHelper');
const catberryUri = require('catberry-uri');
const URI = catberryUri.URI;
const StateProviderBase = require('../base/StateProviderBase');
const RouteParser = require('../tokenizers/RouteParser');

@@ -10,65 +9,6 @@ /**

*/
class StateProvider {
class StateProvider extends StateProviderBase {
/**
* Create a new instance of the state provider.
* @param {ServiceLocator} locator Service locator for resolving URI mappers.
*/
constructor(locator) {
/**
* Current list of URI mappers.
* @type {Array}
* @private
*/
this._uriMappers = this._getUriMappers(locator);
}
/**
* Gets a state by the specified location URI.
* @param {URI} location The URI location.
* @returns {Object|null} The state object.
*/
getStateByUri(location) {
if (this._uriMappers.length === 0) {
return null;
}
location = location.clone();
location.path = routeHelper.removeEndSlash(location.path);
const state = this._mapState(location);
if (!state) {
return null;
}
// make state object immutable
Object.keys(state).forEach(storeName => Object.freeze(state[storeName]));
Object.freeze(state);
return state;
}
/**
* Maps the state.
* @param {URI} location URI that describes the state.
* @returns {Object|null} The state from URI.
* @private
*/
_mapState(location) {
var state = null;
this._uriMappers.some(mapper => {
if (mapper.expression.test(location.path)) {
state = mapper.map(location) || Object.create(null);
return true;
}
return false;
});
return state;
}
/**
* Gets a list of URI mappers.
* Gets a list of route descriptors.
* @param {ServiceLocator} serviceLocator The Service locator

@@ -79,4 +19,5 @@ * for getting route definitions.

*/
_getUriMappers(serviceLocator) {
const uriMappers = [];
_getRouteDescriptors(serviceLocator) {
const descriptors = [];
const parser = new RouteParser();

@@ -95,5 +36,3 @@ var routeDefinitions;

if (typeof (route) === 'string') {
const routeUri = new URI(route);
routeUri.path = routeHelper.removeEndSlash(routeUri.path);
uriMappers.push(routeHelper.compileRoute(routeUri));
descriptors.push(parser.parseRouteExpression(route));
return;

@@ -104,17 +43,15 @@ }

if (typeof (route) === 'object' &&
(typeof (route.expression) === 'string') &&
(route.map instanceof Function)) {
typeof (route.expression) === 'string') {
const mapperUri = new URI(route.expression);
mapperUri.path = routeHelper.removeEndSlash(mapperUri.path);
const descriptor = parser.parseRouteExpression(route.expression);
const mapper = routeHelper.compileRoute(mapperUri);
if (typeof (route.name) === 'string') {
descriptor.name = route.name;
}
uriMappers.push({
expression: mapper.expression,
map: uri => {
const state = mapper.map(uri);
return route.map(state);
}
});
if (route.map instanceof Function) {
descriptor.map = route.map;
}
descriptors.push(descriptor);
return;

@@ -127,6 +64,6 @@ }

(route.map instanceof Function)) {
uriMappers.push(route);
descriptors.push(route);
}
});
return uriMappers;
return descriptors;
}

@@ -133,0 +70,0 @@ }

@@ -195,2 +195,11 @@ 'use strict';

parameters = parameters || Object.create(null);
const stores = this._storeLoader.getStoresByNames();
const parameterNames = Object.keys(parameters);
parameterNames.forEach(storeName => {
if (!(storeName in stores)) {
this._eventBus.emit('warn', `Store "${storeName}" does not exist (might be a typo in a route)`);
}
});
if (!this._lastState) {

@@ -211,3 +220,3 @@ this._currentBasicContext = basicContext;

Object.keys(parameters)
parameterNames
.forEach(storeName => {

@@ -214,0 +223,0 @@ // new parameters were set for store

{
"name": "catberry",
"version": "8.2.0",
"version": "8.3.0",
"author": {

@@ -73,2 +73,3 @@ "name": "Denis Rechkunov",

"./lib/providers/ModuleApiProvider.js": "./browser/providers/ModuleApiProvider.js",
"./lib/providers/StateProvider.js": "./browser/providers/StateProvider.js",
"./lib/loaders/ComponentLoader.js": "./browser/loaders/ComponentLoader.js",

@@ -75,0 +76,0 @@ "./lib/loaders/StoreLoader.js": "./browser/loaders/StoreLoader.js",

@@ -12,3 +12,3 @@ # Catberry

Catberry was developed to help create ["isomorphic/Universal" Web applications](https://github.com/catberry/catberry/blob/8.2.0/docs/index.md#isomorphicuniversal-applications).
Catberry was developed to help create ["isomorphic/Universal" Web applications](https://github.com/catberry/catberry/blob/8.3.0/docs/index.md#isomorphicuniversal-applications).

@@ -45,5 +45,5 @@ Long story short, isomorphic/universal applications are apps that use the same codebase on both the server and client environments to render what the client would see as a "[Single Page Application](http://en.wikipedia.org/wiki/Single_Page_Application)".

* [Catberry Documentation](https://github.com/catberry/catberry/blob/8.2.0/docs/index.md)
* [Get Started Guide](https://github.com/catberry/catberry/blob/8.2.0/docs/index.md#get-started)
* [Plugins and Tools](https://github.com/catberry/catberry/blob/8.2.0/docs/index.md#plugins-and-tools)
* [Catberry Documentation](https://github.com/catberry/catberry/blob/8.3.0/docs/index.md)
* [Get Started Guide](https://github.com/catberry/catberry/blob/8.3.0/docs/index.md#get-started)
* [Plugins and Tools](https://github.com/catberry/catberry/blob/8.3.0/docs/index.md#plugins-and-tools)
* [Catberry's homepage](http://catberry.org) and its [source code](https://github.com/catberry/catberry-homepage)

@@ -57,4 +57,4 @@ * [Todo application](https://github.com/catberry/catberry-todomvc)

* The entire architecture of the framework is built using the [Service Locator](https://github.com/catberry/catberry/blob/8.2.0/docs/index.md#service-locator) pattern – which helps to manage module dependencies and [create plugins](https://github.com/catberry/catberry/) – and [Flux](https://github.com/catberry/catberry/blob/8.2.0/docs/index.md#flux), for the data layer
* [Cat-components](https://github.com/catberry/catberry/blob/8.2.0/docs/index.md#cat-components) – similar to [web-components](http://webcomponents.org/) but organized as directories, can be rendered on the server and published/installed as NPM packages
* The entire architecture of the framework is built using the [Service Locator](https://github.com/catberry/catberry/blob/8.3.0/docs/index.md#service-locator) pattern – which helps to manage module dependencies and [create plugins](https://github.com/catberry/catberry/) – and [Flux](https://github.com/catberry/catberry/blob/8.3.0/docs/index.md#flux), for the data layer
* [Cat-components](https://github.com/catberry/catberry/blob/8.3.0/docs/index.md#cat-components) – similar to [web-components](http://webcomponents.org/) but organized as directories, can be rendered on the server and published/installed as NPM packages
* Catberry builds a bundle for running the application in a browser as a [Single Page Application](http://en.wikipedia.org/wiki/Single_Page_Application)

@@ -71,6 +71,6 @@ * [ES2015/ES6 support](https://nodejs.org/en/docs/es6/) – native on the server/Node.js and using [Babel](http://babeljs.io/) for a browser

* [Handlebars](https://github.com/catberry/catberry-handlebars), [Dust](https://github.com/catberry/catberry-dust) and
[Jade](https://github.com/catberry/catberry-jade) template engines are [officially supported](https://github.com/catberry/catberry/blob/8.2.0/docs/index.md#template-engines) (and you can implement your own provider to support any other)
[Jade](https://github.com/catberry/catberry-jade) template engines are [officially supported](https://github.com/catberry/catberry/blob/8.3.0/docs/index.md#template-engines) (and you can implement your own provider to support any other)
* Efficient DOM event listening using [event delegation](http://davidwalsh.name/event-delegate)
For more details please proceed to [Catberry Documentation](https://github.com/catberry/catberry/blob/8.2.0/docs/index.md).
For more details please proceed to [Catberry Documentation](https://github.com/catberry/catberry/blob/8.3.0/docs/index.md).

@@ -214,5 +214,5 @@ ### Typical Cat-component example

* [Submit a bug or a feature request](https://github.com/catberry/catberry/issues)
* [Submit a PR](https://github.com/catberry/catberry/blob/8.2.0/CONTRIBUTING.md)
* [Submit a PR](https://github.com/catberry/catberry/blob/8.3.0/CONTRIBUTING.md)
* If you like the logo, you might want to buy a Catberry [T-Shirt](http://www.redbubble.com/people/catberryjs/works/14439373-catberry-js-framework-logo?p=t-shirt) or a [sticker](http://www.redbubble.com/people/catberryjs/works/14439373-catberry-js-framework-logo?p=sticker)
Denis Rechkunov <denis.rechkunov@gmail.com>

@@ -42,2 +42,9 @@ 'use strict';

});
describe('#getRouteURI', function() {
it('should call state provider', function() {
assert.strictEqual(api.getRouteURI('name', {some: 'value'}), 'testURI:name:{"some":"value"}');
});
});
describe('#clearFragment', function() {

@@ -90,2 +97,7 @@ it('should clear URI hash', function(done) {

locator.registerInstance('requestRouter', requestRouter);
locator.registerInstance('stateProvider', {
getRouteURI(name, parameters) {
return `testURI:${name}:${JSON.stringify(parameters)}`;
}
});

@@ -92,0 +104,0 @@ const templateProvider = new UniversalMock(['render']);

@@ -63,2 +63,62 @@ {

{
"name": "should return the correct state for correct URI if the route is an object",
"routes": [{
"expression": "/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
}],
"uri": "/state/val1/val2?a=val3&b=val4",
"expectedState": {
"Store1": {
"arg1": "val1",
"arg3": "val3"
},
"Store2": {
"arg1": "val1",
"arg2": "val2"
},
"Store3": {
"arg4": "val4"
}
}
},
{
"name": "should return the correct state for correct URI and store names which contains slash",
"routes": [
"/state/:arg1[group1/Store1, group2/Store2]/:arg2[group2/Store2]?a=:arg3[group1/Store1]&b=:arg4[group3/Store3]"
],
"uri": "/state/val1/val2?a=val3&b=val4",
"expectedState": {
"group1/Store1": {
"arg1": "val1",
"arg3": "val3"
},
"group2/Store2": {
"arg1": "val1",
"arg2": "val2"
},
"group3/Store3": {
"arg4": "val4"
}
}
},
{
"name": "should return the correct state for correct URI and store names which contains dashes",
"routes": [
"/state/:arg1[group-1/Store1, group-2/Store2]/:arg2[group-2/Store2]?a=:arg3[group-1/Store1]&b=:arg4[group-3/Store3]"
],
"uri": "/state/val1/val2?a=val3&b=val4",
"expectedState": {
"group-1/Store1": {
"arg1": "val1",
"arg3": "val3"
},
"group-2/Store2": {
"arg1": "val1",
"arg2": "val2"
},
"group-3/Store3": {
"arg4": "val4"
}
}
},
{
"name": "should return the state if one query string parameter is not specified",

@@ -299,3 +359,3 @@ "routes": [

{
"name": "should support overriding path parameters by query string parameters",
"name": "should support collecting several values into the list",
"routes": [

@@ -308,3 +368,6 @@ "/state/:arg1[Store1, Store2]/:arg3[Store1]?a=:arg3[Store1]&b=:arg4[Store3]"

"arg1": "val1",
"arg3": "valX"
"arg3": [
"val2",
"valX"
]
},

@@ -362,3 +425,3 @@ "Store2": {

"routes": [
"/state/w:arg1[Store1, Store2]q/q:arg2[Store2]s?a=a:arg3[Store1]z&b=x:arg4[Store3]y"
"/state:noop/w:arg1[Store1, Store2]q/q:arg2[Store2]s?a=a:arg3[Store1]z&b=x:arg4[Store3]y"
],

@@ -397,2 +460,17 @@ "uri": "/state/wq/qs?a=az&b=xy",

{
"name": "should support parameters without values in query",
"routes": [
"/state?a:arg1[Store1]&b:arg2[Store2]=x:arg3[Store3]&b=some"
],
"uri": "/state?aval1&bval2",
"expectedState": {
"Store1": {
"arg1": "val1"
},
"Store2": {
"arg2": "val2"
}
}
},
{
"name": "should return null if partial parameters are absent in path",

@@ -405,3 +483,209 @@ "routes": [

}
],
"getRouteURI": [
{
"name": "should throw an error when there is no such route",
"routes": [
{
"name": "test",
"expression": "/:section[Store1, Store2]/:subsection[Store2]"
}
],
"arguments": {
"name": "wrong",
"parameters": {
"section": "test-section",
"subsection": "test-subsection"
}
},
"expectedError": "There is no such route called \"wrong\""
},
{
"name": "should throw an error when a path parameter has an array value",
"routes": [
{
"name": "test",
"expression": "/:section[Store1, Store2]/:subsection[Store2]"
}
],
"arguments": {
"name": "test",
"parameters": {
"section": ["test-section"],
"subsection": "test-subsection"
}
},
"expectedError": "Array value is not supported for the parameter \"section\""
},
{
"name": "should throw an error when a quern name parameter has an array value",
"routes": [
{
"name": "test",
"expression": "/some?:qParam1[Store2]"
}
],
"arguments": {
"name": "test",
"parameters": {
"qParam1": ["test-section"]
}
},
"expectedError": "Array value is not supported for the parameter \"qParam1\""
},
{
"name": "should paste an empty string when there is no parameter in the path",
"routes": [
{
"name": "test",
"expression": "/:section[Store1, Store2]/:subsection[Store2]"
}
],
"arguments": {
"name": "test",
"parameters": {
"subsection": "test-subsection"
}
},
"expectedURI": "//test-subsection"
},
{
"name": "should return URI for path parameters",
"routes": [
{
"name": "test",
"expression": "/:section[Store1, Store2]/:subsection[Store2]"
}
],
"arguments": {
"name": "test",
"parameters": {
"section": "test-section",
"subsection": "test-subsection"
}
},
"expectedURI": "/test-section/test-subsection"
},
{
"name": "should encode path parameters",
"routes": [
{
"name": "test",
"expression": "/:section[Store1, Store2]/:subsection[Store2]"
}
],
"arguments": {
"name": "test",
"parameters": {
"section": "test/section",
"subsection": "test/subsection"
}
},
"expectedURI": "/test%2Fsection/test%2Fsubsection"
},
{
"name": "should return URI for path and query parameters",
"routes": [
{
"name": "test",
"expression": "/:param1[Store1, Store2]/:param2[Store2]?:qParam1[Store2]=value&query=:qParam2[Store2]&:qParam3[Store3]"
}
],
"arguments": {
"name": "test",
"parameters": {
"param1": "value1",
"param2": "value2",
"qParam1": "qValue1",
"qParam2": "qValue2",
"qParam3": "qValue3"
}
},
"expectedURI": "/value1/value2?qValue1=value&query=qValue2&qValue3"
},
{
"name": "should return URI for path and query parameters surrounded by text",
"routes": [
{
"name": "test",
"expression": "/pa:param1[Store1]th1/pa:param2[Store2]th2?que:qParam1[Store2]ry1=value&query=va:qParam2[Store2]lue1&que:qParam3[Store3]ry2&que:qParam4[Store4]ry3=val:qParam5[Store5]ue2"
}
],
"arguments": {
"name": "test",
"parameters": {
"param1": "!value1!",
"param2": "!value2!",
"qParam1": "!qValue1!",
"qParam2": "!qValue2!",
"qParam3": "!qValue3!",
"qParam4": "!qValue4!",
"qParam5": ["!qValue5-1!", "!qValue5-2!", "!qValue5-3!"]
}
},
"expectedURI": "/pa!value1!th1/pa!value2!th2?que!qValue1!ry1=value&query=va!qValue2!lue1&que!qValue3!ry2&que!qValue4!ry3=val!qValue5-1!ue2&que!qValue4!ry3=val!qValue5-2!ue2&que!qValue4!ry3=val!qValue5-3!ue2"
},
{
"name": "should return URI for path and query parameters with array values",
"routes": [
{
"name": "test",
"expression": "/some?:qParam1[Store2]=:qParam2[Store2]"
}
],
"arguments": {
"name": "test",
"parameters": {
"qParam1": "qValue1",
"qParam2": ["qValue2-1", "qValue2-2", "qValue2-3"]
}
},
"expectedURI": "/some?qValue1=qValue2-1&qValue1=qValue2-2&qValue1=qValue2-3"
},
{
"name": "should return URI for path and optional query parameters",
"routes": [
{
"name": "test",
"expression": "/:param1[Store1, Store2]/:param2[Store2]?:qParam1[Store2]=value&query=:qParam2[Store2]&:qParam3[Store3]"
}
],
"arguments": {
"name": "test",
"parameters": {
"param1": "value1",
"param2": "value2",
"qParam2": "qValue2"
}
},
"expectedURI": "/value1/value2?query=qValue2"
},
{
"name": "should return URI without query string if parameters=undefined for optional parameters",
"routes": [
{
"name": "test",
"expression": "/some?:qParam1[Store2]=value&query=:qParam2[Store2]&:qParam3[Store3]"
}
],
"arguments": {
"name": "test"
},
"expectedURI": "/some"
},
{
"name": "should return URI without query parameter if the value was not specified",
"routes": [
{
"name": "test",
"expression": "/some?qParam=:qValue[Store]"
}
],
"arguments": {
"name": "test",
"parameters": {}
},
"expectedURI": "/some"
}
]
}

@@ -26,2 +26,7 @@ 'use strict';

locator.registerInstance('serviceLocator', locator);
locator.registerInstance('stateProvider', {
getRouteURI(name, parameters) {
return `testURI:${name}:${JSON.stringify(parameters)}`;
}
});
locator.registerInstance('eventBus', new events.EventEmitter());

@@ -133,2 +138,8 @@ api = new ModuleApiProvider(locator);

describe('#getRouteURI', function() {
it('should call state provider', function() {
assert.strictEqual(api.getRouteURI('name', {some: 'value'}), 'testURI:name:{"some":"value"}');
});
});
describe('#clearFragment', function(done) {

@@ -135,0 +146,0 @@ it('should save flag that hash has been cleared', function() {

@@ -44,3 +44,32 @@ 'use strict';

});
it('should throw an error in case of wrong syntax', function() {
const locator = createLocator([
'/:wrong[some'
]);
assert.throws(() => {
const provider = new StateProvider(locator);
}, /Illegal/);
});
});
describe('#getRouteURI', function() {
testCases.getRouteURI.forEach(testCase => {
it(testCase.name, function() {
const locator = createLocator(testCase.routes);
const provider = new StateProvider(locator);
if (testCase.expectedError) {
assert.throws(
() => provider.getRouteURI(testCase.arguments.name, testCase.arguments.parameters),
error => error.message === testCase.expectedError
);
} else {
const uri = provider.getRouteURI(testCase.arguments.name, testCase.arguments.parameters);
assert.strictEqual(uri, testCase.expectedURI);
}
});
});
});
});

@@ -52,2 +81,5 @@

routeDefinitions.forEach(function(routeDefinition) {
if (typeof (routeDefinition) === 'object' && typeof (routeDefinition.expression) === 'string') {
routeDefinition.map = state => state;
}
locator.registerInstance('routeDefinition', routeDefinition);

@@ -54,0 +86,0 @@ });

@@ -584,2 +584,31 @@ 'use strict';

});
it('should trigger warning if the store does not exist', function(done) {
const stores = {
store: {
name: 'store',
constructor: storeMocks.SyncDataStore
}
};
const locator = createLocator(stores);
const eventBus = locator.resolve('eventBus');
const dispatcher = locator.resolve('storeDispatcher');
const initState = {
wrong: {}
};
eventBus
.once('error', done)
.once('warn', message => {
try {
assert.strictEqual(message, 'Store "wrong" does not exist (might be a typo in a route)');
done();
} catch (e) {
done(e);
}
});
dispatcher.setState(initState, context);
});
});

@@ -586,0 +615,0 @@

'use strict';
const assert = require('assert');
const tests = require('../../cases/lib/streams/HTMLTagTokenizer.json');
const tests = require('../../cases/lib/tokenizers/HTMLTagTokenizer.json');
const HTMLTagTokenizer = require('../../../lib/tokenizers/HTMLTagTokenizer');

@@ -6,0 +6,0 @@

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc