npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

data-transformer

v0.1.12

Published

Transformation helpers for JavaScript iterables

Downloads

14

Readme

data-transformer.js

data-transformer.js supplies assorted helper functions to facilitate transformations of data structures. It utilizes iterables for lazy evaluation behavior of data sequences.

Installation

npm

npm install data-transformer

bower

bower install data-transformer

CDN

data-transformer.js is available from jsdelivr.com. You can copy the latest version URL from the project page. It looks like this:

https://cdn.jsdelivr.net/data-transformer/<VERSION>/data-transformer-browser.min.js

Usage

data-transformer.js relies on iterable support. It is built using Babel's regeneratorRuntime, so babel-polyfill is a requirement to use data-transformer.js.

Using ES6

import "babel-polyfill";
import {
    iterableOfIterablesToObjects,
    map,
    fold,
    flattenOneToN
} from "data-transformer";

console.log(Array.from(map(x => x * x, [1, 2, 3])));

Without ES6

require("babel-polyfill");
var dataTransformer = require("data-transformer");

console.log(Array.from(dataTransformer.map(function(x) { return x * x; }, [1, 2, 3])));

In the browser

You can include both babel-polyfill and data-transformer directly from the bower_components directory, or alternatively use CDN paths:

<html>
  <head>
    <script src="bower_components/babel-polyfill/browser-polyfill.js"></script>
    <script src="bower_components/data-transformer/dist/data-transformer-browser.js"></script>
  </head>
  <body>
    <div id="output"></div>
    <script>
      (function() {
      var result = Array.from(dataTransformer.map(function(x) { return x * x; }, [1, 2, 3]));
      document.getElementById("output").textContent = result;
      })();
    </script>
  </body>
</html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.min.js"></script>
    <script src="https://cdn.jsdelivr.net/data-transformer/0.1.12/data-transformer-browser.min.js"></script>
  </head>
  <body>
    <div id="output"></div>
    <script>
      (function() {
      var result = Array.from(dataTransformer.map(function(x) { return x * x; }, [1, 2, 3]));
      document.getElementById("output").textContent = result;
      })();
    </script>
  </body>
</html>

Examples

Note that many the examples below show the use of the Array.from helper to convert resulting iterables to arrays. To preserve lazy evaluation behavior of the sequences, you should only convert iterables to arrays if necessary, and generally this should be done as late as possible.

map

map applies a function sequentially to elements of a source iterable and yields the result of each call.

Call map like this:

Array.from(map(x => x * 2, [1, 2]))

[2, 4]

You can obtain the index of the element in the source sequence:

Array.from(map((x, index) => x * i, [1, 2]))

[0, 2]

Since map works with iterables, your input data doesn't have to be an array:

Array.from(map(x => x * x, (function*() => yield 3)()))

[9]

Any iterable data type is supported:

Array.from(map(x=> x + x, "hello"))

["hh", "ee", "ll", "ll", "oo"]

fold

fold aggregates values in a sequence using a reducer function and a starting value. It assumes an iterable as a source sequence, the behavior is unsurprising.

fold((r, v) => r + v, 0, [1, 2, 3])

6

Indices can be obtained using a third parameter on the reducer:

fold((r, v, i) => r + v * i, 0, [1, 2, 3])

8

iterableOfIterablesToObjects

Assuming this source array of arrays:

const source = [[1, 2], ["one", "two"]];

You can pass in the names for fields expected in the result objects:

Array.from(iterableOfIterablesToObjects(source, ["one", "two"]))

[ { one: 1, two: 2 }, { one: "one", two: "two" } ]

If you don't pass in enough field names, they are generated automatically:

Array.from(iterableOfIterablesToObjects(source))

[ { field0: 1, field1: 2 }, { field0: "one", field1: "two" } ]

Array.from(iterableOfIterablesToObjects(source, ["one"]))

[ { one: 1, field1: 2 }, { one: "one", field1: "two" } ]

To use a different field prefix instead of the standard "field", pass it as a third parameter:

Array.from(iterableOfIterablesToObjects(source, [], "xxx"))

[ { xxx0: 1, xxx1: 2 }, { xxx0: "one", xxx1: "two" } ]

Alternatively, pass a function that generates a field prefix, or generates a full field name and skips automatic field numbering:

Array.from(iterableOfIterablesToObjects(source, [], () => "xxx"))

[ { xxx0: 1, xxx1: 2 }, { xxx0: "one", xxx1: "two" } ]

Array.from(iterableOfIterablesToObjects(source, [], (a, ai, v, vi) => 
    ({ prefix: "i" + ai + "-f" + (vi + 1), skipNumbering: true })))
	
[ { "i0-f1": 1, "i0-f2": 2 }, { "i1-f1": "one", "i1-f2": "two" } ]

Since input values don't have to be arrays, you can also use any other iterable data type:

