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

unfold-cli

v1.0.18

Published

Let your codebase write itself.

Downloads

2

Readme

Unfold

Let your codebase write itself.

yarn global add unfold-cli

Writing code is almost always about deciding on a pattern and then the boring part is implementing it, unfold allows you to focus on the pattern and have the code write itself.

unfold transforms a codebase into a reactive, event driven system - it sees a change made to code as an event, a message that is emitted to all other parts of the codebase.

A developer can then decide which other parts of the code should change as a result, and unfold will make those changes automatically.

Usage

Initialisation

Once installed, navigate in your terminal to the top of your codebase and then run:

unfold

Syntax

unfold commands currently live with your code and use a JSX-like syntax.

Listeners

Listener folds listen for changes to particular types of syntax in locations you point them at:

// ./some-file.js
// <myFirstFold downstream exported_functions />

This fold will listen for any new exported functions in its local directory and any lower directories, and emit an event when this occurs.

unfold runs queries on the ASTs for the files in your codebase, and so can distinguish between, e.g. a new function being written and a function being exported.

The downstream prop instructs the fold to watch all files in the local directory and any lower directories.

Using a non-self-closing fold instructs it to listen to only what is between its opening and closing tags.

// <myFirstFold exported_functions >
// Just watch the JavaScript in here!
export const foo = () => {} // <-- this will trigger
// </myFirstFold>
export const bar = () => {} // <-- this will not trigger

Consumers

Consumer folds listen for those emitted events and make modifications to the codebase based on those events:

// ./some-other-dir/some-other-file.js
// <*myFirstFold overwrite snippet="{{ name }}">

// </*myFirstFold>

This fold will fire when myFirstFold emits an event, it will then write the names of the downstream exported functions between its opening and closing tags.

The snippet prop allows a developer to write an inline template for whatever new code they want to be added. These templates use HandlebarsJS and are called with data coming through on the event.

So in the above example, were I to create a new function like this:

const myFilter = (data, predicate) => data.filter(predicate) 

The consumer would write:

myFilter

Consumers also accept a where prop, which allows us to get greater control over when a consumer should do its work.

where accepts JavaScript as a string, and will execute it in the context of the data coming through on the event.

// <*myFirstFold overwrite snippet="{{ name }}" where="name.startsWith('user')">

// </*myFirstFold>

This consumer fold is listening to the same event, but will only write the names of functions that start with the token user.

Consumer folds take a number of commands when deciding how to make modifications:

  • overwrite
    • used non-self-closing folds and will overwrite anything between its opening and closing tags.
  • overwrite_below
    • used in self-closing folds and will overwrite everything below

Tiny Example

Wire up your code:

// ./my-math.js
// <newFunction arrow_function>
// </newFunction>

export {
// <*newFunction overwrite snippet={"{{name}},"}>
// </*newFunction
}

Make a change:

// ./my-math.js
// <newFunction arrow_function>
const add = () => {}
const subtract = () => {}
const divide = () => {}
const multiply = () => {}
// </newFunction>

export {
// <*newFunction overwrite snippet={"{{name}},"}>
// </*newFunction
}

Save and let unfold write the rest of your code:

// ./my-math.js
// <newFunction arrow_function>
const add = () => {}
const subtract = () => {}
const divide = () => {}
const multiply = () => {}
// </newFunction>

export {
// <*newFunction overwrite_below snippet={"  {{name}},"}>
    add,
    subtract,
    divide,
    multiply,
// </*newFunction
}

Case Study: index file

Often we'll want to organise functions into directories and then for ease of use export them all from an index file at a higher level.

Copy this into your index file:

// utils/index.js

// <newFunctionExportedBelowThis downstream exported_functions />
// <*newFunctionExportedBelowThis overwrite_below snippet="export { {{ name }} } from './{{ relativePath }}'"/>

And unfold will magically find any exported functions below or at the same level as that index, and export them.

Case Study: Redux

Redux is a popular, powerful state management system for front-end applications; as developers we enumerate a number of actions which describe the behaviour of the application, and we write types, reducers and action creators as the boilerplate to allow our views to access it.

unfold allows us to declare up front "for each of my types I need this code", write the types, and let the code write itself.

// ./types.js
// <newType named_exports>
// </newType>

// ./actions/user.js
import {
// <*newType overwrite snippet='  {{name}},' where="data.name.startsWith('user')">
// </*newType> 
} from './types'

// <*newType where="data.name.startsWith('user')" snippet="export const {{ name }}Action = (data) => ({ type: {{ name }}, data })">
// </*newType>

// ./actions/auth.js
import {
// <*newType overwrite snippet='  {{name}},' where="data.name.startsWith('auth')">
// </*newType> 
} from './types'
// <*newType where="data.name.startsWith('auth')" snippet="export const {{ name }}Action = (data) => ({ type: {{ name }}, data })>
// </*newType>

Make a change.

// ./types.js
// <newType named_exports >
export const userCreate = 'userCreate';
export const authLogin = 'authLogin';
// </newType>

Hit save and unfold writes the rest of the code for you in the way you've described it.

// ./actions/user.js
import {
// <*newType overwrite snippet='  {{name}},' where="data.name.startsWith('user')">
    userCreate
// </*newType> 
} from './types'
// <*newType where="data.name.startsWith('user')" snippet="export const {{ name }}Action = (data) => ({ type: {{ name }}, data })">
export const userCreateAction = (data) => ({ type: userCreate, data });
// </*newType>

// ./actions/auth.js
import {
// <*newType overwrite snippet='  {{name}},' where="data.name.startsWith('user')">
    authLogin
// </*newType> 
} from './types'
// <*newType where="data.name.startsWith('auth')" snippet="export const {{ name }}Action = (data) => ({ type: {{ name }}, data })>
export const authLoginAction = (data) => ({ type: authLogin, data });
// </*newType>