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

nock.js

v1.1.0

Published

Nock interpreter

Readme

nock.js

Nock is a combinator interpreter on nouns. A noun is an atom or a cell. An atom is an unsigned integer of any size; a cell is an ordered pair of nouns.

Nock is the foundational layer of Urbit.

nock.js is a toy interpreter, built for the fun of it.

usage

  • install from npm: npm install nock.js
var nock = require('nock.js')
nock.nock(1, [0, 1])
// => 1
  • or, clone and run
git clone https://github.com/joemfb/nock.js.git
cd nock.js
node example.js
  • run unit tests
npm install
npm test
  • load it in the browser (nock.js is a UMD module):
<script src="./nock.js"></script>
<script>
  nock.nock(1, [0, 1])
  // => 1
</script>

methods

See urbit.org/docs/nock/definition/ for an explanation of the pseudocode reduction rules that make up the Nock spec.

nock
nock(a)          *a
[a b c]          [a [b c]]
*[a [b c] d]     [*[a b c] *[a d]]
*a               *a

nock() recursively applies formulas (tail of its argument) to the subject (head of its argument).

nock.nock(1, [0, 1])
// 1

Nock nouns are always atoms (unsigned integers) or cells (a pair of nouns). The JS analogue to a cell is Array(2), so nock() converts Array arguments into nouns, associating right:

nock.nock([1, 2, 3], [0, 1])
// [1,[2,3]]

The subject can be omitted if the formula doesn't reference it:

nock.nock([1, 1])
// 1

Formulas without a subject are evaluated against [1, 0], which is Hoon null (~).

For convenience in evaluating generated formulas, arguments can be passed as strings (see generating formulas below):

nock.nock("[1 2 3]", "[0 1]")
// [1,[2,3]]
operators

Nock defines four operators:

?[a b]           0
?a               1
+[a b]           +[a b]
+a               1 + a
=[a a]           0
=[a b]           1
=a               =a

/[1 a]           a
/[2 a b]         a
/[3 a b]         b
/[(a + a) b]     /[2 /[a b]]
/[(a + a + 1) b] /[3 /[a b]]
/a               /a
  • wut (?): test for an atom (1) or cell (0)
  • lus (+): increment an atom
  • tis (=): test equality
  • fas (/): resolve a tree address

See urbit.org/docs/hoon/syntax for an explanation of the the method names

Operators are exported in the nock.operators namespace:

nock.operators.fas(2, [5, 9])
// 5

Unlike nock(), operators require both arguments to be present and valid nouns.

formulas

Nock defines 6 primitive formulas:

*[a 0 b]         /[b a]
*[a 1 b]         b
*[a 2 b c]       *[*[a b] *[a c]]
*[a 3 b]         ?*[a b]
*[a 4 b]         +*[a b]
*[a 5 b]         =*[a b]
  • slot (0): resolve a tree address
  • constant (1): return the formula regardless of subject
  • evaluate (2): evaluate the product of second formula against the product of the first
  • cell (3): test if the product is a cell
  • incr (4): increment the product
  • eq (5): test for equality between nouns in the product

And five additional formulas, reducible to the 6 above:

*[a 6 b c d]     *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
*[a 7 b c]       *[a 2 b 1 c]
*[a 8 b c]       *[a 7 [[7 [0 1] b] 0 1] c]
*[a 9 b c]       *[a 7 c 2 [0 1] 0 b]
*[a 10 [b c] d]  *[a 8 c 7 [0 3] d]
*[a 10 b c]      *[a c]
  • ife (6): if/then/else
  • compose (7): evaluate formulas composed left-to-right
  • extend (8): evaluate the second formula against [product of first, subject]
  • invoke (9): construct a core and evaluate one of it's arms against it
  • hint (10): skip first formula, evaluate second

Formulas are exported in the nock.formulas namespace:

nock.nock(2, [8, [[4, [1, 1]], [0, 1]]])
// [2, 2]
nock.formulas.eq(2, [8, [[4, [1, 1]], [0, 1]]])
// 0

As in the case of nock.operators, formulas require both arguments to be present and valid nouns.

Formulas 6-10 are implemented in two ways: directly by the interpreter, and as evaluated macro expansions:

nock.formulas.extend(42, [[4, [0, 1]], [0, 1]])
// [43, 42]
nock.formulas.macroExtend(42, [[4, [0, 1]], [0, 1]])
// [43, 42]