function* innerIterable(x) {
    yield x * 3;
    yield x * 5;
}

function* outerIterable() {
    yield innerIterable(3);
    yield innerIterable(5);
}
    
Array.from(iterableOfIterablesToObjects(outerIterable()))

[ { field0: 9, field1: 15 }, { field0: 15, field1: 25 } ]

flattenOneToN

In a 1-N data structure, the top-level sequence is assumed to contain objects which have one or more properties that refer to sub-sequences. We call these fields "n-fields". They can either be auto-detected or specified manually.

Auto-detection

Assuming a 1-N structure of completely fictitious data, a simple call to flattenOneToN returns a flat data structure:

const data = [
  { country: "UK",
    cities: [
      { city: "London", population: 10000000 },
      { city: "Edinburgh", population: 800000 } ] },
  { country: "USA",
    cities: [
      { city: "New York", population: 12000000 }] } 
]

Array.from(flattenOneToN(data))

[
  { country: "UK", city: "London", population: 10000000 },
  { country: "UK", city: "Edinburgh", population: 800000 },
  { country: "USA", city: "New York", population: 12000000 }
]

If there are several n-fields in the source objects, the resulting sequence contains permutations:

Array.from(flattenOneToN([
  { country: "UK",
    cities: [
      { city: "London", population: 10000000 },
      { city: "Edinburgh", population: 800000 } ],
    counties: [
      { county: "Kent" },
      { county: "Buckinghamshire" },
      { county: "Warwickshire" },
      { county: "Yorkshire" } ]
  } 
]))
	
[
  { "city": "London", "country": "UK", "county": "Kent", "population": 10000000 },
  { "city": "London", "country": "UK", "county": "Buckinghamshire", "population": 10000000 },
  { "city": "London", "country": "UK", "county": "Warwickshire", "population": 10000000 },
  { "city": "London", "country": "UK", "county": "Yorkshire", "population": 10000000 },
  { "city": "Edinburgh", "country": "UK", "county": "Kent", "population": 800000 },
  { "city": "Edinburgh", "country": "UK", "county": "Buckinghamshire", "population": 800000 },
  { "city": "Edinburgh", "country": "UK", "county": "Warwickshire", "population": 800000 },
  { "city": "Edinburgh", "country": "UK", "county": "Yorkshire", "population": 800000 }
]

By default, the auto-detection of n-fields is performed once, using the first element of the top-level sequence. If the sequence contains objects with varying n-fields, you can run auto-detection for each object separately.

Note: This example also shows the handling of sub-sequences that use primitive types. These are projected to the result set using the sub-sequence name as a field name.

Array.from(flattenOneToN([
  {
    order: "12345",
    productIds: [7, 8, 9]
  },
  {
    order: "87463",
    remoteRefs: ["one", "two", "three"]
  }
], undefined, {
  perSourceObject: true
}))

[
  { order: '12345', productIds: 7 },
  { order: '12345', productIds: 8 },
  { order: '12345', productIds: 9 },
  { order: '87463', remoteRefs: 'one' },
  { order: '87463', remoteRefs: 'two' },
  { order: '87463', remoteRefs: 'three' } 
]

It is possible to override the standard auto-detection mechanism for n-fields by passing a function. This works for both per-object detection (in the following sample) or one-time detection.

Array.from(flattenOneToN([
  {
    type: "order",
    orderId: "987987",
    productIds: [7, 8]
  },
  {
    type: "delivery",
    deliveryId: "432141",
    deliveryRefs: ["one", "two"]
  }], undefined, {
    perSourceObject: true,
    dynamicDetector: o => {
      if (o.type === "order") {
        return ["productIds"];			
      }
      else if (o.type === "delivery") {
        return ["deliveryRefs"];
      }
      else {
        return [];
      }
    }
  }))
  
[
  { type: "order", orderId: '987987', productIds: 7 },
  { type: "order", orderId: '987987', productIds: 8 },
  { type: "delivery", deliveryId: '432141', deliveryRefs: "one" },
  { type: "delivery", deliveryId: '432141', deliveryRefs: "two" } 
]

Manual n-fields

Instead of relying on the automatic detection of n-fields, you can pass in their names explicitly. If there are fields that would automatically be recognized as n-fields but are excluded explicitly, they will become part of the result objects without flattening:

Array.from(flattenOneToN([
  { country: "UK",
    cities: [
      { city: "London", population: 10000000 },
      { city: "Edinburgh", population: 800000 } ],
    counties: [
      { county: "Kent" },
      { county: "Buckinghamshire" } ]
  } ],
["cities"]))

[
  { "city": "London", "country": "UK",  "population": 10000000, counties: [
    { county: "Kent" },
    { county: "Buckinghamshire" }
  ] },
  { "city": "Edinburgh", "country": "UK", "population": 800000, counties: [
    { county: "Kent" },
    { county: "Buckinghamshire" }
  ] }
]

