comprehensive
Lightweight (1KB gzipped) Python-inspired object (dictionary) comprehension for JavaScript via template literals.
Overview
comprehensive
provides a syntax for object comprehension in Javascript similar to Python's dictionary comprehension.
import toObj from 'comprehensive';
const people = [{name: 'Aidan', age: 20}, {name: 'Becca', age: 21}];
const ages = toObj`{person.name: person.age for person of ${people}}`;
// {Aidan: 20, Becca: 21}
or
const ages = toObj`{it.name: it.age over ${people}}`;
or
// Arbitrary transformations can be applied to the keys and/or values
const ages = toObj`${p => p.name}: ${p => p.age} over ${people}`
You can automatically unpack values from fixed-size nested arrays, which is particularly useful for iterating over another object.
const people = {
ABC: {name: 'Aidan', age: 20},
DEF: {name: 'Becca', age: 21}
}
const idMap = toObj`{id: person.name for id, person of ${Object.entries(people)}}`
// { ABC: 'Aidan', DEF: 'Becca' }
Or, you can iterate over the keys of an object using the for key in
construct.
const places = {
Toronto: {population: 2809500},
Montreal: {population: 1714000}
}
toObj`{city: ${city => places[city].population} for city in ${places}`
// {Toronto: 2809500, Montreal: 1714000}
This is a shorthand for for city of ${Object.keys(places)}
.
Installation
$ npm install comprehensive
You can also include dist/comprehensive.min.js in your project.
Usage
Basic syntax is as follows:
toObj`{k: v for var1, (var2, ...) of ${someArray}}`
toObj`{k: v over ${someArray}}`
toObj`{k: v for key in ${someObject}}`
where k
and v
can either be a property path (e.g. a.b.c
), a function (e.g. ${a => a.b.c.toLowerCase()}
), or a static value (e.g. ${123}
). The key must either be a string
or a number
, otherwise toObj
will throw. It will also throw if the syntax is invalid.
If you want to ensure the call never throws, you can use toObjSafe
, which will return null
on invalid input.
Note that toObj
does not require curly brackets, and extra whitespace is allowed.
Examples
Basic Example
import toObj from 'comprehensive';
const people = [{name: 'Aidan', age: 20}, {name: 'Becca', age: 21}];
const personLookup = toObj`{p.name: p for p of ${people}}`;
// {Aidan: {name: Aidan, age: 20}, Becca: {name: 'Becca', age: 21}}
over
syntax
const squares = toObj`{it: ${it => it ** 2} over ${[1, 2, 3, 4, 5]}}`;
// { '1': 1, '2': 4, '3': 9, '4': 16, '5': 25 }
Static Values
const obj = toObj`it: ${{hello: 'world'}} over ${'A,B,C'.split(',')}`;
// {A: {hello: 'world'}, B: {hello: 'world'}, C: {hello: 'world'}}
Mapped Key
const people = [{name: 'Daniel', hobby: 'Karate'}];
toObj`${p => `${p.name}-san`}: p for p of ${people}`;
// {'Daniel-san': {name: 'Daniel', hobby: 'Karate'}}
Iterate Over Object
const movie2Id = {'Shrek': 'tt0126029', 'Shrek 2': 'tt0298148'};
const id2Movie = toObj`{id: title for title, id of ${Object.entries(movie2Id)}}`;
// {tt0126029: 'Shrek', tt0298148: 'Shrek 2'}
or
const id2Movie = toObj`{${title => movie2Id[title]}: title for title in ${movie2Id}}}`;
// {tt0126029: 'Shrek', tt0298148: 'Shrek 2'}
or
const id2Movie = toObj`{${title => movie2Id[title]}: title for title of ${Object.keys(movie2Id)}}}`;
// {tt0126029: 'Shrek', tt0298148: 'Shrek 2'}
Nested Object Comprehensions
const provinces = [
{
province: 'Ontario',
cities: [{city: 'Toronto', population: 2809500}]
},
{
province: 'Quebec',
cities: [{city: 'Montreal', population: 1714000}]
}
];
const populations = toObj`{
p.province : ${p => toObj`{c.city: c.population for c of ${p.cities}}`} for p of ${provinces}
}`;
// { Ontario: { Toronto: 2809500 }, Quebec: { Montreal: 1714000 }