# custom-factory

> more easily add the factory ability to your class for node and javascript

Latest version **3.0.1** (published 2026-07-10) · MIT license · 0 weekly downloads

## Install

```sh
npm install custom-factory
pnpm add custom-factory
yarn add custom-factory
bun add custom-factory
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 3.0.1 |
| Published | 2026-07-10 |
| First published | 2015-01-31 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=8 |
| Dependencies | 2 |
| Unpacked size | 104.1 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 2 |
| Author | Riceball LEE |
| Maintainers | riceball |
| Keywords | ability, abstract, factory, custom, custom-factory, register, unregister, alias, object, class |

## Links

- npm: https://www.npmjs.com/package/custom-factory
- Repository: https://github.com/snowyu/custom-factory.js
- Issues: https://github.com/snowyu/custom-factory.js/issues
- npm.io page: https://npm.io/package/custom-factory

## Dependencies (2)

- [inherits-ex](https://npm.io/package/inherits-ex.md) ^2.2.2
- [custom-ability](https://npm.io/package/custom-ability.md) ^2.3.1

## Recent versions

- 3.0.1 (latest) — 2026-07-10
- 2.3.0-alpha.6 (alpha) — 2024-03-15
- 3.0.0 — 2026-01-08
- 2.5.0 — 2026-01-08
- 2.4.0 — 2026-01-08
- 2.3.1 — 2026-01-08
- 2.3.0 — 2024-08-29
- 2.3.0-alpha.5 — 2023-12-23
- 2.3.0-alpha.4 — 2023-12-21
- 2.3.0-alpha.3 — 2023-04-19
- 2.3.0-alpha.2 — 2023-04-19
- 2.3.0-alpha.1 — 2023-04-18
- 2.3.0-alpha.0 — 2023-04-17
- 2.2.0 — 2023-03-13
- 2.1.0 — 2023-03-11
- … 42 more at https://npm.io/package/custom-factory/versions

## README

# CustomFactory [![Build Status](https://github.com/snowyu/custom-factory.js/actions/workflows/nodejs.yml/badge.svg)](https://github.com/snowyu/custom-factory.js/actions/workflows/nodejs.yml) [![npm](https://img.shields.io/npm/v/custom-factory.svg)](https://npmjs.org/package/custom-factory) [![downloads](https://img.shields.io/npm/dm/custom-factory.svg)](https://npmjs.org/package/custom-factory) [![license](https://img.shields.io/npm/l/custom-factory.svg)](https://npmjs.org/package/custom-factory)

**CustomFactory** is a powerful utility that adds factory capabilities to your classes or objects. It allows you to manage classes and instances through registration, aliasing, and hierarchical structures.

Whether you need a simple flat registry or a complex hierarchical system (like a file system), CustomFactory has you covered. It supports both **Inheritance** (extending a base class) and **Ability** (mixin/trait) patterns, making it easy to integrate into existing codebases.

## Features

* **Factory Patterns:**
  * **Flat Factory (`BaseFactory`):** A simple, single-level registry.
  * **Hierarchical Factory (`CustomFactory`):** A multi-level registry where factories can contain other factories (like folders).
* **Flexible Registration:** Register classes with unique names, display names, and multiple aliases.
* **Smart Naming:** Automatically deduces registered names by stripping suffixes (e.g., `TextCodec` -> `Text` in a `Codec` factory).
* **Singleton Support:** Retrieve or create singleton instances.
* **Integration Styles:**
  * **Inheritance:** Extend `BaseFactory` or `CustomFactory`.
  * **Ability (Mixin):** Add factory features to *any* existing class without breaking the inheritance chain.
* **Automatic Inheritance:** Automatically inherits from the factory class upon registration (configurable).
* **Case Sensitivity:** Configurable name formatting (case-sensitive by default).

## Installation

```bash
npm install custom-factory
```

## Quick Start

### Method 1: Inheritance (Recommended for new projects)

#### Flat Factory (`BaseFactory`)

Use `BaseFactory` for a simple, non-nested registry.

```javascript
import { BaseFactory } from 'custom-factory'

class ShapeFactory extends BaseFactory {}

// 1. Register classes
class Circle extends ShapeFactory {} // Auto-registers as 'Circle'
ShapeFactory.register(Circle)

