Skip to content

Commit

Permalink
add formal support for primitive wrappers
Browse files Browse the repository at this point in the history
  • Loading branch information
planttheidea committed Oct 2, 2022
1 parent 7317d65 commit faeeb45
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
**Enhancements**

- Can now create a custom copier, allowing maximum performance for specific use-cases
- Correctly handle primitive wrappers, e.g. `new String('foo')`

## 2.1.7

Expand Down
3 changes: 3 additions & 0 deletions DEV_ONLY/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const object: PlainObject = {
arrayBuffer: new ArrayBuffer(8),
blob: new Blob(['<a id="a">hey!</a>'], { type: 'text/html' }),
boolean: true,
booleanConstructor: new Boolean(true),
customPrototype: Object.create({
method() {
return 'foo';
Expand Down Expand Up @@ -56,6 +57,7 @@ const object: PlainObject = {
nan: NaN,
nil: null,
number: 123,
numberConstructor: new Number('123'),
object: { foo: { bar: 'baz' } },
promise: Promise.resolve('foo'),
react: React.createElement('main', {
Expand Down Expand Up @@ -83,6 +85,7 @@ const object: PlainObject = {
regexp: /foo/gi,
set: new Set().add('foo').add({ bar: 'baz' }),
string: 'foo',
stringConstructor: new String('foo'),
symbol: Symbol('foo'),
typedArray: new Uint8Array([12, 15]),
undef: undefined,
Expand Down
24 changes: 24 additions & 0 deletions __tests__/copier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,30 @@ describe('copyMapStrict', () => {
});
});

describe('copyPrimitiveWrapper', () => {
it('will create a copy of the value of the primitive in a new wrapper', () => {
const boolean = new Boolean(true);
const number = new Number('123');
const string = new String('foo');

[boolean, number, string].forEach((primitiveWrapper) => {
const mockCopier = jest.fn().mockImplementation((arg) => arg);
const cache = createCache();
const prototype = Object.getPrototypeOf(primitiveWrapper);

const result = copier.copyPrimitiveWrapper(primitiveWrapper, {
Constructor: prototype.constructor,
cache,
copier: mockCopier,
prototype,
});

expect(result).not.toBe(primitiveWrapper);
expect(result).toEqual(primitiveWrapper);
});
});
});

describe('copySetStrict', () => {
it('will copy both values and explicit properties', () => {
const object: any = new Set(['foo', 'bar']);
Expand Down
11 changes: 11 additions & 0 deletions src/copier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,17 @@ export function copyObjectStrict<Value extends Record<string, any>>(
return copyOwnPropertiesStrict(object, clone, state);
}

/**
* Create a new primitive wrapper from the value of the original.
*/
export function copyPrimitiveWrapper<
// Specifically use the object constructor types
// eslint-disable-next-line @typescript-eslint/ban-types
Value extends Boolean | Number | String
>(primitiveObject: Value, state: State): Value {
return new state.Constructor(primitiveObject.valueOf());
}

/**
* Create a new RegExp based on the value and flags of the original.
*/
Expand Down
5 changes: 5 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
copyMapStrict,
copyObjectLoose,
copyObjectStrict,
copyPrimitiveWrapper,
copyRegExp,
copySelf,
copySetLoose,
Expand Down Expand Up @@ -66,9 +67,11 @@ function getTagSpecificCopiers(
options: Required<CreateCopierOptions>
): Record<string, InternalCopier<any>> {
return {
Arguments: options.object,
Array: options.array,
ArrayBuffer: options.arrayBuffer,
Blob: options.blob,
Boolean: copyPrimitiveWrapper,
DataView: options.dataView,
Date: options.date,
Error: options.error,
Expand All @@ -78,10 +81,12 @@ function getTagSpecificCopiers(
Int16Array: options.arrayBuffer,
Int32Array: options.arrayBuffer,
Map: options.map,
Number: copyPrimitiveWrapper,
Object: options.object,
Promise: copySelf,
RegExp: options.regExp,
Set: options.set,
String: copyPrimitiveWrapper,
WeakMap: copySelf,
WeakSet: copySelf,
Uint8Array: options.arrayBuffer,
Expand Down

0 comments on commit faeeb45

Please sign in to comment.