https://github.com/samdenty/context-scope
Context support for Javascript / Typescript
https://github.com/samdenty/context-scope
Last synced: 2 months ago
JSON representation
Context support for Javascript / Typescript
- Host: GitHub
- URL: https://github.com/samdenty/context-scope
- Owner: samdenty
- Created: 2018-06-30T08:05:25.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2018-07-01T07:01:06.000Z (almost 7 years ago)
- Last Synced: 2025-03-16T22:18:03.372Z (3 months ago)
- Language: TypeScript
- Size: 16.6 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# context-scope
Context 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.
## Getting started
### Example
```ts
import Context from 'context-scope'interface User {
name: string
surname: string
email: string
}const user = new Context()
const fullName = () => `${user.value.name} ${user.value.surname}`
const link = () => `mailto:${user.value.email}`
const title = () => `${fullName()} [${user.value.email}]`const getHTML = () => `${fullName()}`
user.scope(scope => {
scope.set({
name: 'Rick',
surname: 'Astley',
email: '[email protected]'
})const link = getHTML()
console.log(link)
// Rick Astley
})
```### How
By 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.
From there, it's as simple as parsing the stack trace and extracting the identifiers inside a getter.
### Why
You 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.
This 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.
## Options
### `initialValue`
Defines 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.
### `customHandlers`
Handlers are methods defined on the scope, which take the current context + arguments and return a new version of the data.
```ts
const context = new Context({
customHandlers: {
increment: value => (amount = 1) => +value + amount,
decrement: value => (amount = 1) => +value - amount
}
})context.scope(scope => {
scope.set(0)scope.increment()
console.log(scope) // 1scope.decrement(2)
console.log(scope) // -1
})
```### `strictMode`
Strict mode is enabled by default as it provides extra runtime context safety.
When it's enabled, it throws errors if context is consumed but unable to be resolved in the stack trace.On:
```ts
const context = new Context()
context.value // Throws error
```Off:
```ts
const context = new Context()
context.value // undefined
```## Context methods
### `destroy`
Destroys a specified scope ID from memory
```ts
context.scope(scope => {
scope.set(1)
const { id } = scopecontext.destroy(id)
})
```### `getScopes`
Returns an array of all the parent scope IDs from which the function was called
```ts
context.scope(scope => {
context.scopes() // [ 0 ]
})
```### `value`
Returns the value of the current scope from the stack trace
```ts
context.scope(scope => {
scope.set(1)context.value // 1
})
```### `getScope`
Returns the value of a scope ID
```ts
context.scope(scope => {
scope.set('hello')
})context.getScope(0) // { value: 'hello', initialized: 'true' }
```## Scope methods
### `set`
```ts
context.scope(scope => {
// Set the value
scope.set(1)// Increment the value based on previous
scope.set(value => value + 1)
})
```### `value`
Returns the direct value of the initialized scope, without parsing the stack trace.
```ts
context.scope(scope => {
scope.set(1)
scope.value // 1
})
```### `destroy`
Destroy'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.
```ts
context.scope(scope => {
scope.set(1)
scope.destroy()context.value // error
})
```### `id`
Returns the internal ID to the current scope
```ts
context.scope(scope => {
scope.set(1)
const { id } = scope // 0context.destroy(id)
})
```## Examples
### Inheriting values
```ts
import Context from 'context-scope'const context = new Context()
function b() {
console.log(context.value)
}function a() {
context.scope(scope => {
scope.set(value => (value + 1))
b()
})
}context.scope(scope => {
scope.set(0)console.log(context.value) // 0
a() // 1
b() // 0
})
```### Multiple contexts
```ts
import Context from 'context-scope'const cat = new Context()
const dog = new Context()function test() {
console.log(cat.value, dog.value) // 'Cat' 'Dog'
}cat.scope(feline => {
feline.set('Cat')
dog.scope(doggie => {
doggie.set('Dog')
test()
})
})
```### Return values from scopes
```ts
import Context from 'context-scope'const context = new Context()
async function main() {
const result = await context.scope(scope => new Promise((resolve) => {
scope.set('test')
setTimeout(() => resolve(scope.value), 1000)
}))console.log(result) // 'test'
}main()
```