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

hickery

v0.26.3

Published

Composeable queries for hyperscript trees

Downloads

35

Readme

Hickery

pipeline status coverage report

But by and by pap got too handy with his hick 'ry, and I couldn't stand it.

Scalable data manipulation with a special focus on Virtual DOM trees.

A Lens-like Library with a convenient interface.
  • Very Composeable
  • VDOM library neutral
  • Query any structure, built in utils for frontend.
  • fast
  • <3kb
  • Client + Server Compatible (no tricks!)
  • Built for testing, decorating, theming and state management!

Quick Start

// Works with any hyperscript query library (see configs)
const $ = require('hickery')

// A given hyperscript library (could be JSX too)
const m = require('mithril')

const tree = () =>
    m( 'div'
        , m('ul'
            ,m('li', 1)
            ,m('li', 2)
            ,m('li', 3)
        )
    )


const query = f =>
    $.compose( 
        $.child.first
        , $.child.all
        , $.className 
    )

query ( x => x + ' red') (tree)

/* Returns:
*
* m('div'
*    ,m('ul
*        ,m('li.red', 1)
*        ,m('li.red', 2)
*        ,m('li.red', 3)
*    )
* )
*
*/

Modules

Hickery is a general purpose idea. It's easy to use them to work with any data format. But hickery comes with some modules preconfigured for certain use cases. If there's a module you'd like to see here, please submit a pull request!

Why would I use hickery queries?

Let's say you are using an autocomplete library like manuel.

It offers oodles of configuration, but despite all that, you find you still need to update a classname in a place that would require recreating business logic to override.

This library let's you define queries that allow you to make that transform. And you can decorate the original component so the rest of your codebase doesn't need to know about the changes you've made.

// queries
const $div = $.root
const $ul = $div($.child.nth(1))
const $li = $ul($.child.all)
const $input = $div($.child.first)

// action
const addRedToListItems =
    $li(
        $.className(
            $.class.add('red')
        )
     )
// action
const increaseInputFontSize =
    $input(
        $.style( $.merge({ fontSize: '1.1em' }) )
    )

// a decorated component, it will be styled after the original component runs
const decorated =
    $.compose(
        increaseInputFontSize,
        addRedToListItems,
        autocomplete
    )

// in your view, call it as normal
decorated(normalLibraryOptions)

The one smell in all of this is that you need to know the particular HTML structure of the library you are using. But this is where I'd like to encourage library others to export queries to points of interest in their components.

The dream is, instead of providing 100's of overrides and hooks, the library can provide you with a composeable interface to add styles, attributes and event listeners without needing to open any issues or pull requests.

Of course it's early days, but I'm planning to do exactly that with my libraries. And in doing so I'll be able to delete a lot of hooks that guess at my user's requirements.

You don't need to import Hickery to do that. It's just a particular pattern you can use when providing a hook.

const aQuery = visitor = context => {

    // do something with visitor on context
    visitor(context)

    // return an object with the same structure as the original context
    return context
}

If you follow this pattern, your queries will compose with other queries. And we can build a standard library for composeable traversals of nested data. Meanwhile your users are handed a query to a particular focal point in your DOM heirarchy and their transformations are decoupled from library internals.

API

TODO UNSTABLE

  • pathOr
  • path
  • Query
  • QueryOr
  • PureQuery
  • PureQueryOr
  • compose
  • merge
  • class.add
  • class.remove
  • child.nth
  • child.all
  • child.first
  • child.last
  • style
  • root
  • attrs
  • children
  • tag
  • props
  • events
  • className
  • select
  • set
  • lens.view
  • lens.set
  • lens.over

Examples

TODO UNSTABLE

Supporting Hickery Queries for your Component Library

Hickery Queries are more a pattern than a library. In the same that node style callbacks allowed a lot of libraries to write interoperable async code prior to the introduction of promises - Hickery is a pattern that allows users of your library to safely transform output.

You can support Hickery Queries without importing Hickery. Let's say for example, you want to provide the user of your library the ability to query an input that is nested within a larger structure. You don't want them to hard code against that structure, but you also don't want to assume their intentions and give them an overly specific hook.

This is how you could do that in 100% Vanilla JS

export $input = visitor => rootNode => {

    const inputReference =
        // manually grab it wherever it lives
        rootNode.children[0].children[0]

    visitor(n)

    return rootNode
}

You could export this as part of your library, and you can ignore the naming conventions hickery uses.

E.g. you might export $input as:

export default {
    someComponent
    ,queries: {
        input: $input
    }
}

Or

export default {
    someComponent
    ,tranformInputNode: $input
}

Now users of your library could use this function directly to define hooks that are relevant to them.

import { transformInputNode, someComponent } from 'wherever'


const addOnFocusOnBlurHooks =
    transformInputNode( input => Object.assign(input.attrs,{ onfocus, onblur }) )

addOnFocusOnBlurHooks( someComponent({ /* normal component options */ }) )

But because you followed this standard query format, they could import hickery and access a suite of utilities for transforming virtual dom trees.

const { transformInputNode, someComponent } = require('wherever')
const $ = require('hickery')

const addOnFocusOnBlurHooks =
    transformInputNode(
        // vdom library neutral transform
        $.events( o => ({...o, onfocus, onblur))
    )

const newComponent =
    $.compose(
        addOnFocusOnBlurHooks
        ,someComponent
    )

// decorated component
newComponent(/* normal component options */)

Acknowledgements and Prior Art

Thanks to Keith Cirkel for helping me set up the automated NPM deployment.

Thanks to all the thinkers who in aggregate invented/uncovered functional references. Including Jeremy Gibbons, Bruno C. D. S Oliviera, Luke Palmer, Twan van Laarhoven, Russel O'Connor and Edward Knett. I don't know enough of the history (yet) but I appreciate all the deep thought and hard work required.

Special thanks to Hardy Jones, Scott Christopher, Johnny Hauser, Vesa Karvonen and Brad Compton for helping me to understand Lenses. Hanging out in the Ramda chatroom is good for the soul.

Special thanks to Barney Carroll for all the design discussions and the many insights you provided. Patchinko was a huge inspiration for this library's interpretation of lenses.