New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

actml

Package Overview
Dependencies
Maintainers
1
Versions
70
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

actml - npm Package Compare versions

Comparing version 0.9.0 to 0.9.1

lib/__helpers__/utils.js

110

lib/index.js

@@ -6,71 +6,89 @@ 'use strict';

});
exports.Redux = exports.Processor = exports.run = exports.A = undefined;
exports.createUniverse = createUniverse;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _Processor = require('./Processor');
var _redux = require('./elements/redux');
var _Processor2 = _interopRequireDefault(_Processor);
var ReduxMethods = _interopRequireWildcard(_redux);
var _isActMLElement = require('./utils/isActMLElement');
var _execute = require('./middlewares/execute');
var _isActMLElement2 = _interopRequireDefault(_isActMLElement);
var _execute2 = _interopRequireDefault(_execute);
var _ActElement = require('./ActElement');
var _result = require('./middlewares/result');
var _ActElement2 = _interopRequireDefault(_ActElement);
var _result2 = _interopRequireDefault(_result);
var _useChildren = require('./hooks/useChildren');
var _children = require('./middlewares/children');
var _useChildren2 = _interopRequireDefault(_useChildren);
var _children2 = _interopRequireDefault(_children);
var _useElement = require('./hooks/useElement');
var _Element = require('./Element');
var _useElement2 = _interopRequireDefault(_useElement);
var _Element2 = _interopRequireDefault(_Element);
var _useProduct = require('./hooks/useProduct');
var _utils = require('./utils');
var _useProduct2 = _interopRequireDefault(_useProduct);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _usePubSub = require('./hooks/usePubSub');
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
var _usePubSub2 = _interopRequireDefault(_usePubSub);
function create(func, props) {
for (var _len = arguments.length, children = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
children[_key - 2] = arguments[_key];
}
var _useState = require('./hooks/useState');
// using A as a dymmy component
if (func === create) {
return (0, _Element2.default)(function A() {
return {
scope: this.scope,
context: this.context
};
}, _extends({}, props, { scope: '*' }), children);
}
return (0, _Element2.default)(func, props, children);
}
var _useState2 = _interopRequireDefault(_useState);
async function run(element) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var _useReducer = require('./hooks/useReducer');
var rootElement = _Element2.default.createRootElement(context);
var _useReducer2 = _interopRequireDefault(_useReducer);
if ((0, _utils.isItAnElement)(element)) {
if ((0, _utils.isItAnElement)(element.func)) {
element.func.mergeToProps(element.props);
return await element.func.run(rootElement);
var _useElements = require('./hooks/useElements');
var _useElements2 = _interopRequireDefault(_useElements);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function createUniverse() {
var processor = (0, _Processor2.default)();
function A(func, props) {
for (var _len = arguments.length, children = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
children[_key - 2] = arguments[_key];
}
return await element.run(rootElement);
return (0, _ActElement2.default)(func, props, children);
}
return await create(element, null).run(rootElement);
function run(element) {
if (!(0, _isActMLElement2.default)(element)) {
throw new Error('ActML element expected. Instead ' + element.toString() + ' passed.');
}
return processor.run(element);
}
var Fragment = function Fragment() {};
var useChildren = (0, _useChildren2.default)(processor);
var useElement = (0, _useElement2.default)(processor);
var useState = (0, _useState2.default)(processor);
var useProduct = (0, _useProduct2.default)(processor, useState);
var usePubSub = (0, _usePubSub2.default)(processor);
var useReducer = (0, _useReducer2.default)(useState);
var useElements = (0, _useElements2.default)(processor, useChildren, usePubSub);
return {
A: A,
run: run,
Fragment: Fragment,
processor: processor,
useChildren: useChildren,
useElement: useElement,
useProduct: useProduct,
usePubSub: usePubSub,
useState: useState,
useReducer: useReducer,
useElements: useElements
};
}
var Redux = _extends({}, ReduxMethods);
var Processor = { execute: _execute2.default, result: _result2.default, children: _children2.default };
var A = create;
var universe = createUniverse();
exports.A = A;
exports.run = run;
exports.Processor = Processor;
exports.Redux = Redux;
module.exports = universe;
module.exports.createUniverse = createUniverse();

@@ -6,82 +6,292 @@ 'use strict';

});
exports.default = createProcessor;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _isActMLElement = require('./utils/isActMLElement');
exports.default = Processor;
var _isActMLElement2 = _interopRequireDefault(_isActMLElement);
var _middlewares = require('./middlewares');
var _Tree = require('./Tree');
var _deburger = require('./deburger');
var _Tree2 = _interopRequireDefault(_Tree);
var _deburger2 = _interopRequireDefault(_deburger);
var _usePubSub = require('./hooks/usePubSub');
var _utils = require('./utils');
var _usePubSub2 = _interopRequireDefault(_usePubSub);
var _useState = require('./hooks/useState');
var _useState2 = _interopRequireDefault(_useState);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var DEFAULT_MIDDLEWARES = [_middlewares.execute, _middlewares.exports, _middlewares.result, _middlewares.children];
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var setDebugger = function setDebugger(element, d, level) {
if ((0, _utils.isItAnElement)(element) && !element.debug) {
element.debug = d(element, level);
if (element.children && element.children.length > 0) {
element.children.forEach(function (e) {
return setDebugger(e, d, level + 1);
});
}
}
};
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } /* eslint-disable no-use-before-define */
function Processor(element) {
var middlewares = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_MIDDLEWARES;
if (!element) {
throw new Error('The processor requires an element as first argument.');
}
// import initializeHooks from './hooks';
var props = element.props;
function createProcessor() {
var _this = this;
// debugging
var tree = (0, _Tree2.default)();
var currentNode = null;
var debugMode = element.debug;
if (props && props.debug) {
var debug = props.debug;
var processNode = function () {
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(node, stack) {
var result, genResult, toGenValue;
return regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
currentNode = node;
stack = [].concat(_toConsumableArray(stack), [node.element]);
node.enter(stack);
node.rerun = function () {
return processNode(node, stack);
};
node.callChildren = function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
var childrenResult,
children,
i,
_children$i,
funcResult,
_args = arguments;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
childrenResult = [];
children = node.element.children;
if (debug === true) {
debugMode = true;
setDebugger(element, (0, _deburger2.default)(), 1);
} else if (debug && (typeof debug === 'undefined' ? 'undefined' : _typeof(debug)) === 'object') {
debugMode = true;
setDebugger(element, (0, _deburger2.default)(debug), 1);
}
}
if (!(children && children.length > 0)) {
_context.next = 30;
break;
}
// running the middlewares
return async function () {
var entry = void 0;
var index = 0;
i = 0;
try {
debugMode && element.debug('IN');
while (entry = middlewares[index]) {
debugMode && element.debug(entry._name + '_IN');
await entry(element);
index++;
debugMode && element.debug(entry._name + '_OUT');
}
debugMode && element.debug('OUT');
} catch (error) {
if (props && props.onError) {
props.onError.mergeToProps({ error: error });
if (!(await props.onError.run(element))) {
index = middlewares.length + 1;
};
} else {
throw error;
}
case 4:
if (!(i < children.length)) {
_context.next = 30;
break;
}
if (!(0, _isActMLElement2.default)(children[i])) {
_context.next = 14;
break;
}
(_children$i = children[i]).mergeProps.apply(_children$i, _args);
_context.t0 = childrenResult;
_context.next = 10;
return processNode(node.addChildNode(children[i]), stack);
case 10:
_context.t1 = _context.sent;
_context.t0.push.call(_context.t0, _context.t1);
_context.next = 27;
break;
case 14:
if (!(typeof children[i] === 'function')) {
_context.next = 27;
break;
}
_context.next = 17;
return children[i].apply(children, _args);
case 17:
funcResult = _context.sent;
if (!(0, _isActMLElement2.default)(funcResult)) {
_context.next = 26;
break;
}
_context.t2 = childrenResult;
_context.next = 22;
return processNode(node.addChildNode(funcResult), stack);
case 22:
_context.t3 = _context.sent;
_context.t2.push.call(_context.t2, _context.t3);
_context.next = 27;
break;
case 26:
childrenResult.push(funcResult);
case 27:
i++;
_context.next = 4;
break;
case 30:
return _context.abrupt('return', childrenResult);
case 31:
case 'end':
return _context.stop();
}
}
}, _callee, _this);
}));
return function () {
return _ref2.apply(this, arguments);
};
}();
// actual call of the ActML element
_context2.next = 7;
return node.element.run();
case 7:
result = _context2.sent;
genResult = void 0, toGenValue = void 0;
// handling a promise
if (!(result && result.then)) {
_context2.next = 15;
break;
}
_context2.next = 12;
return result;
case 12:
result = _context2.sent;
_context2.next = 38;
break;
case 15:
if (!(result && typeof result.next === 'function')) {
_context2.next = 34;
break;
}
genResult = result.next();
case 17:
if (genResult.done) {
_context2.next = 25;
break;
}
if (!(0, _isActMLElement2.default)(genResult.value)) {
_context2.next = 22;
break;
}
_context2.next = 21;
return processNode(node.addChildNode(genResult.value), stack);
case 21:
toGenValue = _context2.sent;
case 22:
genResult = result.next(toGenValue);
_context2.next = 17;
break;
case 25:
if (!(0, _isActMLElement2.default)(genResult.value)) {
_context2.next = 31;
break;
}
_context2.next = 28;
return processNode(node.addChildNode(genResult.value), stack);
case 28:
result = _context2.sent;
_context2.next = 32;
break;
case 31:
result = genResult.value;
case 32:
_context2.next = 38;
break;
case 34:
if (!(0, _isActMLElement2.default)(result)) {
_context2.next = 38;
break;
}
_context2.next = 37;
return processNode(node.addChildNode(result), stack);
case 37:
result = _context2.sent;
case 38:
if (!node.element.shouldProcessChildrenAutomatically()) {
_context2.next = 41;
break;
}
_context2.next = 41;
return node.callChildren();
case 41:
node.out();
currentNode = null;
return _context2.abrupt('return', result);
case 44:
case 'end':
return _context2.stop();
}
}
}, _callee2, _this);
}));
return function processNode(_x, _x2) {
return _ref.apply(this, arguments);
};
}();
return {
node: function node() {
return currentNode;
},
run: function run(element) {
var resolvedRootNode = tree.resolveRoot(element);
return processNode(resolvedRootNode, []);
},
onNodeEnter: function onNodeEnter(callback) {
tree.addNodeEnterCallback(callback);
},
onNodeOut: function onNodeOut(callback) {
tree.addNodeOutCallback(callback);
},
onNodeRemove: function onNodeRemove(callback) {
tree.onNodeRemove(callback);
},
system: function system() {
return {
tree: tree,
reset: function reset() {
tree.reset();
_usePubSub2.default.clear();
_useState2.default.clear();
}
};
}
return element.result;
};
}
};
{
"name": "actml",
"version": "0.9.0",
"version": "0.9.1",
"description": "Like jsx but for your business logic",
"main": "lib",
"main": "lib/index.js",
"scripts": {
"bundle": "browserify ./lib/index.js -o ./standalone/actml.js --standalone actml && uglifyjs ./standalone/actml.js -o ./standalone/actml.min.js",
"test": "BABEL_ENV=development ./node_modules/.bin/jest \"(.*)\\.spec\\.js\"",
"build": "./node_modules/.bin/babel ./src --out-dir ./lib --ignore spec.js",
"release": "yarn test && yarn build"
"test-watch": "BABEL_ENV=development ./node_modules/.bin/jest \"(.*)\\.spec\\.js\" --watch --verbose false",
"build": "rm -rf ./lib/* && ./node_modules/.bin/babel ./src --out-dir ./lib --ignore spec.js",
"release": "yarn test && yarn build && yarn bundle"
},

@@ -27,10 +29,14 @@ "repository": {

"devDependencies": {
"babel-cli": "6.26.0",
"babel-core": "6.26.3",
"babel-cli": "6.26.0",
"babel-eslint": "8.0.3",
"babel-jest": "23.4.2",
"babel-plugin-transform-object-rest-spread": "6.26.0",
"babel-preset-es2015": "6.24.1",
"babel-preset-react": "6.24.1",
"babel-plugin-transform-object-rest-spread": "6.26.0",
"babel-preset-stage-3": "6.24.1",
"babelify": "8.0.0",
"browserify": "14.5.0",
"eslint": "4.18.2",
"eslint-plugin-react": "7.5.1",
"fsevents": "1.2.4",

@@ -40,2 +46,3 @@ "jest": "23.5.0",

"regenerator-runtime": "0.12.1",
"uglify-js": "^3.0.28",
"watchify": "3.9.0"

@@ -47,3 +54,9 @@ },

]
},
"jest": {
"verbose": false
},
"dependencies": {
"fast-deep-equal": "2.0.1"
}
}

