Code Monkey home page Code Monkey logo

jhildenbiddle / mergician Goto Github PK

View Code? Open in Web Editor NEW
65.0 2.0 3.0 934 KB

Uniquely flexible and light-weight utility for cloning and deep (recursive) merging of JavaScript objects. Supports descriptor values, accessor functions, and custom prototypes. Provides advanced options for customizing the clone/merge process.

Home Page: https://jhildenbiddle.github.io/mergician/

License: MIT License

JavaScript 99.62% TypeScript 0.38%
array clone deep extend filter immutable merge object recursive accessor

mergician's Introduction

Mergician

NPM GitHub Workflow Status (main) Codacy code quality License: MIT jsDelivr Sponsor this project

Mergician is a uniquely flexible and light-weight utility for cloning and deep (recursive) merging of JavaScript objects.

Unlike native methods and other utilities, Mergician faithfully clones and merges objects by properly handling descriptor values, accessor functions, and prototype properties while offering advanced options for customizing the clone/merge process.

Features

  • Deep (recursive) clone/merge JavaScript objects
  • Generates new object without modifying source object(s)
  • Clone/merge enumerable and non-enumerable properties
  • Clone/merge property descriptor values
  • Retain, skip, or convert accessor functions to static values
  • Inspect, filter, and modify properties
  • Merge, skip, or hoist prototype properties
  • Merge or skip key intersections, unions, and differences
  • Merge, sort, and remove duplicate array items
  • IntelliSense / code hinting support
  • TypeScript support
  • Lightweight (2k min+gzip) and dependency-free

Platform Support

Node 10+
Chrome 61+
Edge 16+
Firefox 60+
Safari 10.1+

Examples

Basic object cloning using default options:

// ES module shown. CommonJS module also available (see below).
import { mergician } from 'mergician';

const obj1 = { a: [1, 1], b: { c: 1, d: 1 } };
const clonedObj = mergician({}, obj1);

// Results
console.log(clonedObj); // { a: [1, 1], b: { c: 1, d: 1 } }
console.log(clonedObj === obj1); // false
console.log(clonedObj.a === obj1.a); // false
console.log(clonedObj.b === obj1.b); // false

Advanced object merging using custom options:

// ES module shown. CommonJS module also available (see below).
import { mergician } from 'mergician';

const obj1 = { a: [1, 1], b: { c: 1, d: 1 } };
const obj2 = { a: [2, 2], b: { c: 2 } };
const obj3 = { e: 3 };

const mergedObj = mergician({
  skipKeys: ['d'],
  appendArrays: true,
  dedupArrays: true,
  filter({ depth, key, srcObj, srcVal, targetObj, targetVal }) {
    if (key === 'e') {
      targetObj['hello'] = 'world';
      return false;
    }
  }
})(obj1, obj2, obj3);

// Result
console.log(mergedObj); // { a: [1, 2], b: { c: 2 }, hello: 'world' }

Installation

NPM

npm install mergician
// ES module
import { mergician } from 'mergician';
// CommonJS module
const { mergician } = require('mergician');

CDN

Available on jsdelivr (below), unpkg, and other CDN services that auto-publish npm packages.

πŸ’‘ Note the @ version lock in the URLs below. This prevents breaking changes in future releases from affecting your project and is therefore the safest method of loading dependencies from a CDN. When a new major version is released, you will need to manually update your CDN URLs by changing the version after the @ symbol.

// ES module @ latest v2.x.x
import { mergician } from 'https://cdn.jsdelivr.net/npm/mergician@2';

Usage & Options

See the documentation site for details.

Sponsorship

A sponsorship is more than just a way to show appreciation for the open-source authors and projects we rely on; it can be the spark that ignites the next big idea, the inspiration to create something new, and the motivation to share so that others may benefit.

If you benefit from this project, please consider lending your support and encouraging future efforts by becoming a sponsor.

Thank you! πŸ™πŸ»

Contact & Support

  • Follow πŸ‘¨πŸ»β€πŸ’» @jhildenbiddle on Twitter and GitHub for announcements
  • Create a πŸ’¬ GitHub issue for bug reports, feature requests, or questions
  • Add a ⭐️ star on GitHub and 🐦 tweet to promote the project
  • Become a πŸ’– sponsor to support the project and future efforts

License

This project is licensed under the MIT license.

Copyright (c) John Hildenbiddle (@jhildenbiddle)

mergician's People

Contributors

boylett avatar jhildenbiddle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

mergician's Issues

Mergician Does Not Maintain All Properties

When merging two objects, the original data is not always included in the resultant object.

Consider the following example:

import mergician from 'mergician';

// See attached files for const values
import { input, translation } from './data.js';

const main = () => {
  // See attached file for what this looks like
  const result = mergician(input, translation);
  // This always exists
  console.log(input.events[0].decisions);
  // This SHOULD exist, but doesn't
  console.log(result.events[0].decisions);
};

main();

data.js.input.json
data.js.translation.json
data.js.result.json

Basically, input + translation = result, but result is missing events[0].decisions that is found in input. This is also true for lands.shire.population, lands.shire.isFrodoHome, lands.rivendell.isSafeHaven, lands.rivendell.architecture.age, villians.saruman.powerLevel, and villians.sauron.powerLevel – essentially every case where the original value has an object with a property that doesn't have the merged value with the corresponding object doesn't have that property.

TypeScript support

Cool work.