API Reference

data-transformer

A module of data transformation helpers.

data-transformer.map(iterator, source) ⇒ iterable

map is a generator function that accepts an iterable source parameter and an iterator function. It iterates the source and applies the iterator to each element, yielding the results. map implements the standard map function known from many functional environments, differing from standard JavaScript language implementations as well as those in lodash or underscore by accepting and returning iterators.

Kind: static method of data-transformer
Returns: iterable - The iterable sequence of mapped values

| Param | Type | Description | | --- | --- | --- | | iterator | function | The iterator function to apply to each element of source. For compatibility with other implementations, an index is passed as a second parameter. The iterator is expected to return the result of mapping the given element. | | source | iterable | The source iterable that will be iterated |

data-transformer.fold(reducer, initialValue, source) ⇒ value

fold accepts an iterable source parameter, a reducer function and an initialValue for the reduction. It iterates the source and applies the reducer sequentially to the values of the sequence, passing in the result from the previous reduction to each new reducer call. This function is similar to the standard reduce function on JavaScript arrays, and to reduce and fold implementations in various libraries. It is supplied here to eliminate dependencies for data-transformer.js, and to supply an implementation that works with iterables as input.

Kind: static method of data-transformer
Returns: value - The result returned by the final call to reducer

| Param | Type | Description | | --- | --- | --- | | reducer | function | The reducer function that is called for each value from the source sequence. The result parameter receives initialValue on first call, afterwards the result from the previous reduction. An index is also passed for compatibility with other implementations. The reducer is expected to return the result of the value reduction step. | | initialValue | value | The value used for result in the first call to reducer | | source | iterable | The source iterable that will be iterated |

data-transformer.iterableOfIterablesToObjects(source, fieldNames, fieldPrefix) ⇒ iterable

iterableOfIterablesToObjects is a generator function that accepts a source parameter, which is expected to be an iterable containing other iterables. The outer iterable is iterated and each of the sub-iterables is converted into an object. The field names for this object can be passed in the parameter fieldNames and are applied sequentially to the data found in the sub-iterables. If fewer fieldNames are given then there are values in a given sub-iterable, field names for further values are generated automatically, by default using the fieldPrefix and a sequential number for the field position. fieldPrefix can also be a function, in which case it is invoked as a callback expected to return a field name.

Kind: static method of data-transformer
Returns: iterable - The iterable sequence of generated objects

| Param | Type | Description | | --- | --- | --- | | source | iterable | The source iterable that will be iterated | | fieldNames | array | Field names for elements of the sub-iterables. Default value: [] | | fieldPrefix | string | function | Defines the field name prefix used for generated field names, if there are fewer field names given in fieldNames than there are elements in a given sub-iterable. If the type of this parameter is string, it overrides the default field prefix of "field". If fieldPrefix is a function, it is called with four parameters when a field name needs to be generated: (1) the sub-iterable, (2) the index of the current sub-iterable in the top-level iterable, (3) the current element of the sub-iterable for which a field name is to be generated and (4) the index of the current element of the sub-iterable. A fieldPrefix function is expected to return either a string (the prefix) or an object of this structure: { prefix: string, skipNumbering: bool }. If skipNumbering is true, no field position indicator is appended to the prefix. |

data-transformer.flattenOneToN(source, nFields, nFieldHandling) ⇒ iterable

flattenOneToN is a generator function that accepts a source parameter, which is expected to be an iterable yielding objects that include other iterables in their fields. These fields are called n-fields and a list of such n-fields can be passed in the nFields parameter. If no n-field names are passed, n-fields will be auto-detected. flattenOneToN returns a sequence of objects composed of all fields from the source objects, plus the fields from objects referred to by iterable n-fields.

Kind: static method of data-transformer
Returns: iterable - An iterable sequence of result objects. These objects contain all fields found in the source sequence objects with the exception of those declared as n-fields. In addition, the objects contain all fields from the sub-iterable objects of the n-fields. If there is more than one n-field, the sequence contains objects reflecting all permutations of the n-field sub-iterable combinations.

| Param | Type | Description | | --- | --- | --- | | source | iterable | The source iterable, the "one" part of a 1-to-N data structure | | nFields | array | fields of the source objects that should be projected to the result set. Default values is []. N-fields are auto-detected if none are provided for this parameter. | | nFieldHandling | object | Defines how n-field detection works. Default value is { perSourceObject: false, dynamicDetector: undefined }, and n-field auto-detection is performed by analyzing the first object yielded by the source sequence. dynamicDetector can be set to a function that handles n-field detection instead of the built-in algorithm, and if perSourceObject is true, detection will be performed for each object instead of once for the sequence (this works both with the built-in detection algorithm and with a custom one). |