# dbl-utils

`dbl-utils` is a JavaScript/TypeScript utility library designed to simplify common application development tasks. This collection includes functions for event handling, queue processing, text manipulation, and date and currency formatting, among others.

[![Documentation](https://img.shields.io/badge/docs-view-green.svg)](https://joneldiablo.github.io/dbl-utils/modules.html)
[![DeepWiki Analysis](https://img.shields.io/badge/DeepWiki-analysis-blue.svg)](https://deepwiki.com/joneldiablo/dbl-utils)

## Table of Contents

- [Installation](#installation)
- [Usage](#usage)
- [Main Modules](#main-modules)
- [Utilities](#utilities)
- [Documentation](#documentation)
- [License](#license)

## Installation

You can install `dbl-utils` via npm:

```bash
npm install dbl-utils
```

Or using yarn:

```bash
yarn add dbl-utils
```

## Usage

Import the modules and functions in your project as needed. Below is a basic example of how to use `dbl-utils`:

```javascript
// Import individual functions
import { formatCurrency, flatten, t } from 'dbl-utils';
// Use functions
console.log(formatCurrency(1234.56)); // Example of currency formatting
console.log(flatten({ a: { b: { c: 1 } } })); // Converts a nested object into a flat object
```

Minimal example of the CLI logic for CSS purging:

```ts
import purgeCss from 'dbl-utils/src/purge-css';
purgeCss('styles.css', 'index.html', 'clean.css');
```

Imports directly from any file to don't include all:

CommonJS use **/dist/cjs/\***

```javascript
// Import individual functions
const i18n = require('dbl-utils/dist/cjs/i18n');
// Use functions
console.log(i18n.formatCurrency(1234.56));
```

ESM use **/dist/esm/\***

```javascript
// Import individual functions
import t, { formatCurrency } from 'dbl-utils/dist/esm/i18n';
// Use functions
console.log(i18n.formatCurrency(1234.56));
```

TypeScript use **/src/\***

```javascript
// Import individual functions
import t, { formatCurrency } from 'dbl-utils/src/i18n';
// Use functions
console.log(i18n.formatCurrency(1234.56));
```

For a complete reference of all available functions, visit the [full documentation here](https://joneldiablo.github.io/dbl-utils/modules.html).

## Main Modules

Below are the main modules available in `dbl-utils`:

- [event-handler](https://github.com/joneldiablo/dbl-utils/blob/master/src/event-handler.ts)
- [fetch-queue](https://github.com/joneldiablo/dbl-utils/blob/master/src/fetch-queue.ts)
- [flat](https://github.com/joneldiablo/dbl-utils/blob/master/src/flat.ts)
- [format-value](https://github.com/joneldiablo/dbl-utils/blob/master/src/format-value.ts)
- [i18n](https://github.com/joneldiablo/dbl-utils/blob/master/src/i18n.ts)
- [object-mutation](https://github.com/joneldiablo/dbl-utils/blob/master/src/object-mutation.ts)
- [resolve-refs](https://github.com/joneldiablo/dbl-utils/blob/master/src/resolve-refs.ts)
- [utils](https://github.com/joneldiablo/dbl-utils/blob/master/src/utils.ts)

## Utilities

### event-handler

Decouple communication by subscribing to and dispatching custom events.

```ts
import { EventHandler } from 'dbl-utils';

const handler = new EventHandler();
handler.subscribe('ping', msg => console.log(msg), 'id'); // listen to events
await handler.dispatch('ping', 'pong'); // emit an event
handler.unsubscribe('ping', 'id'); // stop listening
```

### fetch-queue

Deduplicate concurrent HTTP calls so the same request is only made once.

```ts
import FetchQueue from 'dbl-utils/src/fetch-queue';

const queue = new FetchQueue(fetch);
const [a, b] = await Promise.all([
  queue.addRequest('https://example.com'),
  queue.addRequest('https://example.com')
]);
// a === b
```

### flat

Convert nested objects to and from dot notation.

```ts
import { flatten, unflatten } from 'dbl-utils';

flatten({ a: { b: 1 } }); // { 'a.b': 1 }
unflatten({ 'a.b': 1 }); // { a: { b: 1 } }
```

### format-value

Format numbers, dates, or dictionary entries using locale-aware helpers.

```ts
import formatValue from 'dbl-utils/src/format-value';

formatValue(1000, { format: 'currency', currency: 'USD' }); // "$1,000.00"
```

### i18n

Manage dictionaries and locale-aware formatting.

```ts
import t, { addDictionary, setLang, formatDate } from 'dbl-utils';

addDictionary({ es: { hello: 'Hola' } });
setLang('es');
t('hello'); // 'Hola'
formatDate(); // date formatted in Spanish
```

### object-mutation

Combine and transform objects without modifying the originals.

```ts
import { deepMerge, mergeWithMutation, transformJson } from 'dbl-utils';

deepMerge({}, { a: 1 }, { b: 2 }); // merge nested structures
await mergeWithMutation({ a: { b: 1 } }, { mutation: () => ({ c: 2 }) }); // async mutation
transformJson({ a: { b: 1 } }, { filter: 'a' }); // extract subset
```

### resolve-refs

Advanced reference resolution system for dynamic object composition and template inheritance. Perfect for configuration management, content templating, and complex data transformations.

#### Core Features

- **🌐 Global References**: Access any value in your data schema
- **🔗 Relative References**: Reference values within the current object context  
- **📝 String Interpolation**: Embed references within strings seamlessly
- **🎨 Template Inheritance**: Create reusable object templates with property overrides
- **⚙️ Custom Rules & Tasks**: Define advanced transformation logic
- **🔄 Recursive Resolution**: Handle complex nested reference chains

#### Reference Types

**1. Global References**
```ts
const config = { api: { url: "https://api.com", key: "secret" } };
const settings = {
  endpoint: "$api/url",           // Direct reference → "https://api.com"
  auth: "Bearer ${api/key}",      // String interpolation → "Bearer secret"
  full: "${api/url}/v1/users"     // Mixed interpolation → "https://api.com/v1/users"
};
```

**2. Template Inheritance**
```ts
const data = {
  // Base template
  userTemplate: { name: "Guest", role: "viewer", active: false },
  
  // Inherit and override properties
  admin: { ref: "$userTemplate", name: "Admin", role: "admin", active: true },
  john: { ref: "$userTemplate", name: "John Doe" }
};

const result = resolveRefs(data);
// result.admin = { name: "Admin", role: "admin", active: true }
// result.john = { name: "John Doe", role: "viewer", active: false }
```

**3. Relative References with Template System**
```ts
const data = {
  user1: { ref: "$templates/user", firstName: "Alice", lastName: "Smith" },
  user2: { ref: "$templates/user", firstName: "Bob", lastName: "Jones" },
  
  templates: {
    user: {
      firstName: "",
      lastName: "",
      ".": {
        // These resolve AFTER template merging
        fullName: "${./firstName} ${./lastName}",           // Relative interpolation
        email: "${./firstName}.${./lastName}@company.com",  // Complex relative refs
        profile: {
          displayName: "$./fullName",    // Reference to another relative ref
          initials: "${./firstName/0}${./lastName/0}"  // Access array/string indices
        }
      }
    }
  }
};

const result = resolveRefs(data);
// result.user1.fullName = "Alice Smith"
// result.user1.email = "Alice.Smith@company.com"  
// result.user1.profile.displayName = "Alice Smith"
// result.user1.profile.initials = "AS"
```

#### Advanced Usage

**Configuration Management**
```ts
const config = {
  // Environment settings
  env: { 
    name: "production",
    domain: "myapp.com",
    apiVersion: "v2"
  },
  
  // Service definitions using templates
  services: {
    auth: { ref: "$templates/service", path: "/auth", timeout: 5000 },
    users: { ref: "$templates/service", path: "/users", port: 8080 },
    payments: { ref: "$templates/service", path: "/payments", ssl: true }
  },
  
  templates: {
    service: {
      path: "/",
      port: 3000,
      timeout: 30000,
      ssl: false,
      ".": {
        // Dynamic URL generation
        baseUrl: "http${./ssl ? 's' : ''}://${env/domain}:${./port}",
        fullUrl: "${./baseUrl}/${env/apiVersion}${./path}",
        
        // Service configuration
        config: {
          endpoint: "$./fullUrl",
          timeout: "$./timeout",
          retries: 3,
          headers: {
            "X-Service-Name": "${env/name}",
            "X-API-Version": "${env/apiVersion}"
          }
        }
      }
    }
  }
};

const result = resolveRefs(config);
// result.services.auth.fullUrl = "http://myapp.com:3000/v2/auth"
// result.services.users.fullUrl = "http://myapp.com:8080/v2/users"
// result.services.payments.fullUrl = "https://myapp.com:3000/v2/payments"
```

**Custom Rules and Tasks**
```ts
const data = {
  users: ["Alice", "Bob", "Charlie"],
  products: [{ name: "Widget", price: 10 }, { name: "Gadget", price: 25 }]
};

const template = {
  welcomeMessage: "$greetUsers",
  productSummary: "$summarizeProducts",
  totalValue: "$calculateTotal"
};

// Define custom processing rules
const rules = {
  "$greetUsers": ["join", "$users", " and "],
  "$summarizeProducts": ["iterate", "$products", "product"],
  "$calculateTotal": ["sum", "$products", "price"]
};

// Custom task implementations
const extraTasks = {
  sum: (array: any[], property: string) => 
    array.reduce((total, item) => total + item[property], 0),
  
  format: (template: string, ...values: any[]) =>
    template.replace(/{(\d+)}/g, (_, i) => values[i]),
    
  conditional: (condition: boolean, trueVal: any, falseVal: any) =>
    condition ? trueVal : falseVal
};

const result = resolveRefs(template, data, rules, extraTasks);
// result.welcomeMessage = "Alice and Bob and Charlie"
// result.totalValue = 35
```

#### Built-in Tasks

- **`iterate(array, itemName)`** - Process array items with current schema context
- **`join(values, separator, ...extras)`** - Join arrays or concatenate values
- **`ignore(path, fallback)`** - Safe property access with fallback values
- **`if(condition, trueValue, falseValue)`** - Conditional value resolution

#### API Reference

```ts
resolveRefs<T>(
  object: ResolvableValue,      // Object/array with references to resolve
  schema?: Record<string, any>, // Base schema for global references
  rules?: ResolveRefsRules,     // Custom rule definitions
  extraTasks?: ResolveRefsTasks // Additional task implementations
): T
```

#### Best Practices

1. **🏗️ Structure**: Organize templates in dedicated sections (e.g., `templates/`, `definitions/`)
2. **📋 Naming**: Use descriptive paths like `config/database/url` over abbreviated versions
3. **🎯 Performance**: Avoid deep circular references and excessive nesting
4. **🔒 Type Safety**: Define TypeScript interfaces for your schema structure
5. **🧪 Testing**: Test complex reference chains with various data combinations

#### Real-World Examples

For comprehensive examples and advanced use cases, see the [detailed examples documentation](./examples/resolve-refs-examples.md).

- **Multi-environment Configuration**: Different API endpoints per environment
- **Component Templates**: Reusable UI component configurations
- **Dynamic Content**: Blog posts with shared metadata and custom overrides
- **API Documentation**: Auto-generated endpoint documentation from templates
- **Feature Flags**: Conditional configuration based on environment/user settings

### utils

#### sliceIntoChunks
Split an array into smaller arrays for batching.

```ts
import { sliceIntoChunks } from 'dbl-utils';
sliceIntoChunks([1,2,3,4],2); // [[1,2],[3,4]]
```

#### splitAndFlat
Turn a list of strings into unique tokens.

```ts
import { splitAndFlat } from 'dbl-utils';
splitAndFlat(['a b','c']); // ['a','b','c']
```

#### generateRandomColors
Generate distinct colors for visualizations.

```ts
import { generateRandomColors } from 'dbl-utils';
generateRandomColors(2); // ['#aabbcc', '#ddeeff']
```

#### evaluateColorSimilarity
Check how close colors are to each other.

```ts
import { evaluateColorSimilarity } from 'dbl-utils';
evaluateColorSimilarity(['#fff','#ffe']); // value near 1
```

#### normalize
Remove accents and lowercase text.

```ts
import { normalize } from 'dbl-utils';
normalize('á'); // 'a'
```

#### slugify
Create URL-friendly slugs.

```ts
import { slugify } from 'dbl-utils';
slugify('Hello World'); // 'hello-world'
```

#### randomS4
Produce a short hex segment.

```ts
import { randomS4 } from 'dbl-utils';
randomS4(); // '9f3b'
```

#### randomString
Generate a random alphanumeric string.

```ts
import { randomString } from 'dbl-utils';
randomString(5); // e.g., 'abcde'
```

#### timeChunks
Build time intervals between two dates.

```ts
import { timeChunks } from 'dbl-utils';
timeChunks({ from:'2020-01-01', to:'2020-01-02', step:3600 }); // [...]
```

#### delay
Pause execution for a given time.

```ts
import { delay } from 'dbl-utils';
await delay(10); // waits 10ms
```

#### hash
Generate a numeric hash.

```ts
import { hash } from 'dbl-utils';
hash('data'); // 123456789
```

#### LCG
Deterministic pseudo-random number generator.

```ts
import { LCG } from 'dbl-utils';
const gen = new LCG(123);
gen.random(); // 0.5967...
```

## Documentation

For a detailed description of each module and function, visit the [full documentation](https://joneldiablo.github.io/dbl-utils/modules.html) automatically generated with Typedoc. The documentation includes usage examples and in-depth explanations of each function.

For an in-depth analysis of the project architecture, codebase structure, and implementation details, check out the comprehensive [DeepWiki analysis](https://deepwiki.com/joneldiablo/dbl-utils).

## Testing

Run the test suite with:

```bash
npm test
```

This project uses Jest with ts-jest. New tests cover the `i18n` and `object-mutation` modules.

## Recent Changes

- **Comprehensive resolve-refs documentation**: Completely redesigned documentation with:
  - Enhanced JSDoc comments with detailed examples and use cases
  - Full TypeScript type definitions and interfaces
  - Comprehensive README section with visual examples
  - Real-world usage examples including configuration management, API documentation, and component systems
  - Advanced examples covering feature flags, e-commerce catalogs, and multi-environment setups
- **Enhanced resolve-refs module**: Added support for relative references with `$./` and `${./}` syntax
  - New template system using the `"."` key for relative references
  - Ability to create reusable templates that can be extended with different values
  - Support for references that point to other references (recursive resolution)
  - Comprehensive unit tests covering all relative reference scenarios
- Fixed handling of numeric keys in `unflatten` so arrays are reconstructed correctly.
- Added unit tests for the `i18n` and `object-mutation` modules.
- Expanded coverage with additional tests for `utils`, `format-value`, and `i18n`.

## TODO

- Move number compact formatting to the i18n module.

## Development & Testing

When developing or debugging tests, use `yarn test -- <pattern>` to run only the relevant test cases.

## License

This project is under the ISC license. See the `LICENSE` file for more details.
