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

broute

v2.2.0

Published

procedural router

Downloads

5

Readme

broute - brutal router

Build Status

import {path, navigate} from 'broute'

path

path(f)
path(p,f)
path(p,f,fe)

Tests the given part fragment p and if current path matches, consumes the fragment and invokes function f. If not match, no consume and invoke optional function fe.

  • p - path fragment to match from current scope
  • f - function to invoke if fragment matches
  • fe - optional "else" function to invoke if fragment doesnt match
  • return - the result of f or fe

vararg paths to test

path(p1,f1,p2,f2,...,pn,fn,fe)

Any number of paths can be tested and the first one that matches is run.

function args

The f or fe is invoked with (left, query). The first is the path that is left after the p fragment has been consumed (not for fe).

  • left - the path that is left after consuming fragment p
  • search - the search parameters as object ?a=b becomes {a:'b'}

root

On the root level, we can use path without a string arg. This is the starting point of the route function that is invoked for every url change. There can only be one root level path installed for each router.

path(() => {

})
navigate() // run route on startup

The root level path returns the navigate function. path(() => {...})('/start')

path usage

The following usage shows how nested path declarations creates "scoped" functions that consumes part of the current url.

// the current url is: "/some/path/deep?panda=42"

path(() => {

    path('/some', (left, query) => {
        // at this point we "consumed" '/some'
        // and left is "/path/deep"
        // and query is {panda:42}
        path('/path/deep', (left, query) => {
          // left is "" and query is {panda:42}
        })
    })
    // at this point we haven't consumed anything
    path('/another', () => {
        // will not be invoked for the current url
    })
})
navigate() // run first route

path example 2

path(() => {

    path('/news/', (slugId) => {                  // consume '/news/'
        action('selectarticle', slugid)           // fire action to fetch article
    }, () => {
        action('refreshnewslist')                 // else refresh news list
    })
    path('/aboutus', () => {                      // consume '/aboutus'
        action('showaboutus')
    })
})() // run first route

navigate

navigate(l,trigger)
navigate(l)
navigate()

Navigates to the location l using pushState and checks to see if the url changed in which case the path function is invoked.

  • l - location to set. example /my/page?foo=42.
  • trigger - whether to trigger the route. defaults to true.

Navigate with no argument is used to trigger a check of the current path in the window.location object. It's typically only used on startup or to detect path changes due to pushState without using navigate.

navigate example

// if browser is at "http://my.host/some/where"

navigate('other')   // changes url to "http://my.host/some/other"
navigate('/news')   // changes url to "http://my.host/news"

lazy

navigate is lazy when used inside a path. in this example, only /a and /c would be run. Furthermore the invocation of /c only happens at the end of the root path function.

path(() => {
    navigate("/b")
    navigate("/c")
    if (someCondition()) {
        ... // more code
    }
    // conceptually navigate("/c") happens here
})  
navigate("/a")

Creating routers

For advanced usages, new routers can be created around arbitrary "window" objects.

Conceptually broute does this for the default path and navigate functions around a current global window variable:

import router from 'broute'         // router function

{path, navigate} = router(window)  // create a router around window

If the window argument has an addEventListener function, a listener will be added for popstate events. This means broute will run the path function also for the back button as well as via navigate.

On each popstate or navigate invocation, the window argument is inspected for a property window.location which is expected to hold an object:

{
  pathname: "/current/path", 
  search:   "?my=query"
}

If this object changes on navigate or popstate, the path function is run.

If the window doesn't have a window.history.pushState function, navigate will fall back on manipulating window.location directly.

License

The MIT License (MIT)

Copyright © 2016 Martin Algesten

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.