setDependency - greydragon888/real-router GitHub Wiki

getDependenciesApi().set

1. Overview

  • What it does: Sets one router dependency by name. undefined value is silently ignored (feature for conditional configuration). Warns when overwriting an existing dependency with a different value.
  • When to use:
    • For adding a single dependency (service, API client, analytics)
    • For conditional configuration: depsApi.set("analytics", __DEV__ ? mockAnalytics : undefined)
    • For updating an existing dependency (with warning)

2. Signature

import { getDependenciesApi } from "@real-router/core/api";

const depsApi = getDependenciesApi(router);

depsApi.set<K extends keyof Dependencies & string>(
  name: K,
  value: Dependencies[K],
): void;

Usage Examples

import { getDependenciesApi } from "@real-router/core/api";

const depsApi = getDependenciesApi(router);

// Add dependency
depsApi.set("apiClient", new ApiClient());

// Conditional configuration (undefined ignored)
depsApi.set("devTools", __DEV__ ? devToolsInstance : undefined);

// Update existing dependency (outputs warning)
depsApi.set("config", newConfig); // console.warn

// Idempotency (same value -- no warning)
depsApi.set("version", "1.0.0");
depsApi.set("version", "1.0.0"); // No warning

3. Parameters

name (required)

  • Type: K extends keyof Dependencies & string
  • Purpose: Dependency name
  • Allowed values: Any string (including empty)
  • On error: TypeError -- [router.setDependency]: dependency name must be a string, got {type}

value (required)

  • Type: Dependencies[K]
  • Purpose: Dependency value
  • Allowed values: Any value, including:
    • Primitives: number, string, boolean, null, 0, false, ""
    • Objects: plain objects, class instances, functions, arrays
    • Special: Infinity, -Infinity, NaN
    • Circular references
  • Special behavior:
    • undefined -- silently does nothing (dependency is not set, no error)
    • null -- set as a normal value

4. Return Value

  • Type: void
  • Description: Does not return a value.

5. Side Effects

  • State change: Adds or updates dependency in the store
  • Warnings:
    • console.warn when overwriting an existing dependency with a different value
    • console.warn when reaching the warn threshold (20% of maxDependencies, i.e. 20 at default limit of 100)
    • console.error when reaching the error threshold (50% of maxDependencies, i.e. 50 at default limit of 100)
  • Errors: Error when exceeding maxDependencies limit (default: 100)
  • NaN idempotency: Overwriting NaN with NaN does NOT trigger a warning (treated as same value via Number.isNaN())

6. Possible Errors

Condition Error Type Message
Router disposed RouterError Code: DISPOSED
name is not a string TypeError [router.setDependency]: dependency name must be a string, got {type}
Dependency limit exceeded (default 100) Error [router.setDependency] Dependency limit exceeded (100). Current: {count}...

Error Examples

import { getDependenciesApi } from "@real-router/core/api";

const depsApi = getDependenciesApi(router);

// TypeError: invalid name
depsApi.set(123, "value");
// TypeError: [router.setDependency]: dependency name must be a string, got number

depsApi.set(null, "value");
// TypeError: [router.setDependency]: dependency name must be a string, got object

// RouterError: router disposed
router.dispose();
depsApi.set("foo", "bar");
// RouterError: DISPOSED

// Error: limit exceeded (after adding 100 dependencies)
depsApi.set("dep101", value);
// Error: [router.setDependency] Dependency limit exceeded (100)...

7. Related Methods

Method When to use
getDependenciesApi().get Get dependency by name
getDependenciesApi().setAll Set multiple dependencies
getDependenciesApi().has Check existence
getDependenciesApi().remove Remove dependency
getDependenciesApi().getAll Get all dependencies
getDependenciesApi().reset Clear all dependencies

8. Behavior

Main Scenarios

  • New dependency: Added without warnings
  • Overwrite with different value: Updated with console.warn
  • Overwrite with same value: Updated without warning (idempotent)
  • undefined value: Silently ignored (conditional configuration)
  • NaN idempotency: NaN overwrites NaN without warning

Test Examples

import { getDependenciesApi } from "@real-router/core/api";

const depsApi = getDependenciesApi(router);

// Set new dependency
depsApi.set("bar", "hello");
expect(depsApi.get("bar")).toBe("hello");

// Overwrite existing
depsApi.set("foo", 2);
expect(depsApi.get("foo")).toBe(2);

// undefined ignored
depsApi.set("foo", undefined);
expect(depsApi.get("foo")).toBe(1); // Kept initial value

// Conditional configuration
const isDev = false;
depsApi.set("devLogger", isDev ? console : undefined);
expect(depsApi.has("devLogger")).toBe(false);

Overwrite Warnings

// Warning when overwriting with different value
depsApi.set("foo", 1);
depsApi.set("foo", 2); // console.warn

// No warning for same value
depsApi.set("foo", 42);
depsApi.set("foo", 42); // No warning

// Special NaN handling
depsApi.set("foo", NaN);
depsApi.set("foo", NaN); // No warning (NaN === NaN for idempotency check)

Prototype Pollution Protection

// Safe due to Object.create(null)
depsApi.set("constructor", "safe1");
depsApi.set("__proto__", "safe2");
depsApi.set("hasOwnProperty", "safe3");

expect(depsApi.get("constructor")).toBe("safe1");
expect(depsApi.get("__proto__")).toBe("safe2");
expect(depsApi.get("hasOwnProperty")).toBe("safe3");

Value Types

// Falsy values (except undefined)
depsApi.set("foo", 0); // OK
depsApi.set("bar", false); // OK
depsApi.set("baz", ""); // OK
depsApi.set("qux", null); // OK

// Special numeric values
depsApi.set("inf", Infinity); // OK
depsApi.set("neg", -Infinity); // OK
depsApi.set("nan", NaN); // OK

// Functions and classes
depsApi.set("factory", () => ({ value: 42 }));
depsApi.set("Service", ServiceClass);

// Circular references
const obj = { name: "circular" };
obj.self = obj;
depsApi.set("circular", obj); // OK

Dependency Limits

Default thresholds (with maxDependencies = 100):

Threshold Count Action
Warn 20 console.warn
Error 50 console.error
Max 100 throws Error
// Overwriting existing at limit -- allowed (doesn't increase count)
depsApi.set("dep0", 999); // OK

Disposed Router

router.dispose();
depsApi.set("foo", "bar");
// throws RouterError with code DISPOSED

Edge Cases

  • Empty string as key: Accepted
  • undefined as value: Silently ignored (no changes, no error)
  • null as value: Set normally
  • NaN idempotency: NaN overwrites NaN without warning
  • Circular references: Supported
  • Overwriting at limit: Allowed (overwrite does not increase count)

9. Migration

Old API (removed)

// Old -- no longer available
router.setDependency("apiClient", new ApiClient());

// Fluent chaining -- no longer available
router
  .setDependency("analytics", analyticsService)
  .setDependency("store", reduxStore);

New API

import { getDependenciesApi } from "@real-router/core/api";

const depsApi = getDependenciesApi(router);

// New -- standalone API
depsApi.set("apiClient", new ApiClient());

// No fluent chaining (returns void), use separate calls
depsApi.set("analytics", analyticsService);
depsApi.set("store", reduxStore);

Key Differences

Aspect Old (router.setDependency) New (getDependenciesApi(router).set)
Access Method on router instance Standalone API function
Return value Router (fluent interface) void
Chaining Supported Not supported
Tree-shaking Always bundled Tree-shakeable
Import N/A (on router) import { getDependenciesApi }