Socket
Socket
Sign inDemoInstall

catberry

Package Overview
Dependencies
387
Maintainers
1
Versions
41
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 8.6.1 to 9.0.0

lib/appDefinitions.js

40

browser/Bootstrapper.js

@@ -1,29 +0,9 @@

/**
* This file is a template and it is used only for some string replaces
* by BrowserBundleBuilder module. It does not work by itself.
*/
'use strict';
const stores = [
const Catberry = require('./Catberry.js');
const BootstrapperBase = require('../lib/base/BootstrapperBase');
const StoreDispatcher = require('../lib/StoreDispatcher');
const ModuleApiProvider = require('./providers/ModuleApiProvider');
const CookieWrapper = require('./CookieWrapper');
/** __stores **/
];
const components = [
/** __components **/
];
const routeDefinitions = '__routeDefinitions' || [];
const routeDescriptors = '__routes' || [];
const Catberry = require('./node_modules/catberry/browser/Catberry.js');
const BootstrapperBase = require('./node_modules/catberry/lib/base/BootstrapperBase.js');
const StoreDispatcher = require('./node_modules/catberry/lib/StoreDispatcher');
const ModuleApiProvider = require('./node_modules/catberry/browser/providers/ModuleApiProvider');
const CookieWrapper = require('./node_modules/catberry/browser/CookieWrapper');
class Bootstrapper extends BootstrapperBase {

@@ -51,12 +31,2 @@

locator.registerInstance('window', window);
routeDefinitions.forEach(routeDefinition =>
locator.registerInstance('routeDefinition', routeDefinition));
routeDescriptors.forEach(routeDescriptor =>
locator.registerInstance('routeDescriptor', routeDescriptor));
stores.forEach(store => locator.registerInstance('store', store));
components.forEach(component => locator.registerInstance('component', component));
}

@@ -63,0 +33,0 @@ }

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

wrapDocument() {
const appDefinitions = require('appDefinitions');
appDefinitions.routeDefinitions
.forEach(routeDefinition => this.locator.registerInstance('routeDefinition', routeDefinition));
appDefinitions.routeDescriptors
.forEach(routeDescriptor => this.locator.registerInstance('routeDescriptor', routeDescriptor));
appDefinitions.stores
.forEach(store => this.locator.registerInstance('store', store));
appDefinitions.components
.forEach(component => this.locator.registerInstance('component', component));
this._router = this.locator.resolve('requestRouter');

@@ -33,0 +46,0 @@ }

@@ -1014,4 +1014,2 @@ 'use strict';

};
componentContext.sendBroadcastAction = (name, args) =>
this._storeDispatcher.sendBroadcastAction(name, args);

@@ -1018,0 +1016,0 @@ return Object.freeze(componentContext);

'use strict';
const moduleHelper = require('../../lib/helpers/moduleHelper');
const templateHelper = require('../../lib/helpers/templateHelper');
const LoaderBase = require('../../lib/base/LoaderBase');

@@ -36,7 +37,8 @@

/**
* Current template provider.
* @type {TemplateProvider}
* Current template provider map.
* @type {Object}
* @private
*/
this._templateProvider = locator.resolve('templateProvider');
this._templateProvidersByNames = templateHelper
.resolveTemplateProvidersByNames(locator);

@@ -102,16 +104,13 @@ /**

}
component = transformed;
this._templateProvider.registerCompiled(
component.name, component.templateSource
);
component.template = {
render: dataContext => this._templateProvider.render(component.name, dataContext)
};
if (typeof (component.errorTemplateSource) === 'string') {
const errorTemplateName = moduleHelper.getNameForErrorTemplate(component.name);
this._templateProvider.registerCompiled(errorTemplateName, component.errorTemplateSource);
component.errorTemplate = {
render: dataContext => this._templateProvider.render(errorTemplateName, dataContext)
};
component = Object.create(transformed);
component.templateProvider = this._templateProvidersByNames[component.templateProviderName];
component.errorTemplateProvider = this._templateProvidersByNames[component.errorTemplateProviderName];
if (!component.templateProvider &&
(component.errorTemplateProviderName && !component.errorTemplateProvider)) {
throw new Error(`Template provider required by the component "${component.name}" not found`);
}
templateHelper.registerTemplates(component);
this._eventBus.emit('componentLoaded', component);

@@ -118,0 +117,0 @@ return component;

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

*/
this.version = '8.6.1';
this.version = '9.0.0';

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

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

const BrowserBundleBuilder = require('./builders/BrowserBundleBuilder');
const BootstrapperBuilder = require('./builders/BootstrapperBuilder');
const AppDefinitionsBuilder = require('./builders/AppDefinitionsBuilder');
const StoreFinder = require('./finders/StoreFinder');

@@ -46,3 +46,3 @@ const ComponentFinder = require('./finders/ComponentFinder');

