{"id":24382258,"url":"https://github.com/milankinen/francis","last_synced_at":"2026-03-12T01:38:14.075Z","repository":{"id":72026970,"uuid":"90267688","full_name":"milankinen/francis","owner":"milankinen","description":"Reactive programming with focus on developer friendly stream semantics, high performance and functional usage","archived":false,"fork":false,"pushed_at":"2019-04-01T21:05:02.000Z","size":1025,"stargazers_count":17,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-11T00:06:42.438Z","etag":null,"topics":["baconjs","frp","frp-library","observable","reactive-programming","reactive-streams"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/milankinen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-05-04T13:37:13.000Z","updated_at":"2024-11-05T08:44:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"31aca767-184f-4277-9f58-f73cfdd7bf01","html_url":"https://github.com/milankinen/francis","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/milankinen/francis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milankinen%2Ffrancis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milankinen%2Ffrancis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milankinen%2Ffrancis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milankinen%2Ffrancis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/milankinen","download_url":"https://codeload.github.com/milankinen/francis/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milankinen%2Ffrancis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30412090,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-12T00:40:14.898Z","status":"ssl_error","status_checked_at":"2026-03-12T00:40:08.439Z","response_time":84,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["baconjs","frp","frp-library","observable","reactive-programming","reactive-streams"],"created_at":"2025-01-19T09:17:10.076Z","updated_at":"2026-03-12T01:38:14.070Z","avatar_url":"https://github.com/milankinen.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Francis\n\n[![Build status](https://img.shields.io/travis/milankinen/francis/master.svg?style=flat-square)](https://travis-ci.org/milankinen/francis)\n[![npm](https://img.shields.io/npm/v/francis.svg?style=flat-square)](https://www.npmjs.com/package/francis)\n[![Bundle size (minified + gzip)](https://img.shields.io/bundlephobia/minzip/francis.svg?style=flat-square)](https://bundlephobia.com/result?p=francis)\n[![Dependencies](https://david-dm.org/milankinen/francis.svg?style=flat-square)](https://github.com/milankinen/francis/blob/master/package.json)\n\nFrancis is a reactive programming library for TypeScript and JavaScript, inspired by\n[Bacon.js](https://github.com/baconjs/bacon.js) and [most](https://github.com/cujojs/most),\nwith focus on developer friendly stream semantics, high performance and functional usage.\n\n```typescript\nimport * as F from \"francis\"\n\nF.pipe(\n  F.interval(1000, \"!\"),\n  F.scan(\"Francis\", (s, x) =\u003e s + x),\n  F.map(s =\u003e \"Hello \" + s.toUpperCase()),\n  F.skip(2),\n  F.take(2),\n  F.onValue(console.log),\n)\n// Hello FRANCIS!!\n// Hello FRANCIS!!!\n```\n\n## Motivation\n\n**tl;dr** I wanted a functional-first, treeshakeable [Bacon.js](https://github.com/baconjs/bacon.js)\nthat is [6-10x faster](perf#latest-test-results), has lower memory footprint and is written\nentirely with TypeScript.\n\n\n## Installation\n\n```bash\nnpm i --save francis\n```\n\n## API\n\nSee **[API docs](https://milankinen.github.io/francis)** (still WIP!) for complete\nreference of the available functions and their usage.\n\n### Bacon.js compatibility\n\nBecause the stream semantics are same (with [few differences](BACON.md)) in Francis and\nBacon, Francis provides a drop-in replacement module for Bacon. The required changes\nin codebase are:\n\n```diff\n-import B from \"baconjs\"\n+import B from \"francis/bacon\"\n\nB.once(\"Bacon\")\n  .map(x =\u003e \"Hello \" + x + \"!\")\n  .map(\".toUpperCase\")\n  .onValue(console.log)\n```\n\n### Experimental proxied API\n\nYou can convert any Francis observable to a \"proxied\" observable by using `F.proxied`\nutility. Proxied observables are just like their \"normal\" counterparts, but in\naddition they provide a way to traverse the underlying data structure by using\nthe traditional dot notation. And being typed, of course.\n\n**ATTENTION!** This feature is experimental and is probably subject to change.\n\n```ts\nimport * as F from \"francis\"\n\nconst state = F.proxied(\n  F.atom({\n    msg: \"Tsers\",\n    inner: { nums: [1, 2, 4, 5] },\n  }),\n)\n\n// typeof nums === F.Proxied.Atom\u003cnum[]\u003e\nconst { nums } = state.inner\n// typeof str === F.Proxied.Property\u003cstring\u003e\nconst str = nums\n  .map(n =\u003e n + 1)\n  .filter(n =\u003e n % 2 === 1)\n  .join(\",\")\n\nF.log(\"str:\", str)\nF.set(nums, [5, 6])\n// logs \"3,5\" and \"7\"\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmilankinen%2Ffrancis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmilankinen%2Ffrancis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmilankinen%2Ffrancis/lists"}