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 🙏

© 2026 – Pkg Stats / Ryan Hefner

foldmaker

v1.0.5

Published

A small parser generator toolkit that can be used to build parsers, transpilers, formatters.

Downloads

5

Readme

Foldmaker is a lightweight tool (~120 lines uncommented), and a way of thinking for building parsers. It was designed to be minimal and user-friendly. Foldmaker has its own characteristic parsing technique. This technique results in very compact parsers. You can implement a JSON parser only in ~45 lines or SCSS-like preprocessors only in ~50 lines.

"Parsing is re-tokenization"

This is Foldmaker's motto, and its embodied in Foldmaker's architecture. The tokenizer function is also used as the parser function internally. First to tokenize our string, then to tokenize our token stream. Then we use it again, on the resulting token stream, and so on. More on this is explained below.

Special versions

Examples

Installation

Foldmaker can be installed with npm, by the following command:

npm install foldmaker

Importing Foldmaker by the default export is enough:

import  Foldmaker  from  'foldmaker'

How it works?

In Foldmaker, tokenization and parsing are analogous processes. Our tokenizer function is also used as the parser function under the hood. First our string gets tokenized by it, then our token stream gets tokenized. This is possible, because in Foldmaker, token stream is a string! This is possible thanks to the first rule of Foldmaker's specification:

  1. Always use one-character token names

While this rule may seem to restrict the user, but it has its own advantages. Let me explain. Let's say, in the following string, we want to match the condition inside the if block. We want to identify foo === 1 part as the "condition" .

if(foo === 1) { print('ONE') }

Imagine, after tokenization, we have the following array of tokens. i for if, p for primitive, o for operator and b for body.

let tokens = [
  {type: "i", value: "if"},
  {type: "(", value: "("},
  {type: "p", value: "foo"},
  {type: "o", value: "==="},
  {type: "p", value: "1"},
  {type: ")", value: ")"},
  {type: "b", value: "{ print('ONE') }"}
]

Now let's input our array of tokens inside Foldmaker like below:

let fm = Foldmaker(tokens)

we get the following FoldmakerObject.

{
  array: ["if", "(", "foo ", "=== ", "1", ") ", "{ print('ONE') }"  ],
  string: "i(pop)b",
  __proto__: FoldmakerObject
}

This is the first maneuver of Foldmaker. It creates two streams by joining types and values. Observe that each element of the string maps to an element in the array with the same index, and vice versa. Now, let's return to our case. In our case, we need to match the string that is represented by pop (primitive, operator, primitive in series) right? Let's say that we are going to mark that as c (condition). First, let's log our matching occurrence in the console.

We simply use replace method of Foldmaker:

let fm = fm.replace(/pop/, result => console.log(result))
console.log(fm.string)

Console output:

First log: {
  raw: ["foo",  "===",  "1"],
  map: ["pop",  index:  0,  input:  "pop)b",  groups:  undefined],
  index: 2,
  count: 3
}
Second log: "i(pop)b"

As you can see on the first log, our occurrence is shown in the raw key. Since we didn't return anything inside the callback function of the replace method, the string in our Foldmaker instance (fm.string) did not change, as can be seen on the second log. Let's manipulate If we return something inside the callback function as the following:

let fm = fm.replace(/pop/, result => {
	return ['c', { value: result.raw }]
})
console.log(fm)

console output will be:

{
  array: ["if", "(", Object, ") ", "{ print('ONE') }"  ],
  string: "i(c)b",
}

Input string:

{"a": 1, "b": 2, "c": [1, 2, 3, {"deep": {}}]}

Foldmaker's parsing steps:

Token stream : {s:n,s:n,s:[n,n,n,{s:{}}]}
Iteration 1  : {k,k,s:[n,n,n,{s:o}]}
Iteration 2  : {k,k,s:[n,n,n,{k}]}
Iteration 3  : {k,k,s:[n,n,n,o]}
Iteration 4  : {k,k,s:a}
Iteration 5  : {k,k,k}
Iteration 6  : o
Iteration 7  : o

API

Exports

| Export | Usage | Description | |-----------------------------|--------------------------------------|--------------| | default (function) | Foldmaker(tokensArray) | Takes a tokensArray and returns a FoldmakerObject | | tokenize (function) | tokenize(string, dictionary {, callback }) | Tokenizes the string by using dictionary. Returns an array of tokens. | | traverse (function) | traverse(node, callback) | Conducts tree traversal for node. Node can be of type non-array or array. | | visitor (function) | visitor(regexp, callback) | Is a helper function | | FoldmakerObject (class) | - | | | fm (function) | fm(tokensArray) | Is a shorthand for default export (circular) |

Methods of FoldmakerObject

| Method | Usage | Arguments of callback | | | |----------|--------------------------------------|---------------------------------|---|---| | parse | parse(regex , callback {, debug }) | (result {, state {, oldState}}) | | | | replace | replace(regex , callback {, debug }) | (result {, state {, oldState}}) | | | | traverse | traverse(callback) | (object {, alsoTraverse}) | | | | add | add(string, array) | - | | |

Useful Links

License

Licensed by the MIT License.