@mobiusz/core
Donate
Description
@mobiusz/core
is the very root module that defines the domain for the whole Möb:üsz ecosystem to work with.
@mobiusz/core
provides basic types, entities, abstract classes and helpers to be used or extended elsewhere (e.g. in other framework's namespaces: @mobiusz
, @vuoz
, @pipeline
and @mmmap
). As other mobiusz modules, @mobiusz/core
tends to be agnostic, that is: it can be used in any dependent module as a helper or a frame, even besides the mobiusz framework itself.
The main purpose of these is to propose a common language to make community development and discussion easier.
Targets: node, browser, electron.
Warning
This module is still a work in progress, and API or implementations can change drastically from one version ot another.
Use at your own risks!
Install
With yarn (recommended)
yarn add @mobiusz/core
With npm
npm install @mobiusz/core
Usage
Domain
@mobiusz/core
provides types, entities and handlers models to be extended and implemented by user's modules.
Some types are only a redefinition of native types.
export type UniqueIdString = string;
export type NameString = string;
export type PropertyName = NameString;
// ...
It also exports a basic UseCaseModel
entity to be implemented by concrete handlers.
The goal is to strongly encourage separation of concerns and code reuse.
export interface UseCaseModel<T = unknown, S = unknown> {
execute(...args: T[]): S;
dispose?(): void;
}
@mobiusz/core
proposes a similar common interface for validation and sanitization.
export interface Validator<T = unknown, S = unknown> {
execute(...args: T[]): S;
}
export interface Sanitizer<T = unknown, S = unknown> {
execute(...args: T[]): S;
}
As we can see, these interfaces are only a proposal for a basic vocabulary to be used, extended and refactored through the whole Möb:üsz framework.
Example
// We implement a handler for a specific use case.
export class MyHandler implements UseCaseModel<string, Record<string, any>> {
private _anotherInstanceOfSomething: Something | null = null;
constructor () {
this._anotherInstanceOfSomething = new Something();
}
public execute(value: string): Record<string, any> {
const endValue = this._anotherInstanceOfSomething.transform(value)
return { foo: endValue };
}
public dispose(): void {
this._anotherInstanceOfSomething.dispose();
this._anotherInstanceOfSomething = null;
}
}
// Then we 'inject' our handler(s) in a higher level object.
export class MyGreatClass {
constructor (
private _myHandler: MyHandler = new MyHandler(),
private _myOtherHandler: MyOtherHandler = new MyOtherHandler()
) {
// ...
}
public doSomething(value: string): Record<string, any> {
return this._myHandler.execute(value),
}
public doSomethinElse(value: any): void {
this._myOtherHandler_.execute(value),
}
public dispose(): void {
this._myHandler.dispose();
this._myOtherHandler.dipose();
}
}
The end user only has access to MyGreatClass
that acts as a façade for exposed functionalities.
const myObject = new MyGreatClass();
const result = myObject.doSomething('bar');
console.log(result); // { foo: 'bar' }
Decorators
Following decorators are exposed by @mobiusz/core
:
StaticImplements
Allows to implement use cases / ports with static methods.
Usage
// Decorator.
export function StaticImplements<T>() {
return <U extends T>(constructor: U) => {
constructor;
};
}
// Example from @mobiusz/security, that uses the jsonwebtoken package.
@StaticImplements<WebTokenDecodePort>()
export class JwtDecode {
public static async execute(token: Token): Promise<Record<string, any> | null | Error> {
return new Promise((resolve, reject) => {
try {
const decoded = jwt.decode(token);
resolve(decoded);
} catch (err) {
resolve(err);
}
});
}
}
// Where WebTokenDecodePort model is:
export interface WebTokenDecodePort {
execute(token: Token): Promise<Record<string, any>>;
}
// Then, to decode a token.
const decoded = JwtDecode.execute(token)
Errors
@mobiusz/core
exposes a DefaultErrorModel
entity to be implemented by concrete handlers.
export interface ErrorModel {
name?: NameString;
message?: ErrorMessage;
statusCode?: ErrorStatusCode;
messages?: ErrorMessage[];
stack?: Error['stack'];
}
Additionaly, a DefaultError
abstract class can be extended to create custom errors.
export abstract class DefaultError extends Error implements ErrorModel {
public statusCode: ErrorStatusCode;
public messages: ErrorMessage[] = [];
constructor(message?: ErrorMessage, code?: ErrorStatusCode) {
super(message);
this.name = this.constructor.name;
this.message = message || this.name;
this.messages.push(this.message);
if (code) {
this.statusCode = code;
} else {
if (isClient()) {
// In the browser.
this.statusCode = 400;
} else {
// In node.
this.statusCode = 500;
}
}
}
}
Example
export class ImmutablePropertyError extends DefaultError {
constructor(property: MessageString, object?: any) {
if (object) {
super(`Property ${property} on ${object} is immutable.`);
} else {
super(`Property ${property} is immutable.`);
}
}
}
@mobiusz/core
provides the following standard errors.
ImmutablePropertyError
InvalidProperyError
InvalidTypeError
OnceError
PrivatePropertyError
UninplementedError
Implementations
Serialization
Serializer
Serializes an object (array or object) to a string in given encoding.
In the browser it uses window.btoa
, in node Buffer.from
const serializer = new Serializer();
const result = serializer.toString('foo', 'utf8', 'base64');
Helpers
For its helpers modules, @mobiusz/core
uses the Vue 3 composables syntax.
They are used widely through the mobiusz framework.
List of helpers
-
useTimeHelper
:-
nextTick
: Provides a context-awarenextTick
method.
-
-
usePropertyHelper
:-
isInternal
(mobiusz specific): Checks if a given property is internal (surrounded by double underscores, e.g.__property__
).
-
-
useJwtHelper
:-
parseToken
: Context-aware parsing of a JSON Web Token.
-
-
useArrayHelper
:-
isStringArray
: Checks if the provided array is filled with strings. -
isNumberArray
: Checks if the provided array is filled with numbers. -
sortStringArray
: Sorts an array of strings in ascending or descending order. -
sortNumberArray
: Sorts an array of numbers in ascending or descending order. -
arrayIntersection
: Gets the intersection of two arrays (values present in both). -
arrayDifference
: Gets the difference between two arrays (values present in first array and not in second one) -
arraySymmetric
: Gets the symmetric difference between two arrays (values present in first and second array that are not present in the other one). -
parseOptionsArray
: Parses an array that has alternate key / value pairs.
-
-
useTypeCheck
: If nothing is mentioned, the method is only a syntactic sugar fortypeof foo === type
orinstance instanceof klass
isArray
isBoolean
-
isDate
: Checks if the given value is an object (isObject
) and if it exposes thegetTime
method. -
isDefined
: Checks if the value is norundefined
neithernull
. isFunction
isInstanceOf
isNull
isNumber
-
isObject
: Checks if the value is defined, is an 'object' and NOT an Array. -
isPromise
: Checks if the value is an object (ìsObject
) and if it exposes thethen
andcatch
methods. -
isRawObject
: Similar totypeof foo === 'object'
isString
isSymbol
isUndefined
-
usePrimitiveConverter
toArray
toNumber
toBoolean
toInteger
toObject
toString
toSet
-
useFunctionHelper
isAsync
isPromise
wrapFunction
wrapAsyncFunction
getCallerFunctionName
getCallerObjectName
-
useGlobalHelper
isClient
isDefault
isCommonJS
-
useNumberHelper
isNaN
-
isFinite
, isInfinite
isFloat
isOdd
isEven
isInRange
roundToNearestTen
-
useObjectHelper
getMethodNames
getDescriptorsKeys
hasPropertyDescriptor
deepClone
flatten
-
useStringHelper
toCamelCase
toPascalCase
toKebabCase
splitAtFirst
onlyAlpha
onlyAlphaNumeric
removeWhitespaces
isIntegerString
isNumberString
- and all the methods availables in validator.js package.
Example
import { useTypeCheck } from '@mobiusz/core';
const { isString, isObject, isRawObject } = useTypeCheck();
console.log(isString('foo')); // true
console.log(isString(64)); // false
console.log(isObject({ foo: 'bar' })); // true
console.log(isObject(['foo', 'bar'])); // false
console.log(isRawObject({ foo: 'bar' })); // true
console.log(isRawObject(['foo', 'bar'])); // true
Tests
Tests are handled with Jest.
yarn test