almost-core

ALMOsT is an AgiLe MOdel Transformation framework for JavaScript

Stats

stars 🌟issues ⚠️updated 🛠created 🐣size 🏋️‍♀️
00Dec 20, 2019Feb 3, 2017Minified + gzip package size for almost-core in KB

Readme

almostjs-core

ALMOsT is an AgiLe MOdel Transformation framework for JavaScript

NPM Version Build Build Test Coverage MIT licensed

This repository contains a low level graph traversing and aggregation framework used by ALMOsT. It is mainly manted as a generic graph to tree transformation framework.

Installation

$ npm install almost-core

The Pipeline

The transformation follows the following steps

  • Graph Traversing during this phase the input graph (JSON Object) is traversed and a set of analysis points are set
  • Analysis Execution the analysis points are execute one at a time and results are collected
  • Results Aggregation the results are aggregated to generated a final tree

This is an high level view over the system, under the hood we optimize the process in order to interleave analyis points execution and aggregation. This allows us to reduce the final memory footprint.

The Transformer

A transformer is a reusable function which hides the previously presented pipeline. It can be constructed using the createTransformer(traverse, [reduce]) maker function.

 var core = require('almost-core');
 
 var transform = core.createTransformer(traverse);
 
 var output1 = transform(input1);
 var output2 = transform(input2);
 // ...
 var outputN = transform(inputN);

The arguments of createTransformer are the following:

  • traverse function (input, emit) it is responsible of traversing the graph and "emit" a set of functions which represent the analysis points on the graph. Each function emitted will be invoked once (potentially out of order), with the input object as parameter
  • reduce [optional] 'function (accumulator, value)', it is responsible of aggregate the results of the analysis points (by default the results are concatenated)

Basic Examples

toPairs

This example creates a transformer which transforms an Object into an Array of [key, value] pairs.

 var core = require('almost-core');
 
 var toPairs = core.createTransformer(function (input, emit) {
  Object.keys(input).forEach(function (key) {
   emit(function (object) { return object[key]; });
  });
 });
 
 toPairs({a: 1, b: 2, c: 3}) // result: [['a', 1], ['b', 2], ['c', 3]]

fromPairs

This example creates a transformer which transforms an a Array of [key, value] pairs into an Object.

 var core = require('almost-core');
 
 var fromPairs = core.createTransformer(function (input, emit) {
  input.forEach(function (pair) {
   emit(function () { var object = {}; object[pair[0]] = pair[1]; return object; });
  });
 }, function (accumulator, value) {
  Object.keys(value).forEach(function (key) {
    accumulator[key] = value[key];
  });
  return accumulator;
 });
 
 fromPairs([['a', 1], ['b', 2], ['c', 3]]) // result: {a: 1, b: 2, c: 3}

Reducer

In order to make custom reduction policies, we provide a reduce(iteratee, [accumulator], [terminate]) maker function.

 var core = require('almost-core');

 var first = core.reduce(function (accumulator) { return accumulator; });
 var sum = core.reduce(function (accumulator, value) { return accumulator + value; }, 0);
 var avg = core.reduce(
  function (accumulator, value) {
   accumulator.sum += value;
   accumulator.count += 1;
   return accumulator;
  },
  {sum: 0, count: 0},
  function (accumulated) {
   if (accumulated.count > 0) {
    return accumulated.sum / accumulated.count;
   }
  }
 );

We provide a set of helpers to generate complex reduction policies:

  • none([error]) if even one value is generated an exception is thrown (useful in conjunction with merge)
  • single([error]) if more than one value is generated an exception is thrown (useful in conjunction with merge)
  • first([default]) it returns the first value encountered (if the default argument is passed it will be considered as first element if none are generated)
  • last([default]) it returns the last value encountered (if the default argument is passed it will be considered as first element in the sequence)
  • concat() it concatenates all the encountered values in an array
  • flatten() it concatenates all the encountered values in an array (arrays are flattened in single elements)
  • flattenDeep() it concatenates all the encountered values in an array (arrays are flattened in single elements recursively)
  • merge([policy], [specials]) all the encountered objects will be merged using the last value encountered for each property (if the policy argument is provided it will be used to reduce the different values encountered for each property, if the specials argument is provided it is expected to be an object with the form {key: policy, ...} the policies defined will be used instead of the default one for the related key)
  • mergeOrSingle() if objects are encountered it recursively merges them with the same policy, if arrays are encountered it concatenates and recursively merges them with the same policy, if anything else is encountered it behaves like single
  • groupBy(key, [policy]) it returns an object which keys are the unique values of the key filed in each input and the value is the reduction of all the inputs with the same key, by default concat
  • lazy(policy) if at least one input is present policy policy is applied normally, if no input is present it is like the policy was never there

Example

fromPairs 2.0

This example creates a transformer which transforms an a Array of [key, value] pairs into an Object.

 var core = require('almost-core');
 
 var fromPairs = core.createTransformer(function (input, emit) {
  input.forEach(function (pair) {
   emit(function () { var object = {}; object[pair[0]] = pair[1]; return object; });
  });
 }, core.merge());
 
 fromPairs([['a', 1], ['b', 2], ['c', 3]]) // result: {a: 1, b: 2, c: 3}

ALMOsT Model Merging

This example creates a transformer which transforms an a Array of {elements:[...], relations: [...], metadata: {}} intermediate models into an a final Object.

 var core = require('almost-core');
 
 var M2MReduce = core.merge(
  core.none('Just elements, realtions and metadata should be generated'),
  {
   elements: core.flatten(),
   relations: core.flatten(),
   metadata: core.merge()
  }
 );

If you find any bugs or have a feature request, please open an issue on github!

The npm package download data comes from npm's download counts api and package details come from npms.io.