{"id":16223176,"url":"https://github.com/inve1951/unsub","last_synced_at":"2026-04-20T14:03:09.333Z","repository":{"id":34291064,"uuid":"174630207","full_name":"Inve1951/UnSub","owner":"Inve1951","description":"ReSub compatibility layer for CoffeeScript","archived":false,"fork":false,"pushed_at":"2026-04-02T07:45:00.000Z","size":51,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-04-08T09:12:00.236Z","etag":null,"topics":["coffee","compat","decorators","react","resub","stores"],"latest_commit_sha":null,"homepage":null,"language":"CoffeeScript","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/Inve1951.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}},"created_at":"2019-03-09T00:35:52.000Z","updated_at":"2024-03-13T14:25:35.000Z","dependencies_parsed_at":"2024-12-21T16:38:46.440Z","dependency_job_id":"48fdc301-5437-4643-b6ff-ec2d3795ae29","html_url":"https://github.com/Inve1951/UnSub","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Inve1951/UnSub","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inve1951%2FUnSub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inve1951%2FUnSub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inve1951%2FUnSub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inve1951%2FUnSub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Inve1951","download_url":"https://codeload.github.com/Inve1951/UnSub/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inve1951%2FUnSub/sbom","scorecard":{"id":67202,"data":{"date":"2025-08-11","repo":{"name":"github.com/Inve1951/UnSub","commit":"a0d034ddf6d2b921fb8f99aa6e529b58f239422a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.9,"checks":[{"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":"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":"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":"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":"Code-Review","score":0,"reason":"Found 0/10 approved changesets -- score normalized to 0","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":"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":"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":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"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":"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":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 1 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":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8"],"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-15T02:52:17.427Z","repository_id":34291064,"created_at":"2025-08-15T02:52:17.427Z","updated_at":"2025-08-15T02:52:17.427Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32050451,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T11:35:06.609Z","status":"ssl_error","status_checked_at":"2026-04-20T11:34:48.899Z","response_time":94,"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":["coffee","compat","decorators","react","resub","stores"],"created_at":"2024-10-10T12:17:46.828Z","updated_at":"2026-04-20T14:03:09.275Z","avatar_url":"https://github.com/Inve1951.png","language":"CoffeeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# UnSub\n\nThis package provides a compatibility layer to [ReSub](https://github.com/Microsoft/ReSub) making it viable to code written in [CoffeeScript](https://coffeescript.org/).\n\n## Installation\n\n`npm install unsub resub`\n\n## Usage\n\n```coffee\n## TodosStore.coffee\nimport { StoreBase, AutoSubscribeStore } from \"unsub\"\n\nexport default new TodosStore = AutoSubscribeStore class extends StoreBase\n  @Key_SomeFilter = \"Key_SomeFilter\"\n\n  @autoSubscribeWithKey @Key_SomeFilter, getTodos: -\u003e\n    @_todosFiltered\n\n  @autoSubscribe @key getTodosForUser: (username) -\u003e\n    @_todosByUser[username]\n\n## TodoList.coffee\nimport { ComponentBase } from \"unsub\"\nimport TodosStore from \"./TodosStore\"\n\nexport class TodoList extends ComponentBase\n  buildState: (props, state, bInit) -\u003e\n    todosFiltered: TodosStoreInstance.getTodos()\n    userTodos: TodosStoreInstance.getTodosForUser @props.username\n\n  render: -\u003e\n    \u003cdiv\u003e\n    { @state.userTodos.map (todo) -\u003e\n      \u003cTodo key={todo.id}\u003e\n        {todo.text}\n      \u003c/Todo\u003e\n    }\n    \u003c/div\u003e\n```\n\nAbove code is equivalent to this TypeScript code: \u003cbr id=ts\u003e\n\n```ts\n/// TodosStore.ts\nimport { StoreBase, AutoSubscribeStore, autoSubscribe, key } from 'resub';\n\n@AutoSubscribeStore\nclass TodosStore extends StoreBase {\n    static Key_SomeFilter = \"Key_SomeFilter\";\n\n    @autoSubscribeWithKey(TodosStore.Key_SomeFilter)\n    getTodos() {\n        return this._todosFiltered;\n    }\n\n    @autoSubscribe\n    getTodosForUser(@key username: string) {\n        return this._todosByUser[username];\n    }\n}\n\nexport = new TodosStore();\n\n/// TodoList.tsx\nimport { ComponentBase } from 'resub';\nimport TodosStore from './TodosStore';\n\nexport class TodoList extends ComponentBase\u003c{}, TodoListState\u003e {\n    protected _buildState(props: {}, initialBuild: boolean, state: {}): TodoListState {\n        return {\n            todosFiltered: TodosStoreInstance.getTodos(),\n            userTodos: TodosStoreInstance.getTodosForUser(this.props.username)\n        }\n    }\n\n    render() {\n      return (\n          \u003cdiv\u003e\n          { this.state.userTodos.map( todo =\u003e (\n              \u003cTodo key={ todo.id }\u003e\n                  { todo.text }\n              \u003c/Todo\u003e\n          ))}\n          \u003c/div\u003e\n      );\n    }\n}\n```\n\n\n## Breaking Change in v2.0.0\n\n**ReSub** `v2.0.0-rc.2` introduced a new argument to stores' `_buildState` function.\n\n```coffee\n# old:\nbuildState: (props, bInit) -\u003e\n_buildState: (props, bInit) -\u003e\n# new:\nbuildState: (props, state, bInit) -\u003e\n_buildState: (props, bInit, state) -\u003e\n```\n\n### Reasoning for the new argument:\n\nChanges in ReSub/React made it unreliable and bugprone to use `this.state` inside `_buildState`. It was not always updated and would reflect old state. As a workaround they added `state` as a third argument.\n\n### Reasoning for breaking the old signature:\n\nThere's 2 parts to that answer.\n\nFirstly it feels far more natural to have `state` follow `props`. Most (if not all these days) of React's functions taking both `props` and `state` have them as the first 2 arguments and in that same order; especially if you use [preact](https://preactjs.com/) (which you should).\n\nSecondly, if you made use of `@state` inside `buildState` there's a high chance it's buggy now (breaking change in React/ReSub). To fix that you are required to go thru your code and switch to using the `state` argument. While doing that you may as well switch to the new (and better) signature.\n\nYes, if you aren't affected by \\#2 `bInit` still moved and I broke your components. The above 2 reasons are big enough to warrant you do a search and replace.\n\n\n## Overview\n\n**UnSub** principially is used the same way as **ReSub**. One key difference is that decorators which take an argument do not return a decorator when called but instead are called with the arguments, followed by whatever they are decorating.\n\n```coffee\n# correct:\n@autoSubscribeWithKey @Key_Filtered, getFilteredData: -\u003e @filteredData\n# incorrect:\n@autoSubscribeWithKey(@Key_Filtered) getFilteredData: -\u003e @filteredData\n```\n\nFurthermore it allows you to omit the underscore on your overrides. E.g. `buildState` instead of `_buildState`. This more closely follows React's style of writing components.\n\nAlso see v2's breaking changes in the previous section.\n\n### Exports\n\n#### Classes\n\n- `StoreBase`\n- `ComponentBase`\n\n#### Class Decorators\n\n- `AutoSubscribeStore`\n- `DeepEqualityShouldComponentUpdate`\n- `CustomEqualityShouldComponentUpdate COMPARE`\n\n```coffee\nMyStore = CustomEqualityShouldComponentUpdate shouldComponentUpdateCb, class extends StoreBase\n  getData: -\u003e @data\n```\n\n#### Member Function Decorators\n\n- `@autoSubscribe`\n- `@autoSubscribeWithKey KEY`\n- `@disableWarnings`  \n  Native to ReSub, undocumented.\n- `@bound`  \n  Helper which binds the function in the constructor.  \n  This is necessary because fat arrows would bind to the constructor/class.\n\n#### Parameter Decorators\n\n- `@key [INDEX]`  \n  Used outside parameter list. Index represents `arguments[index]`, is optional and defaults to 0.\n\n```coffee\nMyStore = AutoSubscribeStore class extends StoreBase\n  @autoSubscribe @key 1, @bound getData: (a, b) -\u003e\n     # `b` is the key ^\n    @data[b][a]\n```\n\n#### Utilities\n\n- `setPerformanceMarkingEnabled`\n- `formCompoundKey`\n\nNote that member function and parameter decorators (prefixed with `@`) are actually static class members of `StoreBase`. This means that you must not have static members on your store that use the same identifier as a decorator you make use of inside the class body. It also means that you only need to import classes, class decorators and utility functions.\n\nFor more information please refer to the [ReSub documentation](https://github.com/Microsoft/ReSub#readme).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finve1951%2Funsub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finve1951%2Funsub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finve1951%2Funsub/lists"}