{"id":16095861,"url":"https://github.com/joakin/furgoneta","last_synced_at":"2025-04-05T20:15:41.236Z","repository":{"id":7379880,"uuid":"8707200","full_name":"joakin/furgoneta","owner":"joakin","description":"Functional JS library","archived":false,"fork":false,"pushed_at":"2013-06-10T19:57:46.000Z","size":2100,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-11T21:38:36.826Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joakin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-03-11T16:00:48.000Z","updated_at":"2014-01-18T12:26:21.000Z","dependencies_parsed_at":"2022-08-27T23:02:49.051Z","dependency_job_id":null,"html_url":"https://github.com/joakin/furgoneta","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joakin%2Ffurgoneta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joakin%2Ffurgoneta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joakin%2Ffurgoneta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joakin%2Ffurgoneta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joakin","download_url":"https://codeload.github.com/joakin/furgoneta/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247393573,"owners_count":20931813,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-09T17:09:15.594Z","updated_at":"2025-04-05T20:15:41.185Z","avatar_url":"https://github.com/joakin.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## furgoneta\n\nHelper library to make functional programming in JS easier.\n\nDisclaimer: **This is a work in progress and a personal project to learn\nfunctional concepts, how are they implemented and to become familiar with\nthem. Despite all this, it is usable, tested and it works.**\n\n## Usage\n\n### From a browserify enabled client side module\n\nIf you are developing a module or application and using browserify as a module\nloader, then just include furgoneta on the `package.json` as a\ndependency, and require it normally.\n\n### From a server side node.js module\n\nSame as above. Declare the dependency on the `package.json` of your module/app\nand require it normally.\n\n### From a browser side application that does NOT use browserify\n\nYou have to grab the file `browser/furgoneta.js` or\n`browser/furgoneta-min.js` and include it on your page after the\nrequired dependencies. It will define a global variable on the window object\ncalled `furgoneta`, that you can use then normally.\n\n\n## Contents\n\nNext you will find a list of functions exported by furgoneta, classified by groups,\nas they are in the source code.\n\nOn the samples, we will asume that we imported and are using the furgoneta library\nwith the variable `f` as if we had done:\n\n```javascript\nvar f = require('furgoneta')\n```\n\n#### Documentation terms and reference\n\n* `...args` : refers to an indeterminate number of arguments, a variadic function\n* `idx`     : var name of an index or key\n* `x`       : var name usually used to indicate an item or value\n* `xs`      : var name of a sequence or collection\n* `fn`      : var name of a function.\n* `fn(x)`   : var name of a function that will receive a param `x` (an item).\n\nNote that along the docs, the examples' output will be noted in nearby comments.\n\n\n### Arguments\n\nUtilities and functions to work with arguments.\n\n#### toArray(...args)\n\nConverts an arguments variable into a JS array.\n\n```javascript\n(function() {\n  console.log(f.toArray(arguments))  // \u003e [ 1, 'Hello', 2 ]\n})(1, 'Hello', 2)\n```\n\n\n### Arrays\n\nUtilities and functions to work with javascript arrays.\n\n#### first(xs)\n\nReturns the first element of the array.\n\n```javascript\nf.first([ 1, 2, 3, 4 ]) // \u003e 1\n```\n\n#### last(xs)\n\nReturns the last element of the array.\n\n```javascript\nf.last([ 1, 2, 3, 4 ])  // \u003e 4\n```\n\n#### rest(xs)\n\nReturns the rest of elements of the array, that is all but the first one.\n\n```javascript\nf.rest([ 1, 2, 3, 4 ])  // \u003e [ 2, 3, 4 ]\n```\n\n#### initial(xs)\n\nReturns the initial elements of the array, that is all but the last one.\n\n```javascript\nf.initial([ 1, 2, 3, 4 ])  // \u003e [ 1, 2, 3 ]\n```\n\n\n### Objects\n\nUtilities and functions to work with javascript objects.\n\n#### keys(obj)\n\nReturns the keys of the object in an array.\n\n```javascript\nf.keys({ a: 1, b: 2 }) // \u003e [ 'a', 'b' ]\n```\n\n#### extend(...args)\n\nExtends all the objects passed as arguments from right to left into a new\nobject. For the moment it is not recursive so properties that are objects will\nbe copied by reference.\n\n```javascript\nvar o = f.extend(\n  { a: 1, b: 1 },\n  { b: 2 },\n  { c: 3 }\n)\n// \u003e { a: 1, b: 2, c: 3 }\n```\n\n\n### Collections\n\nWe can consider collections to groups of items, and there are multiple\nfunctions we can use to manipulate them. Any object or array will work with\nthis functions.\n\n#### each(fn(x, idx, xs), xs)\n\nIterate through a collection from left to right calling fn.\n\n```javascript\nvar logger = function(x, idx, xs) {\n  console.log('Item: ', x, ', Idx: ', idx, ', Coll: ', xs)\n}\n\n// With arrays:\n\nf.each(logger, [ 1, 2, 3 ])\n// \u003e Item: 1 , Idx: 0 , Coll: [ 1, 2, 3 ]\n// \u003e Item: 2 , Idx: 1 , Coll: [ 1, 2, 3 ]\n// \u003e Item: 3 , Idx: 2 , Coll: [ 1, 2, 3 ]\n\n// With objects\n\nf.each(logger, { a: 1, b: 2, c: 3 })\n// \u003e Item:  1 , Idx:  a , Coll:  { a: 1, b: 2, c: 3 }\n// \u003e Item:  2 , Idx:  b , Coll:  { a: 1, b: 2, c: 3 }\n// \u003e Item:  3 , Idx:  c , Coll:  { a: 1, b: 2, c: 3 }\n```\n\n#### eachRight(fn(x, idx, xs), xs)\n\nIterate through a collection from right to left calling fn.\n\n```javascript\nvar logger = function(x, idx, xs) {\n  console.log('Item: ', x, ', Idx: ', idx, ', Coll: ', xs)\n}\n\n// With arrays:\n\nf.eachRight(logger, [ 1, 2, 3 ])\n// \u003e Item:  3 , Idx:  2 , Coll:  [ 1, 2, 3 ]\n// \u003e Item:  2 , Idx:  1 , Coll:  [ 1, 2, 3 ]\n// \u003e Item:  1 , Idx:  0 , Coll:  [ 1, 2, 3 ]\n\n// With objects\n\nf.eachRight(logger, { a: 1, b: 2, c: 3 })\n// \u003e Item:  3 , Idx:  c , Coll:  { a: 1, b: 2, c: 3 }\n// \u003e Item:  2 , Idx:  b , Coll:  { a: 1, b: 2, c: 3 }\n// \u003e Item:  1 , Idx:  a , Coll:  { a: 1, b: 2, c: 3 }\n```\n\n#### map(function(x, idx, xs), xs)\n\nApply fn through the items of a collection and return an array of the results.\n\n```javascript\nvar double = function(x) { return x * x }\n\nf.map(double, [ 1, 2, 3 ])\n// \u003e [ 1, 4, 9 ]\n\nf.map(double, { a: 1, b: 2, c: 3 })\n// \u003e [ 1, 4, 9 ]\n```\n\n#### reduce(fn(memo, x, idx, xs), seed, coll) *Alias: fold*\n\nApply fn to each element of the collection passing an accumulator.\n\nThe return value of fn will be the accumulator for the next iteration, when\nthe collection is over the last memo will be returned by `reduce`.\n\nThe first time it is called, `memo` gets the value of the parameter `seed`.\n\n```javascript\nvar scoreReducer = function(acc, x, idx, xs) {\n  console.log('Total:', acc, 'Item:', x, ', Idx:', idx, ', Coll:', xs)\n  return acc + x\n}\n\nf.reduce(scoreReducer, 10, [ 1, 2, 3 ])\n// \u003e Total: 10 Item: 1 , Idx: 0 , Coll: [ 1, 2, 3 ]\n// \u003e Total: 11 Item: 2 , Idx: 1 , Coll: [ 1, 2, 3 ]\n// \u003e Total: 13 Item: 3 , Idx: 2 , Coll: [ 1, 2, 3 ]\n// \u003e 16\n\nf.reduce(scoreReducer, 0, { john: 5, mary: 8 })\n// \u003e Total: 0 Item: 5 , Idx: john , Coll: { john: 5, mary: 8 }\n// \u003e Total: 5 Item: 8 , Idx: mary , Coll: { john: 5, mary: 8 }\n// \u003e 13\n```\n\n#### reduce1(fn(memo, x, idx, xs), coll) *Alias: fold1*\n\nWorks like reduce but it uses as seed value the first element of the\ncollection.\n\n```javascript\nvar scoreReducer = function(acc, x, idx, xs) {\n  console.log('Total:', acc, 'Item:', x, ', Idx:', idx, ', Coll:', xs)\n  return acc + x\n}\n\nf.reduce1(scoreReducer, [ 1, 2, 3 ])\n// \u003e Total: 1 Item: 2 , Idx: 1 , Coll: [ 1, 2, 3 ]\n// \u003e Total: 3 Item: 3 , Idx: 2 , Coll: [ 1, 2, 3 ]\n// \u003e 6\n\nf.reduce1(scoreReducer, { john: 5, mary: 8 })\n// \u003e Total: 5 Item: 8 , Idx: mary , Coll: { john: 5, mary: 8 }\n// \u003e 13\n```\n\n#### reduceRight(fn(memo, x, idx, xs), seed, coll) *Alias: foldR*\n\nSame as reduce but from right to left instead of left to right.\n\n```javascript\nvar scoreReducer = function(acc, x, idx, xs) {\n  console.log('Total:', acc, 'Item:', x, ', Idx:', idx, ', Coll:', xs)\n  return acc + x\n}\n\nf.reduceRight(scoreReducer, 10, [ 1, 2, 3 ])\n// \u003e Total: 10 Item: 3 , Idx: 2 , Coll: [ 1, 2, 3 ]\n// \u003e Total: 13 Item: 2 , Idx: 1 , Coll: [ 1, 2, 3 ]\n// \u003e Total: 15 Item: 1 , Idx: 0 , Coll: [ 1, 2, 3 ]\n// \u003e 16\n\nf.reduceRight(scoreReducer, 0, { john: 5, mary: 8 })\n// \u003e Total: 0 Item: 8 , Idx: mary , Coll: { john: 5, mary: 8 }\n// \u003e Total: 8 Item: 5 , Idx: john , Coll: { john: 5, mary: 8 }\n// \u003e 13\n```\n\n#### reduceRight1(fn(memo, x, idx, xs), coll) *Alias: foldR1*\n\nSame as reduce1 but from right to left instead of left to right.\n\n```javascript\nvar scoreReducer = function(acc, x, idx, xs) {\n  console.log('Total:', acc, 'Item:', x, ', Idx:', idx, ', Coll:', xs)\n  return acc + x\n}\n\nf.reduceRight1(scoreReducer, [ 1, 2, 3 ])\n// \u003e Total: 3 Item: 2 , Idx: 1 , Coll: [ 1, 2, 3 ]\n// \u003e Total: 5 Item: 1 , Idx: 0 , Coll: [ 1, 2, 3 ]\n// \u003e 6\n\nf.reduceRight1(scoreReducer, { john: 5, mary: 8 })\n// \u003e Total: 8 Item: 5 , Idx: john , Coll: { john: 5, mary: 8 }\n// \u003e 13\n```\n\n#### find(fn(x, idx, coll), xs) *Alias: detect*\n\nReturn the first element that passes the truth test `fn`.\n\n```javascript\nvar even = function(x) { return !(x % 2) }\nvar odd = f.compose(f.not, even)\n\nf.find(even, [ 1, 2, 3 ])\n// \u003e 2\n\nf.find(odd, { a: 4, b: 5, c: 6 })\n// \u003e 5\n```\n\n#### filter(fn(x, idx, coll), xs) *Alias: select*\n\nReturn all the elements that pass the truth test `fn`.\n\n```javascript\nvar even = function(x) { return !(x % 2) }\nvar odd = f.compose(f.not, even)\n\nf.filter(odd, [ 1, 2, 3 ])\n// \u003e [ 1, 3 ]\n\nf.filter(even, { a: 4, b: 5, c: 6 })\n// \u003e [ 4, 6 ]\n```\n\n#### reject(fn(x, idx, coll), xs)\n\nReturn all the elements that didn't pass the truth test `fn`. Returns the\ninverse of `filter`.\n\n```javascript\nvar even = function(x) { return !(x % 2) }\nvar odd = f.compose(f.not, even)\n\nf.reject(odd, [ 1, 2, 3 ])\n// \u003e [ 2 ]\n\nf.reject(even, { a: 4, b: 5, c: 6 })\n// \u003e [ 5 ]\n```\n\n#### every(fn(x, idx, coll), xs) *Alias: all*\n\nReturns true if all the elements in the collection pass the truth test `fn`.\n\n```javascript\nvar isEven = function(x) { return !(x % 2) }\n\nf.every(isEven, [1, 2, 3])\n// \u003e false\n\nf.all(isEven, [2, 4, 6])\n// \u003e true\n```\n\n#### some(fn(x, idx, coll), xs) *Alias: any*\n\nReturns true if any of the elements in the collection pass the truth test `fn`.\n\n```javascript\nvar isEven = function(x) { return !(x % 2) }\n\nf.some(isEven, [1, 2, 3])\n// \u003e true\n\nf.any(isEven, [2, 4, 6])\n// \u003e true\n\nf.any(isEven, [1, 3, 5])\n// \u003e false\n```\n\n### Functions\n\n#### compose(...args)\n\nCreates a new function that is the composition of the argument functions. So:\n\n  compose(f, g)(x) \u003c-\u003e f(g(x))\n\n```javascript\nvar even = function(x) { return !(x % 2) }\nvar not = function(x) { return !x }\n\nvar odd = f.compose(not, even)\n\n// So now odd(3) \u003c-\u003e not(even(3))\nconsole.log(odd(3), not(even(3)))\n// \u003e true true\n```\n\n#### partial(fn, ...args)\n\nCreates a function that is fn with bound arguments. You could say that it has\npre-filled arguments.\n\n```javascript\n// A simple example\nvar add = function(x, y) { return x + y }\nvar add5 = f.partial(add, 5)\n// So add5 = f.add(5, ???)\n\nadd5(3)\n// \u003e 8\n\n// Another example\n\nvar even = function(x) { return !(x % 2) }\n\nvar evenNumbers = f.partial(f.filter, even)\n// So evenNumbers = f.filter(even, ???)\n\nevenNumbers([ 1, 2, 3, 4, 5, 6 ])\n// \u003e [ 2, 4, 6 ]\n```\n\n#### id(x)\n\nIdentity function. Returns `x` as it comes in.\n\n```javascript\nf.id(5)\n// \u003e 5\n```\n\n#### functor(x)\n\nIdentity functor, returns a function that returns `x`. If `x` is a function,\nthen `functor(f) === f`\n\n```javascript\n// Basic behaviour\n\n// For *not functions* it returns a function that returns the value\nvar gimme5 = f.functor(5)\n\ngimme5()\n// \u003e 5\n\n// For functions, it returns the function as it is (so this sample is useless)\nvar now = f.functor(function() { return Date.now() })\n\nnow()\n// \u003e 1369228597829\n\n// A more complex example:\n// Using a functor to make a function able to take both vars and functions as\n// arguments\n\n// `getter` is a function which receives a prop and returns a function that\n// gets that property from its parameter obj. It is a getter creator.\n// To make the `getter` function able to accept property as a value or a\n// function that returns a value we can use the functor to normalize the\n// behaviour and make all values behave as functions that return its values.\nvar getter = function(prop) {\n  var getKey = f.functor(prop)\n  return function(obj) {\n    return obj[getKey()]\n  }\n}\n\nvar getName = getter('name')\nvar getAge = getter(function() { return 'age' })\n\ngetName({ age: 21, name: 'John' })\n// \u003e 'John'\ngetAge({ age: 21, name: 'John' })\n// \u003e 21\n```\n\n\n### Operators\n\n`furgoneta` includes some operators as functions to ease its usage through your\nfunctional code.\n\n#### Math\n\n#### add(x, y)\n\nEquivalent to the infix operator `+`\n\n```javascript\nf.add(6, 2)\n// \u003e 8\n```\n\n#### sub(x, y)\n\nEquivalent to the infix operator `-`\n\n```javascript\nf.sub(6, 2)\n// \u003e 4\n```\n\n#### mul(x, y)\n\nEquivalent to the infix operator `*`\n\n```javascript\nf.mul(6, 2)\n// \u003e 12\n```\n\n#### div(x, y)\n\nEquivalent to the infix operator `/`\n\n```javascript\nf.div(6, 2)\n// \u003e 3\n```\n\n#### mod(x, y)\n\nEquivalent to the infix operator `%`\n\n```javascript\nf.mod(6, 2)\n// \u003e 0\n```\n\n#### Comparison\n\n#### eq(x, y)\n\nEquivalent to the infix operator `===`\n\n```javascript\nf.eq(6, '6')\n// \u003e false\n```\n\n#### eqc(x, y)\n\nEquivalent to the infix operator `==`\n\n```javascript\nf.eqc(6, '6')\n// \u003e true\n```\n\n#### neq(x, y)\n\nEquivalent to the infix operator `!==`\n\n```javascript\nf.neq(6, 2)\n// \u003e true\n```\n\n#### neqc(x, y)\n\nEquivalent to the infix operator `!=`\n\n```javascript\nf.neqc(6, '6')\n// \u003e false\n```\n\n#### gt(x, y)\n\nEquivalent to the infix operator `\u003e`\n\n```javascript\nf.gt(6, 2)\n// \u003e true\n```\n\n#### ge(x, y)\n\nEquivalent to the infix operator `\u003e=`\n\n```javascript\nf.ge(6, 2)\n// \u003e true\n```\n\n#### lt(x, y)\n\nEquivalent to the infix operator `\u003c`\n\n```javascript\nf.lt(6, 2)\n// \u003e false\n```\n\n#### le(x, y)\n\nEquivalent to the infix operator `\u003c=`\n\n```javascript\nf.le(6, 2)\n// \u003e false\n```\n\n#### Logic\n\n#### not(x)\n\nEquivalent to the operator `!`\n\n```javascript\nf.not(6)\n// \u003e false\nf.not(true)\n// \u003e false\n```\n\n#### and(x, y)\n\nEquivalent to the infix operator `\u0026\u0026`\n\n```javascript\nf.and(true, null)\n// \u003e false\n```\n\n#### or(x, y)\n\nEquivalent to the infix operator `||`\n\n```javascript\nf.or(true, null)\n// \u003e true\n```\n\n\n### Types\n\nThere are several functions to help with typing conversion and detection.\n\n#### Conversion\n\n#### objToFunc(x)\n\nConverts an object into a function of its keys. Works both with arrays and\nobjects.\n\n```javascript\nvar participant = f.objToFunc({ name: 'John', age: 25, country: 'ES' })\n\nparticipant('name')\n// \u003e 'John'\n\nvar participantStuff = f.map(participant, [ 'name', 'age' ])\nconsole.log(participantStuff)\n// \u003e [ 'John', 25 ]\n```\n\n#### prop(x)\n\nConverts a property into a function that takes an object and gets that\nproperty.\n\n```javascript\nvar people = [\n  { name: 'Johnny', age: '23' },\n  { name: 'Anthony', age: '32' },\n  { name: 'Mary', age: '28' }\n]\n\nvar names = f.map(f.prop('name'), people)\nconsole.log(names)\n// \u003e [ 'Johnny', 'Anthony', 'Mary' ]\n```\n\n#### typeOf(x)\n\nFunction that returns a string with the type from the {}.toString method. That\nis:\n\n```javascript\nf.typeOf('hello')\n// \u003e 'String'\n\nf.typeOf(6)\n// \u003e 'Number'\n\nf.typeOf(true)\n// \u003e 'Boolean'\n\nf.typeOf(function() {})\n// \u003e 'Function'\n\nf.typeOf([1, 2, 3])\n// \u003e 'Array'\n\nf.typeOf({ a: 1, b: 2 })\n// \u003e 'Object'\n```\n\n#### isA(type, x)\n\nTruth tests a type string with the type of x.\n\n```javascript\nf.isA('String', 'hello')\n// \u003e true\nf.isA('Object', { a: 1 })\n// \u003e true\nf.isA('Boolean', 2)\n// \u003e false\n```\n\n#### isNumber(x)\n```javascript\nisNumber(4)\n// \u003e true\n```\n#### isArray(x)\n```javascript\nisArray([1])\n// \u003e true\n```\n#### isObject(x)\n```javascript\nisObject({})\n// \u003e true\n```\n#### isString(x)\n```javascript\nisString('asdf')\n// \u003e true\n```\n#### isFunction(x)\n```javascript\nisFunction(function() {})\n// \u003e true\n```\n#### isBoolean(x)\n```javascript\nisBoolean(false)\n// \u003e true\n```\n\n\n## Development\nTo get the dependencies do a `npm install`\n\nSource is on the `src` folder.\n\nTests on the `test` folder.\n\nMake actions:\n* All: `make`\n* Build browser: `make build-browser`\n* Test: `make test`\n* Tests watcher: `make test-w`\n\nOn the folder `docs` there are pdfs of the three sites that I want to use as\ninspiration.\n\n## Inspiration\n\nThis library is inspired and influenced by various libraries and languages:\n\n  * [Clojure's core library](http://richhickey.github.io/clojure/clojure.core-api.html)\n  * [underscore.js](http://underscorejs.org/)\n  * [culljs](https://github.com/culljs/culljs)\n  * [prelude.ls](http://gkz.github.io/prelude-ls/)\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoakin%2Ffurgoneta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoakin%2Ffurgoneta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoakin%2Ffurgoneta/lists"}