// 2. Register with aliases and options
class Square {}
ShapeFactory.register(Square, {
  name: 'Square',
  aliases: ['sq', 'box']
})

// 3. Usage
const shape = ShapeFactory.createObject('Circle') // Returns a Circle instance
const sq = ShapeFactory.get('sq') // Returns the Square class
```

#### Hierarchical Factory (`CustomFactory`)

Use `CustomFactory` when you need a nested structure (e.g., `Codec` -> `Image` -> `Png`).

```javascript
import { CustomFactory } from 'custom-factory'

class RootFactory extends CustomFactory {}

// Level 1
class Codec extends RootFactory {}
RootFactory.register(Codec)

// Level 2
class ImageCodec extends Codec {}
Codec.register(ImageCodec, { name: 'Image' }) // Registered as 'Image' inside 'Codec'

// Level 3
class PngCodec extends ImageCodec {}
ImageCodec.register(PngCodec, { name: 'Png' })

// Usage
console.log(RootFactory.path(PngCodec)) // Output: '/Codec/Image/Png'
const PngClass = RootFactory.get('Codec').get('Image').get('Png')
```

### Method 2: Ability / Mixin (Recommended for existing classes)

If you already have a class hierarchy and want to add factory powers without changing the superclass, use the `Ability` functions.

```javascript
import { addBaseFactoryAbility, addFactoryAbility } from 'custom-factory'

class MyBaseClass {
  constructor(name) { this.name = name }
}

// Add Flat Factory capability
addBaseFactoryAbility(MyBaseClass)

class Plugin extends MyBaseClass {}
MyBaseClass.register(Plugin, { name: 'MyPlugin' })

