UNPKG

remeda

Version:

A utility library for JavaScript and Typescript.

1 lines 5.02 kB
{"version":3,"file":"clone.cjs","names":["purry","copiedValue: Record<PropertyKey, unknown>","copiedValue: Array<unknown>"],"sources":["../src/clone.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types --\n * The state needed to compute the clone is passed by reference via mutable\n * arrays.\n */\n\nimport { purry } from \"./purry\";\n\n/**\n * Creates a deep copy of the value. Supported types: [plain objects](#isPlainObject),\n * `Array`, `number`, `string`, `boolean`, `Date`, and `RegExp`. Functions are\n * assigned by reference rather than copied. Class instances or any other\n * built-in type that isn't mentioned above are not supported (but might\n * work).\n *\n * @param data - The object to clone.\n * @signature\n * R.clone(data)\n * @example\n * R.clone({foo: 'bar'}) // {foo: 'bar'}\n * @dataFirst\n * @category Object\n */\nexport function clone<T>(data: T): T;\n\n/**\n * Creates a deep copy of the value. Supported types: [plain objects](#isPlainObject),\n * `Array`, `number`, `string`, `boolean`, `Date`, and `RegExp`. Functions are\n * assigned by reference rather than copied. Class instances or any other\n * built-in type that isn't mentioned above are not supported (but might\n * work).\n *\n * @signature\n * R.clone()(data)\n * @example\n * R.pipe({foo: 'bar'}, R.clone()) // {foo: 'bar'}\n * @dataLast\n * @category Object\n */\nexport function clone(): <T>(data: T) => T;\n\nexport function clone(...args: ReadonlyArray<unknown>): unknown {\n return purry(cloneImplementation, args);\n}\n\nfunction cloneImplementation<T>(\n value: T,\n refFrom: Array<unknown> = [],\n refTo: Array<unknown> = [],\n): T {\n if (typeof value === \"function\") {\n // Functions aren't cloned, we return the same instance.\n return value;\n }\n\n if (typeof value !== \"object\" || value === null) {\n // Only objects are interesting when cloning, everything else can use\n // whatever JS does by default.\n return structuredClone(value);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const prototype = Object.getPrototypeOf(value);\n if (\n !Array.isArray(value) &&\n // Keep this check in sync with the same check in the impl of\n // `isPlainObject`.\n prototype !== null &&\n prototype !== Object.prototype\n ) {\n // Our cloning logic is only designed for plain objects and arrays; other\n // object types (like `Date`, `RegExp`, `File`, and user-defined classes)\n // wouldn't clone properly. We fallback to the native cloning for them.\n return structuredClone(value);\n }\n\n // In order to support cyclic/self-referential structures, and to support\n // functions _within_ objects, we need to have our own cloning logic.\n\n // First we check if we've already cloned this value.\n const idx = refFrom.indexOf(value);\n if (idx !== -1) {\n return refTo[idx] as T;\n }\n // And if we haven't, we add it to our list of seen values so that it is kept\n // and clone the deep structure.\n refFrom.push(value);\n return Array.isArray(value)\n ? deepCloneArray(value, refFrom, refTo)\n : deepCloneObject(value, refFrom, refTo);\n}\n\nfunction deepCloneObject<T extends object>(\n value: T,\n refFrom: Array<unknown>,\n refTo: Array<unknown>,\n): T {\n const copiedValue: Record<PropertyKey, unknown> = {};\n\n // It's important to first push the cloned ref so that it's index is kept in\n // sync with the ref to the original value in refFrom.\n refTo.push(copiedValue);\n\n for (const [k, v] of Object.entries(value)) {\n copiedValue[k] = cloneImplementation(v, refFrom, refTo);\n }\n\n return copiedValue as T;\n}\n\nfunction deepCloneArray<T extends ReadonlyArray<unknown>>(\n value: T,\n refFrom: Array<unknown>,\n refTo: Array<unknown>,\n): T {\n const copiedValue: Array<unknown> = [];\n\n // It's important to first push the cloned ref so that it's index is kept in\n // sync with the ref to the original value in refFrom.\n refTo.push(copiedValue);\n\n for (const [index, item] of value.entries()) {\n copiedValue[index] = cloneImplementation(item, refFrom, refTo);\n }\n\n return copiedValue as unknown as T;\n}\n"],"mappings":"wCAwCA,SAAgB,EAAM,GAAG,EAAuC,CAC9D,OAAOA,EAAAA,EAAM,EAAqB,EAAK,CAGzC,SAAS,EACP,EACA,EAA0B,EAAE,CAC5B,EAAwB,EAAE,CACvB,CACH,GAAI,OAAO,GAAU,WAEnB,OAAO,EAGT,GAAI,OAAO,GAAU,WAAY,EAG/B,OAAO,gBAAgB,EAAM,CAI/B,IAAM,EAAY,OAAO,eAAe,EAAM,CAC9C,GACE,CAAC,MAAM,QAAQ,EAAM,EAGrB,IAAc,MACd,IAAc,OAAO,UAKrB,OAAO,gBAAgB,EAAM,CAO/B,IAAM,EAAM,EAAQ,QAAQ,EAAM,CAOlC,OANI,IAAQ,IAKZ,EAAQ,KAAK,EAAM,CACZ,MAAM,QAAQ,EAAM,CACvB,EAAe,EAAO,EAAS,EAAM,CACrC,EAAgB,EAAO,EAAS,EAAM,EAPjC,EAAM,GAUjB,SAAS,EACP,EACA,EACA,EACG,CACH,IAAMC,EAA4C,EAAE,CAIpD,EAAM,KAAK,EAAY,CAEvB,IAAK,GAAM,CAAC,EAAG,KAAM,OAAO,QAAQ,EAAM,CACxC,EAAY,GAAK,EAAoB,EAAG,EAAS,EAAM,CAGzD,OAAO,EAGT,SAAS,EACP,EACA,EACA,EACG,CACH,IAAMC,EAA8B,EAAE,CAItC,EAAM,KAAK,EAAY,CAEvB,IAAK,GAAM,CAAC,EAAO,KAAS,EAAM,SAAS,CACzC,EAAY,GAAS,EAAoB,EAAM,EAAS,EAAM,CAGhE,OAAO"}