Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions benchmarks/bundle-size/clone.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ describe('clone bundle size', () => {

it('es-toolkit', async () => {
const bundleSize = await getBundleSize('es-toolkit', 'clone');
expect(bundleSize).toMatchInlineSnapshot(`1001`);
expect(bundleSize).toMatchInlineSnapshot(`1140`);
});

it('es-toolkit/compat', async () => {
const bundleSize = await getBundleSize('es-toolkit/compat', 'clone');
expect(bundleSize).toMatchInlineSnapshot(`2527`);
expect(bundleSize).toMatchInlineSnapshot(`2625`);
});
});
4 changes: 2 additions & 2 deletions benchmarks/bundle-size/cloneDeep.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ describe('cloneDeep bundle size', () => {

it('es-toolkit', async () => {
const bundleSize = await getBundleSize('es-toolkit', 'cloneDeep');
expect(bundleSize).toMatchInlineSnapshot(`3400`);
expect(bundleSize).toMatchInlineSnapshot(`3509`);
});

it('es-toolkit/compat', async () => {
const bundleSize = await getBundleSize('es-toolkit/compat', 'cloneDeep');
expect(bundleSize).toMatchInlineSnapshot(`3840`);
expect(bundleSize).toMatchInlineSnapshot(`3949`);
});
});
2 changes: 1 addition & 1 deletion benchmarks/bundle-size/find.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ describe('find bundle size', () => {

it('es-toolkit/compat', async () => {
const bundleSize = await getBundleSize('es-toolkit/compat', 'find');
expect(bundleSize).toMatchInlineSnapshot(`9166`);
expect(bundleSize).toMatchInlineSnapshot(`9275`);
});
});
2 changes: 1 addition & 1 deletion benchmarks/bundle-size/findKey.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ describe('findKey bundle size', () => {

it('es-toolkit/compat', async () => {
const bundleSize = await getBundleSize('es-toolkit/compat', 'findKey');
expect(bundleSize).toMatchInlineSnapshot(`8579`);
expect(bundleSize).toMatchInlineSnapshot(`8688`);
});
});
2 changes: 1 addition & 1 deletion benchmarks/bundle-size/fp/pick.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ describe('fp/pick bundle size', () => {
it('es-toolkit/fp', async () => {
expect(
await getBundleSizeFromScript('import { pick } from "es-toolkit/fp"; console.log(pick)')
).toMatchInlineSnapshot(`180`);
).toMatchInlineSnapshot(`278`);
});

it('lodash/fp/pick', async () => {
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/bundle-size/mapKeys.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ describe('mapKeys bundle size', () => {

it('es-toolkit/compat', async () => {
const bundleSize = await getBundleSize('es-toolkit/compat', 'mapKeys');
expect(bundleSize).toMatchInlineSnapshot(`8592`);
expect(bundleSize).toMatchInlineSnapshot(`8701`);
});
});
4 changes: 2 additions & 2 deletions benchmarks/bundle-size/mapValues.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ describe('mapValues bundle size', () => {

it('es-toolkit', async () => {
const bundleSize = await getBundleSize('es-toolkit', 'mapValues');
expect(bundleSize).toMatchInlineSnapshot(`138`);
expect(bundleSize).toMatchInlineSnapshot(`237`);
});

it('es-toolkit/compat', async () => {
const bundleSize = await getBundleSize('es-toolkit/compat', 'mapValues');
expect(bundleSize).toMatchInlineSnapshot(`8592`);
expect(bundleSize).toMatchInlineSnapshot(`8800`);
});
});
2 changes: 1 addition & 1 deletion benchmarks/bundle-size/merge.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ describe('merge bundle size', () => {

it('es-toolkit/compat', async () => {
const bundleSize = await getBundleSize('es-toolkit/compat', 'merge');
expect(bundleSize).toMatchInlineSnapshot(`6381`);
expect(bundleSize).toMatchInlineSnapshot(`6629`);
});
});
2 changes: 1 addition & 1 deletion benchmarks/bundle-size/mergeWith.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ describe('mergeWith bundle size', () => {

it('es-toolkit/compat', async () => {
const bundleSize = await getBundleSize('es-toolkit/compat', 'mergeWith');
expect(bundleSize).toMatchInlineSnapshot(`6325`);
expect(bundleSize).toMatchInlineSnapshot(`6573`);
});
});
2 changes: 1 addition & 1 deletion benchmarks/bundle-size/omit.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ describe('omit bundle size', () => {

it('es-toolkit/compat', async () => {
const bundleSize = await getBundleSize('es-toolkit/compat', 'omit');
expect(bundleSize).toMatchInlineSnapshot(`8877`);
expect(bundleSize).toMatchInlineSnapshot(`9183`);
});
});
2 changes: 1 addition & 1 deletion benchmarks/bundle-size/zipObject.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ describe('zipObject bundle size', () => {

it('es-toolkit/compat', async () => {
const bundleSize = await getBundleSize('es-toolkit/compat', 'zipObject');
expect(bundleSize).toMatchInlineSnapshot(`281`);
expect(bundleSize).toMatchInlineSnapshot(`376`);
});
});
2 changes: 1 addition & 1 deletion benchmarks/bundle-size/zipObjectDeep.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ describe('zipObjectDeep bundle size', () => {

it('es-toolkit/compat', async () => {
const bundleSize = await getBundleSize('es-toolkit/compat', 'zipObjectDeep');
expect(bundleSize).toMatchInlineSnapshot(`3431`);
expect(bundleSize).toMatchInlineSnapshot(`3526`);
});
});
19 changes: 19 additions & 0 deletions src/compat/_internal/assignValue.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { describe, expect, it } from 'vitest';
import { assignValue } from './assignValue';

describe('assignValue', () => {
it('should assign a value to an object', () => {
const object: Record<string, any> = {};

Check warning on line 6 in src/compat/_internal/assignValue.spec.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
assignValue(object, 'a', 1);
expect(object.a).toBe(1);
});

it('should preserve own __proto__ property and not set as prototype', () => {
const object: Record<string, any> = {};

Check warning on line 12 in src/compat/_internal/assignValue.spec.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
assignValue(object, '__proto__', { isAdmin: true });

expect(Object.hasOwn(object, '__proto__')).toBe(true);
expect(Object.getPrototypeOf(object)).toBe(Object.prototype);
expect((object as any).isAdmin).toBeUndefined();

Check warning on line 17 in src/compat/_internal/assignValue.spec.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
});
});
11 changes: 10 additions & 1 deletion src/compat/_internal/assignValue.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import { eq } from '../util/eq.ts';

export const assignValue = (object: any, key: PropertyKey, value: any): void => {

Check warning on line 3 in src/compat/_internal/assignValue.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

Check warning on line 3 in src/compat/_internal/assignValue.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
const objValue = object[key];
if (!(Object.hasOwn(object, key) && eq(objValue, value)) || (value === undefined && !(key in object))) {
object[key] = value;
if (key === '__proto__') {
Object.defineProperty(object, key, {
configurable: true,
enumerable: true,
value,
writable: true,
});
} else {
object[key] = value;
}
}
};
9 changes: 9 additions & 0 deletions src/compat/object/assign.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,13 @@
const result = assign({}, ...values);
expect(result).toEqual({ workId: undefined, exerciseId: '1' });
});

it('should preserve own __proto__ property and not set as prototype', () => {
const parsed = JSON.parse('{"__proto__": {"isAdmin": true}, "x": 1}');
const result = assign({}, parsed);

expect(Object.hasOwn(result, '__proto__')).toBe(true);
expect(Object.getPrototypeOf(result)).toBe(Object.prototype);
expect((result as any).isAdmin).toBeUndefined();

Check warning on line 121 in src/compat/object/assign.spec.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
});
});
11 changes: 10 additions & 1 deletion src/compat/object/assign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
* const result = assign(target, { b: 2 }, { c: 3 }, { d: 4 });
* // => { a: 1, b: 2, c: 3, d: 4 }
*/
export function assign(object: any, ...otherArgs: any[]): any;

