{"id":16520596,"url":"https://github.com/christophp/funpro","last_synced_at":"2025-09-23T15:21:53.946Z","repository":{"id":28137330,"uuid":"116432574","full_name":"ChristophP/funpro","owner":"ChristophP","description":"Be functional by using union types, pattern matching, and pure side-effects","archived":false,"fork":false,"pushed_at":"2023-01-03T20:55:20.000Z","size":1252,"stargazers_count":9,"open_issues_count":6,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-09T06:38:03.479Z","etag":null,"topics":["asynchronous-tasks","functional","javascript","maybe","union-types"],"latest_commit_sha":null,"homepage":"","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/ChristophP.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2018-01-05T22:20:59.000Z","updated_at":"2023-11-19T01:24:20.000Z","dependencies_parsed_at":"2023-01-14T08:12:52.633Z","dependency_job_id":null,"html_url":"https://github.com/ChristophP/funpro","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ChristophP/funpro","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristophP%2Ffunpro","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristophP%2Ffunpro/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristophP%2Ffunpro/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristophP%2Ffunpro/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChristophP","download_url":"https://codeload.github.com/ChristophP/funpro/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristophP%2Ffunpro/sbom","scorecard":{"id":29803,"data":{"date":"2025-08-11","repo":{"name":"github.com/ChristophP/funpro","commit":"1a19c0f1889f951bb859fed96af76e1e82b67e07"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.4,"checks":[{"name":"Code-Review","score":1,"reason":"Found 1/6 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 25 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"43 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx","Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-257v-vj4p-3w2h","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-7r28-3m3f-r2pr","Warn: Project is vulnerable to: GHSA-r8j5-h5cx-65gg","Warn: Project is vulnerable to: GHSA-2pr6-76vf-7546","Warn: Project is vulnerable to: GHSA-8j8c-7jfh-h6hx","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-76p3-8jx3-jpfq","Warn: Project is vulnerable to: GHSA-3rfm-jhwj-7488","Warn: Project is vulnerable to: GHSA-hhq3-ff78-jv3g","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-5fw9-fq32-wv5p","Warn: Project is vulnerable to: GHSA-rp65-9cf3-cjxr","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-566m-qj78-rww5","Warn: Project is vulnerable to: GHSA-7fh5-64p2-3v2j","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-h9rv-jmmf-4pgx","Warn: Project is vulnerable to: GHSA-hxcc-f52p-wc94","Warn: Project is vulnerable to: GHSA-wpg7-2c88-r8xv","Warn: Project is vulnerable to: GHSA-pq67-2wwv-3xjx","Warn: Project is vulnerable to: GHSA-8cj5-5rvv-wf4v","Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-14T18:47:35.035Z","repository_id":28137330,"created_at":"2025-08-14T18:47:35.035Z","updated_at":"2025-08-14T18:47:35.035Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276597138,"owners_count":25670518,"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","status":"online","status_checked_at":"2025-09-23T02:00:09.130Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["asynchronous-tasks","functional","javascript","maybe","union-types"],"created_at":"2024-10-11T16:51:47.056Z","updated_at":"2025-09-23T15:21:53.906Z","avatar_url":"https://github.com/ChristophP.png","language":"JavaScript","readme":"# FunPro\n\nA fun, light-weight and zero-dependency lib for functional programming in JS.\n\nFunPro weighs about 1KB and integrates with [Ramda](http://ramdajs.com/)\nand partly the [Fantasyland](https://github.com/fantasyland/fantasy-land) Spec.\nInspired by [Elm](http://elm-lang.org/), [Haskell](https://www.haskell.org/),\n[Folktale](http://folktale.origamitower.com/) and the legendary\n[Prof. Frisby](https://drboolean.gitbooks.io/mostly-adequate-guide/).\n\n```sh\nnpm i -S funpro\n```\npick your style of importing in your JS code:\n```js\n// commonJS\nconst { union, matchWith, Maybe, Result, Task } = require('funpro');\n\n// ES6\nimport { union, matchWith, Maybe, Result, Task } from 'funpro';\n\n// browser\n\u003cscript src=\"/dist/main.umd.js\"\u003e\u003c/script\u003e\n\u003cscript\u003econst { Maybe } = window.FunPro;\u003c/script\u003e\n```\n\nAlso check out:\n\n- the [guide](https://christophp.gitbooks.io/funpro/), with JS FP background, tips and usage examples\n- the official [API docs](https://christophp.gitbooks.io/funpro/content/ch5.html)\n\n\n## Union types (Algebraic data types)\n\nUnion types or ADTs let you model your domain more precisely than with\nother data type primitives like boolean, strings or integers.\n\nAn optional value can use the `Maybe` type.\n```js\nconst listHead = list =\u003e\n  list.length === 0 ? Maybe.Nothing() : Maybe.Just(list[0]);\n```\n\nAn operation that may fail can be represented with a `Result`.\nMaybe, Result\n\nThis let's you write super safe functions like this:\n```js\nconst safeJsonParse = val =\u003e {\n  try {\n    return Result.Ok(JSON.parse(val));\n  } catch (e) {\n    return Result.Err(e);\n  }\n};\n```\n\nYou don't have to worry about the error and map away.\nAt some point you pattern match to handle the different cases.\n\nThis could also be thinkable:\n```js\nconst safeDate = val =\u003e {\n  try {\n    return Result.Ok(new Date(val));\n  } catch (e) {\n    return Result.Err(e);\n  }\n};\n```\nNo more weird try catch blocks. Yay! :-)\n\nNo how do I use the values when they are wrapped into a context like that?\n\nThe answer is pattern matching:\n\n```js\nconst maybePrice = getItemPrice(item); // returns a Maybe with the price or Nothing\n\nconst displayPrice = matchWith(maybePrice, {\n  Just: val =\u003e `${val.toFixed(2)} $`,\n  Nothing: () =\u003e 'not for sale',\n})\n```\n\nThere are also functions to map, chain, etc with these types.\n\n## Custom union types\n\nIt's also possible to create your own union types. Using boolean to model things\nis very limited, especially if you need more than two states. So for a page\nyou could use something like this.\n\n```js\n// for each value specify the number of arguments it can carry.\nconst PageState = union({\n  Loading: 0,\n  Loaded: 1,\n  Errored: 1,\n})\n```\n\n`Loading` doesn't need any arguments. `Loaded` will need some sort of content.\n`Errored` should contain some kind of error message or reason why it failed.\n\nWith pattern matching all the cases can be handled it one place.\n\n```js\n// create a pageState\n// this could also be Page.Loading() or Page.Errored('Oh no!')\nconst pageState = PageState.Loaded({ user: {name: 'Peter', age: 42} });\n\nconst pageContent = matchWith(pageState, {\n  Loading: () =\u003e 'Loading...',\n  Loaded: ({ user: { name, age } }) =\u003e `${name} is ${age} old`,\n  Errored: msg =\u003e `Something went wrong: ${msg}`,\n})\n```\n\nThis is much more powerful than the dull ON/OFF logic that booleans provide.\n\nGive booleans the finger and make impossible states impossible.\n\n## IO and Async management\n\nTo keep your code free of side-effects this lib gives you s `Task` for asynchronous\nthings and basically anything that would be considered a side-effect.\n\n### Why not a Promise?\n\nPromises always execute their action upon creation. There is no real way for\noperating on a promise without already kicking of the first task.\n\nTasks won't to anything until you pull the trigger and call `.run()`.\nThis allows you to map or chain or pass around your task while knowing it will\nonly be execute when run is called.\n\nIdeally you only call run once in your entire program and chain or map other\ntasks onto the initial one. That way you can make sure that you're entire code\ndoes not have side-effects except for that isolated place where you call `.run()`.\n\n```js\n// function that kicks of your app\nconst startApp = () =\u003e loadAssets();\nmain = Task.of(startApp)\n  .chain(() =\u003e fetchDataTask)\n  .onError(err =\u003e {\n    // catch or log the error\n  })\n\n// then run it somewhere\nmain.run()\n```\n\n## Random\n### The mission\n\nI think FP is awesome, this is my attempt to sneak more FP code into the JS world.\nIf I could choose I, would prefer a true function language like `Elm` or `Haskell`,\nbut sometimes there is no way around JS and luckily, it is also very capable of\nwriting some FP code.\n\n### What's up with the name?\n\nApparently there are no cool names availbale on npm anymore. Then all of a sudden\nI realized, that when taking the first 3 letters from  `functional` and `programming`,\nyou get the words `fun` and `pro`. Tah-Dah.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristophp%2Ffunpro","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchristophp%2Ffunpro","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristophp%2Ffunpro/lists"}