Please add support for TypeScript.
I'm using the following as a work-around:

declare module 'mergician' {

    type ObjectLiteral = Record<any, any>

    export interface MergicianOptions {

        // ----
        // Keys
        // ----

        /**
         * Exclusive array of keys to be merged (others are skipped).
         */
        onlyKeys?: string[];

        /**
         * Array of keys to skip (others are merged).
         */
        skipKeys?: string[];

        /**
         * Merge only keys found in multiple objects (ignore single occurrence keys).
         */
        onlyCommonKeys?: boolean;

        /**
         * Merge only keys found in all objects
         */
        onlyUniversalKeys?: boolean;

        /**
         * Skip keys found in multiple objects (merge only single
         *     occurrence keys)
         */
        skipCommonKeys?: boolean;

        /**
         * Skip keys found in all objects (merge only common keys)
         */
        skipUniversalKeys?: boolean;

        // ------
        // Arrays
        // ------

        /**
         * Merge array values at the end of existing arrays
         */
        appendArrays?: boolean;

        /**
         * Merge array values at the beginning of existing arrays
         */
        prependArrays?: boolean;

        /**
         * Remove duplicate array values in new merged object
         */
        dedupArrays?: boolean;

        /**
         * Sort array values in new merged object
         */
        sortArrays?: boolean;

        // ---------
        // Callbacks
        // ---------

        /**
         * Callback used for inspecting/modifying properties before merge.
         * Return value is used as value to merge.
         */
        beforeEach?(options: { depth: number, key: string, srcObj: ObjectLiteral, srcVal: any, targetObj: ObjectLiteral, targetVal: any }): any | undefined;

        /**
         * Callback used to conditionally merge or skip a property.
         * Return "true" to merge or "false" to skip.
         * Return no value to proceed according to other option values.
         */
        filter?(options: { depth: number, key: string, srcObj: ObjectLiteral, srcVal: any, targetObj: ObjectLiteral, targetVal: any }): boolean;

        /**
         * Callback used for inspecting/modifying properties after merge.
         * Return value is used as merged value.
         */
        afterEach?<M>(options: { depth: number, key: string, mergeVal: M, srcObj: ObjectLiteral, targetObj: ObjectLiteral }): any | undefined;
    }

    /**
     * Deep recursive object merging with options to inspect, modify, and filter
     * keys/values, merge arrays (append/prepend), and remove duplicate values from
     * merged arrays. Returns new object without modifying sources (immutable).
     *
     * @preserve
     *
     * @example
     * const obj1 = { a: 1 };
     * const obj2 = { b: [2, 2], c: { d: 2 } };
     * const obj3 = { b: [3, 3], c: { e: 3 } };
     *
     * const mergedObj = mergician({
     *     appendArrays: true,
     *     dedupArrays: true
     * })(obj1, obj2, obj3);
     *
     * console.log(mergedObj); // { a: 1, b: [2, 3], c: { d: 2, e: 3 } }
     *
     * @param options
     */
    export default function mergician<T extends ObjectLiteral>(options: MergicianOptions): (...objects: ObjectLiteral[]) => T;

    /**
     * Deep recursive object merging with options to inspect, modify, and filter
     * keys/values, merge arrays (append/prepend), and remove duplicate values from
     * merged arrays. Returns new object without modifying sources (immutable).
     *
     * @preserve
     *
     * @example
     * const obj1 = { a: 1 };
     * const obj2 = { b: [2, 2], c: { d: 2 } };
     * const obj3 = { b: [3, 3], c: { e: 3 } };
     *
     * const customMerge = mergician({
     *     appendArrays: true,
     *     dedupArrays: true
     * });
     * const clonedObj = customMerge({}, obj2);
     * const mergedObj = customMerge(obj1, obj2, obj3);
     *
     * console.log(clonedObj);  // { b: [2], c: { d: 2 } }
     * console.log(mergedObj);  // { a: 1, b: [2, 3], c: { d: 2, e: 3 } }
     * @param options
     */
    export default function mergician<T extends ObjectLiteral>(options: MergicianOptions): (options: MergicianOptions) => (...objects: ObjectLiteral[]) => T;

    /**
     * Deep recursive object merging with options to inspect, modify, and filter
     * keys/values, merge arrays (append/prepend), and remove duplicate values from
     * merged arrays. Returns new object without modifying sources (immutable).
     *
     * @preserve
     *
     * @example
     * const obj1 = { a: 1 };
     * const obj2 = { b: [2, 2], c: { d: 2 } };
     * const obj3 = { b: [3, 3], c: { e: 3 } };
     *
     * const clonedObj = mergician({}, obj1);
     * const mergedObj = mergician(obj1, obj2, obj3);
     *
     * console.log(clonedObj);              // { a: 1 }
     * console.log(clonedObj === obj1);     // false
     * console.log(mergedObj);              // { a: 1, b: [3, 3], c: { d: 2, e: 3 } }
     *
     * @param {...object} [objects] - Objects to merge
     * @returns {object} New merged object
     */
    export default function mergician<T extends ObjectLiteral>(...objects: ObjectLiteral[]): T;
}

merge Date object

const obj1 = { date1: new Date() };
const obj2 = merge(obj1, { date2: new Date() });

console.log(obj1.date1.toISOString());
console.log(obj2.date1.toISOString()); // not working
console.log(obj2.date2.toISOString()); // not working

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.