Check warning on line 116 in src/compat/object/assign.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

Check warning on line 116 in src/compat/object/assign.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

Check warning on line 116 in src/compat/object/assign.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

/**
* Assigns properties from multiple source objects to a target object.
Expand All @@ -131,7 +131,7 @@
* const result = assign(target, { b: 2 }, { c: 3 });
* console.log(result); // Output: { a: 1, b: 2, c: 3 }
*/
export function assign(object: any, ...sources: any[]): any {

Check warning on line 134 in src/compat/object/assign.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
for (let i = 0; i < sources.length; i++) {
assignImpl(object, sources[i]);
}
Expand All @@ -145,7 +145,16 @@
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (!(key in object) || !eq(object[key], source[key])) {
object[key] = source[key];
if (key === '__proto__') {
Object.defineProperty(object, key, {
configurable: true,
enumerable: true,
value: source[key],
writable: true,
});
} else {
object[key] = source[key];
}
}
}
}
9 changes: 9 additions & 0 deletions src/compat/object/assignIn.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,13 @@ describe('assignIn', () => {
const result = assignIn({}, ...values);
expect(result).toEqual({ workId: undefined, exerciseId: '1' });
});

it('should preserve own __proto__ property and not set as prototype', () => {
const parsed = JSON.parse('{"__proto__": {"isAdmin": true}, "x": 1}');
const result = assignIn({}, parsed);

expect(Object.hasOwn(result, '__proto__')).toBe(true);
expect(Object.getPrototypeOf(result)).toBe(Object.prototype);
expect((result as any).isAdmin).toBeUndefined();
});
});
11 changes: 10 additions & 1 deletion src/compat/object/assignIn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,16 @@ function assignInImpl(object: any, source: any): any {
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (!(key in object) || !eq(object[key], source[key])) {
object[key] = source[key];
if (key === '__proto__') {
Object.defineProperty(object, key, {
configurable: true,
enumerable: true,
value: source[key],
writable: true,
});
} else {
object[key] = source[key];
}
}
}
}
9 changes: 9 additions & 0 deletions src/compat/object/assignInWith.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,13 @@ describe('assignInWith', () => {
const result = assignInWith(target, source);
expect(result).toEqual({ a: 1, b: 2 });
});