const instance = MyBaseClass.createObject('MyPlugin', 'instanceName')
```

For hierarchical capabilities, use `addFactoryAbility(MyBaseClass)`.

## Core Concepts

### 1. Flat Factory (`BaseFactory`)

The `BaseFactory` provides a single namespace for all registered items. It's ideal for simple plugin systems or type registries.

**Key Methods:**

* `register(Class, [options])`: Registers a class.
* `get(name)`: Retrieves a class by name or alias.
* `createObject(name, ...args)`: Creates an instance of the registered class.
* `forEach(callback)`: Iterates through registered classes.

### 2. Hierarchical Factory (`CustomFactory`)

The `CustomFactory` extends `BaseFactory` to support nesting. Registered items can themselves be factories for other items.

**Key Methods (extends BaseFactory):**

* `register(Class, [parent], [options])`: Registers a class, optionally specifying a parent factory.
* `path(Class)`: Returns the full path string (e.g., `/Root/Parent/Child`).
* `pathArray(Class)`: Returns the path as an array.

### 3. Automatic Name Generation

When you register a class without providing an explicit `name`, the factory attempts to generate a clean name by stripping redundant suffixes.

* **Explicit Name**: You can provide a name during registration, or define a `static name` and `static alias` in the class:

  ```javascript
  // Via registration
  Factory.register(MyClass, { name: "custom-name", aliases: ["c", "alias"] });
  // OR via static properties in class (Declarative Style)
  class MyClass {
    static name = "custom-name";
    static alias = ["c", "alias"];
  }
  Factory.register(MyClass);
  ```

* **`baseNameOnly` (default: 1):** The factory checks if the class name ends with the factory's name (or ancestor names in a hierarchy) and strips it.
  * **Flat Example:** Registering `TextCodec` to `CodecFactory` -> Name becomes `Text`.
  * **Hierarchy Example:**
    * Root: `Codec`
    * Child: `ImageCodec` (Registered as `Image`)
    * Grandchild: `PngImageCodec` (Registered as `Png`) -> Strips `ImageCodec` (parent) and `Codec` (root).
* **`baseNameOnly: 0`:** Disables suffix stripping. Uses the full class name.

### 4. Customizing Name Formatting

By default, names are **case-sensitive**. You can change this behavior by overriding the static `formatName` method in your factory.

```javascript
class MyFactory extends BaseFactory {
  static formatName(name) {
    return name.toLowerCase(); // Make everything case-insensitive
  }
}
```

When using **abilities**, you can also override `formatName` by either defining it on the class before adding the ability, or by passing it in the options:

```javascript
class MyCodec {
  static formatName(name) { return name.toLowerCase() }
}
addFactoryAbility(MyCodec)
// OR
addFactoryAbility(MyCodec, { formatName: (name) => name.toLowerCase() })
```

### 5. Advanced Registration: `isFactory` and `autoInherits`

The `register` method accepts advanced options to control inheritance and factory behavior.

* **`isFactory`** (`boolean` | `Class`, default: `true`):
  * `true`: The registered class is treated as a **Factory Node**. It can have its own children.
  * `false`: The registered class is a **Product/Leaf**. It cannot have children.
  * `Class` (Constructor): The registered class is a factory and **must** inherit from this specific class.

  **Note on `isFactory` Priority:**
  The value is determined in the following order:
  1. `options.isFactory` passed to `register()`.
  2. `static _isFactory` defined on the **registered class**.
  3. `static _isFactory` defined on the **current Factory class**.
  4. `static _isFactory` defined on the **root Factory class** (`this.Factory`).
  5. Defaults to `true`.

* **`autoInherits`** (`boolean`, default: `true`):
  * `true`: If the registered item (which is a Factory) does not already inherit from the parent Factory, CustomFactory will **automatically modify its prototype chain** to inherit from it. This is useful for "Mix-and-Match" composition.
  * `false`: Disables automatic inheritance. If the class does not inherit correctly, a `TypeError` will be thrown.

### 6. Aliases

Aliases allow you to refer to the same registered class by different names. This is useful for providing shortcuts or maintaining backward compatibility.

* **During Registration**:

  ```javascript
  Factory.register(MyClass, { aliases: ['m', 'my'] });
  ```

* **After Registration**:

  ```javascript
  Factory.setAliases(MyClass, 'shortcut', 'another');
  // Or for single alias
  Factory.setAlias(MyClass, 'short');
  ```

* **Using Properties**: If the class is already registered, you can use the `aliases` property:

  ```javascript
  MyClass.aliases = ['a', 'b']; // Replaces current aliases
  console.log(MyClass.aliases); // ['a', 'b']
  ```

* **Important Note for TypeScript/Static Blocks**: 
  Always use `static alias` (singular) for declarative alias definitions in your classes. 
  Avoid using `static aliases` (plural) because `BaseFactory` defines a static setter for `aliases`. Some compilers (like TypeScript or Vitest) may transform `static aliases = [...]` into a static block:
  ```javascript
  class MyClass extends Factory {
    static { this.aliases = [...]; }
  }
  ```
  This will trigger the setter on the `Factory` base class instead of defining a property on `MyClass`, leading to incorrect alias registration. Using `static alias` avoids this conflict.

  **Best Practice for Hierarchies**: If you are designing your own factory hierarchies, prefer using simple static properties (direct assignment) for configuration. If you must use a static setter in a parent class, remember that descendant classes must also define a setter (or getter/setter) to properly override it; otherwise, the parent's setter will be invoked when assigning the property in the child.

* **Retrieval**: Use any alias with `get()` or `createObject()`:

  ```javascript
  const instance = Factory.createObject('shortcut');
  ```

* **Note**: Aliases are also processed by the factory's `formatName` method (e.g., if the factory is case-insensitive, aliases will be too).

## API Reference

### Static Properties

* `_isFactory`: The default `isFactory` value for the factory (default: `true`).
* `_baseNameOnly`: The default `baseNameOnly` value for the factory (default: `1`).

### Static Methods

* `register(class, [options])`: Register a class.
* `unregister(name|class)`: Remove a class from the factory.
* `get(name)`: Get a registered class.
* `createObject(name, ...args)`: Create an instance.
* `setAliases(class, ...aliases)`: Set aliases.
* `getAliases(class)`: Get aliases.
* `forEach(callback)`: Iterate over registered items.
* `formatName(name)`: Override this to change name matching (e.g., for case-insensitivity).

### Instance Methods

* `initialize(...args)`: Called by the constructor. Override this for initialization logic.

*(For `CustomFactory` only)*

* `path(class)`: Get the hierarchical path.
* `pathArray(class)`: Get the hierarchical path as an array.

## License

MIT

---
_Source: https://npm.io/package/custom-factory · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
