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

povjs

v0.1.4

Published

Point-of-view

Downloads

3

Readme

pov

Point-of-view, everybody's got one!

Say you work in the presentation layer and the business concepts that make sense to you are foo and bar, this is your point-of-view.

However, you need to access/mutate these concepts through an API which exposes them as oof and rab.

The obvious solution is to use mappers to transform from one to the other for both read & write, but let's try another approach, that of having a live point-of-view.

const ipa = api.fetch();
// ipa === {oof: 1, rab: 2}

const my_concepts = my_point_of_view(ipa);
// my_concepts === {foo: 1, bar: 2}

Now we can both read & write oof as foo:

my_concepts.foo === ipa.oof; // true

my_concepts.foo = -1;

my_concepts.foo === ipa.oof; // still true

We need to provide some kind of mapping information to associate foo with oof, and bar with rab:

const my_mapping = { foo: 'oof', bar: 'rab' };
const my_concepts = my_point_of_view(ipa, my_mapping);

We don't just need to rename concepts but often times also apply some transformation(s) to fit our point-of-view.

For example API also returns a date of birth 1980-01-01T01:01:01.001Z that we want to use without the time part 1980-01-01.

So instead of only providing the name of the source concept (as oof for foo), our maping should define functions to get & set our concept:

const mapping = {
  foo: 'oof',
  bar: 'rab',
  birth: {
    get: _ipa => _ipa.birth.toISOString().slice(0, 10),
    set: (_ipa, _date) => {
      _ipa.birth = new Date(_date);
    },
  },
};

We can use these mapping functions to perform more complex transformations, including aggregation of concepts and accessing nested levels of concepts.

Since it is a common requirement, an array mapping with get & set functions is provided out-of-the-box. Here is a real example of use of pov:

import pov, { array } from 'povjs';

const ipa = {
  oof: 1,
};

// let's encapsulate the use of pov and its mapping
function mapFoo(source) {
  return pov(source, {
    foo: 'oof',
  });
}
const mapped = mapFoo(ipa); // mapped === {foo: 1}

// now the use of array
const ipas = {
  soof: [{ oof: 2 }],
};
function mapFoos(source) {
  return pov(source, {
    foos: array()('soof', mapFoo),
  });
}
const mappeds = mapFoos(ipas);
mappeds.foos[0].foo === ipas.soof[0].oof; // true

mappeds.foos[0].foo = 3; // true
mappeds.foos[0].foo === ipas.soof[0].oof; // still true

mappeds.foos = [{ foo: 4 }];
mappeds.foos[0].foo === ipas.soof[0].oof; // still true

All good, but why array()(...)?

Because array is a currying function which may accept two parameters, respectively getter and setter, both functions to provide pluggable extensions to the read & write abilities.

As a matter of fact, pov is also a currying function which also accepts the same number of parameters but for convenience, is exposed pre-configured with defaults.

import pov, { pov as currying_pov } from 'povjs';

Here currying_pov() and pov will be equivalent.

With these extension points, we can provide custom getter & setter as interceptors, for example:

import { pov as currying_pov, getter, setter } from 'povjs';

// decorate default getter & setter with...
function _getter(source, path) {
  console.log('getter', { path });
  return getter(source, path);
}
function _setter(source, path, value) {
  console.log('setter', { path, value });
  setter(source, path, value);
}
const pov = currying_pov(_getter, _setter);

Another example would be to provide custom getter & setter to support nested properties:

const ipa = {
  oof: {
    rab: 1,
  },
};
const mapped = pov(ipa, {
  bar: 'oof.rab',
});

This nested path access is such a common requirement, but to avoid reinventing the wheel, a povjs sister project povjs-lodash will provide these functionalities, along with its dependencies to a minimal required subset of the excellent lodash library.