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

moulinette

v1.2.6

Published

A thin wrapper around your functions to provide you with the tools to build a component system.

Downloads

7

Readme

Moulinette

A thin wrapper around your functions to provide you with the tools to build a component system.

Installation

npm install moulinette

Creating a system

The createSystem function takes a builder function as parameter. A builder receives a moulinette function as its single argument and returns a system definition.

The moulinette parameter is a function that performs the computations registered with the .with() method. It's where the magic happens.

A system definition is basically what you want your system to be at its core and is the value that createSystem will return. So if for example you want your systems to behave like functions, your builder should return a function.

import createSystem from 'moulinette'

// define the general behavior of your system and what it actually builds
const System = createSystem(moulinette =>
  function System(props) {
    return moulinette(props)
  }
)

// call the generated System function
const computed = System({ test: true })

A builder function can return anything you want so you can get creative and use it to for example generate React components:

import React from 'react'
import createSystem from 'moulinette'

const System = createSystem(moulinette =>
  class System extends React.Component {
    render() {
      return <div {...moulinette(this.props)} />
    }
  }
)

const App = props => {
  return <System {...props} />
}

Setting defaults

A system component comes with a static method .with() that allows you to define a more specific version of the original system. If you pass it an object, it will define the default props of your specialized component.

// using the System defined in the very first example:

const A = System.with({ value: 'A' })

A({}) === { value: 'A' }

// passed props always have precedence against defaults
A({ value: 'B' }) === { value: 'B' }

Every component generated with .with() will also be a system component so it'll also have access to this method. Defaults will stack in the order they were added, meaning values defined the latest will overwrite any previous one.

const Value = System.with({ value: null, isValue: true })
const A = Value.with({ value: 'A' })
const B = Value.with({ value: 'B' })

Value({}) === { value: null, isValue: true }
A({}) === { value: 'A', isValue: true }
B({}) === { value: 'B', isValue: true }

Using a moulinette

A moulinette is a function that takes props as input and returns a modified version of those props. They are very useful if you want to control your component's final props depending on what was passed to it on render.

// take a and b out of the props
function addAtoB({ a = 0, b = 0, ...props }) {
  return {
    // do not forget to pass down the rest of props for the next moulinettes
    ...props,

    // compute value from a and b
    value: a + b
  }
}

const Value = System.with({ value: null, isValue: true })
const Add = Value.with(addAtoB)

Add({}) === { value: 0, isValue: true }
Add({ a: 10 }) === { value: 10, isValue: true }
Add({ a: 10, b: 100 }) === { value: 110, isValue: true }

For convenience, you can pass many parameters to the .with() method, it's equivalent to chaining the calls.

const Add = System.with({ value: null, isValue: true }, addAtoB)

When you add many moulinettes to a component, the last added one will always be executed first, its result will be passed to the one added before and so on until everything is processed. This means that in a given moulinette, you'll only be able to access props generated by moulinettes added after this one.

function multiply({ n = 1, value = 0, ...props }) {
  return {
    ...props,

    // use the value generated by add()
    value: n * value
  }
}

function add({ a = 0, b = 0, ...props }) {
  return {
    ...props,

    // compute value from a and b
    value: a + b
  }
}

const AddMul = System.with(multiply, add)

AddMul({}) === { value: 0 }
AddMul({ a: 10, b: 100 }) === { value: 110 }
AddMul({ a: 10, b: 100, n: 2 }) === { value: 220 }

As the orders matters, if in the example above add() would have been added before multiply(), the multiplication would happen first and then be overwritten by the addition.

Adding mixins

You can extend the static API of your system components to create helpers that encapsulate common operations made with your systems. A mixin is a function that takes the currently built component as parameter and mutates it by adding it static methods.

import { createSystem, merge } from 'moulinette'

function mixin(System) {
  // shorthand for setting the system default value
  System.value = value => System.with({ value })

  // shorthand to merge an object generated by a chunk function to the current props
  System.chunk = chunk => System.with(props => {
    const chunkProps = chunk(props)
    return merge(props, chunkProps)
  })
}

const System = createSystem(/* ... */).extend(mixin)

const A = System.value('A')

const Chunked = System.chunk(({ ok = false }) => ({
  isOK: ok,
  message: ok ? 'chunk is ok' : 'chunk is NOT ok'
}))

A({}) === { value: 'A' }
Chunked({}) === { isOK: false, message: 'chunk is NOT ok' }
Chunked({ ok: false }) === { ok: false, isOK: false, message: 'chunk is NOT ok' }
Chunked({ ok: true }) === { ok: true, isOK: true, message: 'chunk is ok' }