GithubHelp home page GithubHelp logo

hartl3y94 / clone Goto Github PK

View Code? Open in Web Editor NEW

This project forked from fossabot/clone

0.0 0.0 0.0 310 KB

Fast, deep, scalable object cloning for JavaScript

License: MIT License

JavaScript 17.79% Shell 4.20% TypeScript 78.02%

clone's Introduction

@golden-ants/clone

Node.js CI npm version FOSSA Status install size License: MIT

A new approach to deep cloning. A simple library with no external dependencies gives you the opportunity to customize the cloning strategy.

Table of Contents

Installing

Using npm:

npm install --save @golden-ants/clone

Using yarn:

yarn add @golden-ants/clone

Usage

Create an instance of the Clone class by passing switchers to it.

import { Clone, Switcher } from '@golden-ants/clone'

const switchers: Switcher[] = [
  {
    // all primitive types
    if: (value) => value === null || typeof value !== 'object',

    // just return the same value
    handler: (value) => value,
  },
  {
    // all non-primitive types
    if: (value) => value !== null && typeof value === 'object',
    then: [
      {
        if: (value) => value instanceof Array,

        // copy a nested array using the same switchers
        handler: (value, clone) => clone.it([], value as object),
      },
      {
        if: (value) => value instanceof Object,

        // copy a nested object using the same switchers
        handler: (value, clone) => clone.it({}, value as object),
      },
    ],
  },
]

export const deepClone = new Clone(switchers)

Note: The alternative is to use functional utilities

Declarative solution:

const switchers: Switcher[] = [
  {
    if: not(isObject),
    handler: (value) => value,
  },
  {
    if: isObject,
    then: [
      {
        if: instanceOf(Array),
        handler: retryFor(() => []),
      },
      {
        if: instanceOf(Object),
        handler: retryFor(() => ({})),
      },
    ],
  },
]

Calling the created deepClone for deep recursive copying of objects or arrays.

Note: The target of copying can be an array or an object, but array elements or object property keys can only be those types that meet the conditions of the switchers.

import { deepClone } from ...

// array (object) of any nesting level
const array = [1, [2], { a: [4, 5] }];

const copied = deepClone.it([], array);

Switcher

Switchers are needed to analyze the contents of objects and apply unique ways of processing values.

Each Switcher contains an if property that accepts a predicate function, the second property can be either a handler or an array of nested switches.

const switcher: Switcher[] = [
  {
    // all primitives except null
    if: (value) => typeof value !== 'object',

    /**if the condition is satisfied and the "then" property
     * is defined, the value will be passed from top to bottom
     * until the result of the comparison is true, otherwise
     * an exception will be thrown */
    then: [
      {
        if: (value) => typeof value !== 'string',
        handler: (value) => (value as string).toUpperCase(),
      },
      {
        // We repeated the upper condition to avoid an exception
        if: (value) => typeof value !== 'object',
        handler: (value) => value,
      },
    ],
  },
  /**If an array or object contains a non-primitive
   * value or null, and the corresponding switch is
   * not declared, an error will be thrown */
  //{
  //  if: (value) => typeof value === "object",
  //  handler: (value) => ...
  //}
]

Warning: If you define the then and handler properties in an Switcher, the consequences will be unpredictable

Clone

An instance of the Clone class contains a single public member - the it method.

Warning: Method arguments can only be non-null objects.

Cloning occurs superficially, a handler is applied to each property of the source, the result of which is assigned to the target. But thanks to the hook, you can call the cloning again, but for a nested object.

const clone = new Clone(...)

const target = {}
const source = { foo: "bar" }

const copied = clone.it(target, source)

copied === target // true
copied === source // false

// clone.it(317, source) // runtime error

And so the handler can cause cloning for a nested object.

...{
  if: isObject,
  /**value: object property value
   * clone: an instance of the Clone class to which these switchers will be passed*/
  handler: (value, clone) => clone.it({}, value),
}...

Functional utilities

instanceOf

Higher order function.

class MyClass {}

const isMyClass = instanceOf(MyClass)

const mc = new MyClass()

isMyClass(mc) // true

isObject

Checks whether the value is not primitive.

isObject('clone') // false
isObject(null) // false
isObject({}) // true
isObject(Object.create(null)) // true

retryFor

A higher-order function accepting a supplier.

...{
  if: (value) => value instanceof Array,
  handler: (value, clone) => clone.it([], value as object),
}...

It's clearer this way.

...{
  if: instanceOf(Array),
  handler: retryFor(() => []),
}...

not

A higher-order function, returns a function through the result will be inverted.

const isPrimitive = not(isObject)

isPrimitive(1)) //true
isPrimitive(null)) //true

Examples

Shallow copy

import { Clone, Switcher } from '@golden-ants/clone'

const switchers: Switcher[] = [
  {
    if: () => true,
    handler: (value) => value,
  },
]

const shallowCopy = new Clone(switchers)

const source = {
  foo: {
    bar: 'abc',
  },
}

const target: Record<string, unknown> = {}

shallowCopy.it(target, source)

console.log(target.foo === source.foo) // true

Deep copy

import {
  Clone,
  instanceOf,
  isObject,
  not,
  retryFor,
  Switcher,
} from '@golden-ants/clone'

const switchers: Switcher[] = [
  {
    if: not(isObject),
    handler: (value) => value,
  },
  {
    if: isObject,
    then: [
      {
        if: instanceOf(Array),
        handler: retryFor(() => []),
      },
      {
        if: instanceOf(Object),
        handler: retryFor(() => ({})),
      },
    ],
  },
]

const deepCopy = new Clone(switchers)

const source = {
  foo: {
    bar: 'abc',
  },
}

const target: Record<string, unknown> = {}

deepCopy.it(target, source)

console.log(target.foo === source.foo) // false

Custom copy

import {
  Clone,
  instanceOf,
  isObject,
  not,
  retryFor,
  Switcher,
} from '@golden-ants/clone'

class A {
  private storage: string
  constructor(storage: string) {
    this.storage = storage
  }
  clone = () => new A(this.storage + ' clone A')
  get = () => this.storage
}

const switchers: Switcher[] = [
  {
    if: not(isObject),
    handler: (value) => value,
  },
  {
    if: isObject,
    then: [
      {
        if: instanceOf(A),
        handler: (value) => (value as A).clone(),
      },
      {
        if: instanceOf(Array),
        handler: retryFor(() => []),
      },
      {
        if: instanceOf(Object),
        handler: retryFor(() => ({})),
      },
    ],
  },
]

const customCopy = new Clone(switchers)

const source = [new A('foo'), new A('bar')]

const target: A[] = []

customCopy.it(target, source)

target[0].get() // 'foo clone A'
target[1].get() // 'bar clone A'

License

FOSSA Status

clone's People

Contributors

golden-ants avatar

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.