locator.register('browserBundleBuilder', BrowserBundleBuilder, true);
locator.register('bootstrapperBuilder', BootstrapperBuilder, true);
locator.register('appDefinitionsBuilder', AppDefinitionsBuilder, true);
locator.register('storeFinder', StoreFinder, true);

@@ -49,0 +49,0 @@ locator.register('componentFinder', ComponentFinder, true);

@@ -10,11 +10,14 @@ 'use strict';

const babelify = require('babelify');
const babelifyPreset = require('babel-preset-es2015-ie');
const babelEnv = require('babel-preset-env');
const babili = require('babel-preset-babili');
const browserify = require('browserify');
const hrTimeHelper = require('../helpers/hrTimeHelper');
const UglifyTransform = require('../streams/UglifyTransform');
const DEFAULT_PUBLIC_DIRECTORY = path.join(process.cwd(), 'public');
const TEMPORARY_BOOTSTRAPPER_FILENAME = '__BrowserBundle.js';
const WORKING_DIR = process.cwd();
const DEFAULT_PUBLIC_DIRECTORY = path.join(WORKING_DIR, 'public');
const TEMPORARY_APP_DEFINITIONS_FILENAME = '.appDefinitions.js';
const BROWSER_SCRIPT_FILENAME = 'browser.js';
const BUNDLE_FILENAME = 'bundle.js';
const APP_DEFAULT_FILENAME = 'app.js';
const EXTERNALS_DEFAULT_FILENAME = 'externals.js';
const APP_DEPENDENCY_ID_REGEXP = process.platform === 'win32' ? /^(\.|\w:)/ : /^[\/.]/;

@@ -24,3 +27,3 @@ var packageDescriptionString = '';