it('should preserve own __proto__ property and not set as prototype', () => {
const parsed = JSON.parse('{"__proto__": {"isAdmin": true}, "x": 1}');
const result = assignInWith({}, parsed);

expect(Object.hasOwn(result as any, '__proto__')).toBe(true);
expect(Object.getPrototypeOf(result)).toBe(Object.prototype);
expect((result as any).isAdmin).toBeUndefined();
});
});
11 changes: 10 additions & 1 deletion src/compat/object/assignInWith.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,16 @@ function assignInWithImpl(
const newValue = getValueToAssign?.(objValue, srcValue, key, object, source) ?? srcValue;

if (!(key in object) || !eq(objValue, newValue)) {
object[key] = newValue;
if (key === '__proto__') {
Object.defineProperty(object, key, {
configurable: true,
enumerable: true,
value: newValue,
writable: true,
});
} else {
object[key] = newValue;
}
}
}
}
9 changes: 9 additions & 0 deletions src/compat/object/assignWith.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,13 @@ describe('assignWith', () => {
const result = assignWith(target, source);
expect(result).toEqual({ a: 1, b: 2 });
});

it('should preserve own __proto__ property and not set as prototype', () => {
const parsed = JSON.parse('{"__proto__": {"isAdmin": true}, "x": 1}');
const result = assignWith({}, parsed);

expect(Object.hasOwn(result as any, '__proto__')).toBe(true);
expect(Object.getPrototypeOf(result)).toBe(Object.prototype);
expect((result as any).isAdmin).toBeUndefined();
});
});
11 changes: 10 additions & 1 deletion src/compat/object/assignWith.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,16 @@ function assignWithImpl(
const newValue = getValueToAssign?.(objValue, srcValue, key, object, source) ?? srcValue;

if (!(key in object) || !eq(objValue, newValue)) {
object[key] = newValue;
if (key === '__proto__') {
Object.defineProperty(object, key, {
configurable: true,
enumerable: true,
value: newValue,
writable: true,
});
} else {
object[key] = newValue;
}
}
}
}
9 changes: 9 additions & 0 deletions src/compat/object/clone.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,4 +546,13 @@ describe('clone', () => {
expect(clone(value)).toEqual({});
});
});

