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

scoto

v0.3.0

Published

Prototype-based scope concept

Downloads

5

Readme

Scototypes (Scoto)

Nestable, Testable, Isolable Scopes using Prototype chains

NPM

Since ECMAscript 3, scopes are a foundational element of JavaScript. Concepts like closures depend on the automatic creation of severally-nested scopes. Scopes are not without complications. They all chain up to the root object. They shadow variables. They can't be shared directly.

For most purposes, though, scopes are quite like prototypes.

Enter Scototypes

Scototypes provide the nesting and hierarchy of scopes using JavaScript prototypes. You can walk the hierarchy of a scototype, isolate the current, attach it to a different chain, or even flatten the hierarchy into a new object.

Scototypes can mimic regular scopes by starting with your root object:

const myScope = Scoto.child(window);
const nestedScope = Scoto.child(myScope);

nestedScope.console.log('This works!');

Or you can make isolated scopes:

const myIsolatedScope = Scoto.new(null);
const nestedScope = Scoto.child(myIsolatedScope);

// console is undefined.
nestedScope.console.log('This will error.'); 

Scototypes use a few simple prototype methods to support nesting scope or data inheritance. Forty lines of code and comments cover most of the examples:

// isolate ensures no inherited prototype.
const defaults = Scoto.isolate({
  players: 1,
  gameTime: 60000, // one minute
  maxEnemies: 5
});

// rebase puts keys into a new object with a prototype chain
const appSettings = Scoto.rebase(getAppSettings(), defaults);

const userSettings = {
  gameTime: 45000,
  maxEnemies: 8
};

// rebase again to keep building the hierarchy
const currentSettings = Scoto.rebase(userSettings, appSettings);

// flatten merges the properties into a single object.
// Useful for exporting or saving.
const exportState = Scoto.flatten(currentSettings);

// child continues to build on a hierarchy.
const gameState = Scoto.child(currentSettings);

// Now we can assign additional keys to our state
gameState.enemies = [];
gameState.direction = 0;
gameState.started = true;

if (shouldStartDangerMode()) {
  // We don't need to track previous state for the scototype.
  // We just shadow the "older" values. 
  gameState.maxEnemies = 12;
}

if (shouldEndDangerMode()) {
  // Deleting variables eliminates shadowing.
  delete gameState.maxEnemies;
}

All methods in Scoto are non-mutating.

Scototype Context

Since scototypes provide nested scopes, we can optionally bind them as contexts.

function submitNewScore(score) {
  // Clear variable name for nesting.
  const scoto = this;

  if (undefined === scoto.scores) {
    getScores.call(scoto)
      .then(function(scores) {
        // Push scores onto the current scoto
        scoto.scores = scores;
        // Call this function again with the current scoto
        submitNewScore.call(scoto, score);
      }.bind(scoto));
    return;
  }

  http.post(`${scoto.baseURL}/score`, {score})
  .then(receiveScoreResponse.bind(scoto), handleError.bind(scoto));

}

function receiveAddScoreResponse(data) {
  const scoto = this;
  scoto.scores = data.scores;
  scoto.lastGameRank = data.gameRank;

  updateSplashScreen.call(scoto);
}

Because scototypes are standard objects, you can bind them as a context with the native Function.prototype.bind and with convenience tools like Lo-dash _.bindAll.

Scoto includes bind and binder as well. These provide the ability to create a new nested context instead of binding the current Scoto. binder provides a sort of partial applicaiton to allow easy reuse of a particular bind behavior.

function getMethodsWithContext(context, nest) {
  return myMethods.map(Scoto.binder(context, nest));
}