try {
const packageDescription = require(path.join(process.cwd(), 'package.json'));
const packageDescription = require(path.join(WORKING_DIR, 'package.json'));
if (packageDescription &&

@@ -68,16 +71,23 @@ packageDescription.name &&

/**
* Current path to the bundle.js.
* Current path to the application bundle file.
* @type {string}
* @private
*/
this._bundlePath = path.join(this._publicPath, (config.bundleFilename || BUNDLE_FILENAME));
this._appPath = path.join(this._publicPath, (config.appBundleFilename || APP_DEFAULT_FILENAME));
/**
* Current path to the __BrowserBundle.js.
* Current path to the externals bunlde file.
* @type {string}
* @private
*/
this._bootstrapperPath = path.join(process.cwd(), TEMPORARY_BOOTSTRAPPER_FILENAME);
this._externalsPath = path.join(this._publicPath, (config.externalsBundleFilename || EXTERNALS_DEFAULT_FILENAME));
/**
* Current path to the __appDefinitions.js.
* @type {string}
* @private
*/
this._appDefinitionsPath = path.join(WORKING_DIR, TEMPORARY_APP_DEFINITIONS_FILENAME);
/**
* Current path to the browser.js.

@@ -87,3 +97,3 @@ * @type {string}

*/
this._entryPath = path.join(process.cwd(), BROWSER_SCRIPT_FILENAME);
this._entryPath = path.join(WORKING_DIR, BROWSER_SCRIPT_FILENAME);

@@ -105,7 +115,7 @@ /**

/**
* Current bootstrapper builder.
* @type {BootstrapperBuilder}
* Current app definitions builder.
* @type {AppDefinitionsBuilder}
* @private
*/
this._bootstrapperBuilder = locator.resolve('bootstrapperBuilder');
this._appDefinitionsBuilder = locator.resolve('appDefinitionsBuilder');

@@ -163,14 +173,28 @@ /**

/**
* Current Browserify bundler.
* Current Browserify app bundler.
* @type {Browserify}
* @private
*/
this._bundler = null;
this._appBundler = null;
/**
* Current bootstrapper cache.
* Current Browserify externals bundler.
* @type {Browserify}
* @private
*/
this._externalsBundler = null;
/**
* Current set of external modules.
* @type {Object}
* @private
*/
this._externalModules = {};
/**
* Current app definitions cache.
* @type {string}
* @private
*/
this._bootstrapperCache = '';
this._appDefinitionsCache = '';
}

@@ -185,4 +209,4 @@

.then(isExists => !isExists ? makeDirectory(this._publicPath) : null)
.then(() => this._createBootstrapper())
.then(() => new Promise((fulfill, reject) => this._createBundler()
.then(() => this._createAppDefinitions())
.then(() => new Promise((fulfill, reject) => this._createAppBundler()
.once('error', reject)

@@ -196,5 +220,15 @@ .once('bundle', bundleStream => bundleStream

)
.then(() => new Promise((fulfill, reject) => this._createExternalsBundler()
.once('error', reject)
.once('bundle', bundleStream => bundleStream
.once('end', fulfill)
.on('error', reject)
)
.bundle()
)
)
.then(() => this._doPostBuildActions())
.then(() => this._isRelease ?
pfs.unlink(this._bootstrapperPath) :
pfs.unlink(this._appDefinitionsPath) :
this._watch()

@@ -206,7 +240,7 @@ )

/**
* Creates a bootstrapper file for the bundler.
* Creates a app definitions file for the bundler.
* @returns {Promise} The promise for finished work.
* @private
*/
_createBootstrapper() {
_createAppDefinitions() {
return Promise.all([

@@ -216,9 +250,9 @@ this._storeFinder.find(),

])
.then(found => this._bootstrapperBuilder.build(found[0], found[1]))
.then(realBootstrapper => {
if (realBootstrapper === this._bootstrapperCache) {
.then(found => this._appDefinitionsBuilder.build(found[0], found[1]))
.then(realAppDefinitions => {
if (realAppDefinitions === this._appDefinitionsCache) {
return null;
}
this._bootstrapperCache = realBootstrapper;
return pfs.writeFile(this._bootstrapperPath, realBootstrapper);
this._appDefinitionsCache = realAppDefinitions;
return pfs.writeFile(this._appDefinitionsPath, realAppDefinitions);
});

@@ -228,56 +262,50 @@ }

/**
* Creates the browserify bundler or re-uses the existing one.
* Creates the browserify bundler for the app or re-uses the existing one.
* @returns {Browserify} The browserify instance.
* @private
*/
_createBundler() {
if (this._bundler) {
return this._bundler;
_createAppBundler() {
if (this._appBundler) {
return this._appBundler;
}
this._bundler = browserify([this._entryPath], {
this._appBundler = browserify(this._entryPath, {
cache: {},
packageCache: {},
debug: !this._isRelease
})
.transform(babelify, {
global: true,
ast: false,
comments: false,
sourceMap: !this._isRelease,
presets: [babelifyPreset]
});
debug: !this._isRelease,
filter: id => {
if (APP_DEPENDENCY_ID_REGEXP.test(id)) {
return true;
}
this._externalModules[id] = true;
return false;
}
});
this._appBundler.require(
this._appDefinitionsPath, {expose: 'appDefinitions'}
);
this._appBundler.external('catberry');
if (!this._isRelease) {
this._bundler.plugin(watchify);
this._eventBus.emit('info', 'Watching files for changes to rebuild the bundle...');
} else {
this._bundler.transform(file => {
if (path.extname(file) !== '.js') {
return new stream.PassThrough();
}
this._eventBus.emit('trace', `Minifying code of the file "${file}"...`);
return new UglifyTransform();
}, {
global: true
});
this._appBundler.plugin(watchify);
this._eventBus.emit('info', 'Watching files for changes to rebuild the app bundle...');
}
this._setTransformations();
this._setPlugins();
this._attachExtensionsToBundler(this._appBundler);
var startTime;
const resetHandler = () => {
this._eventBus.emit('info', `Building browser script bundle at "${this._bundlePath}"...`);
this._eventBus.emit('info', `Building browser script bundle for the app at "${this._appPath}"...`);
startTime = hrTimeHelper.get();
};
this._bundler
this._appBundler
.on('update', ids => {
this._eventBus.emit('bundleChanged', {
path: this._bundlePath,
this._eventBus.emit('appBundleChanged', {
path: this._appPath,
changedFiles: ids
});
this._bundler.bundle();
this._appBundler.bundle();
})

@@ -287,3 +315,3 @@ .on('error', error => this._eventBus.emit('error', error))

.on('bundle', sourceStream => {
const outputStream = fs.createWriteStream(this._bundlePath);
const outputStream = fs.createWriteStream(this._appPath);
if (this._isRelease) {

@@ -294,4 +322,4 @@ outputStream.write(packageDescriptionString);

const hrTime = hrTimeHelper.get(startTime);
this._eventBus.emit('bundleBuilt', {
path: this._bundlePath,
this._eventBus.emit('appBundleBuilt', {
path: this._appPath,
hrTime,

@@ -305,6 +333,81 @@ time: hrTimeHelper.toMilliseconds(hrTime)

resetHandler(); // to set startTime universally.
return this._bundler;
return this._appBundler;
}
/**
* Creates the browserify bundler for externals or re-uses the existing one.
* @returns {Browserify} The browserify instances.
* @private
*/
_createExternalsBundler() {
if (this._externalsBundler) {
return this._externalsBundler;
}
this._externalsBundler = browserify({
cache: {},
packageCache: {},
debug: !this._isRelease
});
this._externalsBundler.require(Object.keys(this._externalModules));
this._externalsBundler.external('appDefinitions');
this._attachExtensionsToBundler(this._externalsBundler);
const startTime = hrTimeHelper.get();
this._eventBus.emit('info', `Building browser script bundle for externals at "${this._externalsPath}"...`);
this._externalsBundler
.on('error', error => this._eventBus.emit('error', error))
.on('bundle', sourceStream => {
const outputStream = fs.createWriteStream(this._externalsPath);
outputStream.once('finish', () => {
const hrTime = hrTimeHelper.get(startTime);
this._eventBus.emit('externalsBundleBuilt', {
path: this._externalsPath,
hrTime,
time: hrTimeHelper.toMilliseconds(hrTime)
});
});
sourceStream.pipe(outputStream);
});
return this._externalsBundler;
}
/**
* Attaches necessary plugins and transformations to the bundle.
* @param {Browserify} bundler The bundler to attach extensions.
*/
_attachExtensionsToBundler(bundler) {
const isDebug = !this._isRelease;
const presets = [[
babelEnv, {
targets: {
browsers: [
'last 2 versions',
'not ie <= 10'
]
},
debug: isDebug
}
]];
if (this._isRelease) {
presets.push(babili);
}
bundler.transform(babelify, {
global: true,
ast: false,
comments: false,
presets,
sourceMap: isDebug
});
this._setTransformations(bundler);
this._setPlugins(bundler);
}
/**
* Does all the registered post build actions.

@@ -345,3 +448,3 @@ * @param {number?} index Current action index for recursive calls.

_watch() {
const watchHandler = this._createBootstrapper.bind(this);
const watchHandler = this._createAppDefinitions.bind(this);
this._componentFinder.watch();

@@ -375,3 +478,3 @@ this._componentFinder

}
this._bundler.transform(
this._appBundler.transform(
currentTransformation.transform, currentTransformation.options

@@ -397,3 +500,3 @@ );

}
this._bundler.plugin(
this._appBundler.plugin(
currentPlugin.plugin, currentPlugin.options

@@ -400,0 +503,0 @@ );

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

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

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

@@ -6,2 +6,4 @@ 'use strict';

const moduleHelper = require('../helpers/moduleHelper');
const loadHelper = require('../helpers/loadHelper');
const templateHelper = require('../helpers/templateHelper');
const path = require('path');

@@ -36,7 +38,7 @@ const LoaderBase = require('../base/LoaderBase');

/**
* Current template provider.
* @type {TemplateProvider}
* Current template provider list.
* @type {Array<TemplateProvider>}
* @private
*/
this._templateProvider = locator.resolve('templateProvider');
this._templateProviders = templateHelper.resolveTemplateProviders(locator);

@@ -151,11 +153,12 @@ /**

return this._loadTemplateSources(component)
.then(() => this._compileTemplates(component))
.then(compiledTemplates => this._applyTransforms(component)
return loadHelper.loadTemplateSources(component)
.then(() => loadHelper.assignTemplateProviders(component, this._templateProviders))
.then(() => loadHelper.compileTemplates(component))
.then(() => this._applyTransforms(component)
.then(transformed => {
if (!transformed) {
throw new Error(`Transformation for the "${componentDetails.name}" component returned a bad result`);
throw new Error(`Transformation for the "${component.name}" component returned a bad result`);
}
component = transformed;
return this._registerTemplates(component, compiledTemplates);
return templateHelper.registerTemplates(component);
})

@@ -204,98 +207,2 @@ )

/**
* Loads template sources from the files.
* @param {Object} component The component.
* @returns {Promise} The promise for finished work.
* @private
*/
_loadTemplateSources(component) {
const templateSourcePromise = Promise.resolve()
.then(() => {
const templatePath = path.resolve(
path.dirname(component.path),
component.properties.template
);
return fs.readFile(templatePath)
.then(source => {
component.templateSource = source.toString();
});
});
const errorTemplateSourcePromise = Promise.resolve()
.then(() => {
component.errorTemplateSource = null;
const relativePath = component.properties.errorTemplate;
if (typeof (relativePath) !== 'string') {
return null;
}
const templatePath = path.resolve(
path.dirname(component.path),
component.properties.errorTemplate
);
return fs.readFile(templatePath)
.then(source => {
component.errorTemplateSource = source.toString();
});
});
return Promise.all([
templateSourcePromise, errorTemplateSourcePromise
]);
}
/**
* Compiles template sources of the component.
* @param {Object} component The component.
* @returns {Promise} The promise for finished work.
* @private
*/
_compileTemplates(component) {
const templateCompilePromise = Promise.resolve()
.then(() => this._templateProvider.compile(component.templateSource, component.name));
const errorTemplateName = moduleHelper.getNameForErrorTemplate(component.name);
const errorTemplateCompilePromise = Promise.resolve()
.then(() => {
if (!component.errorTemplateSource) {
return null;
}
return this._templateProvider.compile(component.errorTemplateSource, errorTemplateName);
});
return Promise.all([
templateCompilePromise,
errorTemplateCompilePromise
])
.then(compiledTemplates => ({
template: compiledTemplates[0],
errorTemplate: compiledTemplates[1] || null
}));
}
/**
* Registers templates into the component and template providers.
* @param {Object} component The component.
* @param {{template: string, errorTemplate: string}} templates
* The compiled templates.
* @private
*/
_registerTemplates(component, templates) {
this._templateProvider.registerCompiled(component.name, templates.template);
component.template = {
render: context => this._templateProvider.render(component.name, context)
};
if (!templates.errorTemplate) {
return;
}
const errorTemplateName = moduleHelper.getNameForErrorTemplate(component.name);
this._templateProvider.registerCompiled(errorTemplateName, templates.errorTemplate);
component.errorTemplate = {
render: context => this._templateProvider.render(errorTemplateName, context)
};
}
/**
* Gets an absolute path to the component's logic file.

@@ -302,0 +209,0 @@ * @param {Object} componentDetails The component details object.

@@ -12,7 +12,4 @@ 'use strict';

/* eslint prefer-rest-params:0 */
/* eslint no-invalid-this:0 */
// TODO rewrite this when Spread operator and Rest parameters will be supported
return function() {
const args = Array.prototype.slice.call(arguments);
return function(...args) {
return new Promise((fulfill, reject) => {

@@ -19,0 +16,0 @@ args.push((error, result) => {

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

/**
* Sends an action to every store that has a "handle" method for such action.
* @param {string} actionName Name of the action.
* @param {Object} arg Action arguments.
* @returns {Promise<Array<*>>} Promise for the action handling result.
*/
sendBroadcastAction(actionName, arg) {
const promises = [];
const storesByNames = this._storeLoader.getStoresByNames();
const methodName = moduleHelper.getCamelCaseName('handle', actionName);
Object.keys(storesByNames)
.forEach(storeName => {
const store = storesByNames[storeName];
const protoMethod = store.constructor.prototype[methodName];
if (typeof (protoMethod) !== 'function') {
return;
}
const sendActionPromise = this.sendAction(store.name, actionName, arg);
promises.push(sendActionPromise);
});
return Promise.all(promises);
}
/**
* Sets a new state to the store dispatcher and invokes the "changed" method for all

@@ -325,3 +301,2 @@ * stores which state has been changed.

storeContext.sendAction = (storeName, name, args) => this.sendAction(storeName, name, args);
storeContext.sendBroadcastAction = (name, args) => this.sendBroadcastAction(name, args);

@@ -328,0 +303,0 @@ return storeContext;

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

/**
* Creates q new instance of the parser duplex stream.
* Creates a new instance of the parser duplex stream.
* @param {Object} context Rendering parameters.

@@ -100,4 +100,8 @@ * @param {Object?} options Stream options.

attributes: Object.create(null)
})
.then(html => this.renderHTML(html));
});
if (this._processingFoundTagPromise) {
this._processingFoundTagPromise = this._processingFoundTagPromise
.then(html => this.renderHTML(html));
}
}

@@ -400,4 +404,2 @@

(name, args) => context.storeDispatcher.sendAction(storeName, name, args);
componentContext.sendBroadcastAction =
(name, args) => context.storeDispatcher.sendBroadcastAction(name, args);

@@ -404,0 +406,0 @@ return Object.freeze(componentContext);

{
"name": "catberry",
"version": "8.6.1",
"version": "9.0.0",
"author": {

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

"browser": {
"./lib/Bootstrapper.js": "__BrowserBundle.js",
"./lib/Bootstrapper.js": "./browser/Bootstrapper.js",
"./lib/Catberry.js": "./browser/Catberry.js",

@@ -87,29 +87,29 @@ "./lib/CookieWrapper.js": "./browser/CookieWrapper.js",

"mkdirp": "~0.5.1",
"glob": "^7.0.0",
"chokidar": "^1.4.3",
"catberry-locator": "^2.1.0",
"catberry-uri": "^3.1.0",
"pretty-hrtime": "^1.0.2",
"glob": "^7.1.1",
"chokidar": "^1.6.1",
"catberry-locator": "^2.2.1",
"catberry-uri": "^3.2.2",
"pretty-hrtime": "^1.0.3",
"browser-process-hrtime": "~0.1.2",
"entities": "^1.1.1",
"watchify": "^3.7.0",
"babelify": "^7.2.0",
"babel-preset-es2015-ie": "^6.6.1",
"uglify-js": "^2.6.2",
"browserify": "^13.0.0",
"watchify": "^3.9.0",
"babelify": "^7.3.0",
"babel-preset-babili": "~0.0.12",
"babel-preset-env": "^1.2.2",
"browserify": "^14.1.0",
"promise": "^7.1.1",
"morphdom": "~2.2.0",
"uuid": "^2.0.1"
"uuid": "^3.0.1"
},
"devDependencies": {
"istanbul": "~0.4.2",
"codecov": "^1.0.1",
"jsdom": "^9.4.2",
"mocha": "^3.0.2",
"eslint": "^3.3.1",
"istanbul": "~0.4.5",
"codecov": "^2.1.0",
"jsdom": "^9.12.0",
"mocha": "^3.2.0",
"eslint": "^3.18.0",
"ncp": "^2.0.0",
"rimraf": "^2.5.4"
"rimraf": "^2.6.1"
},
"engines": {
"node": ">=4"
"node": ">=6.10"
},

@@ -116,0 +116,0 @@ "scripts": {

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

Catberry was developed to help create ["isomorphic/Universal" Web applications](https://github.com/catberry/catberry/blob/8.6.1/docs/index.md#isomorphicuniversal-applications).
Catberry was developed to help create ["isomorphic/Universal" Web applications](https://github.com/catberry/catberry/blob/9.0.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.6.1/docs/index.md)
* [Get Started Guide](https://github.com/catberry/catberry/blob/8.6.1/docs/index.md#get-started)
* [Plugins and Tools](https://github.com/catberry/catberry/blob/8.6.1/docs/index.md#plugins-and-tools)
* [Catberry Documentation](https://github.com/catberry/catberry/blob/9.0.0/docs/index.md)
* [Get Started Guide](https://github.com/catberry/catberry/blob/9.0.0/docs/index.md#get-started)
* [Plugins and Tools](https://github.com/catberry/catberry/blob/9.0.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.6.1/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.6.1/docs/index.md#flux), for the data layer
* [Cat-components](https://github.com/catberry/catberry/blob/8.6.1/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/9.0.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/9.0.0/docs/index.md#flux), for the data layer
* [Cat-components](https://github.com/catberry/catberry/blob/9.0.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.6.1/docs/index.md#template-engines) (and you can implement your own provider to support any other)
[Pug](https://github.com/catberry/catberry-pug) template engines are [officially supported](https://github.com/catberry/catberry/blob/9.0.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.6.1/docs/index.md).
For more details please proceed to [Catberry Documentation](https://github.com/catberry/catberry/blob/9.0.0/docs/index.md).

@@ -108,4 +108,4 @@ ### Typical Cat-component example

return {
// CSS selector
'.clickable': () => window.alert('Ouch!');
// CSS selector
'.clickable': () => window.alert('Ouch!');
}

@@ -191,19 +191,4 @@ }

All supported browsers are listed below:
Catberry supports 2 last versions of modern browsers and IE 11. It depends on Babel [babel-preset-env](https://github.com/babel/babel-preset-env) preset which config you can override putting a `.babelrc` file in your project.
| Browser | Version |
|-------------|-----------|
| IE | 9 (partial non-[SPA](http://en.wikipedia.org/wiki/Single-page_application)), 10+ |
| IE Mobile | 10+ |
| Firefox | 4+ |
| Firefox Android | 29+ |
| Chrome | 19+ |
| Chrome Android | 35+ |
| Android Browser | 2.2+, 4.2+ |
| Safari | 6+ |
| iOS Safari | 5+ |
| Opera | 12+ |
| Opera Mobile | 11.1+ |
| Blackberry Browser| 7+ |
## Contributing

@@ -216,5 +201,5 @@

* [Submit a bug or a feature request](https://github.com/catberry/catberry/issues)
* [Submit a PR](https://github.com/catberry/catberry/blob/8.6.1/CONTRIBUTING.md)
* [Submit a PR](https://github.com/catberry/catberry/blob/9.0.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>

@@ -29,7 +29,9 @@ 'use strict';

logic: './logic.js',
errorTemplate: './templates/error.html',
template: './templates/template.html'
errorTemplate: './templates/error.html1',
template: './templates/template.html1'
},
templateSource: 'Hello, world!',
errorTemplateSource: 'Error occurs :('
templateProviderName: 'html1',
errorTemplateProviderName: 'html1',
compiledTemplate: 'Hello, world!',
compiledErrorTemplate: 'Error occurs :('
},

@@ -41,10 +43,44 @@ second: {

logic: './index.js',
template: './template.html'
template: './template.html2'
},
templateSource: 'Hello from second!',
errorTemplateSource: null
templateProviderName: 'html2',
errorTemplateProviderName: null,
compiledTemplate: 'Hello from second!',
compiledErrorTemplate: null
},
third: {
constructor: componentMocks.AsyncComponent,
name: 'third',
properties: {
logic: './index.js',
template: './template.html1',
errorTemplate: './error.html2'
},
templateProviderName: 'html1',
errorTemplateProviderName: 'html2',
compiledTemplate: 'Hello from third!',
compiledErrorTemplate: 'Error from third!'
}
};
registerComponents(components);
locator.unregister('templateProvider');
const templates = {};
locator.registerInstance('templateProvider', {
getName: () => 'html1',
render: name => Promise.resolve(`html1: ${templates[name]}`),
registerCompiled: (name, source) => {
templates[name] = source;
}
});
locator.registerInstance('templateProvider', {
getName: () => 'html2',
render: name => Promise.resolve(`html2: ${templates[name]}`),
registerCompiled: (name, source) => {
templates[name] = source;
}
});
const loader = locator.resolve('componentLoader');

@@ -57,3 +93,3 @@

// can't use deepEqual because of templates
assert.strictEqual(Object.keys(loadedComponents).length, 2);
assert.strictEqual(Object.keys(loadedComponents).length, 3);
Object.keys(loadedComponents).forEach(key => {

@@ -68,5 +104,7 @@ const actual = loadedComponents[key];

const expected = [
'Hello, world!',
'Error occurs :(',
'Hello from second!'
'html1: Hello, world!',
'html1: Error occurs :(',
'html2: Hello from second!',
'html1: Hello from third!',
'html2: Error from third!'
];

@@ -76,3 +114,5 @@ return Promise.all([

loadedComponents['first-cool'].errorTemplate.render(),
loadedComponents.second.template.render()
loadedComponents.second.template.render(),
loadedComponents.third.template.render(),
loadedComponents.third.errorTemplate.render()
])

@@ -91,4 +131,6 @@ .then(rendered => assert.deepEqual(rendered, expected));

properties: {},
templateSource: 'Hello, world!',
errorTemplateSource: 'Error occurs :('
templateProviderName: 'html',
errorTemplateProviderName: 'html',
compiledTemplate: 'Hello, world!',
compiledErrorTemplate: 'Error occurs :('
}

@@ -98,3 +140,3 @@ };

registerComponents(components);
locator.unregister('remplateProvider');
locator.unregister('templateProvider');
locator.registerInstance('templateProvider', {

@@ -112,2 +154,57 @@ register: () => Promise.reject(new Error('TestError'))

it('should not load component if there is no template provider', function(done) {
const components = {
'first-cool': {
constructor: componentMocks.SyncComponent,
name: 'first-cool',
properties: {},
templateProviderName: 'html',
errorTemplateProviderName: 'html',
compiledTemplate: 'Hello, world!',
compiledErrorTemplate: 'Error occurs :('
}
};
registerComponents(components);
locator.unregister('templateProvider');
const loader = locator.resolve('componentLoader');
loader
.load()
.then(loadedComponents => assert.deepEqual(loadedComponents, {}))
.then(done)
.catch(done);
});
it('should not load component if there is no suitable template provider', function(done) {
const components = {
'first-cool': {
constructor: componentMocks.SyncComponent,
name: 'first-cool',
properties: {},
templateProviderName: 'html',
errorTemplateProviderName: 'html',
compiledTemplate: 'Hello, world!',
compiledErrorTemplate: 'Error occurs :('
}
};
registerComponents(components);
locator.unregister('templateProvider');
locator.registerInstance('templateProvider', {
getName: () => 'wrong',
registerCompiled: () => {},
render: () => {}
});
const loader = locator.resolve('componentLoader');
loader
.load()
.then(loadedComponents => assert.deepEqual(loadedComponents, {}))
.then(done)
.catch(done);
});
it('should load nothing if no components are registered', function(done) {

@@ -146,4 +243,6 @@ registerComponents({});

properties: {},
templateSource: 'Hello, world!',
errorTemplateSource: null
templateProviderName: 'html',
errorTemplateProviderName: 'html',
compiledTemplate: 'Hello, world!',
compiledErrorTemplate: null
},

@@ -154,4 +253,6 @@ second: {

properties: {},
templateSource: 'Hello from second!',
errorTemplateSource: null
templateProviderName: 'html',
errorTemplateProviderName: null,
compiledTemplate: 'Hello from second!',
compiledErrorTemplate: null
}

@@ -192,4 +293,6 @@ };

properties: {},
templateSource: 'Hello, world!',
errorTemplateSource: null
templateProviderName: 'html',
errorTemplateProviderName: null,
compiledTemplate: 'Hello, world!',
compiledErrorTemplate: null
},

@@ -200,4 +303,6 @@ second: {

properties: {},
templateSource: 'Hello from second!',
errorTemplateSource: null
templateProviderName: 'html',
errorTemplateProviderName: null,
compiledTemplate: 'Hello from second!',
compiledErrorTemplate: null
}

@@ -239,4 +344,6 @@ };

properties: {},
templateSource: 'Hello, world!',
errorTemplateSource: null
templateProviderName: 'html',
errorTemplateProviderName: null,
compiledTemplate: 'Hello, world!',
compiledErrorTemplate: null
}

@@ -267,4 +374,6 @@ };

properties: {},
templateSource: 'Hello, world!',
errorTemplateSource: null
templateProviderName: 'html',
errorTemplateProviderName: null,
compiledTemplate: 'Hello, world!',
compiledErrorTemplate: null
},

@@ -275,4 +384,6 @@ second: {

properties: {},
templateSource: 'Hello from second!',
errorTemplateSource: null
templateProviderName: 'html',
errorTemplateProviderName: null,
compiledTemplate: 'Hello from second!',
compiledErrorTemplate: null
}

@@ -326,2 +437,3 @@ };

templates: {},
getName: () => 'html',
render: name => Promise.resolve(templateProvider[name]),

@@ -328,0 +440,0 @@ registerCompiled: (name, source) => {

@@ -11,3 +11,3 @@ {

"logic": "./logic.js",
"errorTemplate": "./templates/error.html",
"errorTemplate": "./templates/error.htm",
"template": "./templates/template.html"

@@ -27,7 +27,7 @@ }

"expectedTemplates": [
"Hello, world!",
"Hello from second!"
"HTML: Hello, world!",
"HTML: Hello from second!"
],
"expectedErrorTemplates": [
"Error occurs :(",
"HTM: Error occurs :(",
null

@@ -51,2 +51,26 @@ ]

{
"name": "should not load if component has a unsupported template",
"components": {
"error5": {
"name": "error5",
"path": "test/cases/lib/loaders/ComponentLoader/Error5/error5.json",
"properties": {
"logic": "./index.js",
"template": "./template.wrong"
}
},
"error6": {
"name": "error6",
"path": "test/cases/lib/loaders/ComponentLoader/Error6/error6.json",
"properties": {
"logic": "./index.js",
"template": "./template.html",
"errorTemplate": "./error.wrong"
}
}
},
"expectedCount": 0
},
{
"name": "should not load if component has wrong path in \"template\" field",

@@ -53,0 +77,0 @@ "components": {

@@ -141,14 +141,28 @@ 'use strict';

const templateProvider = {
templates: {},
const HTMLTemplates = {};
const HTMLTemplateProvider = {
getName: () => 'html',
isTemplateSupported: filename => /html$/.test(filename),
compile: str => Promise.resolve(str),
render: name => Promise.resolve(templateProvider[name]),
render: name => Promise.resolve(`HTML: ${HTMLTemplates[name]}`),
registerCompiled: (name, source) => {
templateProvider[name] = source;
HTMLTemplates[name] = source;
}
};
const HTMTemplates = {};
const HTMTemplateProvider = {
getName: () => 'htm',
isTemplateSupported: filename => /htm$/.test(filename),
compile: str => Promise.resolve(str),
render: name => Promise.resolve(`HTM: ${HTMTemplates[name]}`),
registerCompiled: (name, source) => {
HTMTemplates[name] = source;
}
};
locator.registerInstance('eventBus', eventBus);
locator.registerInstance('componentFinder', new ComponentFinder(components));
locator.registerInstance('templateProvider', templateProvider);
locator.registerInstance('templateProvider', HTMLTemplateProvider);
locator.registerInstance('templateProvider', HTMTemplateProvider);
locator.register('contextFactory', ContextFactory);

@@ -155,0 +169,0 @@ locator.register('moduleApiProvider', ModuleApiProvider);

@@ -730,93 +730,2 @@ 'use strict';

describe('#sendBroadcastAction', function() {
it('should send action to all stores with handlers', function(done) {
class Store {
handleSomeAction(args) {
return {
args,
result: this.$context.name
};
}
}
const stores = {
store1: {
name: 'store1',
constructor: Store
},
store2: {
name: 'store2',
constructor: storeMocks.SyncDataStore
},
store3: {
name: 'store3',
constructor: Store
}
};
const actionParameters = {};
const locator = createLocator(stores);
const dispatcher = locator.resolve('storeDispatcher');
dispatcher.setState({}, {});
dispatcher.sendBroadcastAction(
'some-action', actionParameters
)
.then(results => {
assert.strictEqual(results.length, 2);
assert.strictEqual(results[0].args, actionParameters);
assert.strictEqual(results[0].result, 'store1');
assert.strictEqual(results[1].args, actionParameters);
assert.strictEqual(results[1].result, 'store3');
})
.then(done)
.catch(done);
});
it('should send action to all stores with handlers from $context', function(done) {
class Store1 {
handleSome(name) {
return this.$context.sendBroadcastAction('action', name);
}
}
class Store2 {
handleAction(name) {
return `hello from store2, ${name}`;
}
}
class Store3 {
handleAction(name) {
return `hello from store3, ${name}`;
}
}
const stores = {
store1: {
name: 'store1',
constructor: Store1
},
store2: {
name: 'store2',
constructor: Store2
},
store3: {
name: 'store3',
constructor: Store3
}
};
const locator = createLocator(stores);
const dispatcher = locator.resolve('storeDispatcher');
dispatcher.setState({}, {});
dispatcher.sendAction('store1', 'some', 'catberry')
.then(results => {
assert.strictEqual(results.length, 2);
assert.strictEqual(results[0], 'hello from store2, catberry');
assert.strictEqual(results[1], 'hello from store3, catberry');
})
.then(done)
.catch(done);
});
});
});

@@ -823,0 +732,0 @@

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

});
describe('#renderDocument', function() {
it('renders nothing when there is no document', function(done) {
const parser = new ComponentReadable(createContext());
parser.renderDocument();
var concat = '';
parser
.on('data', function(chunk) {
concat += chunk;
})
.on('end', function() {
assert.strictEqual(concat, '', 'Wrong HTML content');
done();
});
});
});
});

@@ -47,2 +66,3 @@

return {
components: Object.create(null),
routingContext: {

@@ -49,0 +69,0 @@ middleware: {

Sorry, the diff of this file is not supported yet

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