{"id":22400962,"url":"https://github.com/samdenty/context-scope","last_synced_at":"2025-08-24T14:17:06.429Z","repository":{"id":57206530,"uuid":"139231052","full_name":"samdenty/context-scope","owner":"samdenty","description":"Context support for Javascript / Typescript","archived":false,"fork":false,"pushed_at":"2018-07-01T07:01:06.000Z","size":17,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-16T22:18:03.372Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","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/samdenty.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":"2018-06-30T08:05:25.000Z","updated_at":"2018-07-14T19:33:02.000Z","dependencies_parsed_at":"2022-09-11T05:01:46.307Z","dependency_job_id":null,"html_url":"https://github.com/samdenty/context-scope","commit_stats":null,"previous_names":["samdenty99/context-scope"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samdenty%2Fcontext-scope","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samdenty%2Fcontext-scope/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samdenty%2Fcontext-scope/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samdenty%2Fcontext-scope/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/samdenty","download_url":"https://codeload.github.com/samdenty/context-scope/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245755708,"owners_count":20667032,"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-12-05T08:17:39.416Z","updated_at":"2025-03-27T00:19:34.028Z","avatar_url":"https://github.com/samdenty.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# context-scope\n\nContext support for Javascript / Typescript. Side effects free. Create a `scope` and all functions called from within it will have access to it. Use multiple context's at the same time with inherited scopes.\n\n## Getting started\n\n### Example\n\n```ts\nimport Context from 'context-scope'\n\ninterface User {\n  name: string\n  surname: string\n  email: string\n}\n\nconst user = new Context\u003cUser\u003e()\n\nconst fullName = () =\u003e `${user.value.name} ${user.value.surname}`\nconst link = () =\u003e `mailto:${user.value.email}`\nconst title = () =\u003e `${fullName()} [${user.value.email}]`\n\nconst getHTML = () =\u003e `\u003ca href=\"${link()}\" title=\"${title()}\"\u003e${fullName()}\u003c/a\u003e`\n\nuser.scope(scope =\u003e {\n  scope.set({\n    name: 'Rick',\n    surname: 'Astley',\n    email: 'hello@example.com'\n  })\n\n  const link = getHTML()\n\n  console.log(link)\n  // \u003ca href=\"mailto:hello@example.com\" title=\"Rick Astley [hello@example.com]\"\u003eRick Astley\u003c/a\u003e\n})\n```\n\n### How\n\nBy using a dynamically generated function and stack traces, it's possible to make the code context-aware. Each scope is given an identifier and bound to a function with it in the name.\n\nFrom there, it's as simple as parsing the stack trace and extracting the identifiers inside a getter.\n\n### Why\n\nYou often find the need to pass data from one place to another. This would normally mean passing down the data via parameters, but this quickly becomes unmaintainable. Context allows you to skip all the hops and pass it directly where you need it.\n\nThis comes with some added benefits, for example - Typescript. As you're only defining your data in one place, you only need to type it once. The rest is done for you.\n\n## Options\n\n### `initialValue`\n\nDefines the initial value to be used for all newly created scopes. It's recommended to directly call `scope.set` from within a scope, as it provides safety in `strictMode` when destroying contexts.\n\n### `customHandlers`\n\nHandlers are methods defined on the scope, which take the current context + arguments and return a new version of the data.\n\n```ts\nconst context = new Context\u003cnumber\u003e({\n  customHandlers: {\n    increment: value =\u003e (amount = 1) =\u003e +value + amount,\n    decrement: value =\u003e (amount = 1) =\u003e +value - amount\n  }\n})\n\ncontext.scope(scope =\u003e {\n  scope.set(0)\n\n  scope.increment()\n  console.log(scope) // 1\n\n  scope.decrement(2)\n  console.log(scope) // -1\n})\n```\n\n### `strictMode`\n\nStrict mode is enabled by default as it provides extra runtime context safety.\nWhen it's enabled, it throws errors if context is consumed but unable to be resolved in the stack trace.\n\nOn:\n\n```ts\nconst context = new Context()\ncontext.value // Throws error\n```\n\nOff:\n\n```ts\nconst context = new Context()\ncontext.value // undefined\n```\n\n## Context methods\n\n### `destroy`\n\nDestroys a specified scope ID from memory\n\n```ts\ncontext.scope(scope =\u003e {\n  scope.set(1)\n  const { id } = scope\n\n  context.destroy(id)\n})\n```\n\n### `getScopes`\n\nReturns an array of all the parent scope IDs from which the function was called\n\n```ts\ncontext.scope(scope =\u003e {\n  context.scopes() // [ 0 ]\n})\n```\n\n### `value`\n\nReturns the value of the current scope from the stack trace\n\n```ts\ncontext.scope(scope =\u003e {\n  scope.set(1)\n\n  context.value // 1\n})\n```\n\n### `getScope`\n\nReturns the value of a scope ID\n\n```ts\ncontext.scope(scope =\u003e {\n  scope.set('hello')\n})\n\ncontext.getScope(0) // { value: 'hello', initialized: 'true' }\n```\n\n## Scope methods\n\n### `set`\n\n```ts\ncontext.scope(scope =\u003e {\n  // Set the value\n  scope.set(1)\n\n  // Increment the value based on previous\n  scope.set(value =\u003e value + 1)\n})\n```\n\n### `value`\n\nReturns the direct value of the initialized scope, without parsing the stack trace.\n\n```ts\ncontext.scope(scope =\u003e {\n  scope.set(1)\n  scope.value // 1\n})\n```\n\n### `destroy`\n\nDestroy's the scope references from memory. If you attempt to read a destroyed scope when `strictMode` is enabled, an error will be thrown. If you disable `strictMode`, then it will fallback to undestroyed parent scopes.\n\n```ts\ncontext.scope(scope =\u003e {\n  scope.set(1)\n  scope.destroy()\n\n  context.value // error\n})\n```\n\n### `id`\n\nReturns the internal ID to the current scope\n\n```ts\ncontext.scope(scope =\u003e {\n  scope.set(1)\n  const { id } = scope // 0\n\n  context.destroy(id)\n})\n```\n\n## Examples\n\n### Inheriting values\n\n\n```ts\nimport Context from 'context-scope'\n\nconst context = new Context\u003cnumber\u003e()\n\nfunction b() {\n  console.log(context.value)\n}\n\nfunction a() {\n  context.scope(scope =\u003e {\n    scope.set(value =\u003e (value + 1))\n    b()\n  })\n}\n\ncontext.scope(scope =\u003e {\n  scope.set(0)\n\n  console.log(context.value) // 0\n\n  a() // 1\n\n  b() // 0\n})\n```\n\n### Multiple contexts\n\n```ts\nimport Context from 'context-scope'\n\nconst cat = new Context\u003cstring\u003e()\nconst dog = new Context\u003cstring\u003e()\n\nfunction test() {\n  console.log(cat.value, dog.value) // 'Cat' 'Dog'\n}\n\ncat.scope(feline =\u003e {\n  feline.set('Cat')\n  dog.scope(doggie =\u003e {\n    doggie.set('Dog')\n    test()\n  })\n})\n```\n\n### Return values from scopes\n\n```ts\nimport Context from 'context-scope'\n\nconst context = new Context\u003cstring\u003e()\n\nasync function main() {\n  const result = await context.scope(scope =\u003e new Promise((resolve) =\u003e {\n    scope.set('test')\n    setTimeout(() =\u003e resolve(scope.value), 1000)\n  }))\n\n  console.log(result) // 'test'\n}\n\nmain()\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamdenty%2Fcontext-scope","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsamdenty%2Fcontext-scope","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamdenty%2Fcontext-scope/lists"}