@@ -1,428 +0,3 @@

# &lt;ActML /> :rocket: <!-- omit in toc -->
![ActML](assets/logo.jpg)
> You know what I really like in React - it teaches you how to build well encapsulated components that are also highly composable. The thing is that React and its JSX is for our UI. It is a view layer that renders stuff on the screen. I want something similar but for my business logic. Something that allows me to use the same patterns but helps me deal with the asynchronous nature of the front-end development. So, I did it. Meet **ActML** - like React but for your business logic.
- [Concept](#concept)
- [What you need to use ActML](#what-you-need-to-use-actml)
- [What is an ActML element](#what-is-an-actml-element)
- [Getting in and out of your function/element](#getting-in-and-out-of-your-functionelement)
- [Scope API](#scope-api)
- [Understanding "exports" and "scope" props](#understanding-%22exports%22-and-%22scope%22-props)
- [Catching all the variables](#catching-all-the-variables)
- [More advanced export and import](#more-advanced-export-and-import)
- [Context API](#context-api)
- [Predefined elements](#predefined-elements)
- [Wrapper that scopes everything](#wrapper-that-scopes-everything)
- [Running elements in parallel](#running-elements-in-parallel)
- [Error handling](#error-handling)
- [Examples](#examples)
## Concept
Wouldn't be cool if we can define a function and execute it the same way as we render React component. Like for example:
```js
const Greeting = function () {
return 'Hey!';
}
run(<Greeting />).then(
message => console.log(message)
);
```
What if we have more functions, they depend on each other and some of them are asynchronous:
```js
const Greeting = function({ name }) {
return `Hey ${name}!`;
};
async function GetProfileName() {
const response = await fetch('https://reqres.in/api/users/2');
const { data: { first_name, last_name } } = await response.json();
return first_name + ' ' + last_name;
}
function Print({ message }) {
console.log(message);
}
run(
<A>
<GetProfileName exports="name" />
<Greeting $name>
{ message => <Print message={message} /> }
</Greeting>
</A>
);
```
Let's see step by step what ActML does:
1. The `<A>` element is just a wrapper.
2. `<GetProfileName>` is an asynchronous function so ActML waits till its promise is resolved. It also returns a result and has `exports` prop defined. That is a special prop which is saying "Export a variable with name `name` and make it available for other elements".
3. `<Greeting>` needs that `name` variable and uses the special dollar sign notation which to ActML processor means "Inject a variable with name `name` as a prop".
4. `<Greeting>` also has a function as child and it sends its result there which in our case is the full message.
5. `<Print>` just gets the message and prints it out in the console.
_Here is a working [Codesandbox](https://codesandbox.io/s/341xn5vrlq) of the code above._
So, that is the concept of ActML. It allows us to define in a declarative fashion our business logic. Same as our UI. There is nothing (almost) imperative. In fact all the code that we pass to the `run` function is nothing but definitions of _what_ should happen. It is not saying _how_. This is extremely powerful concept because it shifts the responsibility to another level and makes the development a lot more easier. We use composition over raw implementation. If you like this way of thinking then ActML may be your way to deal with asynchronous logic.
## What you need to use ActML
ActML uses React's JSX transpiler to convert markup to function calls. By default the transpiler translates every tag to a `React.createElement` call so to make your code works with ActML you have to add
```js
/** @jsx A */
import { A } from 'actml';
```
The first line is to say to the transpiler that we don't want `React.createElement()` but `A()`. The second line is there because otherwise you'll get `ReferenceError: A is not defined` error. And of course because the `A` function is defining the core unit of ActML - an ActML element.
From a tools perspective you need some sort of [Babel](https://babeljs.io/docs/en/babel-preset-react) integration. There's a React+Redux+ActML example app [here](https://github.com/krasimir/actml/tree/master/examples/react-redux-app) that you can check.
## What is an ActML element
In the context of ActML the _element_ is a JavaScript function. The code below defines two different ActML elements:
```js
/** @jsx A */
import { A, run } from 'actml';
const Foo = function () { console.log('Foo'); }
const Bar = function () { console.log('Bar'); }
run(
<A>
<Foo />
<Bar />
</A>
);
// > Foo
// > Bar
```
To be more specific the element may be three things:
* A function
* An asynchronous function
* A generator
ActML processor assumes that every of the elements is asynchronous. It executes the functions from the outer to inner ones and from top to bottom. All the three types of elements may return another element. In the case of generator we may `yield` also another element. For example:
```js
function Print({ message }) {
console.log(message);
}
async function GetSeason({ endpoint }) {
const result = await fetch(endpoint);
const { season } = await result.json();
return season;
}
function * Logic() {
const season = yield (
<GetSeason endpoint="https://www.mocky.io/v2/5ba2a2b52f00006a008d2e0d" />
);
if (season === 'not summer') {
yield <Print message="No beach!" />;
} else {
yield <Print message="Oh yeah!" />;
}
}
run(<Logic />); // prints out: No beach!
```
_[Codesandbox](https://codesandbox.io/s/o41140ro85) with the example._
## Getting in and out of your function/element
The input to your ActML element is the attributes that we pass to the tag or if we have to make a parallel with React - the `props`. For example:
```js
const Foo = function (props) {
console.log(`Hello ${ props.name }`);
}
run(<Foo name='John' />); // outputs "Hello John"
```
The output or in other words the returned value of your element is available to its children via the [FACC (function as children pattern)](https://github.com/krasimir/react-in-patterns/blob/master/book/chapter-4/README.md#function-as-a-children-render-prop):
```js
const Foo = function (props) {
return `Hello ${ props.name }`;
}
run(
<Foo name='John'>
{ message => console.log(message) }
</Foo>
);
// outputs again "Hello John"
```
Another way to pass data between elements is the Scope API.
## Scope API
The scope API is a primary mechanism for transferring data between ActML elements.
### Understanding "exports" and "scope" props
Using the FACC pattern everywhere is not very convenient. So there is a Scope API that can keep data and share it with other elements. Let's take the following example:
```js
const Foo = () => 'Jon Snow';
const App = () => {};
const Zoo = ({ name }) => console.log('Zar: ' + name);
const Bar = ({ name }) => console.log('Bar: ' + name);
<App>
<Foo exports='name'>
<Zoo $name />
</Foo>
<Bar $name />
</App>
```
Every ActML element has a `scope` object. It is really just a plain JavaScript object `{}` and every time when we use `exports` we are saving something there. For example the `scope` object of the `Foo` element is equal to `{ name: 'Jon Snow' }`. Together with creating the `name` variable in the `scope` of `Foo` we are also _sending_ an event to the parent `App` element. Then the `App` element should decide if it is interested in that variable or not. If yes then it keeps it in its scope. In the example above that is not happening so the `name` variable is only set in the scope of `<Foo>`. That is why in this latest example we will get `Zar: Jon Snow` followed by the error `Undefined variable "name".`.
To solve the problem we have to instruct `<App>` element to _catch_ the `name` variable and also keeps it in its scope. This happens by the special prop called `scope`:
```js
const Foo = () => 'Jon Snow';
const App = () => {};
const Zoo = ({ name }) => console.log('Zar: ' + name);
const Bar = ({ name }) => console.log('Bar: ' + name);
<App scope='name'>
<Foo exports='name'>
<Zoo $name />
</Foo>
<Bar $name />
</App>
```
Now the result of `<Foo>` is available for `<Bar>` element too. The value of `name` is consistent across the different scopes. Changing it in one place means that it is updated in the other ones too.
Another important note here is that once a variable gets caught it doesn't bubble up. So if there are other elements as parents they will not receive it.
### Catching all the variables
There is a special `*` (star) value that we can pass to the `scope` prop which means "Catch all the variables". The example above will look like this:
```js
<App scope='*'>
<Foo exports='name'>
<Zoo $name />
</Foo>
<Bar $name />
</App>
```
For convenience the element `<A>` has its `scope` property set to `*` by default. So `<App scope='*'>` could be just replaced by `<A>`. Or in other words if we want to catch all the variables we may use `<A>` directly.
### More advanced export and import
The `exports` prop may also accept a function. The function receives the result of the function and **must** return an object (key-value pairs). This approach is useful when we want to apply some transformation of the element's result without modifying the actual element. For example:
```js
const Foo = () => 'Jon Snow';
const transform = name => ({
originalName: name,
lowercaseName: name.toLowerCase(),
uppercaseName: name.toUpperCase()
});
run(
<A>
<Foo exports={ transform }>
<Zoo $lowercaseName />
</Foo>
<Bar $uppercaseName />
</A>
);
```
`<Zoo>` and `<Bar>` now accept `lowercaseName` and `uppercaseName` as props. This however may be too long for typing. We can rename those like so:
```js
run(
<A>
<Foo exports={ transform }>
<Zoo $lowercaseName="name" />
</Foo>
<Bar $uppercaseName="name" />
</A>
);
```
We can also pass a function and apply some transformation of the data before importing.
```js
<Bar $uppercaseName={ name => ({ len: name.length }) } />
```
This wat `<Bar>` element will receive a prop called `len` which contains the number of letters in the `uppercaseName` variable.
## Context API
Now when you know about the scope API we could make a parallel with the context API. The scope API is more like a local placeholder of information. While the context API is globally available and it is more about injecting elements.
The `run` function accepts a second argument which is the initial context. We can pass an object in the format of key-value pairs. For example:
```js
const Zoo = ({ message }) => console.log('The message is: ' + message);
const context = {
getMessage({ name }) {
return `Hello ${name}!`;
}
};
run(
<getMessage name="Jon Snow" exports="message">
<Zoo $message />
</getMessage>,
context
);
// Prints out: The message is: Hello Jon Snow!
```
Notice how `getMessage` is defined in the context. We have to stress out that this is only possible because of the JSX transpiler. Everything that goes into the context must start with a lower case letter. That is because:
```js
<getMessage />
```
gets transpiled to
```js
A("getMessage", null);
```
while
```js
<GetMessage />
```
to
```js
A(GetMessage, null);
```
In the second case there **must** be a function called `GetMessage` while in the first case there's just a string `getMessage` passed to ActML processor. This may looks weird but is really powerful API for delivering dependencies deep down your ActML tree. Imagine how you define your context once and then write your logic distributed between different files.
## Predefined elements
There are some predefined elements that come with ActML core package.
### Wrapper that scopes everything
The `<A>` element has the ability to scope everything. So if you need that functionality and you a wrapper this is a good element to use.
### Running elements in parallel
```js
import { A, run, Parallel } from 'actml';
const Z = await function () { ... }
const M = function () { ... }
run(<Parallel><Z /><M /></Parallel>);
```
`Z` and `M` run in parallel which means that `M` is not waiting for `Z` to finish.
## Error handling
Because `run` returns a promise we can just `catch` the error at a _global_ level:
```js
const Problem = function() {
return iDontExist; // throws an error "iDontExist is not defined"
};
const App = function() {};
run(
<App>
<Problem />
</App>
).catch(error => {
console.log('Ops, an error: ', error.message);
// Ops, an error: iDontExist is not defined
});
```
That's all fine but it is not really practical. What we may want is to handle the error inside our ActML. In such cases we have the special `onError` prop. It accepts another ActML element which receives the error as a prop.
```js
const Problem = function() {
return iDontExist;
};
const App = function() {};
const HandleError = ({ error }) => console.log(error.message); // logs "iDontExist is not defined"
run(
<App>
<Problem onError={ <HandleError /> } />
</App>
);
```
ActML stops the execution of the current logic. However, if our handler returns `true` it continues. For example:
```js
const Problem = function() {
return iDontExist;
};
const App = function() {};
const HandleError = () => true;
const AfterError = () => console.log('I am still here :)');
run(
<App exports='answer'>
<Problem onError={ <HandleError /> } />
<AfterError />
</App>
);
// outputs "I am still here :)" even tho there's an error
```
And by stopping the execution we mean only the current branch. For example:
```js
const Problem = function() {
return iDontExist;
};
const App = function() {};
const Wrapper = function() {};
const HandleError = () => {};
const Z = () => console.log('Z');
const B = () => console.log('B');
const C = () => console.log('C');
await run(
<App exports='answer'>
<Wrapper>
<Problem onError={ <HandleError /> } />
<Z />
</Wrapper>
<Wrapper>
<B />
<C />
</Wrapper>
</App>
);
```
We will see `B` followed by `C` but not `Z` because there's an error at that level. Here is a [Codesandbox](https://codesandbox.io/s/qlpwp2nn06) with an example.
## Examples
* [Codesandbox](https://codesandbox.io/s/qx667yqvj9)
* [React+Redux+ActML app](https://github.com/krasimir/actml/tree/master/examples/react-redux-app)
SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc