{"id":22697546,"url":"https://github.com/tomaskraus/stateful-predicates","last_synced_at":"2025-03-29T18:26:58.557Z","repository":{"id":63796088,"uuid":"568253445","full_name":"tomaskraus/stateful-predicates","owner":"tomaskraus","description":"Bunch of stateful predicate wrappers. RxJS \u0026 Array.filter compliant.","archived":false,"fork":false,"pushed_at":"2024-02-23T20:10:40.000Z","size":510,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-04-25T04:21:30.254Z","etag":null,"topics":["array","filter","fp","functional","predicate","rxjs","stateful","ts","typescript","wrapper"],"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/tomaskraus.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}},"created_at":"2022-11-19T23:26:44.000Z","updated_at":"2022-11-26T04:22:35.000Z","dependencies_parsed_at":"2024-02-23T21:25:46.396Z","dependency_job_id":null,"html_url":"https://github.com/tomaskraus/stateful-predicates","commit_stats":{"total_commits":59,"total_committers":3,"mean_commits":"19.666666666666668","dds":"0.23728813559322037","last_synced_commit":"684aba7c72d7b649f87253243395b761f94b8328"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomaskraus%2Fstateful-predicates","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomaskraus%2Fstateful-predicates/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomaskraus%2Fstateful-predicates/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomaskraus%2Fstateful-predicates/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tomaskraus","download_url":"https://codeload.github.com/tomaskraus/stateful-predicates/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246225452,"owners_count":20743561,"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":["array","filter","fp","functional","predicate","rxjs","stateful","ts","typescript","wrapper"],"created_at":"2024-12-10T05:14:19.816Z","updated_at":"2025-03-29T18:26:58.522Z","avatar_url":"https://github.com/tomaskraus.png","language":"TypeScript","readme":"![build](https://github.com/tomaskraus/stateful-predicates/actions/workflows/node.js.yml/badge.svg)\n[![codecov](https://codecov.io/gh/tomaskraus/stateful-predicates/branch/main/graph/badge.svg?token=MDg1JIIPnx)](https://codecov.io/gh/tomaskraus/stateful-predicates)\n[![Code Style: Google](https://img.shields.io/badge/code%20style-google-blueviolet.svg)](https://github.com/google/gts)\n\n# stateful-predicates\n\nCarefully selected, minimalistic collection of predicate wrappers.  \n`stateful-predicates ` bring new power to standard _predicates_, required by [Array.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), [RxJS](https://rxjs.dev/api/operators/takeWhile) or other methods/libraries that use predicates.\n\nPredicate list:\n\n- [switchTrueFalse](#switchtruefalse)\n- [nthElementAfter](#nthelementafter)\n- [nthMatch](#nthmatch)\n- [onChange](#onchange)\n\n**Example**: Get an inside of a block documetation comment:\n\n```ts\nimport {switchTrueFalse, nthElementAfter} from 'stateful-predicates';\n\n// prettier-ignore\nconst linesInsideADocBlockComment = lines.filter(\n    switchTrueFalse(\n      nthElementAfter(1,        // start to \"return true\" one line after a `/**`\n        s =\u003e /\\/\\*\\*/i.test(s)\n      ),  \n      s =\u003e /\\*\\//i.test(s)      // start to \"return false\" on a line with `*/`\n    )\n  );\n```\n\nsee a [complete example](#complete-example)\n\n`stateful-predicates` library is all about [predicates](#tpredicate) applied to **elements** of some **list**. That list is typically an [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#iterables).  \nWhen a _predicate_ is applied to an _element_, that _predicate_ can either **succeed** on that _element_ (i.e. **match** that _element_), or not.\n\n## Why to use\n\n- No state variable mess as it uses _closures_ to preserve the state.\n- Functional programming friendly.\n- Typed. With `d.ts` for Javascript.\n- Well tested. 100% code coverage.\n\n## Installation\n\n```bash\n$ npm install stateful-predicates\n```\n\n## Usage\n\nTypescript / ES module:\n\n```ts\nimport * as SP from 'stateful-predicates';\n```\n\nJavascript / CommonJS:\n\n```js\nconst SP = require('stateful-predicates');\n```\n\n## API\n\n### TPredicate\n\n```ts\ntype TPredicate\u003cT\u003e = (value: T, index: number) =\u003e boolean;\n```\n\nPredicate is a function, that accepts some value and returns a boolean value, based on its condition.\n\nIt's something you can pass as callback to [Array.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) or [RxJS](https://rxjs.dev/api/operators/takeWhile) operators.\n\nAlmost every function of `stateful-predicates` library accepts at least one `TPredicate` argument and returns another `TPredicate` value.\n\n### switchTrueFalse\n\n```ts\nfunction switchTrueFalse\u003cT\u003e(\n  predicateForTrue: TPredicate\u003cT\u003e,\n  predicateForFalse: TPredicate\u003cT\u003e\n): TPredicate\u003cT\u003e;\n```\n\nReturns a predicate(value, index) `P` that fulfills the following:\n\n1.  `P` stays _true_ \"on and after\" `predicateForTrue` has succeeded on some element\n2.  `P` becomes _false_ again \"on and after\" `predicateForFalse` has succeeded on some element that follows.  \n    At the beginning, `P` is _false_.\n3.  `P` is **reusable**: able to switch _true_/_false_ multiple times.\n4.  `P` is **greedy**:\n\n- switches to _true_ on the first of consecutive elements `predicateForTrue` can succeed\n- switches to _false_ on the first of consecutive elements `predicateForFalse` can succeed\n\n**Example**:\n\n```ts\nconst elementsEnclosedByZeroAndMinusOne = [2, 1, 0, 0, 5, 9, -1, -1, 7].filter(\n  switchTrueFalse(\n    x =\u003e x === 0,\n    x =\u003e x === -1\n  )\n);\nconsole.log(elementsEnclosedByZeroAndMinusOne);\n//=\u003e [ 0, 0, 5, 9 ]\n```\n\n### nthElementAfter\n\n```ts\nfunction nthElementAfter\u003cT\u003e(\n  offset: number,\n  parentPredicate: TPredicate\u003cT\u003e\n): TPredicate\u003cT\u003e;\n```\n\nReturns predicate(value, index) `P`, that:\n\n- returns _true_ if its `parentPredicate` has \"succeeded at element\" `offset` number of elements before.\n\n**Example**:\n\n```ts\nconst isThree = (x: number) =\u003e x === 3;\nconst secondElemsAfter3 = [2, 3, 0, 7, 4, 3, 5, -8].filter(\n  nthElementAfter(2, isThree)\n);\nconsole.log(secondElemsAfter3);\n//=\u003e [ 7, -8 ]\n```\n\nIt kind of shifts (or delays) the succesful element evaluation.\n\n- `P` is **greedy**: tries to succeed as soon as possible. If there are more elements within the \"`offset` range\" `parentPredicate` could succeed, they are not recognized.\n- `P` is **repeatable**: is ready to detect elements again as soon as it is at least `offset` elements after its last detected element.\n\n```ts\nconst result = [3, 2, 2, 2, 5, 1].map(nthElementAfter(1, x =\u003e x === 2));\nconsole.log(result);\n//=\u003e [ false, false, true, false, true, false ]\n```\n\n### nthMatch\n\n```ts\nfunction nthMatch\u003cT\u003e(n: number, parentPredicate: TPredicate\u003cT\u003e): TPredicate\u003cT\u003e;\n```\n\nReturns predicate(value, index) `P`, that:\n\n- returns _true_ if its `parentPredicate` has succeeded `n` times\n\n**Example**:\n\n```ts\nconst isEven = x =\u003e x % 2 === 0;\nconst secondMatchingElem = [2, 3, 5, 4, 8, 5, -8].filter(nthMatch(2, isEven));\nconsole.log(secondMatchingElem);\n//=\u003e [ 4 ]`\n```\n\n### onChange\n\n```ts\nfunction onChange\u003cT\u003e(parentPredicate: TPredicate\u003cT\u003e): TPredicate\u003cT\u003e;\n```\n\nReturns predicate(value, index) `P`, that:\n\n- returns _true_ whenever its `parentPredicate` changes value - i.e. result of `parent predicate` differs from `P`'s internal state.\n\nAt the begin, the internal state of `P` is _false_.\n\n**Example**:\n\n```ts\nconst isThree = (x: number) =\u003e x === 3;\nconst changes = [2, 3, 3, 3, 4, 3, 5, -8].map(onChange(isThree));\nconsole.log(changes);\n//=\u003e [ false, true, false, false, true, true, true, false ]\n```\n\n## Complete Example\n\nShow only documentation comments from a source code input text:\n\n```ts\nimport {switchTrueFalse, nthElementAfter} from 'stateful-predicates';\n\nconst input = `\n  /** \n   * greaterThanOne\n   * @param x number value\n   * @returns true if x is greater than one, false otherwise\n   */\n   */\n  function greaterThanOne(x: number): boolean {\n    return x \u003e 1;\n  }\n\n  /**\n   * An increment function\n   * @param x number value\n   * @returns that value incremented by one\n   */\n  const inc = (x: number) =\u003e ++x;`;\n\nconst docCommentPredicate = () =\u003e\n  switchTrueFalse\u003cstring\u003e(\n    s =\u003e /\\/\\*\\*/.test(s), // true at '/**' (begin-mark)\n    nthElementAfter(1, s =\u003e /\\*\\//.test(s)) // false after '*/' (end-mark)\n  );\n\n// prettier-ignore\nconst onlyDocComments = input\n  .split('\\n')\n  .filter(docCommentPredicate())\n  .join('\\n');\nconsole.log(onlyDocComments);\n//=\u003e /**\n//    * greaterThanOne\n//    * @param x number value\n//    * @returns true if x is greater than one, false otherwise\n//    */\n//   /**\n//    * An increment function\n//    * @param x number value\n//    * @returns that value incremented by one\n//    */\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomaskraus%2Fstateful-predicates","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftomaskraus%2Fstateful-predicates","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomaskraus%2Fstateful-predicates/lists"}