it('should preserve own __proto__ property and not set as prototype', () => {
const parsed = JSON.parse('{"__proto__": {"isAdmin": true}, "x": 1}');
const cloned = clone(parsed);

expect(Object.hasOwn(cloned, '__proto__')).toBe(true);
expect(Object.getPrototypeOf(cloned)).toBe(Object.prototype);
expect((cloned as any).isAdmin).toBeUndefined();
});
});
11 changes: 10 additions & 1 deletion src/compat/object/clone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,16 @@ function isCloneableObject(object: any): boolean {
function copyOwnProperties(target: any, source: any): void {
for (const key in source) {
if (Object.hasOwn(source, key)) {
target[key] = source[key];
if (key === '__proto__') {
Object.defineProperty(target, key, {
configurable: true,
enumerable: true,
value: source[key],
writable: true,
});
} else {
target[key] = source[key];
}
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/compat/object/cloneDeep.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,13 @@ describe('cloneDeep', () => {

expect(actual).toEqual(expected);
});

it('should preserve own __proto__ property and not set as prototype', () => {
const parsed = JSON.parse('{"__proto__": {"isAdmin": true}, "x": 1}');
const cloned = cloneDeep(parsed);

expect(Object.hasOwn(cloned, '__proto__')).toBe(true);
expect(Object.getPrototypeOf(cloned)).toBe(Object.prototype);
expect((cloned as any).isAdmin).toBeUndefined();
});
});
9 changes: 9 additions & 0 deletions src/compat/object/mapValues.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,13 @@ describe('mapValues', () => {
it('should return empty object when object is undefined', () => {
expect(mapValues(undefined)).toEqual({});
});

it('should preserve own __proto__ property and not set as prototype', () => {
const parsed = JSON.parse('{"__proto__": {"isAdmin": true}, "x": 1}');
const result = mapValues(parsed, v => v);

expect(Object.hasOwn(result, '__proto__')).toBe(true);
expect(Object.getPrototypeOf(result)).toBe(Object.prototype);
expect((result as any).isAdmin).toBeUndefined();
});
});
9 changes: 9 additions & 0 deletions src/compat/object/omit.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,13 @@ describe('omit', () => {
expect('3' in result).toBe(false);
expect('4' in result).toBe(false);
});

it('should preserve own __proto__ property and not set as prototype', () => {
const parsed = JSON.parse('{"__proto__": {"isAdmin": true}, "x": 1}');
const result = omit(parsed, 'x');

expect(Object.hasOwn(result, '__proto__')).toBe(true);
expect(Object.getPrototypeOf(result)).toBe(Object.prototype);
expect((result as any).isAdmin).toBeUndefined();
});
});
24 changes: 22 additions & 2 deletions src/compat/object/omit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,16 @@ function shallowCloneInOmit<T extends object>(obj: T): Partial<T> {

for (let i = 0; i < keysToCopy.length; i++) {
const key = keysToCopy[i];
result[key] = obj[key];
if (key === '__proto__') {
Object.defineProperty(result, key, {
configurable: true,
enumerable: true,
value: obj[key],
writable: true,
});
} else {
result[key] = obj[key];
}
}

return result;
Expand All @@ -144,13 +153,24 @@ function deepCloneInOmit<T extends object>(obj: T): Partial<T> {

for (let i = 0; i < keysToCopy.length; i++) {
const key = keysToCopy[i];
result[key] = cloneDeepWith(obj[key], valueToClone => {
const clonedValue = cloneDeepWith(obj[key], valueToClone => {
if (isPlainObject(valueToClone)) {
return undefined;
}

return valueToClone;
});

if (key === '__proto__') {
Object.defineProperty(result, key, {
configurable: true,
enumerable: true,
value: clonedValue,
writable: true,
});
} else {
result[key] = clonedValue;
}
}

return result;
Expand Down
Loading
Loading