@@ -0,0 +1,365 @@
1+---
2+navhome: /docs
3+title: Javascript
4+sort: 9
5+next: true
6+---
7+
8+# Javascript
9+
10+From [Joe Bryan](https://github.com/joemfb/nock.js/blob/master/nock.js):
11+
12+```js
13+(function (self, factory) {
14+ 'use strict'
15+
16+ if (typeof define === 'function' && define.amd) {
17+ define([], factory)
18+ } else if (typeof module === 'object' && typeof module.exports === 'object') {
19+ module.exports = factory()
20+ } else {
21+ self.nock = factory()
22+ }
23+}(this, function () {
24+ 'use strict'
25+
26+ /**
27+ * Nock is a combinator interpreter on nouns. A noun is an atom or a cell.
28+ * An atom is an unsigned integer of any size; a cell is an ordered pair of nouns.
29+ *
30+ * @see http://urbit.org/docs/nock/definition/
31+ * @see http://media.urbit.org/whitepaper.pdf
32+ */
33+
34+ var useMacros = false
35+
36+ /*
37+ * code conventions:
38+ *
39+ * `n` is a noun,
40+ * `s` is a subject noun,
41+ * `f` is a formula (or cell of formulas)
42+ */
43+
44+ /* operators */
45+
46+ /**
47+ * wut (?): test for atom (1) or cell (0)
48+ *
49+ * ?[a b] 0
50+ * ?a 1
51+ */
52+ function wut (n) {
53+ return typeof n === 'number' ? 1 : 0
54+ }
55+
56+ /**
57+ * lus (+): increment an atom
58+ *
59+ * +[a b] +[a b]
60+ * +a 1 + a
61+ */
62+ function lus (n) {
63+ if (wut(n) === 0) throw new Error('lus cell')
64+ return 1 + n
65+ }
66+
67+ /**
68+ * tis (=): test equality
69+ *
70+ * =[a a] 0
71+ * =[a b] 1
72+ * =a =a
73+ */
74+ function tis (n) {
75+ if (wut(n) === 1) throw new Error('tis atom')
76+ return deepEqual(n[0], n[1]) ? 0 : 1
77+ }
78+
79+ /**
80+ * fas (/): resolve a tree address
81+ *
82+ * /[1 a] a
83+ * /[2 a b] a
84+ * /[3 a b] b
85+ * /[(a + a) b] /[2 /[a b]]
86+ * /[(a + a + 1) b] /[3 /[a b]]
87+ * /a /a
88+ */
89+ function fas (addr, n) {
90+ if (n === undefined) throw new Error('invalid fas noun')
91+ if (addr === 0) throw new Error('invalid fas addr: 0')
92+
93+ if (addr === 1) return n
94+ if (addr === 2) return n[0]
95+ if (addr === 3) return n[1]
96+
97+ return fas(2 + (addr % 2), fas((addr / 2) | 0, n))
98+ }
99+
100+ /* formulas */
101+
102+ /**
103+ * slot (0): resolve a tree address
104+ *
105+ * *[a 0 b] /[b a]
106+ */
107+ function slot (s, f) {
108+ var p = fas(f, s)
109+
110+ if (p === undefined) throw new Error('invalid fas addr: ' + f)
111+
112+ return p
113+ }
114+
115+ /**
116+ * constant (1): return the formula regardless of subject
117+ *
118+ * *[a 1 b] b
119+ */
120+ function constant (s, f) {
121+ return f
122+ }
123+
124+ /**
125+ * evaluate (2): evaluate the product of second formula against the product of the first
126+ *
127+ * *[a 2 b c] *[*[a b] *[a c]]
128+ */
129+ function evaluate (s, f) {
130+ return nock(nock(s, f[0]), nock(s, f[1]))
131+ }
132+
133+ /**
134+ * cell (3): test if the product is a cell
135+ *
136+ * *[a 3 b] ?*[a b]
137+ */
138+ function cell (s, f) {
139+ return wut(nock(s, f))
140+ }
141+
142+ /**
143+ * incr (4): increment the product
144+ *
145+ * *[a 4 b] +*[a b]
146+ */
147+ function incr (s, f) {
148+ return lus(nock(s, f))
149+ }
150+
151+ /**
152+ * eq (5): test for equality between nouns in the product
153+ *
154+ * *[a 5 b] =*[a b]
155+ */
156+ function eq (s, f) {
157+ return tis(nock(s, f))
158+ }
159+
160+ /* macro-formulas */
161+
162+ /**
163+ * ife (6): if/then/else
164+ *
165+ * *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
166+ */
167+ function macroIfe (s, f) {
168+ return nock(s, [2, [[0, 1], [2, [[1, [f[1][0], f[1][1]]], [[1, 0], [2, [[1, [2, 3]], [[1, 0], [4, [4, f[0]]]]]]]]]]])
169+ }
170+
171+ function ife (s, f) {
172+ var cond = nock(s, f[0])
173+
174+ if (cond === 0) return nock(s, f[1][0])
175+ if (cond === 1) return nock(s, f[1][1])
176+
177+ throw new Error('invalid ife conditional')
178+ }
179+
180+ /**
181+ * compose (7): evaluate formulas composed left-to-right
182+ *
183+ * *[a 7 b c] *[a 2 b 1 c]
184+ */
185+ function macroCompose (s, f) {
186+ return nock(s, [2, [f[0], [1, f[1]]]])
187+ }
188+
189+ function compose (s, f) {
190+ // alternate form:
191+ // return nock(nock(s, f[0]), constant(s, f[1]))
192+ return nock(nock(s, f[0]), f[1])
193+ }
194+
195+ /**
196+ * extend (8): evaluate the second formula against [product of first, subject]
197+ *
198+ * *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
199+ */
200+ function macroExtend (s, f) {
201+ return nock(s, [7, [[[7, [[0, 1], f[0]]], [0, 1]], f[1]]])
202+ }
203+
204+ function extend (s, f) {
205+ // alternate form:
206+ // return nock([compose(s, [[0, 1], f[0]]), s], f[1])
207+ return nock([nock(s, f[0]), s], f[1])
208+ }
209+
210+ /**
211+ * invoke (9): construct a core and evaluate one of it's arms against it
212+ *
213+ * *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
214+ */
215+ function macroInvoke (s, f) {
216+ return nock(s, [7, [f[1], [2, [[0, 1], [0, f[0]]]]]])
217+ }
218+
219+ function invoke (s, f) {
220+ var prod = nock(s, f[1])
221+ return nock(prod, slot(prod, f[0]))
222+ }
223+
224+ /**
225+ * hint (10): skip first formula, evaluate second
226+ *
227+ * *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
228+ * *[a 10 b c] *[a c]
229+ */
230+ function macroHint (s, f) {
231+ if (wut(f[0]) === 0) return nock(s, [8, [f[0][1], [7, [[0, 3], f[1]]]]])
232+ return nock(s, f[1])
233+ }
234+
235+ function hint (s, f) {
236+ if (wut(f[0]) === 0) {
237+ if (wut(f[0][1]) === 1) throw new Error('invalid hint')
238+ nock(s, f[0][1])
239+ }
240+ return nock(s, f[1])
241+ }
242+
243+ /* indexed formula functions */
244+ var macroFormulas = [slot, constant, evaluate, cell, incr, eq, macroIfe, macroCompose, macroExtend, macroInvoke, macroHint]
245+ var formulas = [slot, constant, evaluate, cell, incr, eq, ife, compose, extend, invoke, hint]
246+
247+ /**
248+ * nock (*)
249+ *
250+ * the nock function
251+ *
252+ * *[a [b c] d] [*[a b c] *[a d]]
253+ * *a *a
254+ */
255+ function nock (s, f) {
256+ if (wut(f[0]) === 0) return [nock(s, f[0]), nock(s, f[1])]
257+
258+ var idx = f[0]
259+
260+ if (idx > 10) throw new Error('invalid formula: ' + idx)
261+
262+ if (useMacros) return macroFormulas[idx](s, f[1])
263+
264+ return formulas[idx](s, f[1])
265+ }
266+
267+ /* construct a JS noun (group an array into pairs, associating right) */
268+ function assoc (x) {
269+ if (!x.length) return x
270+
271+ if (x.length === 1) return assoc(x[0])
272+
273+ return [assoc(x[0]), assoc(x.slice(1))]
274+ }
275+
276+ /* deep equality for arrays or primitives */
277+ function deepEqual (a, b) {
278+ if (a === b) return true
279+
280+ if (!(Array.isArray(a) && Array.isArray(b))) return false
281+ if (a.length !== b.length) return false
282+
283+ for (var i = 0; i < a.length; i++) {
284+ if (!deepEqual(a[i], b[i])) return false
285+ }
286+
287+ return true
288+ }
289+
290+ /* parse a hoon-serialized nock formula and construct a JS noun */
291+ function parseNoun (x) {
292+ if (Array.isArray(x)) return assoc(x)
293+
294+ if (typeof x === 'string') {
295+ var str = x.replace(/[\."']/g, '').split(' ').join(',')
296+ return assoc(JSON.parse(str))
297+ }
298+
299+ return x
300+ }
301+
302+ function nockInterface () {
303+ var args = [].slice.call(arguments)
304+ var subject, formula, noun
305+
306+ if (args.length === 1) {
307+ formula = parseNoun(args[0])
308+ } else if (args.length === 2) {
309+ subject = parseNoun(args[0])
310+ formula = parseNoun(args[1])
311+ } else {
312+ noun = assoc(args)
313+ subject = noun[0]
314+ formula = noun[1]
315+ }
316+
317+ if (!formula) throw new Error('formula required')
318+
319+ if (!subject) {
320+ // !=(~)
321+ subject = [1, 0]
322+ }
323+
324+ return nock(subject, formula)
325+ }
326+
327+ return {
328+ nock: nockInterface,
329+ _nock: nock,
330+ useMacros: function (arg) {
331+ useMacros = arg === undefined || arg
332+ return this
333+ },
334+ util: {
335+ assoc: assoc,
336+ parseNoun: parseNoun,
337+ deepEqual: deepEqual
338+ },
339+ operators: {
340+ wut: wut,
341+ lus: lus,
342+ tis: tis,
343+ fas: fas
344+ },
345+ formulas: {
346+ slot: slot,
347+ constant: constant,
348+ evaluate: evaluate,
349+ cell: cell,
350+ incr: incr,
351+ eq: eq,
352+ macroIfe: macroIfe,
353+ ife: ife,
354+ macroCompose: macroCompose,
355+ compose: compose,
356+ macroExtend: macroExtend,
357+ extend: extend,
358+ macroInvoke: macroInvoke,
359+ invoke: invoke,
360+ macroHint: macroHint,
361+ hint: hint
362+ }
363+ }
364+}))
365+```