By default, the direct implementations are used. To use the macro expansions instead:

nock.useMacros()
nock.nock(42, [8, [[4, [0, 1]], [0, 1]]])
// [43, 42]

generating formulas

Hoon, the native language of Urbit, is also the language of dojo, the Urbit shell. Hoon expressions are compiled into Nock formulas, which are interpreted.

~novlen-hanweb:dojo> 1
1

Hoon -> Nock compilation is a first class primitive in Hoon (:code or !=):

~novlen-hanweb:dojo> !=(1)
[1 1]

as is the Nock formula itself (:nock or .*):

~novlen-hanweb:dojo> .*(. [1 1])
1
~novlen-hanweb:dojo> .*(. !=(1))
1

As previously noted, nock() can evaluate formulas passed as strings:

nock.nock('[1 1]')
// => 1

For convenience, convert your Nock formula to a string directly in dojo (technically, print your noun to a tape):

~novlen-hanweb:dojo> <!=(1)>
"[1 1]"

generating decrement

Hoon provides a decrement function in it's standard library:

~novlen-hanweb:dojo> (dec 10)
9

The implemention for dec is in a core - compiling it to Nock results in a formula that references that core, not a standalone decrement implementation:

~novlen-hanweb:dojo> !=((dec 10))
[8 [9 24.834.031 0 31] 9 2 [0 4] [7 [0 3] 1 10] 0 11]

There's probably a way to de-reference that core address (24.834.031) and compile the implementation - but I don't know it... Instead, we can evaluate the standard-library decrement implementation directly:

++  dec                                                 ::  decrement
  ~/  %dec
  |=  a/@
  ~|  %decrement-underflow
  ?<  =(0 a)
  =+  b=0
  |-  ^-  @
  ?:  =(a +(b))  b
  $(b +(b))

from urbit.org/docs/hoon/library/1a/#-dec

Converting the linked implementation from tall-form to flat-form (and removing the hint instructions) results in this expression:

|=(a/@ ?<(=(0 a) =+(b=0 |-(^-(@ ?:(=(a +(b)) b $(b +(b))))))))

which we can evaluate:

~novlen-hanweb:dojo> (|=(a/@ ?<(=(0 a) =+(b=0 |-(^-(@ ?:(=(a +(b)) b $(b +(b)))))))) 10)
9

compile to Nock (with !=):

~novlen-hanweb:dojo> !=((|=(a/@ ?<(=(0 a) =+(b=0 |-(^-(@ ?:(=(a +(b)) b $(b +(b)))))))) 10))
[ 8
  [8 [1 0] [1 6 [5 [1 0] 0 6] [0 0] 8 [1 0] 8 [1 6 [5 [0 30] 4 0 6] [0 6] 9 2 [0 2] [4 0 6] 0 7] 9 2 0 1] 0 1]
  9
  2
  [0 4]
  [7 [0 3] 1 10]
  0
  11
]

evaluate the compiled Nock (with .*):

~novlen-hanweb:dojo> .*(~ !=((|=(a/@ ?<(=(0 a) =+(b=0 |-(^-(@ ?:(=(a +(b)) b $(b +(b)))))))) 10)))
9

print to a tape (with <...>):

~novlen-hanweb:dojo> <!=((|=(a/@ ?<(=(0 a) =+(b=0 |-(^-(@ ?:(=(a +(b)) b $(b +(b)))))))) 10))>
"[8 [8 [1 0] [1 6 [5 [1 0] 0 6] [0 0] 8 [1 0] 8 [1 6 [5 [0 30] 4 0 6] [0 6] 9 2 [0 2] [4 0 6] 0 7] 9 2 0 1] 0 1] 9 2 [0 4] [7 [0 3] 1 10] 0 11]"

and, finally, evaluate in nock.js:

nock.nock("[8 [8 [1 0] [1 6 [5 [1 0] 0 6] [0 0] 8 [1 0] 8 [1 6 [5 [0 30] 4 0 6] [0 6] 9 2 [0 2] [4 0 6] 0 7] 9 2 0 1] 0 1] 9 2 [0 4] [7 [0 3] 1 10] 0 11]")
// 9

To get up and and running with an urbit, see github.com/urbit/urbit and urbit.org/docs/using/install/.