Skip to content
This repository has been archived by the owner on Dec 30, 2023. It is now read-only.

Commit

Permalink
refactor(object): ♻️ Major reorganization (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
xeho91 authored Jun 1, 2023
1 parent 263dd08 commit e38a9b4
Show file tree
Hide file tree
Showing 22 changed files with 183 additions and 85 deletions.
5 changes: 5 additions & 0 deletions .changeset/friendly-horses-film.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@terminal-nerds/snippets-object": minor
---

♻️ Major reorganization
13 changes: 4 additions & 9 deletions packages/object/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,14 @@

| Name | Size |
| ------------------------------------------ | ----------------------------------------------------- |
| [`@terminal-nerds/snippets-object/keys`] | ![keys size gzip badge] ![keys size brotli badge] |
| [`@terminal-nerds/snippets-object/schema`] | ![schema size gzip badge] ![schema size brotli badge] |
| [`@terminal-nerds/snippets-object/misc`] | ![misc size gzip badge] ![misc size brotli badge] |
| [`@terminal-nerds/snippets-object/schema`] | ![schema size gzip badge] ![schema size brotli badge] |

<!-- prettier-ignore-start -->
<!-- MODULES LINKS -->
[`@terminal-nerds/snippets-object/keys`]: https://github.com/terminal-nerds/snippets/blob/main/packages/object/source/keys/keys.ts
[keys size gzip badge]: https://badgen.net/badgesize/gzip/file-object/unpkg.com/@terminal-nerds/snippets-object/dist/keys/keys.js?label=gzip
[keys size brotli badge]: https://badgen.net/badgesize/brotli/file-object/unpkg.com/@terminal-nerds/snippets-object/dist/keys/keys.js?label=brotli

[`@terminal-nerds/snippets-object/merge`]: https://github.com/terminal-nerds/snippets/blob/main/packages/object/source/merge/merge.ts
[merge size gzip badge]: https://badgen.net/badgesize/gzip/file-object/unpkg.com/@terminal-nerds/snippets-object/dist/merge/merge.js?label=gzip
[merge size brotli badge]: https://badgen.net/badgesize/brotli/file-object/unpkg.com/@terminal-nerds/snippets-object/dist/merge/merge.js?label=brotli
[`@terminal-nerds/snippets-object/misc`]: https://github.com/terminal-nerds/snippets/blob/main/packages/object/source/misc/misc.ts
[misc size gzip badge]: https://badgen.net/badgesize/gzip/file-object/unpkg.com/@terminal-nerds/snippets-object/dist/misc/misc.js?label=gzip
[misc size brotli badge]: https://badgen.net/badgesize/brotli/file-object/unpkg.com/@terminal-nerds/snippets-object/dist/misc/misc.js?label=brotli

[`@terminal-nerds/snippets-object/schema`]: https://github.com/terminal-nerds/snippets/blob/main/packages/object/source/schema/schema.ts
[schema size gzip badge]: https://badgen.net/badgesize/gzip/file-object/unpkg.com/@terminal-nerds/snippets-object/dist/schema/schema.js?label=gzip
Expand Down
15 changes: 12 additions & 3 deletions packages/object/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,18 @@
"require": "./dist/main.cjs"
},
"./*": {
"types": "./dist/*/*.d.ts",
"import": "./dist/*/*.js",
"require": "./dist/*/*.cjs"
"types": [
"./dist/*.d.ts",
"./dist/*/index.d.ts"
],
"import": [
"./dist/*.js",
"./dist/*/index.js"
],
"require": [
"./dist/*.cjs",
"./dist/*/index.cjs"
]
}
},
"files": [
Expand Down
28 changes: 0 additions & 28 deletions packages/object/source/keys/keys.ts

This file was deleted.

5 changes: 2 additions & 3 deletions packages/object/source/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* MODULES */
export * from "./keys/keys.ts";
export * from "./merge/merge.ts";
export * from "./schema/schema.ts";
export * from "./misc/index.ts";
export * from "./schema/index.ts";
4 changes: 4 additions & 0 deletions packages/object/source/misc/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./sub/merge.ts";
export * from "./sub/omit.ts";
export * from "./sub/pick.ts";
export * from "./sub/rename.ts";
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { returns, throws } from "@terminal-nerds/snippets-test/unit";
import { describe, it } from "vitest";
import { ZodError } from "zod";

import { mergeDeepObjects } from "./merge.ts";
import { mergeObjects } from "./merge.ts";

const SAMPLE_OBJECT1 = { a: [1] } as const;
const SAMPLE_OBJECT2 = { a: [2, 3], b: false } as const;
Expand All @@ -12,12 +12,12 @@ const SAMPLE_OBJECT3 = { a: [4, 5], b: true, c: "terminal nerds" } as const;
describe(`deepMergeObjects(objects)`, () => {
it(throws(ZodError).on(`invalid object values`).samples(SAMPLE_PRIMITIVES), ({ expect }) => {
// @ts-expect-error Testing
expect(() => mergeDeepObjects(SAMPLE_PRIMITIVES)).toThrowError(ZodError);
expect(() => mergeObjects(SAMPLE_PRIMITIVES)).toThrowError(ZodError);
});

const expected = { a: [1, 2, 3, 4, 5], b: true, c: "terminal nerds" } as const;

it(returns(expected).on(`sample objects`), ({ expect }) => {
expect(mergeDeepObjects([SAMPLE_OBJECT1, SAMPLE_OBJECT2, SAMPLE_OBJECT3])).toEqual(expected);
expect(mergeObjects([SAMPLE_OBJECT1, SAMPLE_OBJECT2, SAMPLE_OBJECT3])).toEqual(expected);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { OBJECT_SCHEMA } from "@terminal-nerds/snippets-type/non-primitive";
import { deepmerge } from "deepmerge-ts";
import { z } from "zod";

export function mergeDeepObjects(objects: ReadonlyArray<object>): object {
export function mergeObjects(objects: ReadonlyArray<object>): object {
z.array(OBJECT_SCHEMA).parse(objects);

return deepmerge(...objects) as object;
Expand Down
22 changes: 22 additions & 0 deletions packages/object/source/misc/sub/omit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { SAMPLE_PRIMITIVES } from "@terminal-nerds/snippets-test/sample";
import { returns, throws } from "@terminal-nerds/snippets-test/unit";
import { describe, it } from "vitest";
import { ZodError } from "zod";

import { omitObjectEntries } from "./omit.ts";

describe("omitObjectEntries(object, keys)", () => {
it(throws(ZodError).on(`invalid object values`).samples(SAMPLE_PRIMITIVES), ({ expect }) => {
// @ts-expect-error Testing
expect(() => omitObjectEntries(SAMPLE_PRIMITIVES)).toThrowError(ZodError);
});

it(
returns({ b: 2 })
.on(`sample object`)
.with({ keys: ["a"] }),
({ expect }) => {
expect(omitObjectEntries({ a: 1, b: 2 }, ["a"])).toEqual({ b: 2 });
},
);
});
11 changes: 11 additions & 0 deletions packages/object/source/misc/sub/omit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { validateObject } from "../../schema/sub/native.ts";

export function omitObjectEntries<const O extends object, K extends keyof O>(object: O, keys: K[]): Omit<O, K> {
validateObject(object);

const keysSet = new Set(keys);

return Object.fromEntries(
(Object.entries(object) as Array<[K, O[K]]>).filter(([key]) => !keysSet.has(key)),
) as unknown as Omit<O, K>;
}
22 changes: 22 additions & 0 deletions packages/object/source/misc/sub/pick.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { SAMPLE_PRIMITIVES } from "@terminal-nerds/snippets-test/sample";
import { returns, throws } from "@terminal-nerds/snippets-test/unit";
import { describe, it } from "vitest";
import { ZodError } from "zod";

import { pickObjectEntries } from "./pick.ts";

describe("pickObjectEntries(object, keys)", () => {
it(throws(ZodError).on(`invalid object values`).samples(SAMPLE_PRIMITIVES), ({ expect }) => {
// @ts-expect-error Testing
expect(() => pickObjectEntries(SAMPLE_PRIMITIVES)).toThrowError(ZodError);
});

it(
returns({ a: 1 })
.on(`sample object`)
.with({ keys: ["a"] }),
({ expect }) => {
expect(pickObjectEntries({ a: 1, b: 2 }, ["a"])).toEqual({ a: 1 });
},
);
});
12 changes: 12 additions & 0 deletions packages/object/source/misc/sub/pick.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { validateObject } from "../../schema/sub/native.ts";

export function pickObjectEntries<const O extends object, K extends keyof O>(object: O, keys: K[]): Pick<O, K> {
validateObject(object);

const keysSet = new Set(keys);

return Object.fromEntries((Object.entries(object) as Array<[K, O[K]]>).filter(([key]) => keysSet.has(key))) as Pick<
O,
K
>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { returns, throws } from "@terminal-nerds/snippets-test/unit";
import { describe, it } from "vitest";
import { ZodError } from "zod";

import { renameObjectKeys } from "./keys.ts";
import { renameObjectKeys } from "./rename.ts";

const SAMPLE_OBJECT = {
one: "one",
Expand All @@ -25,7 +25,7 @@ describe("renameObjectKeys(object, renamer)", () => {
throws(ZodError)
.on(`passed sample object`)
.sample(SAMPLE_OBJECT)
.and(`with renamer returning non-string value`),
.and(`with renamer returning invalid object key type`),
({ expect }) => {
// @ts-ignore Testing
expect(() => renameObjectKeys(SAMPLE_OBJECT, () => void 0)).toThrowError(ZodError);
Expand Down
32 changes: 32 additions & 0 deletions packages/object/source/misc/sub/rename.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { z } from "zod";

import { type ObjectKey, SCHEMA_OBJECT_KEY, validateObjectKey } from "../../schema/sub/key.ts";
import { validateObject } from "../../schema/sub/native.ts";

/* prettier-ignore */
const SCHEMA_RENAMER = z.function()
.args(SCHEMA_OBJECT_KEY, z.number().optional())
.returns(SCHEMA_OBJECT_KEY);

export function renameObjectKeys<OldKey extends ObjectKey, Value, NewKey extends ObjectKey>(
object: Record<OldKey, Value>,
renamer: (key: OldKey, index: number) => NewKey,
): Record<NewKey, Value> {
validateObject(object);
SCHEMA_RENAMER.parse(renamer);

const handleRename = (key: OldKey, index: number) => {
const renamedKey = renamer(key, index);

validateObjectKey(renamedKey);

return renamedKey;
};

return Object.fromEntries(
(Object.entries(object) as Array<[OldKey, Value]>).map(([key, value], index) => [
handleRename(key, index),
value,
]),
) as Record<NewKey, Value>;
}
14 changes: 0 additions & 14 deletions packages/object/source/schema/empty/empty.ts

This file was deleted.

2 changes: 2 additions & 0 deletions packages/object/source/schema/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./sub/empty.ts";
export * from "./sub/native.ts";
11 changes: 0 additions & 11 deletions packages/object/source/schema/schema.ts

This file was deleted.

14 changes: 14 additions & 0 deletions packages/object/source/schema/sub/empty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { EmptyObject as ObjectEmpty } from "type-fest/source/empty-object";
import { z } from "zod";

export const EMPTY_OBJECT_SCHEMA = z.record(z.undefined());

export type { EmptyObject as ObjectEmpty } from "type-fest/source/empty-object";

export function isObjectEmpty(value: object): value is ObjectEmpty {
return EMPTY_OBJECT_SCHEMA.safeParse(value).success;
}

export function validateEmptyObject(value: object): asserts value is ObjectEmpty {
EMPTY_OBJECT_SCHEMA.parse(value);
}
13 changes: 13 additions & 0 deletions packages/object/source/schema/sub/key.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { z } from "zod";

export const SCHEMA_OBJECT_KEY = z.number().or(z.string()).or(z.symbol());

export type ObjectKey = number | string | symbol;

export function isValidObjectKey(key: unknown): key is ObjectKey {
return SCHEMA_OBJECT_KEY.safeParse(key).success;
}

export function validateObjectKey(key: unknown): asserts key is ObjectKey {
SCHEMA_OBJECT_KEY.parse(key);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,35 @@ import { returns, throws } from "@terminal-nerds/snippets-test/unit";
import { describe, it } from "vitest";
import { ZodError } from "zod";

import { isObject, validateObject } from "./schema.ts";
import { isObject, validateObject } from "./native.ts";

const VALID_OBJECTS = [{}, { a: 1 }] as const;
const INVALID_OBJECTS = SAMPLE_PRIMITIVES;

describe("validateObject(value)", () => {
it(throws(ZodError).on("invalid objects").samples(INVALID_OBJECTS), ({ expect }) => {
describe("isObject(value)", () => {
it(returns(false).on("invalid objects").samples(INVALID_OBJECTS), ({ expect }) => {
for (const object of INVALID_OBJECTS) {
expect(() => validateObject(object)).toThrowError(ZodError);
expect(isObject(object)).toBe(false);
}
});

it(returns().on("valid objects").samples(VALID_OBJECTS), ({ expect }) => {
it(returns(true).on("valid objects").samples(VALID_OBJECTS), ({ expect }) => {
for (const object of VALID_OBJECTS) {
expect(() => validateObject(object)).not.toThrowError();
expect(isObject(object)).toBe(true);
}
});
});

describe("isObject(value)", () => {
it(returns(false).on("invalid objects").samples(INVALID_OBJECTS), ({ expect }) => {
describe("validateObject(value)", () => {
it(throws(ZodError).on("invalid objects").samples(INVALID_OBJECTS), ({ expect }) => {
for (const object of INVALID_OBJECTS) {
expect(isObject(object)).toBe(false);
expect(() => validateObject(object)).toThrowError(ZodError);
}
});

it(returns(true).on("valid objects").samples(VALID_OBJECTS), ({ expect }) => {
it(returns().on("valid objects").samples(VALID_OBJECTS), ({ expect }) => {
for (const object of VALID_OBJECTS) {
expect(isObject(object)).toBe(true);
expect(() => validateObject(object)).not.toThrowError();
}
});
});
11 changes: 11 additions & 0 deletions packages/object/source/schema/sub/native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { z } from "zod";

export const SCHEMA_OBJECT = z.object({});

export function isObject(value: unknown): value is object {
return SCHEMA_OBJECT.safeParse(value).success;
}

export function validateObject(value: unknown): asserts value is object {
SCHEMA_OBJECT.parse(value);
}

0 comments on commit e38a9b4

Please sign in to comment.