@ayana/bento
Advanced tools
Comparing version 1.0.0-alpha9 to 1.0.0-beta.1
@@ -1,138 +0,131 @@ | ||
import { ComponentEvents } from './helpers/ComponentEvents'; | ||
import { Component, Plugin } from './interfaces'; | ||
import { ApplicationState, Component, EventEmitterLike, Plugin } from './interfaces'; | ||
import { ComponentManager, PluginManager, PropertyManager, VariableManager } from './managers'; | ||
export interface BentoOptions { | ||
createID?(len?: number): string; | ||
eventEmitter?(): EventEmitterLike; | ||
} | ||
export interface SetProperties { | ||
[key: string]: any; | ||
} | ||
export declare class Bento { | ||
readonly components: ComponentManager; | ||
readonly plugins: PluginManager; | ||
readonly properties: PropertyManager; | ||
readonly variables: VariableManager; | ||
readonly options: BentoOptions; | ||
readonly version: string; | ||
constructor(options?: BentoOptions); | ||
/** | ||
* Runtime Application properties (static) (ex: name, version, time started) | ||
* Alias for Bento.components.addComponent() | ||
* @param component Component | ||
* | ||
* @see ComponentManager#addComponent | ||
* @returns See Bento.components.addComponent() | ||
*/ | ||
readonly properties: Map<string, any>; | ||
addComponent(component: Component): Promise<string>; | ||
/** | ||
* Runtime component variables (dynamic) | ||
* Alias for Bento.components.removeComponent() | ||
* @param name Component name | ||
* | ||
* @see ComponentManager#removeComponent | ||
* @returns See Bento.components.removeComponent() | ||
*/ | ||
readonly variables: Map<string, any>; | ||
removeComponent(name: string): Promise<void>; | ||
/** | ||
* Currently loaded validators | ||
* Alias for Bento.plugins.addPlugin() | ||
* @param plugin Plugin | ||
* | ||
* @see PluginManager#addPlugin | ||
* @returns See Bento.plugins.addPlugin() | ||
*/ | ||
readonly validators: Map<string, (value: any, ...args: any[]) => boolean>; | ||
addPlugin(plugin: Plugin): Promise<string>; | ||
/** | ||
* Currently loaded Bento plugins | ||
* Alias for Bento.plugins.removePlugin() | ||
* @param name Plugin name | ||
* | ||
* @see PluginManager#removePlugin | ||
* @returns See Bento.plugins.removePlugin() | ||
*/ | ||
readonly plugins: Map<string, Plugin>; | ||
removePlugin(name: string): Promise<void>; | ||
/** | ||
* Currently loaded components | ||
* Alias for Bento.plugins.addPlugins() | ||
* @param plugins Array of Plugins | ||
* | ||
* @see PluginManager#addPlugins | ||
* @returns See Bento.plugins.addPlugins() | ||
*/ | ||
readonly components: Map<string, Component>; | ||
private readonly componentConstructors; | ||
addPlugins(plugins: Plugin[]): Promise<string[]>; | ||
/** | ||
* Components currently pending to be loaded | ||
* Alias for Bento.properties.hasProperty() | ||
* @param name Property name | ||
* | ||
* @see PropertyManager#hasProperty | ||
* @returns See Bento.properties.hasProperty() | ||
*/ | ||
private readonly pending; | ||
hasProperty(name: string): boolean; | ||
/** | ||
* @ignore | ||
* Alias for Bento.properties.setProperty() | ||
* @param name Property name | ||
* @param value Property value | ||
* | ||
* @see PropertyManager#setProperty | ||
* @returns See Bento.properties.setProperty() | ||
*/ | ||
readonly events: Map<string, ComponentEvents>; | ||
/** | ||
* @ignore | ||
*/ | ||
readonly opts: BentoOptions; | ||
constructor(opts?: BentoOptions); | ||
/** | ||
* Generates a uniqueID | ||
* @param len - length of id | ||
*/ | ||
createID(len?: number): string; | ||
/** | ||
* Update a given application property value | ||
* @param name -name of variable to update | ||
* @param value - new value | ||
*/ | ||
setProperty(name: string, value: any): void; | ||
/** | ||
* Fetch a value for given application property | ||
* @param name - name of variable to get | ||
* Alias for Bento.properties.getProperty() | ||
* @param name Property name | ||
* | ||
* @see PropertyManager#getProperty | ||
* @returns See Bento.properties.getProperty() | ||
*/ | ||
getProperty(name: string): any; | ||
/** | ||
* Define multiple application properties at once | ||
* @param properties - SetProperties object | ||
* Alias for Bento.properties.setProperties() | ||
* @param properties Object with property key: value pairs | ||
* | ||
* @see PropertyManager#setProperties | ||
* @returns See Bento.properties.setProperties() | ||
*/ | ||
setProperties(properties: SetProperties): void; | ||
setProperties(properties: { | ||
[key: string]: any; | ||
}): void; | ||
/** | ||
* Check if a given variable exists | ||
* @param name - name of variable to get | ||
* Alias for Bento.variables.hasVariable() | ||
* @param name Variable name | ||
* | ||
* @see VariableManager#hasVariable | ||
* @returns See Bento.variables.hasVariable() | ||
*/ | ||
hasVariable(name: string): boolean; | ||
/** | ||
* Update a given variables value | ||
* @param name - name of variable to update | ||
* @param value - new value | ||
* Alias for Bento.variables.getVariable() | ||
* @param name Variable name | ||
* | ||
* @see VariableManager#getVariable | ||
* @returns See Bento.variables.getVariable() | ||
*/ | ||
setVariable(name: string, value: any): void; | ||
getVariable(name: string): any; | ||
/** | ||
* Fetch a value for given variable name | ||
* @param name - name of variable to get | ||
* Alias for Bento.variables.setVariable() | ||
* @param name Variable name | ||
* @param value Variable value | ||
* | ||
* @see VariableManager#setVariable | ||
* @returns See Bento.variables.setVariable() | ||
*/ | ||
getVariable(name: string): any; | ||
setVariable(name: string, value: any): void; | ||
/** | ||
* Fully removes all traces of a variable from bento | ||
* @param name - name of variable | ||
* Alias for Bento.variables.deleteVariable() | ||
* @param name Variable name | ||
* | ||
* @see VariableManager#deleteVariable | ||
* @returns See Bento.variables.deleteVariable() | ||
*/ | ||
deleteVariable(name: string): void; | ||
/** | ||
* Add a new validator into Bento | ||
* @param name - validator name | ||
* @param validator - validator function | ||
* Verifies the state of your Application, Will throw an error at anything | ||
* "weird" looking. For example if any components are pending when this is | ||
* called it will throw | ||
* | ||
* @returns Application state Object | ||
*/ | ||
addValidator(name: string, validator: (value: any, ...args: any[]) => boolean): void; | ||
/** | ||
* Remove validator from Bento | ||
* @param name - validator name | ||
*/ | ||
removeValidator(name: string): void; | ||
/** | ||
* Run a validator | ||
* @param name - validator name | ||
* @param args - array of args to be passed | ||
*/ | ||
runValidator(name: string, ...args: any[]): any; | ||
/** | ||
* Add a Plugin to Bento | ||
* @param plugin - plugin to add | ||
*/ | ||
addPlugin(plugin: Plugin): Promise<string>; | ||
/** | ||
* Remove a Plugin from Bento | ||
* @param name - name of plugin to remove | ||
*/ | ||
removePlugin(name: string): Promise<void>; | ||
/** | ||
* Adds plugins to Bento in order of array | ||
* @param plugins - array of plugins | ||
*/ | ||
addPlugins(plugins: Plugin[]): Promise<string[]>; | ||
private registerPlugin; | ||
resolveComponentName(component: Component | string): string; | ||
/** | ||
* Enforces Bento API and prepares component to be loaded | ||
* @param component - Component to be prepared | ||
*/ | ||
private prepareComponent; | ||
/** | ||
* Add a Component to Bento | ||
* @param component - Component | ||
*/ | ||
addComponent(component: Component): Promise<string>; | ||
/** | ||
* Remove a Component from Bento | ||
* @param name - Name of component | ||
*/ | ||
removeComponent(name: string): Promise<void>; | ||
resolveDependencies(dependencies: Component[] | string[]): string[]; | ||
private getMissingDependencies; | ||
private handlePendingComponents; | ||
private loadComponent; | ||
verify(): Promise<ApplicationState>; | ||
} |
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const crypto = require("crypto"); | ||
const events_1 = require("events"); | ||
const errors_1 = require("@ayana/errors"); | ||
const internal_1 = require("./constants/internal"); | ||
const errors_2 = require("./errors"); | ||
const ComponentAPI_1 = require("./helpers/ComponentAPI"); | ||
const ComponentEvents_1 = require("./helpers/ComponentEvents"); | ||
const managers_1 = require("./managers"); | ||
class Bento { | ||
constructor(opts) { | ||
/** | ||
* Runtime Application properties (static) (ex: name, version, time started) | ||
*/ | ||
this.properties = new Map(); | ||
/** | ||
* Runtime component variables (dynamic) | ||
*/ | ||
this.variables = new Map(); | ||
/** | ||
* Currently loaded validators | ||
*/ | ||
this.validators = new Map(); | ||
/** | ||
* Currently loaded Bento plugins | ||
*/ | ||
this.plugins = new Map(); | ||
/** | ||
* Currently loaded components | ||
*/ | ||
this.components = new Map(); | ||
this.componentConstructors = new Map(); | ||
/** | ||
* Components currently pending to be loaded | ||
*/ | ||
this.pending = new Map(); | ||
/** | ||
* @ignore | ||
*/ | ||
this.events = new Map(); | ||
this.opts = opts; | ||
constructor(options) { | ||
const { version } = require('../package.json'); | ||
this.version = version; | ||
this.options = Object.assign({}, { | ||
createID: (len = 16) => crypto.randomBytes(len).toString('base64').replace(/[^a-z0-9]/gi, '').slice(0, len), | ||
eventEmitter: () => new events_1.EventEmitter(), | ||
}, options); | ||
// now that options has been defined, create our managers | ||
this.components = new managers_1.ComponentManager(this); | ||
this.plugins = new managers_1.PluginManager(this); | ||
this.properties = new managers_1.PropertyManager(this); | ||
this.variables = new managers_1.VariableManager(this); | ||
} | ||
// COMPONENTS Aliases | ||
/** | ||
* Generates a uniqueID | ||
* @param len - length of id | ||
* Alias for Bento.components.addComponent() | ||
* @param component Component | ||
* | ||
* @see ComponentManager#addComponent | ||
* @returns See Bento.components.addComponent() | ||
*/ | ||
createID(len = 16) { | ||
return crypto.randomBytes(len) | ||
.toString('base64') | ||
.replace(/[^a-z0-9]/gi, '') | ||
.slice(0, len); | ||
async addComponent(component) { | ||
return this.components.addComponent(component); | ||
} | ||
/** | ||
* Update a given application property value | ||
* @param name -name of variable to update | ||
* @param value - new value | ||
* Alias for Bento.components.removeComponent() | ||
* @param name Component name | ||
* | ||
* @see ComponentManager#removeComponent | ||
* @returns See Bento.components.removeComponent() | ||
*/ | ||
setProperty(name, value) { | ||
if (typeof name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Property name must be a string'); | ||
this.properties.set(name, value); | ||
async removeComponent(name) { | ||
return this.components.removeComponent(name); | ||
} | ||
// PLUGINS Aliases | ||
/** | ||
* Fetch a value for given application property | ||
* @param name - name of variable to get | ||
* Alias for Bento.plugins.addPlugin() | ||
* @param plugin Plugin | ||
* | ||
* @see PluginManager#addPlugin | ||
* @returns See Bento.plugins.addPlugin() | ||
*/ | ||
getProperty(name) { | ||
if (typeof name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Property name must be a string'); | ||
if (!this.properties.has(name)) | ||
return null; | ||
return this.properties.get(name); | ||
async addPlugin(plugin) { | ||
return this.plugins.addPlugin(plugin); | ||
} | ||
/** | ||
* Define multiple application properties at once | ||
* @param properties - SetProperties object | ||
* Alias for Bento.plugins.removePlugin() | ||
* @param name Plugin name | ||
* | ||
* @see PluginManager#removePlugin | ||
* @returns See Bento.plugins.removePlugin() | ||
*/ | ||
setProperties(properties) { | ||
for (const [name, value] of Object.entries(properties)) { | ||
this.setProperty(name, value); | ||
} | ||
async removePlugin(name) { | ||
return this.plugins.removePlugin(name); | ||
} | ||
/** | ||
* Check if a given variable exists | ||
* @param name - name of variable to get | ||
* Alias for Bento.plugins.addPlugins() | ||
* @param plugins Array of Plugins | ||
* | ||
* @see PluginManager#addPlugins | ||
* @returns See Bento.plugins.addPlugins() | ||
*/ | ||
hasVariable(name) { | ||
if (typeof name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Variable name must be a string'); | ||
if (this.variables.has(name)) | ||
return true; | ||
return false; | ||
async addPlugins(plugins) { | ||
return this.plugins.addPlugins(plugins); | ||
} | ||
// PROPERTIES Aliases | ||
/** | ||
* Update a given variables value | ||
* @param name - name of variable to update | ||
* @param value - new value | ||
* Alias for Bento.properties.hasProperty() | ||
* @param name Property name | ||
* | ||
* @see PropertyManager#hasProperty | ||
* @returns See Bento.properties.hasProperty() | ||
*/ | ||
setVariable(name, value) { | ||
if (typeof name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Variable name must be a string'); | ||
if (value === undefined) | ||
return; | ||
this.variables.set(name, value); | ||
hasProperty(name) { | ||
return this.properties.hasProperty(name); | ||
} | ||
/** | ||
* Fetch a value for given variable name | ||
* @param name - name of variable to get | ||
* Alias for Bento.properties.setProperty() | ||
* @param name Property name | ||
* @param value Property value | ||
* | ||
* @see PropertyManager#setProperty | ||
* @returns See Bento.properties.setProperty() | ||
*/ | ||
getVariable(name) { | ||
if (typeof name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Variable name must be a string'); | ||
if (!this.variables.has(name)) | ||
return null; | ||
return this.variables.get(name); | ||
setProperty(name, value) { | ||
return this.properties.setProperty(name, value); | ||
} | ||
/** | ||
* Fully removes all traces of a variable from bento | ||
* @param name - name of variable | ||
* Alias for Bento.properties.getProperty() | ||
* @param name Property name | ||
* | ||
* @see PropertyManager#getProperty | ||
* @returns See Bento.properties.getProperty() | ||
*/ | ||
deleteVariable(name) { | ||
if (typeof name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Variable name must be a string'); | ||
if (this.variables.has(name)) | ||
this.variables.delete(name); | ||
getProperty(name) { | ||
return this.properties.getProperty(name); | ||
} | ||
/** | ||
* Add a new validator into Bento | ||
* @param name - validator name | ||
* @param validator - validator function | ||
* Alias for Bento.properties.setProperties() | ||
* @param properties Object with property key: value pairs | ||
* | ||
* @see PropertyManager#setProperties | ||
* @returns See Bento.properties.setProperties() | ||
*/ | ||
addValidator(name, validator) { | ||
if (typeof name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Validator name must be a string'); | ||
if (typeof validator !== 'function') | ||
throw new errors_1.IllegalArgumentError('Validator must be a function'); | ||
this.validators.set(name, validator); | ||
setProperties(properties) { | ||
return this.properties.setProperties(properties); | ||
} | ||
// VARIABLES Aliases | ||
/** | ||
* Remove validator from Bento | ||
* @param name - validator name | ||
* Alias for Bento.variables.hasVariable() | ||
* @param name Variable name | ||
* | ||
* @see VariableManager#hasVariable | ||
* @returns See Bento.variables.hasVariable() | ||
*/ | ||
removeValidator(name) { | ||
if (typeof name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Validator name must be a string'); | ||
if (!this.validators.has(name)) | ||
throw new errors_1.IllegalStateError(`Validator "${name}" does not exist`); | ||
this.validators.delete(name); | ||
hasVariable(name) { | ||
return this.variables.hasVariable(name); | ||
} | ||
/** | ||
* Run a validator | ||
* @param name - validator name | ||
* @param args - array of args to be passed | ||
* Alias for Bento.variables.getVariable() | ||
* @param name Variable name | ||
* | ||
* @see VariableManager#getVariable | ||
* @returns See Bento.variables.getVariable() | ||
*/ | ||
runValidator(name, ...args) { | ||
if (typeof name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Validator name must be a string'); | ||
if (!this.validators.has(name)) | ||
throw new errors_1.IllegalStateError(`Validator "${name}" does not exist`); | ||
const validator = this.validators.get(name); | ||
try { | ||
return validator.call(undefined, ...args); | ||
} | ||
catch (e) { | ||
throw new errors_2.ValidatorRegistrationError(name, `Validator "${name}" failed to execute`).setCause(e); | ||
} | ||
getVariable(name) { | ||
return this.variables.getVariable(name); | ||
} | ||
/** | ||
* Add a Plugin to Bento | ||
* @param plugin - plugin to add | ||
* Alias for Bento.variables.setVariable() | ||
* @param name Variable name | ||
* @param value Variable value | ||
* | ||
* @see VariableManager#setVariable | ||
* @returns See Bento.variables.setVariable() | ||
*/ | ||
async addPlugin(plugin) { | ||
if (plugin == null || typeof plugin !== 'object') | ||
throw new errors_1.IllegalArgumentError('Plugin must be a object'); | ||
if (typeof plugin.name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Plugin name must be a string'); | ||
if (!plugin.name) | ||
throw new errors_2.PluginRegistrationError(plugin, 'Plugin must specify a name'); | ||
if (this.plugins.has(plugin.name)) | ||
throw new errors_2.PluginRegistrationError(plugin, 'Plugin names must be unique'); | ||
await this.registerPlugin(plugin); | ||
return plugin.name; | ||
setVariable(name, value) { | ||
return this.variables.setVariable(name, value); | ||
} | ||
/** | ||
* Remove a Plugin from Bento | ||
* @param name - name of plugin to remove | ||
* Alias for Bento.variables.deleteVariable() | ||
* @param name Variable name | ||
* | ||
* @see VariableManager#deleteVariable | ||
* @returns See Bento.variables.deleteVariable() | ||
*/ | ||
async removePlugin(name) { | ||
if (typeof name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Plugin name must be a string'); | ||
if (!name) | ||
throw new errors_1.IllegalArgumentError('Plugin name must not be empty'); | ||
const plugin = this.plugins.get(name); | ||
if (!plugin) | ||
throw new Error(`Plugin "${name}" is not currently attached`); | ||
// call onUnload | ||
if (plugin.onUnload) { | ||
try { | ||
await plugin.onUnload(); | ||
} | ||
catch (e) { | ||
// force unload | ||
} | ||
} | ||
deleteVariable(name) { | ||
return this.variables.deleteVariable(name); | ||
} | ||
/** | ||
* Adds plugins to Bento in order of array | ||
* @param plugins - array of plugins | ||
* Verifies the state of your Application, Will throw an error at anything | ||
* "weird" looking. For example if any components are pending when this is | ||
* called it will throw | ||
* | ||
* @returns Application state Object | ||
*/ | ||
async addPlugins(plugins) { | ||
if (!Array.isArray(plugins)) | ||
throw new errors_1.IllegalArgumentError('addPlugins only accepts an array.'); | ||
const results = []; | ||
for (const plugin of plugins) { | ||
const name = await this.addPlugin(plugin); | ||
results.push(name); | ||
async verify() { | ||
// check for any pending components | ||
const pending = this.components.getPendingComponents(); | ||
if (pending.length > 0) { | ||
throw new errors_1.IllegalStateError(`One or more components are still in a pending state: '${pending.map(p => p.name).join('\', \'')}'`); | ||
} | ||
return results; | ||
const state = { components: [], plugins: [], variables: [] }; | ||
// add component names | ||
const components = this.components.getComponents(); | ||
components.forEach(c => state.components.push(c.name)); | ||
// add plugin names | ||
const plugins = this.plugins.getPlugins(); | ||
plugins.forEach(p => state.plugins.push(p.name)); | ||
// TODO: variable names | ||
// freze object | ||
Object.freeze(state); | ||
return state; | ||
} | ||
async registerPlugin(plugin) { | ||
Object.defineProperty(plugin, 'name', { | ||
configurable: true, | ||
writable: false, | ||
enumerable: true, | ||
value: plugin.name, | ||
}); | ||
// Define bento instance | ||
Object.defineProperty(plugin, 'bento', { | ||
configurable: false, | ||
writable: false, | ||
enumerable: true, | ||
value: this, | ||
}); | ||
// call onLoad | ||
if (plugin.onLoad) { | ||
await plugin.onLoad(); | ||
} | ||
this.plugins.set(plugin.name, plugin); | ||
} | ||
resolveComponentName(component) { | ||
let name = null; | ||
if (typeof component === 'string') | ||
name = component; | ||
else if (component != null) { | ||
// check if we have the constructor | ||
if (this.componentConstructors.has(component)) | ||
name = this.componentConstructors.get(component); | ||
// check if .name exists on the object | ||
else if (Object.prototype.hasOwnProperty.call(component, 'name')) | ||
name = component.name; | ||
} | ||
if (name == null) | ||
throw new Error('Could not determine component name'); | ||
return name; | ||
} | ||
/** | ||
* Enforces Bento API and prepares component to be loaded | ||
* @param component - Component to be prepared | ||
*/ | ||
prepareComponent(component) { | ||
// take control and redefine component name | ||
Object.defineProperty(component, 'name', { | ||
configurable: true, | ||
writable: false, | ||
enumerable: true, | ||
value: component.name, | ||
}); | ||
// if component has constructor lets track it | ||
if (component.constructor) { | ||
this.componentConstructors.set(component.constructor, component.name); | ||
} | ||
// Create component events if it does not already exist | ||
if (!this.events.has(component.name)) { | ||
const events = new ComponentEvents_1.ComponentEvents(component.name); | ||
this.events.set(component.name, events); | ||
} | ||
// run dependencies through the resolver | ||
component.dependencies = this.resolveDependencies(component.dependencies || []); | ||
Object.defineProperty(component, 'dependencies', { | ||
configurable: true, | ||
writable: false, | ||
enumerable: true, | ||
value: component.dependencies, | ||
}); | ||
// Create components' api | ||
const api = new ComponentAPI_1.ComponentAPI(this, component); | ||
// Define api | ||
Object.defineProperty(component, 'api', { | ||
configurable: false, | ||
writable: false, | ||
enumerable: true, | ||
value: api, | ||
}); | ||
// Add property descriptors for all the decorated variables | ||
const variables = component.constructor[internal_1.Symbols.variables]; | ||
if (Array.isArray(variables)) { | ||
for (const variable of variables) { | ||
component.api.injectVariable(Object.assign({}, variable.definition, { property: variable.propertyKey })); | ||
} | ||
} | ||
} | ||
/** | ||
* Add a Component to Bento | ||
* @param component - Component | ||
*/ | ||
async addComponent(component) { | ||
if (component == null || typeof component !== 'object') | ||
throw new errors_1.IllegalArgumentError('Component must be a object'); | ||
if (typeof component.name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Component name must be a string'); | ||
if (!component.name) | ||
throw new errors_2.ComponentRegistrationError(component, 'Components must specify a name'); | ||
if (this.components.has(component.name)) | ||
throw new errors_2.ComponentRegistrationError(component, `Component name "${component.name}" must be unique`); | ||
// Check dependencies | ||
if (component.dependencies != null && !Array.isArray(component.dependencies)) { | ||
throw new errors_2.ComponentRegistrationError(component, `"${component.name}" Component dependencies is not an array`); | ||
} | ||
else if (component.dependencies == null) | ||
component.dependencies = []; | ||
// prepare component | ||
this.prepareComponent(component); | ||
// determine dependencies | ||
const missing = this.getMissingDependencies(component.dependencies); | ||
if (missing.length === 0) { | ||
// All dependencies are already loaded, go ahead and load the component | ||
await this.loadComponent(component); | ||
// loaded successfuly, if any pending components, attempt to handle them now | ||
if (this.pending.size > 0) | ||
await this.handlePendingComponents(); | ||
} | ||
else { | ||
// not able to load this component yet :c | ||
this.pending.set(component.name, component); | ||
} | ||
return component.name; | ||
} | ||
/** | ||
* Remove a Component from Bento | ||
* @param name - Name of component | ||
*/ | ||
async removeComponent(name) { | ||
if (typeof name !== 'string') | ||
throw new errors_1.IllegalArgumentError('Name must be a string'); | ||
if (!name) | ||
throw new errors_1.IllegalArgumentError('Name must not be empty'); | ||
const component = this.components.get(name); | ||
if (!component) | ||
throw new Error(`Component '${name}' is not currently loaded.`); | ||
// TODO: check if required, required components can't be unloaded | ||
// call unMount | ||
if (component.onUnload) { | ||
try { | ||
await component.onUnload(); | ||
} | ||
catch (e) { | ||
// force unload | ||
} | ||
} | ||
// remove componentConstructor | ||
if (component.constructor && this.componentConstructors.has(component.constructor)) { | ||
this.componentConstructors.delete(component.constructor); | ||
} | ||
} | ||
resolveDependencies(dependencies) { | ||
if (!Array.isArray(dependencies)) | ||
throw new errors_1.IllegalArgumentError(`Dependencies is not an array`); | ||
const resolved = []; | ||
for (const dependency of dependencies) { | ||
try { | ||
const name = this.resolveComponentName(dependency); | ||
resolved.push(name); | ||
} | ||
catch (e) { | ||
throw new errors_1.IllegalStateError('Unable to resolve dependency').setCause(e); | ||
} | ||
} | ||
return resolved; | ||
} | ||
getMissingDependencies(dependencies) { | ||
if (!Array.isArray(dependencies)) | ||
throw new errors_1.IllegalArgumentError(`Dependencies is not an array`); | ||
// run dependencies through the resolver | ||
dependencies = this.resolveDependencies(dependencies); | ||
return dependencies.reduce((a, dependency) => { | ||
if (!this.components.has(dependency)) | ||
a.push(dependency); | ||
return a; | ||
}, []); | ||
} | ||
async handlePendingComponents() { | ||
let loaded = 0; | ||
for (const component of this.pending.values()) { | ||
const missing = await this.getMissingDependencies(component.dependencies); | ||
if (missing.length === 0) { | ||
this.pending.delete(component.name); | ||
await this.loadComponent(component); | ||
loaded++; | ||
} | ||
} | ||
if (loaded > 0) | ||
await this.handlePendingComponents(); | ||
} | ||
async loadComponent(component) { | ||
// Subscribe to all the events from the decorator subscriptions | ||
const subscriptions = component.constructor[internal_1.Symbols.subscriptions]; | ||
if (Array.isArray(subscriptions)) { | ||
for (const subscription of subscriptions) { | ||
component.api.subscribe(subscription.type, subscription.namespace, subscription.name, subscription.handler, component); | ||
} | ||
} | ||
// Call onLoad if present | ||
if (component.onLoad) { | ||
try { | ||
await component.onLoad(); | ||
} | ||
catch (e) { | ||
throw new errors_2.ComponentRegistrationError(component, `Component "${component.name}" failed loading`).setCause(e); | ||
} | ||
} | ||
this.components.set(component.name, component); | ||
} | ||
} | ||
exports.Bento = Bento; | ||
//# sourceMappingURL=Bento.js.map |
export declare class Symbols { | ||
static injections: symbol; | ||
static runtimeIdentifier: symbol; | ||
static subscriptions: symbol; | ||
static variables: symbol; | ||
static parent: symbol; | ||
static childOf: symbol; | ||
} |
@@ -5,5 +5,9 @@ 'use strict'; | ||
} | ||
Symbols.injections = Symbol('injections'); | ||
Symbols.runtimeIdentifier = Symbol('runtimeIdentifier'); | ||
Symbols.subscriptions = Symbol('subscriptions'); | ||
Symbols.variables = Symbol('variables'); | ||
Symbols.parent = Symbol('parent'); | ||
Symbols.childOf = Symbol('childOf'); | ||
exports.Symbols = Symbols; | ||
//# sourceMappingURL=Symbols.js.map |
@@ -0,2 +1,4 @@ | ||
export * from './ChildOf'; | ||
export * from './Inject'; | ||
export * from './Subscribe'; | ||
export * from './Variable'; |
@@ -6,4 +6,6 @@ 'use strict'; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./ChildOf")); | ||
__export(require("./Inject")); | ||
__export(require("./Subscribe")); | ||
__export(require("./Variable")); | ||
//# sourceMappingURL=index.js.map |
import { SubscriptionType } from '../constants'; | ||
import { Component } from '../interfaces'; | ||
export declare function Subscribe(type: SubscriptionType, namespace: Component | string, name: string): MethodDecorator; | ||
export declare function SubscribeEvent(namespace: Component | string, eventName: string): MethodDecorator; | ||
export declare function SubscribeSubject(namespace: Component | string, subjectName: string): MethodDecorator; | ||
export declare function Subscribe(type: SubscriptionType, namespace: string | Function, name: string): MethodDecorator; | ||
export declare function SubscribeEvent(namespace: string | Function, eventName: string): MethodDecorator; | ||
export declare function SubscribeSubject(namespace: string | Function, subjectName: string): MethodDecorator; |
import { VariableDefinition } from '../interfaces'; | ||
export declare function Variable(definition: VariableDefinition): PropertyDecorator; | ||
export declare function Variable(definition: VariableDefinition & { | ||
property?: never; | ||
}): PropertyDecorator; |
@@ -13,5 +13,5 @@ 'use strict'; | ||
ComponentError = __decorate([ | ||
errors_1.GlobalInstanceOf('@ayana/components', '1') | ||
errors_1.GlobalInstanceOf('@ayana/bento', '1') | ||
], ComponentError); | ||
exports.ComponentError = ComponentError; | ||
//# sourceMappingURL=ComponentError.js.map |
import { ComponentError } from './ComponentError'; | ||
export declare class ComponentLoadError extends ComponentError { | ||
readonly componentLocation: string; | ||
constructor(componentLocation: string, msg?: string); | ||
constructor(location: string, msg?: string); | ||
} |
@@ -12,13 +12,13 @@ 'use strict'; | ||
let ComponentLoadError = class ComponentLoadError extends ComponentError_1.ComponentError { | ||
constructor(componentLocation, msg = 'Failed to load component') { | ||
if (componentLocation == null) | ||
componentLocation = 'Unknown component location'; | ||
super(`${msg}: ${componentLocation}`); | ||
this.define('componentLocation', componentLocation); | ||
constructor(location, msg = 'Failed to load component') { | ||
if (location == null) | ||
location = 'Unknown component location'; | ||
super(msg); | ||
this.define('location', location); | ||
} | ||
}; | ||
ComponentLoadError = __decorate([ | ||
errors_1.GlobalInstanceOf('@ayana/components', '1') | ||
errors_1.GlobalInstanceOf('@ayana/bento', '1') | ||
], ComponentLoadError); | ||
exports.ComponentLoadError = ComponentLoadError; | ||
//# sourceMappingURL=ComponentLoadError.js.map |
@@ -18,5 +18,5 @@ 'use strict'; | ||
ComponentRegistrationError = __decorate([ | ||
errors_1.GlobalInstanceOf('@ayana/components', '1') | ||
errors_1.GlobalInstanceOf('@ayana/bento', '1') | ||
], ComponentRegistrationError); | ||
exports.ComponentRegistrationError = ComponentRegistrationError; | ||
//# sourceMappingURL=ComponentRegistrationError.js.map |
export * from './ComponentLoadError'; | ||
export * from './ComponentRegistrationError'; | ||
export * from './PluginRegistrationError'; | ||
export * from './VariableProcessError'; | ||
export * from './VariableProcessingError'; | ||
export * from './ValidatorRegistrationError'; |
@@ -9,4 +9,4 @@ 'use strict'; | ||
__export(require("./PluginRegistrationError")); | ||
__export(require("./VariableProcessError")); | ||
__export(require("./VariableProcessingError")); | ||
__export(require("./ValidatorRegistrationError")); | ||
//# sourceMappingURL=index.js.map |
@@ -13,5 +13,5 @@ 'use strict'; | ||
PluginError = __decorate([ | ||
errors_1.GlobalInstanceOf('@ayana/components', '1') | ||
errors_1.GlobalInstanceOf('@ayana/bento', '1') | ||
], PluginError); | ||
exports.PluginError = PluginError; | ||
//# sourceMappingURL=PluginError.js.map |
@@ -18,5 +18,5 @@ 'use strict'; | ||
PluginRegistrationError = __decorate([ | ||
errors_1.GlobalInstanceOf('@ayana/components', '1') | ||
errors_1.GlobalInstanceOf('@ayana/bento', '1') | ||
], PluginRegistrationError); | ||
exports.PluginRegistrationError = PluginRegistrationError; | ||
//# sourceMappingURL=PluginRegistrationError.js.map |
@@ -17,5 +17,5 @@ 'use strict'; | ||
ValidatorRegistrationError = __decorate([ | ||
errors_1.GlobalInstanceOf('@ayana/components', '1') | ||
errors_1.GlobalInstanceOf('@ayana/bento', '1') | ||
], ValidatorRegistrationError); | ||
exports.ValidatorRegistrationError = ValidatorRegistrationError; | ||
//# sourceMappingURL=ValidatorRegistrationError.js.map |
@@ -5,3 +5,3 @@ /// <reference types="node" /> | ||
import { SubscriptionType } from '../constants'; | ||
import { Component, VariableDefinition } from '../interfaces'; | ||
import { Component, Plugin, VariableDefinition } from '../interfaces'; | ||
/** | ||
@@ -25,44 +25,67 @@ * The gateway of a component to the rest of the application. | ||
/** | ||
* Fetch the value of given application property | ||
* @param name - name of application property | ||
* Fetch the provided component instance | ||
* | ||
* @param reference Component name or reference | ||
* | ||
* @returns Component instance | ||
*/ | ||
getProperty(name: string): any; | ||
getComponent<T extends Component>(reference: Component | Function | string): T; | ||
/** | ||
* Define multiple variables at once | ||
* @param definitions - Array of definitions | ||
* Inject component dependency into invoking component | ||
* @param reference Component name or reference | ||
* @param injectName name to inject into | ||
*/ | ||
injectVariables(definitions: VariableDefinition[]): void; | ||
injectComponent(reference: Component | Function | string, injectName: string): void; | ||
/** | ||
* Defines and attaches a variable to component | ||
* @param definition - The definition of the variable to define | ||
* Invokes a plugins loadComponents method. Allowing for easy loading of peer/children components | ||
* @param reference Plugin name or reference | ||
* @param args Arguments to be passed to Plugin.loadComponents() method | ||
* | ||
* @returns Plugin.loadComponents() result | ||
*/ | ||
injectVariable(definition: VariableDefinition): void; | ||
loadComponents(reference: Plugin | Function | string, ...args: any[]): Promise<any>; | ||
getPlugin<T extends Plugin>(reference: Plugin | Function | string): T; | ||
/** | ||
* Check if bento has a variable or not | ||
* @param name - name of variable | ||
* Fetch the value of given application property | ||
* @param name name of application property | ||
* | ||
* @returns Property value | ||
*/ | ||
getProperty(name: string): any; | ||
/** | ||
* Check if bento has a given variable | ||
* @param name name of variable | ||
* | ||
* @returns boolean | ||
*/ | ||
hasVariable(name: string): boolean; | ||
/** | ||
* Gets the value of a variable | ||
* @param definition - Variable name or definition | ||
* @param definition Variable name or definition | ||
* | ||
* @returns Variable value | ||
*/ | ||
getVariable(definition: VariableDefinition | string): any; | ||
private getValue; | ||
/** | ||
* Fetch the provided component instance | ||
* | ||
* @param referece - Component name or reference | ||
* Define multiple variables at once | ||
* @param definitions Array of definitions | ||
*/ | ||
getComponent<T extends Component>(reference: Component | string): T; | ||
injectVariables(definitions: VariableDefinition[]): void; | ||
/** | ||
* Inject component dependency into invoking component | ||
* @param reference - Component name or reference | ||
* @param name - name to inject into | ||
* Defines and attaches a variable to component | ||
* @param definition Variable definition | ||
*/ | ||
injectComponent(reference: Component | string, injectName: string): void; | ||
injectVariable(definition: VariableDefinition): void; | ||
private getValue; | ||
/** | ||
* Emit a event on Component Events | ||
* @param eventName Name of event | ||
* @param args Ordered Array of args to emit | ||
*/ | ||
emit(eventName: string, ...args: any[]): Promise<void>; | ||
/** | ||
* Re-emits events from a standard event emitter into component events. | ||
* | ||
* @param fromEmitter - Emitter to re-emit from | ||
* @param events - Events to watch for | ||
* @param fromEmitter Emitter to re-emit from | ||
* @param events Events to watch for | ||
* | ||
@@ -74,22 +97,20 @@ * @throws IllegalStateError if the emitter on the current component wasn't initialized | ||
/** | ||
* Emit a event on Component Events | ||
* @param eventName - Name of event | ||
* @param args - Ordered Array of args to emit | ||
*/ | ||
emit(eventName: string, ...args: any[]): Promise<void>; | ||
/** | ||
* Subscribe to a Component event | ||
* @param type - Type of subscription. Normal event or Subject | ||
* @param namespace - Component Reference / Name | ||
* @param name - Name of the event | ||
* @param handler - The function to be called | ||
* @param context - Optional `this` context for above handler function | ||
* @param type Type of subscription. Normal event or Subject | ||
* @param namespace Component Reference / Name | ||
* @param name Name of the event | ||
* @param handler The function to be called | ||
* @param context Optional `this` context for above handler function | ||
* | ||
* @returns Subscription ID | ||
*/ | ||
subscribe(type: SubscriptionType, namespace: Component | string, name: string, handler: (...args: any[]) => void, context?: any): string; | ||
subscribe(type: SubscriptionType, namespace: Component | Function | string, name: string, handler: (...args: any[]) => void, context?: any): string; | ||
/** | ||
* Alias for subscribe with normal event | ||
* @param namespace - Component Reference / Name | ||
* @param eventName - Name of the event | ||
* @param handler - The function to be called | ||
* @param context - Optional `this` context for above handler function | ||
* @param namespace Component Reference / Name | ||
* @param eventName Name of the event | ||
* @param handler The function to be called | ||
* @param context Optional `this` context for above handler function | ||
* | ||
* @returns Subscription ID | ||
*/ | ||
@@ -99,6 +120,8 @@ subscribeEvent(namespace: Component | string, eventName: string, handler: (...args: any[]) => void, context?: any): string; | ||
* Alias for subscribe with subject | ||
* @param namespace - Component Reference / Name | ||
* @param eventName - Name of the event | ||
* @param handler - The function to be called | ||
* @param context - Optional `this` context for above handler function | ||
* @param namespace Component Reference / Name | ||
* @param subjectName Name of the event | ||
* @param handler The function to be called | ||
* @param context Optional `this` context for above handler function | ||
* | ||
* @returns Subscription ID | ||
*/ | ||
@@ -105,0 +128,0 @@ subscribeSubject(namespace: Component | string, subjectName: string, handler: (...args: any[]) => void, context?: any): string; |
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const errors_1 = require("@ayana/errors"); | ||
const logger_1 = require("@ayana/logger"); | ||
const logger_api_1 = require("@ayana/logger-api"); | ||
const constants_1 = require("../constants"); | ||
const interfaces_1 = require("../interfaces"); | ||
const plugins_1 = require("../plugins"); | ||
/** | ||
@@ -12,3 +13,3 @@ * Logger instance for the ComponentAPI class | ||
*/ | ||
const log = logger_1.Logger.get('ComponentAPI'); | ||
const log = logger_api_1.Logger.get('ComponentAPI'); | ||
/** | ||
@@ -30,4 +31,67 @@ * The gateway of a component to the rest of the application. | ||
/** | ||
* Fetch the provided component instance | ||
* | ||
* @param reference Component name or reference | ||
* | ||
* @returns Component instance | ||
*/ | ||
getComponent(reference) { | ||
const name = this.bento.components.resolveName(reference); | ||
const component = this.bento.components.getComponent(name); | ||
if (!component) | ||
throw new errors_1.IllegalStateError(`Component "${name}" does not exist`); | ||
return component; | ||
} | ||
/** | ||
* Inject component dependency into invoking component | ||
* @param reference Component name or reference | ||
* @param injectName name to inject into | ||
*/ | ||
injectComponent(reference, injectName) { | ||
if (this.component.hasOwnProperty(injectName)) | ||
throw new errors_1.IllegalStateError(`Component already has property "${injectName}" defined.`); | ||
const component = this.getComponent(reference); | ||
if (!component) | ||
throw new errors_1.IllegalStateError('Component not found'); | ||
Object.defineProperty(this.component, injectName, { | ||
configurable: false, | ||
enumerable: true, | ||
writable: false, | ||
value: component, | ||
}); | ||
} | ||
/** | ||
* Invokes a plugins loadComponents method. Allowing for easy loading of peer/children components | ||
* @param reference Plugin name or reference | ||
* @param args Arguments to be passed to Plugin.loadComponents() method | ||
* | ||
* @returns Plugin.loadComponents() result | ||
*/ | ||
async loadComponents(reference, ...args) { | ||
if (reference == null) | ||
reference = plugins_1.FSComponentLoader; | ||
// verify that the plugin exists in bento | ||
let plugin = null; | ||
try { | ||
plugin = this.getPlugin(reference); | ||
} | ||
catch (e) { | ||
throw new errors_1.IllegalStateError(`Failed to find requested component`).setCause(e); | ||
} | ||
if (typeof plugin.loadComponents !== 'function') | ||
throw new errors_1.IllegalStateError(`Plugin "${plugin.name}" does not define loadComponents method`); | ||
return plugin.loadComponents(...args); | ||
} | ||
getPlugin(reference) { | ||
const name = this.bento.plugins.resolveName(reference); | ||
const plugin = this.bento.plugins.getPlugin(name); | ||
if (!plugin) | ||
throw new errors_1.IllegalStateError(`Plugin "${name}" does not exist`); | ||
return plugin; | ||
} | ||
/** | ||
* Fetch the value of given application property | ||
* @param name - name of application property | ||
* @param name name of application property | ||
* | ||
* @returns Property value | ||
*/ | ||
@@ -38,4 +102,38 @@ getProperty(name) { | ||
/** | ||
* Check if bento has a given variable | ||
* @param name name of variable | ||
* | ||
* @returns boolean | ||
*/ | ||
hasVariable(name) { | ||
return this.bento.variables.hasVariable(name); | ||
} | ||
/** | ||
* Gets the value of a variable | ||
* @param definition Variable name or definition | ||
* | ||
* @returns Variable value | ||
*/ | ||
getVariable(definition) { | ||
// if string, convert to basic definition | ||
if (typeof definition === 'string') { | ||
definition = { | ||
name: definition, | ||
type: interfaces_1.VariableDefinitionType.STRING, | ||
}; | ||
} | ||
if (!definition.type) | ||
definition.type = interfaces_1.VariableDefinitionType.STRING; | ||
// validate definition | ||
if (!definition.name) | ||
throw new errors_1.IllegalArgumentError('VariableDefinition must define a name'); | ||
const value = this.getValue(definition); | ||
// if undefined. then is a required variable that is not in bento | ||
if (value === undefined) | ||
throw new errors_1.IllegalStateError(`Failed to find a value for "${definition.name}" variable`); | ||
return value; | ||
} | ||
/** | ||
* Define multiple variables at once | ||
* @param definitions - Array of definitions | ||
* @param definitions Array of definitions | ||
*/ | ||
@@ -51,3 +149,3 @@ injectVariables(definitions) { | ||
* Defines and attaches a variable to component | ||
* @param definition - The definition of the variable to define | ||
* @param definition Variable definition | ||
*/ | ||
@@ -57,4 +155,6 @@ injectVariable(definition) { | ||
throw new errors_1.IllegalArgumentError('A VariableDefinition must define a name'); | ||
if (!definition.type) | ||
definition.type = interfaces_1.VariableDefinitionType.STRING; | ||
// if variable not in bento, and no default defined. Throw an error | ||
if (!this.bento.hasVariable(definition.name) && definition.default === undefined) { | ||
if (!this.bento.variables.hasVariable(definition.name) && definition.default === undefined) { | ||
throw new errors_1.IllegalStateError(`Cannot inject undefined variable "${definition.name}"`); | ||
@@ -70,3 +170,3 @@ } | ||
set: function () { | ||
// TODO Change to IllegalAccessError | ||
// TODO: Change to IllegalAccessError | ||
throw new Error(`Cannot set injected variable "${definition.name}"`); | ||
@@ -76,35 +176,8 @@ } | ||
} | ||
/** | ||
* Check if bento has a variable or not | ||
* @param name - name of variable | ||
*/ | ||
hasVariable(name) { | ||
return this.bento.hasVariable(name); | ||
} | ||
/** | ||
* Gets the value of a variable | ||
* @param definition - Variable name or definition | ||
*/ | ||
getVariable(definition) { | ||
// if string, convert to basic definition | ||
if (typeof definition === 'string') { | ||
definition = { | ||
name: definition, | ||
type: interfaces_1.VariableDefinitionType.STRING, | ||
}; | ||
} | ||
// validate definition | ||
if (!definition.name) | ||
throw new errors_1.IllegalArgumentError('VariableDefinition must define a name'); | ||
const value = this.getValue(definition); | ||
// if undefined. then is a required variable that is not in bento | ||
if (value === undefined) | ||
throw new errors_1.IllegalStateError(`Failed to find a value for "${definition.name}" variable`); | ||
return value; | ||
} | ||
getValue(definition) { | ||
// tslint:disable-next-line:no-unnecessary-initializer | ||
let value = undefined; | ||
// get latest | ||
if (this.bento.hasVariable(definition.name)) { | ||
value = this.bento.getVariable(definition.name); | ||
if (this.bento.variables.hasVariable(definition.name)) { | ||
value = this.bento.variables.getVariable(definition.name); | ||
} | ||
@@ -117,2 +190,4 @@ // if undefined and have default set now | ||
// Verifies that value matches definition type | ||
if (!definition.type) | ||
definition.type = interfaces_1.VariableDefinitionType.STRING; | ||
switch (definition.type) { | ||
@@ -122,3 +197,3 @@ case interfaces_1.VariableDefinitionType.NUMBER: | ||
case interfaces_1.VariableDefinitionType.BOOLEAN: { | ||
if (typeof value !== definition.type) | ||
if (value !== null && typeof value !== definition.type) | ||
throw new errors_1.IllegalStateError('Found value does not match definition type'); | ||
@@ -139,3 +214,2 @@ break; | ||
throw new errors_1.IllegalStateError('VariableDefinition specified an unknown type'); | ||
break; | ||
} | ||
@@ -147,38 +221,18 @@ } | ||
/** | ||
* Fetch the provided component instance | ||
* | ||
* @param referece - Component name or reference | ||
* Emit a event on Component Events | ||
* @param eventName Name of event | ||
* @param args Ordered Array of args to emit | ||
*/ | ||
getComponent(reference) { | ||
const name = this.bento.resolveComponentName(reference); | ||
const component = this.bento.components.get(name); | ||
if (!component) | ||
return null; | ||
return component; | ||
async emit(eventName, ...args) { | ||
const emitter = this.bento.components.getComponentEvents(this.component.name); | ||
if (emitter == null) | ||
throw new errors_1.IllegalStateError('PANIC! Something really bad has happened. Component emitter does not exist?'); | ||
emitter.emit(eventName, ...args); | ||
} | ||
/** | ||
* Inject component dependency into invoking component | ||
* @param reference - Component name or reference | ||
* @param name - name to inject into | ||
*/ | ||
injectComponent(reference, injectName) { | ||
if (this.component.hasOwnProperty(injectName)) | ||
throw new errors_1.IllegalStateError(`Component already has property "${injectName}" defined.`); | ||
const component = this.getComponent(reference); | ||
if (!component) | ||
throw new errors_1.IllegalStateError('Component not found'); | ||
Object.defineProperty(this.component, injectName, { | ||
configurable: false, | ||
enumerable: true, | ||
writable: false, | ||
value: component, | ||
}); | ||
} | ||
// TODO: Add a error handler | ||
// TODO: Consider name and maybe change it | ||
/** | ||
* Re-emits events from a standard event emitter into component events. | ||
* | ||
* @param fromEmitter - Emitter to re-emit from | ||
* @param events - Events to watch for | ||
* @param fromEmitter Emitter to re-emit from | ||
* @param events Events to watch for | ||
* | ||
@@ -189,3 +243,3 @@ * @throws IllegalStateError if the emitter on the current component wasn't initialized | ||
forwardEvents(fromEmitter, events) { | ||
const emitter = this.bento.events.get(this.component.name); | ||
const emitter = this.bento.components.getComponentEvents(this.component.name); | ||
if (emitter == null) | ||
@@ -208,24 +262,16 @@ throw new errors_1.IllegalStateError('PANIC! Something really bad has happened. Component emitter does not exist?'); | ||
/** | ||
* Emit a event on Component Events | ||
* @param eventName - Name of event | ||
* @param args - Ordered Array of args to emit | ||
*/ | ||
async emit(eventName, ...args) { | ||
const emitter = this.bento.events.get(this.component.name); | ||
if (emitter == null) | ||
throw new errors_1.IllegalStateError('PANIC! Something really bad has happened. Component emitter does not exist?'); | ||
emitter.emit(eventName, ...args); | ||
} | ||
/** | ||
* Subscribe to a Component event | ||
* @param type - Type of subscription. Normal event or Subject | ||
* @param namespace - Component Reference / Name | ||
* @param name - Name of the event | ||
* @param handler - The function to be called | ||
* @param context - Optional `this` context for above handler function | ||
* @param type Type of subscription. Normal event or Subject | ||
* @param namespace Component Reference / Name | ||
* @param name Name of the event | ||
* @param handler The function to be called | ||
* @param context Optional `this` context for above handler function | ||
* | ||
* @returns Subscription ID | ||
*/ | ||
// tslint:disable-next-line:max-params | ||
subscribe(type, namespace, name, handler, context) { | ||
const componentName = this.bento.resolveComponentName(namespace); | ||
const componentName = this.bento.components.resolveName(namespace); | ||
// Get the namespace | ||
const events = this.bento.events.get(componentName); | ||
const events = this.bento.components.getComponentEvents(componentName); | ||
if (events == null) | ||
@@ -235,3 +281,3 @@ throw new errors_1.IllegalArgumentError(`Component Events "${componentName}" does not exist`); | ||
// Register subscription so if the current component unloads we can remove all events | ||
// TODO If the componentName component unloads we need to remove that array | ||
// TODO: If the componentName component unloads we need to remove that array | ||
if (!this.subscriptions.has(componentName)) | ||
@@ -244,6 +290,8 @@ this.subscriptions.set(componentName, []); | ||
* Alias for subscribe with normal event | ||
* @param namespace - Component Reference / Name | ||
* @param eventName - Name of the event | ||
* @param handler - The function to be called | ||
* @param context - Optional `this` context for above handler function | ||
* @param namespace Component Reference / Name | ||
* @param eventName Name of the event | ||
* @param handler The function to be called | ||
* @param context Optional `this` context for above handler function | ||
* | ||
* @returns Subscription ID | ||
*/ | ||
@@ -255,6 +303,8 @@ subscribeEvent(namespace, eventName, handler, context) { | ||
* Alias for subscribe with subject | ||
* @param namespace - Component Reference / Name | ||
* @param eventName - Name of the event | ||
* @param handler - The function to be called | ||
* @param context - Optional `this` context for above handler function | ||
* @param namespace Component Reference / Name | ||
* @param subjectName Name of the event | ||
* @param handler The function to be called | ||
* @param context Optional `this` context for above handler function | ||
* | ||
* @returns Subscription ID | ||
*/ | ||
@@ -270,5 +320,5 @@ subscribeSubject(namespace, subjectName, handler, context) { | ||
unsubscribe(namespace, subID) { | ||
const componentName = this.bento.resolveComponentName(namespace); | ||
const componentName = this.bento.components.resolveName(namespace); | ||
// Check if the component events exists | ||
const events = this.bento.events.get(componentName); | ||
const events = this.bento.components.getComponentEvents(componentName); | ||
if (events == null) { | ||
@@ -295,5 +345,5 @@ log.warn(`Could not find events for namespace "${componentName}" while trying to unsubscribe`, this.component.name); | ||
if (namespace != null) { | ||
const componentName = this.bento.resolveComponentName(namespace); | ||
const componentName = this.bento.components.resolveName(namespace); | ||
// Get the namespace events | ||
const events = this.bento.events.get(componentName); | ||
const events = this.bento.components.getComponentEvents(componentName); | ||
if (events == null) { | ||
@@ -300,0 +350,0 @@ log.warn(`Could not find events for namespace "${componentName}" while trying to unsubscribe`, this.component.name); |
@@ -0,1 +1,2 @@ | ||
import { BentoOptions } from '../Bento'; | ||
import { SubscriptionType } from '../constants'; | ||
@@ -8,4 +9,4 @@ export declare class ComponentEvents { | ||
private subscribers; | ||
constructor(name: string); | ||
private createID; | ||
private options; | ||
constructor(name: string, options: BentoOptions); | ||
getSubject(name: string): any; | ||
@@ -12,0 +13,0 @@ updateSubject(name: string, value: any): void; |
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const crypto = require("crypto"); | ||
const EventEmitter = require("eventemitter3"); | ||
const errors_1 = require("@ayana/errors"); | ||
const logger_1 = require("@ayana/logger"); | ||
const constants_1 = require("../constants"); | ||
const logger_api_1 = require("@ayana/logger-api"); | ||
/** | ||
* @ignore | ||
*/ | ||
const log = logger_1.Logger.get('ComponentEvents'); | ||
const log = logger_api_1.Logger.get('ComponentEvents'); | ||
class ComponentEvents { | ||
constructor(name) { | ||
this.name = name; | ||
this.emitter = new EventEmitter(); | ||
this.subjectEmitter = new EventEmitter(); | ||
constructor(name, options) { | ||
this.subjects = new Map(); | ||
this.subscribers = new Map(); | ||
this.name = name; | ||
this.options = options; | ||
this.emitter = this.options.eventEmitter(); | ||
this.subjectEmitter = this.options.eventEmitter(); | ||
// prevent throwing of 'error' events | ||
this.emitter.addListener('error', () => { }); | ||
this.subjectEmitter.addListener('error', () => { }); | ||
} | ||
createID(len = 16) { | ||
return crypto.randomBytes(len) | ||
.toString('base64') | ||
.replace(/[^a-z0-9]/gi, '') | ||
.slice(0, len); | ||
} | ||
getSubject(name) { | ||
@@ -44,6 +40,5 @@ return this.subjects.get(name); | ||
subscribe(type, name, handler, context) { | ||
const subID = this.createID(); | ||
const subscriber = function () { | ||
handler.apply(this, arguments); | ||
}; | ||
const subID = this.options.createID(); | ||
// wrap handler | ||
const subscriber = (...args) => handler.apply(context, args); | ||
this.subscribers.set(subID, { | ||
@@ -55,3 +50,3 @@ handler: subscriber, | ||
if (type === constants_1.SubscriptionType.SUBJECT) { | ||
this.subjectEmitter.on(name, subscriber, context); | ||
this.subjectEmitter.addListener(name, subscriber); | ||
// Instantly call the subscriber with the current state if there is one | ||
@@ -63,3 +58,3 @@ if (this.subjects.has(name)) { | ||
else if (type === constants_1.SubscriptionType.EVENT) { | ||
this.emitter.on(name, subscriber, context); | ||
this.emitter.addListener(name, subscriber); | ||
} | ||
@@ -66,0 +61,0 @@ else { |
import { ConfigDefinition, ConfigDefinitionType } from '../interfaces'; | ||
export interface ConfigValueSource { | ||
export interface ConfigBuilderDefinition { | ||
type: ConfigDefinitionType; | ||
env?: string; | ||
@@ -9,5 +10,5 @@ file?: string; | ||
private definitions; | ||
add(type: ConfigDefinitionType, name: string, values: ConfigValueSource): void; | ||
delete(name: string): void; | ||
add(name: string, item: ConfigBuilderDefinition): this; | ||
delete(name: string): this; | ||
build(): ConfigDefinition[]; | ||
} |
@@ -9,9 +9,11 @@ 'use strict'; | ||
} | ||
add(type, name, values) { | ||
if (Object.values(interfaces_1.ConfigDefinitionType).indexOf(type) === -1) | ||
throw new errors_1.IllegalArgumentError(`Unknown type "${type}"`); | ||
if (typeof name !== 'string' || name == null) | ||
add(name, item) { | ||
if (typeof name !== 'string' || name === '') | ||
throw new errors_1.IllegalArgumentError(`Name must be a string`); | ||
const hasOne = ['env', 'file', 'value'].reduce((a, item) => { | ||
if (Object.prototype.hasOwnProperty.call(values, item)) | ||
if (item == null || typeof item !== 'object') | ||
throw new errors_1.IllegalArgumentError(`Item must be a object`); | ||
if (item.type == null && Object.values(interfaces_1.ConfigDefinitionType).indexOf(item.type) === -1) | ||
throw new errors_1.IllegalArgumentError(`Invalid type "${item.type}"`); | ||
const hasOne = ['env', 'file', 'value'].reduce((a, i) => { | ||
if (Object.prototype.hasOwnProperty.call(item, i)) | ||
a.push(item); | ||
@@ -21,12 +23,14 @@ return a; | ||
if (!hasOne) | ||
throw new errors_1.IllegalArgumentError('ConfigValueSource must define at least one source. env, file, or value'); | ||
const definition = Object.assign({}, { type, name }, values); | ||
throw new errors_1.IllegalArgumentError('Definition must specify one or more sources: env, file, or value'); | ||
const definition = Object.assign({}, { name }, item); | ||
this.definitions.set(name, definition); | ||
return this; | ||
} | ||
delete(name) { | ||
if (typeof name !== 'string' || name == null) | ||
if (typeof name !== 'string' || name === '') | ||
throw new errors_1.IllegalArgumentError(`Name must be a string`); | ||
if (!this.definitions.has(name)) | ||
throw new errors_1.IllegalStateError(`ConfigDefition "${name}" does not exist`); | ||
throw new errors_1.IllegalStateError(`Definition "${name}" does not exist`); | ||
this.definitions.delete(name); | ||
return this; | ||
} | ||
@@ -33,0 +37,0 @@ build() { |
export * from './ComponentAPI'; | ||
export * from './ComponentEvents'; | ||
export * from './ConfigBuilder'; |
@@ -7,3 +7,4 @@ 'use strict'; | ||
__export(require("./ComponentAPI")); | ||
__export(require("./ComponentEvents")); | ||
__export(require("./ConfigBuilder")); | ||
//# sourceMappingURL=index.js.map |
import { ComponentAPI } from '../helpers'; | ||
import { Plugin } from './Plugin'; | ||
import { VariableDefinition } from './VariableDefinition'; | ||
@@ -7,6 +8,10 @@ export interface Component { | ||
version?: string; | ||
dependencies?: Component[] | string[]; | ||
variables?: VariableDefinition[]; | ||
onLoad?(): Promise<void>; | ||
parent?: Component | string; | ||
plugins?: Array<Function | Plugin | string>; | ||
dependencies?: Array<Function | Component | string>; | ||
variables?: Array<VariableDefinition>; | ||
onLoad?(api?: ComponentAPI): Promise<void>; | ||
onUnload?(): Promise<void>; | ||
onChildLoad?(child: Component): Promise<void>; | ||
onChildUnload?(child: Component): Promise<void>; | ||
} |
@@ -1,2 +0,7 @@ | ||
import { ConfigDefinitionType } from './ConfigDefinitionType'; | ||
export declare enum ConfigDefinitionType { | ||
STRING = "string", | ||
NUMBER = "number", | ||
BOOLEAN = "boolean", | ||
LIST = "list" | ||
} | ||
export interface ConfigDefinition { | ||
@@ -3,0 +8,0 @@ type: ConfigDefinitionType; |
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var ConfigDefinitionType; | ||
(function (ConfigDefinitionType) { | ||
ConfigDefinitionType["STRING"] = "string"; | ||
ConfigDefinitionType["NUMBER"] = "number"; | ||
ConfigDefinitionType["BOOLEAN"] = "boolean"; | ||
ConfigDefinitionType["LIST"] = "list"; | ||
})(ConfigDefinitionType = exports.ConfigDefinitionType || (exports.ConfigDefinitionType = {})); | ||
//# sourceMappingURL=ConfigDefinition.js.map |
@@ -0,7 +1,8 @@ | ||
export * from './Component'; | ||
export * from './Plugin'; | ||
export * from './Component'; | ||
export * from './ApplicationState'; | ||
export * from './ConfigDefinition'; | ||
export * from './ConfigDefinitionType'; | ||
export * from './EventEmitterLike'; | ||
export * from './PendingComponentData'; | ||
export * from './VariableDefinition'; | ||
export * from './VariableDefinitionType'; | ||
export * from './VariableDefinitionValidator'; | ||
export * from './VariableSource'; |
@@ -6,4 +6,5 @@ 'use strict'; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./ConfigDefinitionType")); | ||
__export(require("./VariableDefinitionType")); | ||
__export(require("./ConfigDefinition")); | ||
__export(require("./VariableDefinition")); | ||
__export(require("./VariableSource")); | ||
//# sourceMappingURL=index.js.map |
import { SubscriptionType } from '../../constants'; | ||
import { Component } from '../Component'; | ||
export interface DecoratorSubscription { | ||
type: SubscriptionType; | ||
namespace: Component | string; | ||
namespace: string | Function; | ||
name: string; | ||
handler: (...args: any[]) => void; | ||
} |
@@ -0,1 +1,2 @@ | ||
export * from './DecoratorInjection'; | ||
export * from './DecoratorSubscription'; | ||
@@ -2,0 +3,0 @@ export * from './DecoratorVariable'; |
@@ -9,4 +9,4 @@ import { Bento } from '../Bento'; | ||
version?: string; | ||
onLoad?(): Promise<void>; | ||
onLoad?(bento?: Bento): Promise<void>; | ||
onUnload?(): Promise<void>; | ||
} |
@@ -1,9 +0,14 @@ | ||
import { VariableDefinitionType } from './VariableDefinitionType'; | ||
import { VariableDefinitionValidator } from './VariableDefinitionValidator'; | ||
export declare enum VariableDefinitionType { | ||
STRING = "string", | ||
NUMBER = "number", | ||
BOOLEAN = "boolean", | ||
ARRAY = "array", | ||
OBJECT = "object" | ||
} | ||
export interface VariableDefinition { | ||
type?: VariableDefinitionType; | ||
name: string; | ||
property?: string; | ||
type?: VariableDefinitionType; | ||
default?: any; | ||
validator?: VariableDefinitionValidator; | ||
validator?: string; | ||
} |
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var VariableDefinitionType; | ||
(function (VariableDefinitionType) { | ||
VariableDefinitionType["STRING"] = "string"; | ||
VariableDefinitionType["NUMBER"] = "number"; | ||
VariableDefinitionType["BOOLEAN"] = "boolean"; | ||
VariableDefinitionType["ARRAY"] = "array"; | ||
VariableDefinitionType["OBJECT"] = "object"; | ||
})(VariableDefinitionType = exports.VariableDefinitionType || (exports.VariableDefinitionType = {})); | ||
//# sourceMappingURL=VariableDefinition.js.map |
/// <reference types="node" /> | ||
import { Bento } from '../../Bento'; | ||
import { ConfigLoader } from './ConfigLoader'; | ||
export declare class ConfigFileLoader extends ConfigLoader { | ||
bento: Bento; | ||
name: string; | ||
private files; | ||
onLoad(): Promise<void>; | ||
addFile(...file: string[]): void; | ||
/** | ||
* Add file and | ||
* @param file - Path to file | ||
*/ | ||
addFile(...file: Array<string>): void; | ||
removeFile(...file: string[]): void; | ||
@@ -8,0 +15,0 @@ getFileContents(file: string): Promise<Buffer>; |
@@ -19,3 +19,4 @@ 'use strict'; | ||
super(...arguments); | ||
this.files = []; | ||
this.name = 'ConfigFileLoader'; | ||
this.files = new Set(); | ||
} | ||
@@ -25,13 +26,15 @@ async onLoad() { | ||
} | ||
/** | ||
* Add file and | ||
* @param file - Path to file | ||
*/ | ||
addFile(...file) { | ||
const absolute = path.resolve(...file); | ||
this.files.push(absolute); | ||
this.files.add(absolute); | ||
} | ||
removeFile(...file) { | ||
const absolute = path.resolve(...file); | ||
this.files.push(absolute); | ||
const index = this.files.indexOf(absolute); | ||
if (index === -1) | ||
return; | ||
this.files.splice(index, 1); | ||
this.files.add(absolute); | ||
if (this.files.has(absolute)) | ||
this.files.delete(absolute); | ||
} | ||
@@ -38,0 +41,0 @@ async getFileContents(file) { |
@@ -17,2 +17,4 @@ import { Bento } from '../../Bento'; | ||
* @param reload - auto reload config values into betno? | ||
* | ||
* @returns Definition name | ||
*/ | ||
@@ -19,0 +21,0 @@ addDefinition(definition: ConfigLoaderDefinition, reload?: boolean): Promise<string>; |
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const errors_1 = require("@ayana/errors"); | ||
const interfaces_1 = require("../../interfaces"); | ||
class ConfigLoader { | ||
@@ -19,2 +20,4 @@ constructor() { | ||
* @param reload - auto reload config values into betno? | ||
* | ||
* @returns Definition name | ||
*/ | ||
@@ -66,3 +69,9 @@ async addDefinition(definition, reload = true) { | ||
const value = await this.getValue(definition); | ||
this.bento.setVariable(definition.name, value); | ||
// define source | ||
const source = { type: interfaces_1.VariableSourceType.INLINE }; | ||
if (definition.env != null) { | ||
source.type = interfaces_1.VariableSourceType.ENV; | ||
source.source = definition.env; | ||
} | ||
this.bento.variables.setVariable(definition.name, value, source); | ||
} | ||
@@ -73,2 +82,3 @@ } | ||
throw new errors_1.IllegalArgumentError('Definition must be a object'); | ||
// tslint:disable-next-line:no-unnecessary-initializer | ||
let value = undefined; | ||
@@ -75,0 +85,0 @@ // inline value defined |
export * from './cfg'; | ||
export * from './components'; | ||
export * from './loaders'; |
@@ -7,3 +7,3 @@ 'use strict'; | ||
__export(require("./cfg")); | ||
__export(require("./components")); | ||
__export(require("./loaders")); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@ayana/bento", | ||
"version": "1.0.0-alpha9", | ||
"version": "1.0.0-beta.1", | ||
"description": "Modular runtime framework designed to solve complex tasks", | ||
"repository": "https://gitlab.com/ayana/bento", | ||
"repository": "https://gitlab.com/ayana/libs/bento", | ||
"author": "Ayana Developers <devs@ayana.io>", | ||
@@ -12,6 +12,7 @@ "contributors": [ | ||
"main": "build/index.js", | ||
"types": "build/index.d.ts", | ||
"scripts": { | ||
"start": "node build/index.js", | ||
"build": "rm -rf build/ && tsc", | ||
"prepublishOnly": "rm -rf build/ && tsc && nyc mocha", | ||
"prepublishOnly": "rm -rf build/ && tsc", | ||
"test": "rm -rf build && tsc && mocha", | ||
@@ -22,14 +23,10 @@ "testcoverage": "rm -rf build && tsc && nyc mocha" | ||
"@ayana/errors": "^0.0.4", | ||
"@ayana/logger": "^1.1.0", | ||
"eventemitter3": "^3.1.0" | ||
"@ayana/logger-api": "^2.0.0" | ||
}, | ||
"devDependencies": { | ||
"@ayana/eslint-config": "^1.0.3", | ||
"@types/node": "^10.12.12", | ||
"eslint": "^5.9.0", | ||
"mocha": "^5.2.0", | ||
"nyc": "^13.1.0", | ||
"tslint": "^5.11.0", | ||
"tslint-config-xo": "^1.4.0", | ||
"typescript": "^3.2.1" | ||
"@ayana/test": "^1.0.1", | ||
"@ayana/tslint-config": "^1.0.0", | ||
"@types/node": "^10.12.24", | ||
"tslint": "^5.12.1", | ||
"typescript": "^3.3.3" | ||
}, | ||
@@ -36,0 +33,0 @@ "license": "MIT", |
# Bento [![npm (scoped)](https://img.shields.io/npm/v/@ayana/bento.svg)](https://www.npmjs.com/package/@ayana/bento) [![Discord](https://discordapp.com/api/guilds/508903834853310474/embed.png)](https://discord.gg/eaa5pYf) [![install size](https://packagephobia.now.sh/badge?p=@ayana/bento)](https://packagephobia.now.sh/result?p=@ayana/bento) | ||
[Documentation](https://docs.ayana.io/modules/bento.html) | ||
[Documentation](https://docs.ayana.io/modules/bento.html) • [Examples](https://gitlab.com/ayana/libs/bento/tree/master/examples) | ||
Bento is a NodeJS framework designed to make creating and maintaing complex projects a simple and fast process. | ||
Bento is a robust NodeJS application framework designed to make creating and maintaing complex projects a simple and fast process. | ||
### What does Bento do: | ||
## What does Bento do: | ||
* Robust plugable application framework. | ||
* Featuring: Components, Events, Plugins, Properties, Variables | ||
* Component lifecycle state and management | ||
* Provides consistent API for all components | ||
* Config Loading API | ||
* Event API | ||
* Consistent Component API | ||
* Defines strict, opinionated, rules | ||
### What is a Bento Component? | ||
## What is a Bento Component? | ||
Bento indroduces a concept of components. Components are logical chunks of code that all work together to provide your application to the world. | ||
Components should not take on more then required. (IE: instead of having one component for connecting to Discord and processing messages. Have two, one for the connection and one that handles messages) | ||
All components recieve their own ComponentAPI instance. The Component API is consistent across all components and provides a way for components to speak to eachother. As well as many other "Quality of life" features. Such as: variable injection and management, dependency management and injection, component event subscriptions, and more! | ||
### How to use Bento (IN-PROGRESS) | ||
Using bento is pretty simple. First import and initilize bento and any plugins you wish to use. Then simply add plugins to bento | ||
As a rule of thumb, components should not take on more then required. (IE: instead of having one component for connecting to Discord and processing messages. Have two, one for the connection and emitting the message events, and one that handles messages) | ||
```js | ||
'use strict'; | ||
Here is a very basic example of a Bento component: | ||
```ts | ||
import { Component, ComponentAPI } from '@ayana/bento'; | ||
import * as path from 'path'; | ||
export class ExampleComponent { | ||
// this property becomes available after onLoad see ComponentAPI for more info | ||
public api: ComponentAPI; | ||
// required for all components, must be unique | ||
public name: string = 'ExampleComponent'; | ||
// Optionally define other components we depend upon | ||
// Some decorators auto append to this array such as @SubscribeEvent | ||
public dependencies: Array<Component> = []; | ||
// Lifecycle event, called right before component fully loaded | ||
public async onLoad() { | ||
console.log('Hello world!'); | ||
} | ||
// Lifecycle event, called right before component is unloaded | ||
public async onUnload() { | ||
console.log('Goodbye world!'); | ||
} | ||
} | ||
``` | ||
A runnable version of this example is available on [Gitlab](https://gitlab.com/ayana/libs/bento/tree/master/examples/src/bento-basic) | ||
## How to use Bento (IN-PROGRESS) | ||
Using Bento is pretty simple. First import and initilize Bento and any plugins you wish to use. Then simply add the plugins to Bento. The below example assumes you have a directory called "components" in the same directory (relative) to it. | ||
```ts | ||
import { Bento, FSComponentLoader } from '@ayana/bento'; | ||
@@ -32,15 +58,22 @@ | ||
// Create FSComponentLoader | ||
// NOTE: Keep in mind all FSComponentLoader does is find Bento components in the path provided | ||
// Instantiates them and calls bento.addComponent | ||
// Behind the scenes | ||
const loader = new FSComponentLoader({ | ||
directories: [path.resolve(__dirname, 'modules')], | ||
// Anonymous async function so we can use await | ||
(async () => { | ||
// Create FSComponentLoader | ||
// NOTE: Keep in mind all FSComponentLoader does is find components in a path | ||
// Instantiates them and calls Bento.addComponent | ||
// Behind the scenes | ||
const fsloader = new FSComponentLoader(); | ||
await fsloader.addDirectory(__dirname, 'components'); | ||
// Apply plugin to Bento. | ||
await bento.addPlugin(fsloader); | ||
// Verify that Application looks good to continue | ||
await bento.verify(); | ||
})().catch(e => { | ||
console.error(`Error while starting Bento:\n${e}`); | ||
process.exit(1); | ||
}); | ||
``` | ||
// Apply plugin to Bento. | ||
// NOTE: Keep in mind that addPlugin is async and you should .catch any errors | ||
bento.addPlugin(loader).catch(e => { | ||
console.log('Sad day', e); | ||
}); | ||
``` | ||
More examples available [here](https://gitlab.com/ayana/libs/bento/tree/master/examples) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
193907
2
5
162
3415
79
1
+ Added@ayana/logger-api@^2.0.0
+ Added@ayana/logger-api@2.0.0(transitive)
- Removed@ayana/logger@^1.1.0
- Removedeventemitter3@^3.1.0
- Removed@ayana/logger@1.1.0(transitive)
- Removed@colors/colors@1.6.0(transitive)
- Removed@dabh/diagnostics@2.0.3(transitive)
- Removed@types/triple-beam@1.3.5(transitive)
- Removedasync@3.2.6(transitive)
- Removedcolor@3.2.1(transitive)
- Removedcolor-convert@1.9.3(transitive)
- Removedcolor-name@1.1.3(transitive)
- Removedcolor-string@1.9.1(transitive)
- Removedcolors@1.4.0(transitive)
- Removedcolorspace@1.1.4(transitive)
- Removedenabled@2.0.0(transitive)
- Removedeventemitter3@3.1.2(transitive)
- Removedfecha@4.2.3(transitive)
- Removedfn.name@1.1.0(transitive)
- Removedinherits@2.0.4(transitive)
- Removedis-arrayish@0.3.2(transitive)
- Removedis-stream@2.0.1(transitive)
- Removedkuler@2.0.0(transitive)
- Removedlogform@2.7.0(transitive)
- Removedms@2.1.3(transitive)
- Removedone-time@1.0.0(transitive)
- Removedreadable-stream@3.6.2(transitive)
- Removedsafe-buffer@5.2.1(transitive)
- Removedsafe-stable-stringify@2.5.0(transitive)
- Removedsimple-swizzle@0.2.2(transitive)
- Removedstack-trace@0.0.10(transitive)
- Removedstring_decoder@1.3.0(transitive)
- Removedtext-hex@1.0.0(transitive)
- Removedtriple-beam@1.4.1(transitive)
- Removedutil-deprecate@1.0.2(transitive)
- Removedwinston@3.17.0(transitive)
- Removedwinston-transport@4.9.0(transitive)