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

@locustjs/locator

v3.0.0

Published

A locustjs library implementing Service Locator pattern to provide loose coupling through IoC (Inversion of Control).

Downloads

7

Readme

@locustjs/locator

This library implements Service Locator pattern in javascript. Service Locator pattern is one of the ways of implementing IoC (inversion of control) and loose coupling.

Installation

npm install @locustjs/locator

Classes

| Class | description | |-------|-------------| | LocatorBase | Base locator abstract class | | DefaultLocator| Default service locator implementation | | Locator | Static service locator class with a default singleton instance that is by default an instance of DefaultLocator |

ResolveType enum

{
  PerRequest: 0,  // instantiate new instance for each request
  PerApp: 1,      // return a single instance per application (uses localStroage to preserve the instance)
  PerPage: 2,     // return a single instance per page (insiance is created when page loads)
  PerSession: 3   // return single instance per browser session (uses sessionStorage to preserve the instance)
}

LocatorBase API

| Method | description | |-------|-------------| | register(abstraction, concretion, resolveType = Resolve.PerRequest, state = null) | Register concretion class for abstraction class based on resolveType and state. concretion should be a subclass of abstraction. | | registerFactory(abstraction, factory, resolveType = Resolve.PerRequest, state = null) | Register an object that is instantiated by factory method for abstraction based on resolveType and state. The object returned by factory should be an instance of abstraction class. | | registerInstance(abstraction, instance, resolveType = Resolve.PerRequest, state = null) | Register instance object for abstraction based on resolveType and state. instance should be an instance of abstraction class. | | resolveBy(abstraction, state, ...args) | Resolve abstraction based on given state. Passes args when instantiating from the concretion that is already registered for abstraction. | | resolve(abstraction, ...args) | Resolve abstraction. Passes args when instantiating from the concretion that is already registered for abstraction. | | remove(abstraction, state) | Remove registration entry for abstraction based on the given state. | | exists(abstraction, state) | Check whether a registration entry exists for abstraction based on then given state. |

Simple example

./src/services/foo/index.js

// Foo Service
class FooServiceBase {
  getById(id) {
    throw 'getById() is not implemented'
  }
}
class FooServiceRemote extends FooServiceBase {
  async getById(id) {
    const response = await fetch(`/api/foo/${id}`);
    const foo = await response.json();

    return foo;
  }
}
class FooServiceFake extends FooServiceBase {
  constructor() {
    super();

    this._data = [
      { id: 1, name: 'Foo1'},
      { id: 2, name: 'Foo2'},
      { id: 3, name: 'Foo3'}
    ]
  }
  getById(id) {
    return new Promise(res => setTimeout(() => res(this._data.find(x => x.id == id)), 1000))
  }
}

export { FooServiceBase, FooServiceRemote, FooServiceFake }

./src/locator.config.js

import Locator from '@locustjs/locator';
import { FooServiceBase, FooServiceRemote, FooServiceFake } from './services/foo';

configureLocator(mode) {
  if (mode.toLowerCase() == 'production') {
    Locator.instance.register(FooServiceBase, FooServiceRemote);
  } else {
    Locator.instance.register(FooServiceBase, FooServiceFake);
  }
}

export default configureLocator;

./src/index.js

// App startup
import configureLocator from './locator.config.js';

const exec_type = 'development';  // or 'production'

configureLocator(exec_type)

./src/app.js

// FooService Usage
import Locator from '@locustjs/locator';
import { FooServiceBase } from './services/foo';

// Here, our code is independent of any foo service implementation.
// It relies on an abstract foo service. So, we can easily use a fake
// service to develop our app. Whenever our rest api is developed, we
// can switch to FooServiceRemote. No change is needed to be applied on app.js.

const service = Locator.instance.resolve(FooServiceBase);

const foo = await service.getById(1);

console.log(foo)

React example

index.js

import ReactDOM from 'react-dom';
import Locator, { Resolve } from '@locustjs/locator';
import ColorServiceBase from './services/color/base.js';
import ColorServiceDefault from './services/color/default.js';
import App from './App';

Locator.instance.register(ColorServiceBase, ColorServiceDefault);

ReactDOM.render(<App />, document.getElementById('root'));

App.js

import React, { Component } from 'react'
import ColorServiceBase from './services/color/base.js';
import Locator from '@locustjs/locator';

class App extends Component {
  constructor() {
    super();
    
    this.service = Locator.instance.resolve(ColorServiceBase);
    this.state = {
      colors: []
    }
  }
  async componentDidMount() {
    const colors = await this.service.getColors();
    
    this.setState({ colors });
  }
  render() {
    return (
		<React.Fragment>
			<h3>Colors</h3>
			<ul>
				{this.state.colors.map(x => <li>{x}</li>)}
			</ul>
		 </React.Fragment>
    );
  }
}

export default App;

/services/color/base.js

class ColorServiceBase {
  constructor() {
    if (this.constructor === ColorServiceBase) {
        throw 'ColorServiceBase is an abstract class. You cannot instantiate from it.'
    }
  }
  getColors() {
    throw 'getColors() is not implemented'
  }
}

export default ColorServiceBase;

/services/color/default.js

import ColorServiceBase from './base.js';

class ColorServiceDefault extends ColorServiceBase {
  async getColors() {
	  const response = await fetch('/api/colors');
	  const data = await response.json();
	  
	  return data;
  }
}

export default ColorServiceDefault;

/services/color/fake.js

import ColorServiceBase from './base.js';

class ColorServiceFake extends ColorServiceBase {
  getColors() {
    return new Promise((res, rej) => {
      res([ 'Red', 'Green', 'Blue', 'Yellow', 'White', 'Black', 'Purple' ]);
    });
  }
}

export default ColorServiceFake;

Here, the App component is completely decoupled from its ColorService dependency.