fix(commands) implement commands execution and improve error messaging

This commit is contained in:
Benjamin Wegener
2024-01-14 15:19:42 +00:00
parent 29bf68a047
commit bea825b809

View File

@@ -5,6 +5,17 @@ import CetraPlugin from '../plugins/CetraPlugin';
import BaseComponent from './BaseComponent'; import BaseComponent from './BaseComponent';
class Cetra extends Emitter { class Cetra extends Emitter {
static #ERRORS = {
INVALID_IDENTIFIER: 'INVALID_IDENTIFIER',
INVALID_ENTITY_TYPE: 'INVALID_ENTITY_TYPE',
INVALID_ENTITY: 'INVALID_ENTITY',
INVALID_ROOT: 'INVALID_ROOT',
INVALID_COMPONENT_TYPE: 'INVALID_COMPONENT_TYPE',
INVALID_PLUGIN_URL: 'INVALID_PLUGIN_URL',
INVALID_PLUGIN_TYPE: 'INVALID_PLUGIN_TYPE',
INVALID_COMMAND: 'INVALID_COMMAND',
COMMAND_NOT_FOUND: 'COMMAND_NOT_FOUND',
};
// class static globals // class static globals
static #instances = new Map(); static #instances = new Map();
static #entityTypes = { static #entityTypes = {
@@ -103,17 +114,9 @@ class Cetra extends Emitter {
} }
if (typeof this[`add${entityType}s`] === 'undefined') { if (typeof this[`add${entityType}s`] === 'undefined') {
this[`add${entityType}s`] = (entities) => { this[`add${entityType}s`] = function (entities) {
if (!Array.isArray(entities)) { if (!Array.isArray(entities))
if (typeof entities != 'string') throw new TypeError(Cetra.#ERRORS.INVALID_ENTITY_TYPE);
throw new TypeError(
`${entityType} is not of type array or string`
);
throw new TypeError(
`${entityType} is not of type array`
);
}
entities.forEach(({ identifier, _obj }) => { entities.forEach(({ identifier, _obj }) => {
this[`register${entityType}`](identifier, _obj); this[`register${entityType}`](identifier, _obj);
@@ -143,7 +146,11 @@ class Cetra extends Emitter {
*/ */
#addEntity(entityType, identifier, fn) { #addEntity(entityType, identifier, fn) {
if (typeof identifier != 'string') { if (typeof identifier != 'string') {
Logger.error(`invalid identifier for ${entityType} ${identifier}`); Logger.error(
Cetra.#ERRORS.INVALID_IDENTIFIER,
entityType,
identifier
);
return false; return false;
} }
// get entityKey by its value // get entityKey by its value
@@ -151,7 +158,7 @@ class Cetra extends Emitter {
return Cetra.#entityTypes[key] == entityType; return Cetra.#entityTypes[key] == entityType;
}); });
if (!entityKey) { if (!entityKey) {
Logger.error(`invalid entity type ${entityType}`); Logger.error(Cetra.#ERRORS.INVALID_ENTITY_TYPE, entityType);
return false; return false;
} }
@@ -163,16 +170,12 @@ class Cetra extends Emitter {
try { try {
if (typeof fn === 'undefined') { if (typeof fn === 'undefined') {
Registry.unregister(uniqueId, this.#secretKey); Registry.unregister(uniqueId, this.#secretKey);
throw new TypeError( throw new TypeError(Cetra.#ERRORS.INVALID_ENTITY);
`invalid entity constructor for ${entityType} ${identifier}`
);
} }
if (!this.#isValidEntity(entityType, fn)) { if (!this.#isValidEntity(entityType, fn)) {
Registry.unregister(uniqueId, this.#secretKey); Registry.unregister(uniqueId, this.#secretKey);
throw new TypeError( throw new TypeError(Cetra.#ERRORS.INVALID_ENTITY);
`invalid entity constructor for ${entityType} ${identifier}`
);
} }
if (typeof fn == 'function') { if (typeof fn == 'function') {
@@ -265,7 +268,7 @@ class Cetra extends Emitter {
this.#root = document.querySelector(this.#root); this.#root = document.querySelector(this.#root);
if (!this.#root) { if (!this.#root) {
Logger.error('No root found, defaulting to body'); Logger.error(Cetra.#ERRORS.INVALID_ROOT);
this.#root = document.body; this.#root = document.body;
} }
} }
@@ -314,7 +317,7 @@ class Cetra extends Emitter {
try { try {
data = JSON.parse(val); data = JSON.parse(val);
} catch (err) { } catch (err) {
//Logger.error(err); Logger.error(err);
return val; return val;
} }
@@ -339,7 +342,7 @@ class Cetra extends Emitter {
this.#internals.get('settings').get('observeOptions') this.#internals.get('settings').get('observeOptions')
); );
} catch (err) { } catch (err) {
Logger.error('an error occured with the observer!', err); Logger.error(err);
} }
} }
@@ -352,7 +355,7 @@ class Cetra extends Emitter {
*/ */
getPlugin(identifier) { getPlugin(identifier) {
if (!(identifier instanceof String)) { if (!(identifier instanceof String)) {
Logger.error('Plugin identifier is not a string'); Logger.error(Cetra.#ERRORS.INVALID_IDENTIFIER, identifier);
return undefined; return undefined;
} }
@@ -465,7 +468,8 @@ class Cetra extends Emitter {
if (typeof klass.register === 'function') { if (typeof klass.register === 'function') {
return klass.register(uid); return klass.register(uid);
} }
return klass;
throw new TypeError(Cetra.#ERRORS.INVALID_PLUGIN_TYPE);
} }
if (typeof klass === 'function') { if (typeof klass === 'function') {
@@ -478,20 +482,15 @@ class Cetra extends Emitter {
// what else could it be? // what else could it be?
if (typeof klass !== 'object') if (typeof klass !== 'object')
throw new TypeError( throw new TypeError(Cetra.#ERRORS.INVALID_PLUGIN_TYPE);
'plugin is not of a valid plugin type (`CetraPlugin` or `object` or `function` or `url`)'
);
if ( if (
klass.url && klass.url &&
(typeof klass.url !== 'string' || !this.#isUrl(klass.url)) (typeof klass.url !== 'string' || !this.#isUrl(klass.url))
) )
throw new TypeError( throw new TypeError(Cetra.#ERRORS.INVALID_PLUGIN_URL);
'plugin url is not of type string and/or no valid url'
);
if (klass.plugin) { if (klass.plugin) {
Logger.info('registering plugin 5', klass);
return this.#initPlugin(klass.plugin); return this.#initPlugin(klass.plugin);
} }
@@ -542,10 +541,8 @@ class Cetra extends Emitter {
.get('settings') .get('settings')
.get('selector')}-id]` .get('selector')}-id]`
) )
) { )
Logger.info('skipped element', comp);
continue; continue;
}
this.#initComponent(comp); this.#initComponent(comp);
} }
@@ -647,7 +644,7 @@ class Cetra extends Emitter {
comp.getAttribute(this.#internals.get('settings').get('selector')); comp.getAttribute(this.#internals.get('settings').get('selector'));
if (typeof compType == 'undefined' || !compType) { if (typeof compType == 'undefined' || !compType) {
Logger.error(`no component type given`); Logger.error(Cetra.#ERRORS.INVALID_COMPONENT_TYPE);
return null; return null;
} }
@@ -807,63 +804,58 @@ class Cetra extends Emitter {
obj: plugin, obj: plugin,
parent: this.#identifier, parent: this.#identifier,
}); });
if (!identifier) {
Logger.error('Plugin identifier is required');
Registry.unregister(uniqueId, this.#secretKey);
return;
}
if (this.#internals.get('plugins').has(identifier)) { try {
Logger.log(`Overwrite plugin ${identifier}`); if (!identifier) {
Registry.unregister(uniqueId, this.#secretKey); Logger.error(Cetra.#ERRORS.INVALID_IDENTIFIER);
Registry.register({
key: this.#secretKey,
obj: plugin,
parent: this.#identifier,
});
}
if (!plugin) {
Logger.error(
`Plugin ${identifier} is not an url or a plugin instance or class`
);
Registry.unregister(uniqueId, this.#secretKey);
return;
}
if (typeof plugin === 'string') {
if (!this.#isUrl(plugin)) {
Logger.error(`Plugin ${identifier} has an invalid url: ${url}`);
Registry.unregister(uniqueId, this.#secretKey); Registry.unregister(uniqueId, this.#secretKey);
return; return;
} }
Logger.info(`Plugin ${identifier} is loaded from ${plugin}`);
this.#internals.get('plugins').set(identifier, { if (this.#internals.get('plugins').has(identifier)) {
plugin, Registry.unregister(uniqueId, this.#secretKey);
key: uniqueId, Registry.register({
key: this.#secretKey,
obj: plugin,
parent: this.#identifier,
});
}
if (!plugin) throw new TypeError(Cetra.#ERRORS.INVALID_PLUGIN_TYPE);
if (typeof plugin === 'string') {
if (!this.#isUrl(plugin))
throw new TypeError(Cetra.#ERRORS.INVALID_PLUGIN_URL);
Logger.info(`Plugin ${identifier} is loaded from ${plugin}`);
this.#internals.get('plugins').set(identifier, {
plugin,
key: uniqueId,
parent: this.#identifier,
});
return;
}
if (!['function', 'object'].includes(typeof plugin))
throw new TypeError(Cetra.#ERRORS.INVALID_PLUGIN_TYPE);
const pluginInstance = this.#initPlugin(plugin);
if (!pluginInstance)
throw new TypeError(Cetra.#ERRORS.INVALID_PLUGIN_TYPE);
Registry.register({
obj: pluginInstance,
key: this.#secretKey,
parent: this.#identifier, parent: this.#identifier,
}); });
return;
}
if (!['function', 'object'].includes(typeof plugin)) { this.#internals.get('plugins').set(identifier, pluginInstance);
Logger.error('Plugin is not of type function or object'); this.emit('onAfterRegisterPlugin', pluginInstance);
} catch (err) {
Logger.error(err);
Registry.unregister(uniqueId, this.#secretKey); Registry.unregister(uniqueId, this.#secretKey);
return null;
} }
const pluginInstance = this.#initPlugin(plugin);
Registry.unregister(uniqueId, this.#secretKey);
if (!pluginInstance)
throw new TypeError('plugin is not of a valid plugin type');
Registry.register({
key: this.#secretKey,
obj: pluginInstance,
parent: this.#identifier,
});
this.#internals.get('plugins').set(identifier, pluginInstance);
} }
/** /**
@@ -875,26 +867,35 @@ class Cetra extends Emitter {
* @param {any} e - The event object. * @param {any} e - The event object.
* @throws {Error} If the component with the given ID is not found. * @throws {Error} If the component with the given ID is not found.
*/ */
exec(action, varName, componentId, e) { exec(componentId, update = { command, args, evt }) {
if (Array.isArray(update.args)) update.args = [];
const comp = this.#internals.get('compIndex').get(componentId); const comp = this.#internals.get('compIndex').get(componentId);
if (!comp) { if (!comp) {
throw new Error(`component ${componentId} not found`); throw new Error(`component ${componentId} not found`);
} }
if (this.#internals.get('plugins').get('utils')[action]) { if (!this.#internals.get('commands').has(update.command)) {
const value = comp.getValue(varName); Logger.error(Cetra.#ERRORS.COMMAND_NOT_FOUND, update.command);
comp.update([ return;
{
old: value,
new: this.#internals
.get('plugins')
.get('utils')
[action](comp.getValue(varName)),
varName,
},
]);
} }
this.#internals
.get('commands')
.get(update.command)
.forEach((command) => {
if (!command.exec) {
if (typeof command != 'function' || !command.name) {
Logger.error(
Cetra.#ERRORS.INVALID_COMMAND,
update.command
);
}
command(comp, update);
}
command.exec(comp, update);
});
} }
} }