npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

context-scope

v1.0.4

Published

Context (yes context) support for Javascript / Typescript

Downloads

6

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

import Context from 'context-scope'

interface User {
  name: string
  surname: string
  email: string
}

const user = new Context<User>()

const fullName = () => `${user.value.name} ${user.value.surname}`
const link = () => `mailto:${user.value.email}`
const title = () => `${fullName()} [${user.value.email}]`

const getHTML = () => `<a href="${link()}" title="${title()}">${fullName()}</a>`

user.scope(scope => {
  scope.set({
    name: 'Rick',
    surname: 'Astley',
    email: '[email protected]'
  })

  const link = getHTML()

  console.log(link)
  // <a href="mailto:[email protected]" title="Rick Astley [[email protected]]">Rick Astley</a>
})

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.

const context = new Context<number>({
  customHandlers: {
    increment: value => (amount = 1) => +value + amount,
    decrement: value => (amount = 1) => +value - amount
  }
})

context.scope(scope => {
  scope.set(0)

  scope.increment()
  console.log(scope) // 1

  scope.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:

const context = new Context()
context.value // Throws error

Off:

const context = new Context()
context.value // undefined

Context methods

destroy

Destroys a specified scope ID from memory

context.scope(scope => {
  scope.set(1)
  const { id } = scope

  context.destroy(id)
})

getScopes

Returns an array of all the parent scope IDs from which the function was called

context.scope(scope => {
  context.scopes() // [ 0 ]
})

value

Returns the value of the current scope from the stack trace

context.scope(scope => {
  scope.set(1)

  context.value // 1
})

getScope

Returns the value of a scope ID

context.scope(scope => {
  scope.set('hello')
})

context.getScope(0) // { value: 'hello', initialized: 'true' }

Scope methods

set

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.

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.

context.scope(scope => {
  scope.set(1)
  scope.destroy()

  context.value // error
})

id

Returns the internal ID to the current scope

context.scope(scope => {
  scope.set(1)
  const { id } = scope // 0

  context.destroy(id)
})

Examples

Inheriting values

import Context from 'context-scope'

const context = new Context<number>()

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

import Context from 'context-scope'

const cat = new Context<string>()
const dog = new Context<string>()

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

import Context from 'context-scope'

const context = new Context<string>()

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()