iblokz-data

npm version CI codecov License: MIT Documentation

A lightweight, functional JavaScript library providing immutable data manipulation utilities for arrays, objects, strings, and function composition.

Features

Installation

npm install iblokz-data

Usage

const { obj, arr, str, fn } = require('iblokz-data');

// Object operations
const user = { name: 'John', age: 30 };
const updated = obj.patch(user, 'age', 31);
// => { name: 'John', age: 31 }

// Array operations
const items = [1, 2, 3];
const newItems = arr.add(items, 4);
// => [1, 2, 3, 4]

// String operations
const camelCase = str.toCamelCase('hello_world');
// => 'helloWorld'

// Function composition
const addOne = x => x + 1;
const double = x => x * 2;
const addOneThenDouble = fn.pipe(addOne, double);
addOneThenDouble(3); // => 8

API Overview

Object Utilities (obj)

Basic Operations:

Functional Operations:

Advanced:

Array Utilities (arr)

String Utilities (str)

Function Utilities (fn)

Detailed Examples

Working with Nested Objects

const { obj } = require('iblokz-data');

const state = {
  user: {
    profile: {
      name: 'John',
      age: 30
    }
  }
};

// Get nested value
const name = obj.sub(state, ['user', 'profile', 'name']);
// => 'John'

// Update nested value
const updated = obj.patch(state, ['user', 'profile', 'age'], 31);
// => { user: { profile: { name: 'John', age: 31 } } }

// Map over object values
const doubled = obj.map({ a: 1, b: 2, c: 3 }, (k, v) => v * 2);
// => { a: 2, b: 4, c: 6 }

// Filter object properties
const filtered = obj.filter({ a: 1, b: 2, c: 3 }, (k, v) => v > 1);
// => { b: 2, c: 3 }

Immutable Array Operations

const { arr } = require('iblokz-data');

const tags = ['javascript', 'nodejs'];

// Add item
const withReact = arr.add(tags, 'react');
// => ['javascript', 'nodejs', 'react']

// Remove item
const withoutNode = arr.remove(tags, 'nodejs');
// => ['javascript']

// Toggle item (add if not present, remove if present)
const toggled = arr.toggle(tags, 'typescript');
// => ['javascript', 'nodejs', 'typescript']

// Check containment
arr.contains(tags, 'nodejs'); // => true
arr.contains('a,b,c', 'b');   // => true (works with CSV strings too)

String Transformations

const { str } = require('iblokz-data');

// Case conversions
str.toCamelCase('user_name');        // => 'userName'
str.fromCamelCase('userName');       // => 'user_name'
str.fromCamelCase('userName', '-');  // => 'user-name'

// Pluralization
str.singularToPlural('category');    // => 'categories'
str.pluralToSingular('categories');  // => 'category'

// Document ID generation (useful for foreign keys)
str.toDocumentId('user_roles');      // => 'userRoleId'

Function Composition

const { fn } = require('iblokz-data');

const addOne = x => x + 1;
const double = x => x * 2;
const square = x => x * x;

// Pipe: left-to-right execution
const addOneThenDouble = fn.pipe(addOne, double);
addOneThenDouble(3); // => 8 (3 + 1 = 4, 4 * 2 = 8)

// Compose: right-to-left execution
const doubleThenAddOne = fn.compose(addOne, double);
doubleThenAddOne(3); // => 7 (3 * 2 = 6, 6 + 1 = 7)

// Complex pipelines
const complexTransform = fn.pipe(
  x => x + 1,
  x => x * 2,
  x => x * x
);
complexTransform(2); // => 36 (2 + 1 = 3, 3 * 2 = 6, 6 * 6 = 36)

Pattern Matching with Switch

const { obj } = require('iblokz-data');

const handleAction = (action) => obj.switch(action.type, {
  'ADD_TODO': () => console.log('Adding todo'),
  'REMOVE_TODO': () => console.log('Removing todo'),
  'default': () => console.log('Unknown action')
});

// Works with nested paths
const config = {
  database: {
    mysql: { port: 3306 },
    postgres: { port: 5432 }
  }
};

const port = obj.switch(['database', 'mysql'], config);
// => { port: 3306 }

Real-World Example: State Management

const { obj, arr } = require('iblokz-data');

// Initial application state
const initialState = {
  todos: [],
  filter: 'all',
  user: {
    name: 'Guest',
    preferences: {
      theme: 'light'
    }
  }
};

// Add a todo (immutably)
const addTodo = (state, todo) =>
  obj.patch(state, 'todos', arr.add(state.todos, todo));

const state1 = addTodo(initialState, { id: 1, text: 'Learn iblokz-data' });

// Update user preference (deeply nested)
const state2 = obj.patch(state1, ['user', 'preferences', 'theme'], 'dark');

// Toggle filter
const state3 = obj.patch(state2, 'filter', 'completed');

console.log(state3);
// Original initialState remains unchanged!

Documentation

For detailed API documentation with all parameters, return types, and examples, see API.md.

To generate the API documentation locally:

npm run docs

Development

# Install dependencies
npm install

# Run tests
npm test

# Run linter
npm run lint

# Generate documentation
npm run docs

Quick Setup for Contributors

After cloning:

npm install          # Install dependencies
npm run prepare      # Setup git hooks
npm test            # Run tests

The pre-commit hooks will automatically:

Documentation

Testing

The library includes comprehensive test coverage:

npm test           # Run tests with coverage
npm run lint       # Run linter
npm run docs       # Generate documentation

Releases

We use automated releases via GitHub Actions. See docs/RELEASE.md for details.

To release a new version:

npm version patch   # or minor, or major
# This automatically creates a tag and triggers:
# - GitHub Release creation
# - npm package publishing
# - Documentation deployment

License

MIT © iblokz

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feat/amazing-feature)
  3. Commit your changes (git commit -m 'feat: add amazing feature')
  4. Push to the branch (git push origin feat/amazing-feature)
  5. Open a Pull Request