Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement →
Sign In

@plandek-utils/plain-object

Package Overview
Dependencies
Maintainers
2
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@plandek-utils/plain-object - npm Package Compare versions

Comparing version
2.0.0
to
2.0.1
+115
src/__tests__/index.spec.ts
import { parseDayjsOrError } from "@plandek-utils/ts-parse-dayjs";
import { describe, expect, it } from "vitest";
import { isPlainObject, isPlainObjectValue, isValidArray, isValidPrimitive } from "../index.ts";
describe("isPlainObjectValue", () => {
it("should return true for nil values", () => {
expect(isPlainObjectValue(null)).toBe(true);
expect(isPlainObjectValue(undefined)).toBe(true);
});
it("should return true for boolean values", () => {
expect(isPlainObjectValue(true)).toBe(true);
expect(isPlainObjectValue(false)).toBe(true);
});
it("should return true for number values", () => {
expect(isPlainObjectValue(42)).toBe(true);
});
it("should return true for string values", () => {
expect(isPlainObjectValue("hello")).toBe(true);
expect(isPlainObjectValue("42")).toBe(true);
});
it("should return true for Dayjs objects", () => {
const dayjsObj = parseDayjsOrError("2023-01-01");
expect(isPlainObjectValue(dayjsObj)).toBe(true);
});
it("should return false for non-primitive values", () => {
expect(isPlainObjectValue(() => "whatever")).toBe(false);
});
it("should return false for Infinity, -Infinity and NaN", () => {
expect(isPlainObjectValue(Number.POSITIVE_INFINITY)).toBe(false);
expect(isPlainObjectValue(Number.NEGATIVE_INFINITY)).toBe(false);
expect(isPlainObjectValue(Number.NaN)).toBe(false);
});
it("should return false for symbol", () => {
expect(isPlainObjectValue(Symbol("foo"))).toBe(false);
});
it("should recursively check arrays", () => {
const arrayWithPrimitives = [42, "hello", true];
expect(arrayWithPrimitives.every(isPlainObjectValue)).toBe(true);
expect(isPlainObjectValue(arrayWithPrimitives)).toBe(true);
});
it("should recursively check arrays fail nested", () => {
const arrayWithPrimitives = [42, "hello", true, () => "whatever"];
expect(isPlainObjectValue(arrayWithPrimitives)).toBe(false);
});
it("should recursively check nested objects", () => {
const nestedObj = { a: 42, b: "hello", c: { d: true } };
expect(Object.values(nestedObj).every(isPlainObjectValue)).toBe(true);
expect(isPlainObjectValue(nestedObj)).toBe(true);
expect(isPlainObjectValue({ a: 42, b: "hello", c: { d: () => "oh no" } })).toBe(false);
});
});
describe("isPlainObject", () => {
it("should return true for plain objects", () => {
const obj = { a: 42, b: "hello", c: true };
expect(isPlainObject(obj)).toBe(true);
});
it("should return true for empty plain objects", () => {
expect(isPlainObject({})).toBe(true);
});
it("should return false for arrays", () => {
expect(isPlainObject([])).toBe(false);
expect(isPlainObject([1, 2, 3])).toBe(false);
});
it("should return false for null and undefined", () => {
expect(isPlainObject(null)).toBe(false);
expect(isPlainObject(undefined)).toBe(false);
});
});
describe("isValidPrimitive", () => {
it("should return true for valid primitives", () => {
expect(isValidPrimitive(null)).toBe(true);
expect(isValidPrimitive(undefined)).toBe(true);
expect(isValidPrimitive(true)).toBe(true);
expect(isValidPrimitive(false)).toBe(true);
expect(isValidPrimitive(42)).toBe(true);
expect(isValidPrimitive("hello")).toBe(true);
expect(isValidPrimitive(parseDayjsOrError("2023-01-01"))).toBe(true);
});
it("should return false for invalid primitives", () => {
expect(isValidPrimitive(() => "whatever")).toBe(false);
expect(isValidPrimitive(Number.POSITIVE_INFINITY)).toBe(false);
expect(isValidPrimitive(Number.NEGATIVE_INFINITY)).toBe(false);
expect(isValidPrimitive(Number.NaN)).toBe(false);
expect(isValidPrimitive(Symbol("foo"))).toBe(false);
});
});
describe("isValidArray", () => {
it("should return true for an array of PlainObjectValues", () => {
const arrayWithPrimitives = [42, "hello", true];
expect(isValidArray(arrayWithPrimitives)).toBe(true);
});
it("should return false for an array with non-PlainObjectValues", () => {
const arrayWithPrimitives = [42, "hello", true, () => "whatever"];
expect(isValidArray(arrayWithPrimitives)).toBe(false);
});
});
import { dayjsSchema } from "@plandek-utils/ts-parse-dayjs";
import { z } from "zod";
export const plainObjectValuePrimitiveSchema = z.union([
z.undefined(),
z.null(),
z.boolean(),
z.number().finite(),
z.string(),
z.instanceof(Date),
dayjsSchema,
]);
/**
* Union of all possible primitive values (non-array, non-nested-object) of a Plain Object field.
*
* That means:
* - It can be `undefined` or `null`.
* - It can be a boolean, number, or string.
* - It can be a Date object.
* - It can be a Dayjs object.
*/
export type PlainObjectValuePrimitive = z.infer<typeof plainObjectValuePrimitiveSchema>;
/**
* Union of all possible values of a Plain Object field.
*
* That means:
* - It can be `undefined` or `null`.
* - It can be a boolean, number, or string.
* - It can be a Dayjs object.
* - It can be an array of Plain Object values.
* - It can be a Plain Object where all values are Plain Object values.
*
* No other types are allowed, including functions.
*/
export type PlainObjectValue =
| PlainObjectValuePrimitive
| PlainObjectValue[]
| readonly PlainObjectValue[]
| { [prop: string]: PlainObjectValue };
export const plainObjectValueSchema: z.ZodType<PlainObjectValue> = z.lazy(() =>
z.union([
plainObjectValuePrimitiveSchema,
z.array(plainObjectValueSchema),
z.array(plainObjectValueSchema).readonly(),
z.record(plainObjectValueSchema),
]),
);
/**
* Check if the given value is either a Plain Object or a valid value of a Plain Object field.
*
* That means:
* - It can be `undefined` or `null`.
* - It can be a boolean, number, or string.
* - It can be a Dayjs object.
* - It can be an array of Plain Object values.
* - It can be a Plain Object where all values are Plain Object values.
*
* No other types are allowed, including functions.
*/
export function isPlainObjectValue(x: unknown): x is PlainObjectValue {
return plainObjectValueSchema.safeParse(x).success;
}
export const plainObjectSchema = z.record(plainObjectValueSchema);
/**
* Object where all values are Plain Object values.
*/
export type PlainObject = z.infer<typeof plainObjectSchema>;
/**
* Union of Plain Object and an array of Plain Objects.
*/
export type PlainObjectOrArray = PlainObject | PlainObject[];
/**
* Checks if the given PlainObjectValue is a PlainObject.
*
* Since the given value is a PlainObjectValue, we just need to discard the primitive values and arrays.
*
* @param o
* @returns
*/
export function isPlainObject(o: PlainObjectValue): o is Record<string, unknown> & PlainObject {
return plainObjectSchema.safeParse(o).success;
}
/**
* Extension of PlainObjectValue that allows for a generic type to be added as a valid value.
*/
export type PlainObjectValueExtended<T> =
| PlainObjectValuePrimitive
| T
| PlainObjectValueExtended<T>[]
| readonly PlainObjectValueExtended<T>[]
| { [prop: string]: PlainObjectValueExtended<T> };
/**
* Extension of PlainObject that uses PlainObjectValueExtended to add extra possible values.
*/
export type PlainObjectExtended<T> = {
[prop: string]: PlainObjectValueExtended<T>;
};
/**
* Returns true if the given value is a valid primitive: null, undefined, boolean, string, Dayjs, or number.
*/
export function isValidPrimitive(x: unknown): x is PlainObjectValuePrimitive {
return plainObjectValuePrimitiveSchema.safeParse(x).success;
}
/**
* Returns true if the given value is a valid array: array where all elements are PlainObjectValues.
*/
export function isValidArray(x: unknown): x is PlainObjectValue[] {
return Array.isArray(x) && x.every(isPlainObjectValue);
}
+9
-8
{
"name": "@plandek-utils/plain-object",
"version": "2.0.0",
"version": "2.0.1",
"author": "Eduardo TuriƱo <eturino@plandek.com>",

@@ -10,3 +10,4 @@ "description": "TypeScript types and predicate `isPlainObject` and `isPlainObjectValue`, which are serializable POJOs.",

"files": [
"dist"
"dist",
"src"
],

@@ -44,14 +45,14 @@ "scripts": {

"@commitlint/cz-commitlint": "^19.6.1",
"@types/node": "^22.10.7",
"@vitest/coverage-v8": "^3.0.3",
"@types/node": "^22.12.0",
"@vitest/coverage-v8": "^3.0.4",
"commitizen": "^4.3.1",
"husky": "^9.1.7",
"inquirer": "^9.3.7",
"tsup": "^8.3.5",
"tsup": "^8.3.6",
"typescript": "^5.7.3",
"vitest": "^3.0.3"
"vitest": "^3.0.4"
},
"peerDependencies": {
"@plandek-utils/ts-parse-dayjs": "6.3.2",
"zod": "3.24.1"
"@plandek-utils/ts-parse-dayjs": "^6.4.0",
"zod": "^3.24.1"
},

@@ -58,0 +59,0 @@ "config": {

@@ -62,13 +62,4 @@ # @plandek-utils/plain-object

This package is developed with deno 2. The production code is in `src/mod.ts` and its test in
`src/__tests__/mod.spec.ts`
- `deno fmt`: format files
- `deno lint`: lint files
- `deno dev`: run tests on each change in mod.ts
- `deno run test && deno run lcov && deno run html`: run the tests with coverage, then convert to lcov and prepare in
`html_cov` an HTML export of the coverage info.
TypeScript types and predicate `isPlainObject` and `isPlainObjectValue`. PlainObject = POJO where all values are
PlainObjectValue. PlainObjectValue = serializable value (Dayjs, nil, number, string, boolean, PlainObjectValue[],
PlainObject)