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

recreator

v0.3.0

Published

Object factory with polyconstructors and post reassignment

Downloads

4

Readme

recreator

An expressive way to make factory with customizable nested structure. To best understanding conceptual difference from classic factories and classes, imaginate that you work with ES modules tree with one entry point, and each module of nested hierarchy structure you can customize to get new new instance of entry point, holding immutablity of previously.

Install:

npm i recreator --S

Usage:

import recreator from 'recreator';

Principle

In a short, recreator is a composite factory. But it is not so simple.

const factory = recreator({
  a: 1,
  b: ({ a }) => a * 2, // b depends on a
  c: ({ b }) => b + 2, // c depends on b
});
const factory2 = factory({
  a: 2, // cutomize the a value
});
// Build object
const model = factory2(); // {a: 2, b: 4, c: 6}

Each property of passed object can be a function. That function is a factory of this property's value. The value of each plain object property, which you pass to factory creator, can be the another plain object (nested structure), or a function (property-factory), or non-function value.

This kind of object factory founds very usefull for model-driven structure of the applications. You can keep all parts of you model (for example, actions, reducer, sagas, selector, etc) in one object, easily to customize it, or export as another module.

import recreator from 'recreator';

const factory = recreator({
  name: 'DEFAULT',
  helpers: {
    createActionName: ({
      name,
    }) => (suffix) => `${name}_${suffix}`,
  },
  actions: {
    names: ({
      helpers: {
        createActionName,
      }
    }) => ({
      FETCH: createActionName('FETCH'),
    }),
    creators: ({
      actions: {
        names: {
          FETCH,
        }
      },
    }) => ({
      fetch: (id) => ({
        type: FETCH,
        id,
      })
    }),
  },

});

In this example, I defines name of the model, and then creates helpers, which uses the name of the model (defined previously), and then I creates the action names, which uses this helpers, and action creators, which uses action names and helpers.

Important behaviors of property-factory become order of definition. Each next property access previously.

{
  A: () => {}, <--\ Previous factory knows nothing about next property
  B, ({ A }) => {} >--/ Next property can use the values of previous properties
}

Thus, you can create next property value on the basis of previously property.

const factory = recreator({
  a: 1,
  b: ({ a }) => a * 2, // b depends on a
  c: ({ b }) => b + 2, // c depends on b
});

The main goal is customization. After a factory had created, you can customize any part of it by calling factory with another object, which (fully or partially) repeats the form of previous pattern, but contains new values.

const factory2 = factory({
  a: 2, // cutomize the a value
});

You can do it many times.

const factory3 = factory2({
  b: ({ a }) => (a * 3),
})

const factory4 = factory2({
  b: ({ a }) => (a / 2),
})

Each factory's calling with object passing, creates new immutable factory. Each layer you may add do not just overlap previous value as Object.assign. Algorithm extends through the each values as through the tracing-paper. I means that each next property accepts results of previous property, which created using last micro-factory.

Nested structures behave the same way. You can define a nested object and its properties with factories, which will create its object, tracing all layers in the same depth level.

const helloSpeaker = recreator({
  config: {
    lang: 'eng',
  },
  texts: {
    eng: {
      greeting: 'Hello',
    },
    rus: {
      greeting: 'Привет',
    }
  },
  api: {
    sayHello: ({
      config: {
        lang,
      },
      texts,
    }) => (name) => `${texts[lang].greeting}, ${name}`,
  }
});

// Build with default lang value
const engSpeaker = helloSpeaker();
// Customize and build with another lang value
const rusSpeaker = helloSpeaker({
  config: {
    lang: 'rus',
  }
})();
engSpeaker.sayHello('Vova'); // Hello, Vova
rusSpeaker.satHello('Vova'); // Привет, Vova

Builded object is immutable and decomposable. Post mutable changes do not affect its functions result.

engSpeaker.config.lang = 'rus';
// Expects `Привет` instead of `Hello`
// But lang is still english
engSpeaker.sayHello('Sveta'); // Hello, Sveta

But a decomposed function still bound to the values, which depends on.

const { sayHello } = engSpeaker;
sayHello('Anya'); // Hello, Anya

The factory can produce two types of products - another factory or final object. To create another factory you should call existen factory with plain object (or a function - See post transformers). To run factory just call the factory with no arguments.

// Initial factory
const factory = recreator({
  log: () => console.log,
})

// Recreate factory
const factory2 = factory({
  warn: () => console.warn,
});

// Recreate factory with post-transformer
const factory3 = factory2((data) => {
  return data;
});

// Build object
const logger = factory3();

// Build another object
const logger2 = factory3();

You can recreate factories on the basis of other factories an unlimited number of times by feeding factory new values.

Post-transformers

You can pass to the factory a function. This function accepts resultative object. Yes. The function passed to factory will be called when all property-factories will be completely done. You can use this fact to perform free transformation or final object validation.

const factory = recreator({
  api: {
    enhance: () => {...},
  },
})((data) => {
  warning(typeof data === 'function', 'api.enhance must be a function'),
});

Coverage

File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines | ------------------|----------|----------|----------|----------|----------------| All files | 100 | 91.84 | 100 | 100 | | applyFactory.js | 100 | 94.12 | 100 | 100 | 74 | impose.js | 100 | 100 | 100 | 100 | | index.js | 100 | 80 | 100 | 100 | 7,10 | isArray.js | 100 | 100 | 100 | 100 | | isFunction.js | 100 | 100 | 100 | 100 | | isPlainObject.js | 100 | 100 | 100 | 100 | |

Author

Vladimir Kalmykov [email protected]

0.3.0

Released 0.3.0. Now functions passed to the factory executes last. Old style <0.2.0 where functions passed to the factory and executes in normal order is no longer available.

License

MIT, 2017