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

@superhero/locator

v4.2.0

Published

Service locator to locate services by defined locator patterns

Downloads

724

Readme

Locator

A Node.js service locator module, designed to manage dependency injections for services, using an eager or lazy loading approach. This module simplifies service management by dynamically resolving and loading services and their dependencies, supporting wildcard service path maps and agile service resolution methods.

Features

  • Eager Loading: Preload services in bulk for faster access, normally done at bootstrap by an application core process.
  • Lazy Loading: Dynamically load services when they are required, and keep them accessible.
  • Wildcard Service Paths: Resolve services using wildcard paths, to ease the service registry.
  • Locator: Locate a service using different implementation alternatives.
  • Destroy: Support for a graceful release of services resources.
  • Error Handling: Provides detailed errors with specific error codes for different types of errors.

Installation

Install the module using npm:

npm install @superhero/locator

Usage

Importing the Locator

import locator from '@superhero/locator';

Lazyload a Service

const foobar1 = await locator.lazyload('foobar', './service.js');
const foobar2 = locator.locate('foobar');
// foobar1 === foobar2

Eagerload Services

await locator.eagerload({
  serviceA: './services/serviceA.js',
  serviceB: './services/serviceB.js',
});
const serviceA = locator.locate('serviceA');
const serviceB = locator('serviceB'); // optional interface to locate

Using a Wildcard Service Path

await locator.eagerload({ 'services/*': './services/*.js' });
const serviceA = locator.locate('services/serviceA');
const serviceB = locator.locate('services/serviceB');

Using Locators

Create custom locators to manage complex dependency trees.

Example: Exported locate Function

export function locate(locator) {
  return { foobar: locator.locate('foobar') };
}

Example: Locator Class

export class Locator {
  locate(locator) {
    return { foobar: locator.locate('foobar') };
  }
}

Example: Static Class locate Function

export default class Foo {
  constructor(foobar) {
    this.foobar = foobar;
  }

  static locate(locator) {
    return new Foo(locator.locate('foobar'));
  }
}

Destroy

Services can include a destroy method to clean up resources during shutdown or unloading. The locator will automatically call the destroy method for all services when the destroy method is invoked on the service locator.

Example: Using Destroy

Define a service with a destroy method:

export default new class {
  destroy() {
    console.log('Service is being destroyed.');
  }
}

Destroy all loaded services:

await locator.eagerload({
  serviceA: './services/serviceA.js',
  serviceB: './services/serviceB.js',
});

await locator.destroy();

Error Handling During Destroy

If a service's destroy method throws an error, the locator will aggregate these errors and throw a comprehensive error with details.

Example:

try {
  await locator.destroy();
} catch (error) {
  console.error(error.code); // 'E_LOCATOR_DESTROY'
  console.error(error.cause); // Array of errors for each service taht failed to destroy
}

Error Codes:

  • E_LOCATOR_DESTROY: Thrown when one or more destroy methods fail.
  • E_LOCATOR_DESTROY_SERVICE: Thrown for individual service that fail to destroy.

Error Handling

The module provides descriptive errors with unique codes to help debug common issues.

  • E_LOCATOR_LOCATE: Thrown when trying to locate a non-existent service.
  • E_LOCATOR_LAZYLOAD: Thrown when lazy loading a service fails.
  • E_LOCATOR_EAGERLOAD: Thrown when eager loading fails.
  • E_LOCATOR_INVALID_SERVICE_MAP: Thrown for invalid service map formats.
  • E_LOCATOR_SERVICE_UNRESOLVABLE: Thrown when a service path cannot be resolved.
  • E_LOCATOR_INVALID_PATH: Thrown for invalid or mismatched wildcard paths.
  • E_LOCATOR_DESTROY: Thrown when one or more destroy methods fail.
  • E_LOCATOR_DESTROY_SERVICE: Thrown for individual service destroy methods that fail.

Example:

try {
  locator.locate('nonexistent/service');
} catch (error) {
  console.error(error.code, error.message);
}

Running Tests

The module includes a test suite. Run the tests using:

node test

Test Coverage

▶ @superhero/locator
  ▶ Lazyload
    ✔ Lazyload a service (4.828123ms)
    ✔ Lazyload same service multiple times (2.175617ms)
  ✔ Lazyload (7.965349ms)
  
  ▶ Eagerload
    ✔ Eagerload a service (2.271103ms)
    ✔ Eagerload the same service multiple times (0.933762ms)
    ✔ Eagerload multiple services by a collection definition (2.389402ms)
    ✔ Multiple services by a service path map (1.368324ms)
    ✔ Nested wildcard service (6.644221ms)
    ✔ Specific file by a wildcard service path map (2.014441ms)

    ▶ Using a locator
      ✔ Locator file (3.275955ms)
      ✔ Exported locate function (2.851036ms)
      ✔ Exported locator class (4.530722ms)
      ✔ Static self locator (2.690786ms)
      ✔ When the dependent service is loaded after the located service (1.780561ms)
    ✔ Using a locator (15.620721ms)
  ✔ Eagerload (32.099219ms)

  ▶ Rejects
    ✔ Lazyload a nonexistent path (2.06964ms)
    ✔ Lazyload a nonexistent path (1.023868ms)
    ✔ Directory path with no index or locator file (1.619045ms)
    ✔ Invalid wildcard path (0.7834ms)
    ✔ File path is used as a directory path (0.638767ms)
    ✔ Missmatched wildcard count (0.423624ms)
    ✔ Invalid service map types (0.973865ms)
    ✔ Noneexisting path (3.930104ms)
    ✔ Invalid wildcard path (2.209812ms)
    ✔ Throws error for attempting to locate a nonexisting service (0.415812ms)
  ✔ Rejects (14.858727ms)

  ▶ Destroy
    ✔ Successfully destroys a service (2.558189ms)
    ✔ Throws if fails to destroy a service (2.610999ms)
  ✔ Destroy (5.839146ms)

  ✔ Locate using the locator method (0.889694ms)
✔ @superhero/locator (90.014072ms)

tests 26
suites 6
pass 26

----------------------------------------------------------------------------------------------------
file            | line % | branch % | funcs % | uncovered lines
----------------------------------------------------------------------------------------------------
index.js        |  94.42 |    94.34 |   76.67 | 25-27 47-50 331-333 459-463 477-480 494-499 515-518
index.test.js   | 100.00 |   100.00 |   98.00 | 
----------------------------------------------------------------------------------------------------
all files       |  96.66 |    96.18 |   90.00 | 
----------------------------------------------------------------------------------------------------

License

This project is licensed under the MIT License.


Contributing

Feel free to submit issues or pull requests for improvements or additional features.