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 🙏

© 2025 – Pkg Stats / Ryan Hefner

jaff

v0.0.4

Published

Jaff Ain't Filtering Files

Readme

Jaff Appends and Filters Files

build status

Jaff is a small macro language that allows conditional filtering of Files through external programs and Javascript or Coffeescript functions in a way similar to commandline pipes between programs. Jaff scripts can be written to cumulatively apply filters while expanding variables in the text. Here is an example:

#begin coffee
indent = (lines) ->
  return lines.map (line) ->
    return '    ' + line

folder = "/etc"
#end

#if process.env.TEST
foo
#else
bar
#end

Contents of the {folder} folder:

#filter !indent
#  filter nl
#    filter grep rc$
#    run ls -la {folder}
#    end
#  end
#end

Running this will print foo if process.env.TEST is defined and bar otherwise. Next it will list the contents of the /etc folder, filter out files ending with "rc", prepend a line number to each line and finally indent these lines. The output might look like this:

$ jaff example

bar

Contents of the /etc folder:

        1      -rw-r--r--   1 root    root      657 Mar 18  2012 bash.bashrc
        2      -rw-r--r--   1 root    root     3095 Jan  9 21:22 drirc
        3      -rw-r--r--   1 root    root      714 Nov  3  2011 inputrc
        4      drwxr-xr-x   2 root    root     4096 Mar  8  2013 lirc
        5      -rw-r--r--   1 root    root     4243 Dec 28 09:18 mail.rc
        6      -rw-r--r--   1 root    root     1347 Dec  9 21:55 quilt.quiltrc
        7      -rw-r--r--   1 root    root     3312 Jul 14  2011 screenrc
        8      -rw-r--r--   1 root    root     1437 Apr 25  2011 slsh.rc

Install

Using npm:

npm install -g jaff

Invocation

This program takes a single argument:

$ jaff <filename>

Alternatively a script can be written invoking jaff via the shebang line:

#!/usr/bin/env jaff

#begin coffee
foo = "This is foo"
#end
...

Keywords

The following keywords are defined: begin, end, if, elif, else, include, filter and run. Keywords appear following a comment at the beginning of a line. Both Javascript // and Coffeescript comments # are accepted and there may be whitespace between the comment and the keyword.

begin <js|coffee> ... end

Start a block of Javascript or Coffeescript code. Variables and code can be referenced in variable expansions outside of the begin block.

Note that all variable expansions are interpreted as Javascript, even if they have been defined in a begin coffee block. See section variable expansion.

Also note that begin blocks are cumulative meaning that all begin blocks will use the same environment to place functions and variables.

The addition of begin blocks containing javascript code was inspired by PYM - A Macro Preprocessor Based on Python.

end

The end keyword ends the nearest begin, if or filter block.

if <condition>, elif <condition>, else ... end

Evaluate <condition> as Javascript. If it evaluates to a truthy value the lines immediately following this branch of the conditional up to the next else, elif or end statement are included in the output.

#if 'foo' === 'bar'
    Not shown
#elif 1
    This is shown
#else
    Not shown
#end

include <filename>

Attempt to include the file in <filename>. If the file does not exist try if the file can be found in parent paths up to the root.

  • TODO add include! <filename> to include raw data?

run <command>

Run the external program in <command> almost[1] as if it were invoked on the command line.

filter <command|!function> ... end

Run an external program like the run command and pipe the lines until end through this command:

#filter nl
One
Two
#end

Note that filtering through an external program is subject to shell escape limitations. [1]

If the <command> is prefixed with an exclamation mark, command is taken to be a function to filter commands through as in the example at the top of this document.

[1] This is not quite correct at the moment because shell expansion is not taken correctly into account.

Variable expansions

{code}

Run code as javascript. The code may reference variables and functions declared in begin ... end blocks. This code may reference variables and functions that are globals in node as well as some special variables:

  • __version The version of jaff
  • __argv The arguments passed to the script
  • __quotes Change code reference quoting characters

The default quoting of a reference is {} but may be changed using the __quotes() function in a begin block:

__quotes '[[', ']]'