Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
7 views14 pages

Chainflow

ChainFlow.js is a comprehensive JavaScript utility library designed for performing complex operations through a chainable API. It offers a wide range of features including advanced filtering, grouping, sorting, mapping, and asynchronous utilities, all aimed at simplifying data manipulation. The library also includes validation, performance optimization, and error handling capabilities to enhance developer productivity.

Uploaded by

jidangamer7
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views14 pages

Chainflow

ChainFlow.js is a comprehensive JavaScript utility library designed for performing complex operations through a chainable API. It offers a wide range of features including advanced filtering, grouping, sorting, mapping, and asynchronous utilities, all aimed at simplifying data manipulation. The library also includes validation, performance optimization, and error handling capabilities to enhance developer productivity.

Uploaded by

jidangamer7
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 14

/**

* ChainFlow.js - The Ultimate JavaScript Utility Library


* Powerful, complex operations made simple with chainable API
*
* @version 1.0.0
* @author ChainFlow Labs
* @license MIT
*/

(function(global) {
'use strict';

class ChainFlow {
constructor(data) {
this.data = data;
this.operations = [];
this.cached = new Map();
this.middleware = [];
}

// ==================== ARRAY UTILITIES ====================

/**
* Smart filter with multiple conditions and AI-like matching
*/
filter(condition) {
if (typeof condition === 'string') {
// Smart search with fuzzy matching
return this._chain(data => this._smartFilter(data, condition));
} else if (typeof condition === 'object') {
// Multi-field object matching
return this._chain(data => this._objectFilter(data, condition));
} else if (typeof condition === 'function') {
return this._chain(data => data.filter(condition));
}
return this;
}

/**
* Advanced grouping with nested support
*/
groupBy(key, options = {}) {
return this._chain(data => {
const groups = {};
const nested = options.nested || false;
const transform = options.transform || (x => x);

data.forEach(item => {
const groupKey = this._getNestedValue(item, key);
const transformedKey = transform(groupKey);

if (!groups[transformedKey]) {
groups[transformedKey] = [];
}
groups[transformedKey].push(item);
});

if (nested) {
return this._createNestedGroups(groups, options.levels || 1);
}

return groups;
});
}

/**
* Smart sorting with multiple criteria
*/
sort(criteria) {
return this._chain(data => {
if (typeof criteria === 'string') {
return [...data].sort((a, b) => this._smartCompare(a, b,
criteria));
} else if (Array.isArray(criteria)) {
return [...data].sort((a, b) => this._multiSort(a, b,
criteria));
} else if (typeof criteria === 'function') {
return [...data].sort(criteria);
}
return data;
});
}

/**
* Advanced map with async support and error handling
*/
map(transformer, options = {}) {
return this._chain(async data => {
const concurrent = options.concurrent || false;
const batchSize = options.batchSize || 10;
const errorHandler = options.onError || (err =>
console.error(err));

if (concurrent) {
return this._concurrentMap(data, transformer, batchSize,
errorHandler);
} else {
return this._sequentialMap(data, transformer, errorHandler);
}
});
}

/**
* Intelligent reduce with accumulator patterns
*/
reduce(reducer, initialValue, options = {}) {
return this._chain(data => {
const parallel = options.parallel || false;
const chunks = options.chunks || 4;

if (parallel && data.length > 100) {


return this._parallelReduce(data, reducer, initialValue,
chunks);
} else {
return data.reduce(reducer, initialValue);
}
});
}
/**
* Find with fuzzy matching and scoring
*/
find(query, options = {}) {
return this._chain(data => {
const fuzzy = options.fuzzy || false;
const threshold = options.threshold || 0.6;
const key = options.key;

if (fuzzy) {
const results = this._fuzzySearch(data, query, key, threshold);
return options.all ? results : results[0];
} else {
return data.find(item => this._matches(item, query, key));
}
});
}

// ==================== OBJECT UTILITIES ====================

/**
* Deep merge with conflict resolution
*/
merge(...objects) {
return this._chain(data => {
const strategy = objects[objects.length - 1];
const isStrategy = typeof strategy === 'object' &&
strategy.strategy;
const mergeStrategy = isStrategy ? strategy.strategy : 'overwrite';
const objsToMerge = isStrategy ? objects.slice(0, -1) : objects;

return this._deepMerge([data, ...objsToMerge], mergeStrategy);


});
}

/**
* Transform object structure with mapping
*/
transform(mapping) {
return this._chain(data => {
if (Array.isArray(data)) {
return data.map(item => this._transformObject(item, mapping));
} else {
return this._transformObject(data, mapping);
}
});
}

/**
* Extract nested values with default fallbacks
*/
extract(paths, options = {}) {
const defaultValue = options.default;
const flatten = options.flatten || false;

return this._chain(data => {


const extracted = {};
paths.forEach(path => {
const value = this._getNestedValue(data, path, defaultValue);
if (flatten) {
const key = path.split('.').pop();
extracted[key] = value;
} else {
this._setNestedValue(extracted, path, value);
}
});
return extracted;
});
}

// ==================== ASYNC UTILITIES ====================

/**
* Smart retry with exponential backoff
*/
retry(fn, options = {}) {
const maxAttempts = options.attempts || 3;
const delay = options.delay || 1000;
const backoff = options.backoff || 'exponential';
const condition = options.retryIf || (() => true);

return this._chain(async data => {


let attempt = 0;
let lastError;

while (attempt < maxAttempts) {


try {
return await fn(data);
} catch (error) {
lastError = error;
attempt++;

if (attempt >= maxAttempts || !condition(error)) {


throw error;
}

const waitTime = this._calculateDelay(delay, attempt,


backoff);
await this._sleep(waitTime);
}
}
});
}

/**
* Parallel execution with concurrency control
*/
parallel(tasks, options = {}) {
const concurrency = options.concurrency || 5;
const failFast = options.failFast || false;

return this._chain(async data => {


const results = [];
const errors = [];
const executing = [];

for (let i = 0; i < tasks.length; i++) {


const task = tasks[i];
const promise = this._executeTask(task, data, i)
.then(result => {
results[i] = result;
})
.catch(error => {
errors[i] = error;
if (failFast) throw error;
});

executing.push(promise);

if (executing.length >= concurrency) {


await Promise.race(executing);
this._cleanupCompleted(executing);
}
}

await Promise.all(executing);
return { results, errors };
});
}

/**
* Debounce with advanced options
*/
debounce(fn, delay = 300, options = {}) {
const leading = options.leading || false;
const trailing = options.trailing !== false;
const maxWait = options.maxWait;

return this._chain(data => {


return new Promise((resolve) => {
const debounced = this._createDebounce(
() => resolve(fn(data)),
delay,
{ leading, trailing, maxWait }
);
debounced();
});
});
}

/**
* Throttle with burst handling
*/
throttle(fn, limit = 100, options = {}) {
const burst = options.burst || false;
const queue = options.queue || false;

return this._chain(data => {


return new Promise((resolve) => {
const throttled = this._createThrottle(
() => resolve(fn(data)),
limit,
{ burst, queue }
);
throttled();
});
});
}

// ==================== VALIDATION UTILITIES ====================

/**
* Schema validation with custom rules
*/
validate(schema, options = {}) {
const strict = options.strict || false;
const transform = options.transform || false;

return this._chain(data => {


const result = this._validateSchema(data, schema, strict);

if (result.isValid) {
return transform ? result.transformed : data;
} else {
const error = new Error('Validation failed');
error.details = result.errors;
throw error;
}
});
}

/**
* Type checking with coercion
*/
ensureType(type, options = {}) {
const coerce = options.coerce || false;
const strict = options.strict || false;

return this._chain(data => {


const currentType = this._getType(data);

if (currentType === type) return data;

if (coerce) {
return this._coerceType(data, type, strict);
} else if (strict) {
throw new Error(`Expected ${type}, got ${currentType}`);
}

return data;
});
}

// ==================== PERFORMANCE UTILITIES ====================

/**
* Memoization with TTL and size limits
*/
memo(options = {}) {
const ttl = options.ttl || 300000; // 5 minutes
const maxSize = options.maxSize || 100;
const keyGenerator = options.keyGen || JSON.stringify;

return this._chain(data => {


const key = keyGenerator(data);
const cached = this.cached.get(key);

if (cached && Date.now() - cached.timestamp < ttl) {


return cached.value;
}

// Clean cache if too large


if (this.cached.size >= maxSize) {
this._cleanCache();
}

this.cached.set(key, {
value: data,
timestamp: Date.now()
});

return data;
});
}

/**
* Batch processing with progress tracking
*/
batch(processor, options = {}) {
const size = options.size || 10;
const delay = options.delay || 0;
const onProgress = options.onProgress || (() => {});

return this._chain(async data => {


const results = [];
const batches = this._createBatches(data, size);

for (let i = 0; i < batches.length; i++) {


const batch = batches[i];
const batchResult = await processor(batch, i);
results.push(...batchResult);

onProgress({
completed: i + 1,
total: batches.length,
progress: ((i + 1) / batches.length) * 100
});

if (delay > 0 && i < batches.length - 1) {


await this._sleep(delay);
}
}

return results;
});
}

// ==================== CHAIN OPERATIONS ====================

/**
* Conditional execution
*/
when(condition, trueFn, falseFn = null) {
return this._chain(data => {
const shouldExecute = typeof condition === 'function'
? condition(data)
: condition;

if (shouldExecute) {
return trueFn ? trueFn(data) : data;
} else {
return falseFn ? falseFn(data) : data;
}
});
}

/**
* Try-catch with fallback
*/
attempt(fn, fallback = null) {
return this._chain(async data => {
try {
return await fn(data);
} catch (error) {
if (fallback) {
return typeof fallback === 'function' ? fallback(error,
data) : fallback;
}
throw error;
}
});
}

/**
* Tap for side effects without changing data
*/
tap(fn) {
return this._chain(async data => {
await fn(data);
return data;
});
}

/**
* Execute and return final result
*/
async execute() {
let result = this.data;

for (const operation of this.operations) {


result = await operation(result);
}

return result;
}

/**
* Get result synchronously (for non-async operations)
*/
value() {
let result = this.data;

for (const operation of this.operations) {


result = operation(result);
}

return result;
}

// ==================== PRIVATE METHODS ====================

_chain(operation) {
const newChain = new ChainFlow(this.data);
newChain.operations = [...this.operations, operation];
newChain.cached = this.cached;
return newChain;
}

_smartFilter(data, query) {
if (!Array.isArray(data)) return data;

return data.filter(item => {


if (typeof item === 'string') {
return this._fuzzyMatch(item, query) > 0.3;
} else if (typeof item === 'object') {
return Object.values(item).some(value =>
String(value).toLowerCase().includes(query.toLowerCase())
);
}
return false;
});
}

_objectFilter(data, conditions) {
if (!Array.isArray(data)) return data;

return data.filter(item => {


return Object.entries(conditions).every(([key, value]) => {
const itemValue = this._getNestedValue(item, key);
if (typeof value === 'object' && value.operator) {
return this._applyOperator(itemValue, value.operator,
value.value);
}
return itemValue === value;
});
});
}

_smartCompare(a, b, key) {
const aVal = this._getNestedValue(a, key);
const bVal = this._getNestedValue(b, key);

if (typeof aVal === 'number' && typeof bVal === 'number') {


return aVal - bVal;
}

return String(aVal).localeCompare(String(bVal));
}

_multiSort(a, b, criteria) {
for (const criterion of criteria) {
let comparison = 0;
const { key, order = 'asc' } = typeof criterion === 'string'
? { key: criterion, order: 'asc' }
: criterion;

const aVal = this._getNestedValue(a, key);


const bVal = this._getNestedValue(b, key);

if (typeof aVal === 'number' && typeof bVal === 'number') {


comparison = aVal - bVal;
} else {
comparison = String(aVal).localeCompare(String(bVal));
}

if (comparison !== 0) {
return order === 'desc' ? -comparison : comparison;
}
}
return 0;
}

async _concurrentMap(data, transformer, batchSize, errorHandler) {


const results = [];
const batches = this._createBatches(data, batchSize);

for (const batch of batches) {


const promises = batch.map(async (item, index) => {
try {
return await transformer(item, index);
} catch (error) {
errorHandler(error, item, index);
return null;
}
});

const batchResults = await Promise.all(promises);


results.push(...batchResults);
}

return results;
}

async _sequentialMap(data, transformer, errorHandler) {


const results = [];

for (let i = 0; i < data.length; i++) {


try {
const result = await transformer(data[i], i);
results.push(result);
} catch (error) {
errorHandler(error, data[i], i);
results.push(null);
}
}

return results;
}

_parallelReduce(data, reducer, initialValue, chunks) {


const chunkSize = Math.ceil(data.length / chunks);
const promises = [];

for (let i = 0; i < chunks; i++) {


const start = i * chunkSize;
const end = Math.min(start + chunkSize, data.length);
const chunk = data.slice(start, end);

promises.push(
Promise.resolve(chunk.reduce(reducer, initialValue))
);
}

return Promise.all(promises).then(results =>


results.reduce(reducer, initialValue)
);
}

_fuzzySearch(data, query, key, threshold) {


const results = data
.map(item => {
const searchText = key ? this._getNestedValue(item, key) :
item;
const score = this._fuzzyMatch(String(searchText), query);
return { item, score };
})
.filter(result => result.score >= threshold)
.sort((a, b) => b.score - a.score)
.map(result => result.item);

return results;
}

_fuzzyMatch(text, pattern) {
const textLower = text.toLowerCase();
const patternLower = pattern.toLowerCase();

let score = 0;
let textIndex = 0;

for (let i = 0; i < patternLower.length; i++) {


const char = patternLower[i];
const foundIndex = textLower.indexOf(char, textIndex);

if (foundIndex === -1) {


score -= 1;
} else {
score += 1;
if (foundIndex === textIndex) {
score += 1; // Bonus for consecutive matches
}
textIndex = foundIndex + 1;
}
}

return Math.max(0, score / Math.max(text.length, pattern.length));


}

_deepMerge(objects, strategy) {
const result = {};
objects.forEach(obj => {
Object.keys(obj).forEach(key => {
if (result[key] === undefined) {
result[key] = obj[key];
} else if (this._isObject(result[key]) &&
this._isObject(obj[key])) {
result[key] = this._deepMerge([result[key], obj[key]],
strategy);
} else {
switch (strategy) {
case 'concat':
if (Array.isArray(result[key]) &&
Array.isArray(obj[key])) {
result[key] = [...result[key], ...obj[key]];
} else {
result[key] = obj[key];
}
break;
case 'merge':
result[key] = [result[key], obj[key]];
break;
default: // overwrite
result[key] = obj[key];
}
}
});
});

return result;
}

_getNestedValue(obj, path, defaultValue = undefined) {


const keys = path.split('.');
let current = obj;

for (const key of keys) {


if (current == null || typeof current !== 'object') {
return defaultValue;
}
current = current[key];
}

return current !== undefined ? current : defaultValue;


}

_setNestedValue(obj, path, value) {


const keys = path.split('.');
let current = obj;

for (let i = 0; i < keys.length - 1; i++) {


const key = keys[i];
if (!(key in current) || typeof current[key] !== 'object') {
current[key] = {};
}
current = current[key];
}

current[keys[keys.length - 1]] = value;


}

_calculateDelay(baseDelay, attempt, backoff) {


switch (backoff) {
case 'exponential':
return baseDelay * Math.pow(2, attempt - 1);
case 'linear':
return baseDelay * attempt;
case 'fixed':
default:
return baseDelay;
}
}

_sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

_createBatches(array, size) {
const batches = [];
for (let i = 0; i < array.length; i += size) {
batches.push(array.slice(i, i + size));
}
return batches;
}

_isObject(value) {
return value !== null && typeof value === 'object' && !
Array.isArray(value);
}

_getType(value) {
if (value === null) return 'null';
if (Array.isArray(value)) return 'array';
return typeof value;
}

_cleanCache() {
const entries = Array.from(this.cached.entries());
entries.sort((a, b) => a[1].timestamp - b[1].timestamp);

// Remove oldest 25%


const toRemove = Math.ceil(entries.length * 0.25);
for (let i = 0; i < toRemove; i++) {
this.cached.delete(entries[i][0]);
}
}
}

// Static factory methods


ChainFlow.from = (data) => new ChainFlow(data);
ChainFlow.range = (start, end, step = 1) => {
const array = [];
for (let i = start; i < end; i += step) {
array.push(i);
}
return new ChainFlow(array);
};
ChainFlow.empty = () => new ChainFlow([]);
ChainFlow.of = (...items) => new ChainFlow(items);

// Utility shortcuts
const $ = ChainFlow.from;
$.range = ChainFlow.range;
$.empty = ChainFlow.empty;
$.of = ChainFlow.of;

// Export
if (typeof module !== 'undefined' && module.exports) {
module.exports = { ChainFlow, $ };
} else if (typeof define === 'function' && define.amd) {
define([], () => ({ ChainFlow, $ }));
} else {
global.ChainFlow = ChainFlow;
global.$ = ChainFlow.from;
global.CF = ChainFlow.from; // alias tambahan

})(typeof window !== 'undefined' ? window : this);

You might also like