From 892c35f6b81cfa515069721823e8a0eefdda855e Mon Sep 17 00:00:00 2001 From: Orlando Date: Mon, 19 Feb 2024 20:57:13 +0000 Subject: [PATCH] more formatters, types and validators --- CHANGELOG.md | 6 ++++++ README.md | 18 ++++++++++++------ package.json | 2 +- src/formatters/formatCamelCase.ts | 7 +++++++ src/formatters/index.ts | 3 ++- src/helpers/serialize.ts | 2 +- src/random/randomObject.test.ts | 9 +++++++++ src/random/randomObject.ts | 19 +++++++++++++++++++ src/random/randomValue.ts | 16 ++++++++++++++++ src/types/Function.ts | 1 + src/types/HashMap.ts | 13 +++++++------ src/types/Object.ts | 5 +++-- src/types/PlainObject.ts | 10 +++++++++- src/validators/index.ts | 2 ++ src/validators/isBuffer.test.ts | 15 +++++++++++++++ src/validators/isBuffer.ts | 11 +++++++++++ src/validators/isFile.ts | 2 ++ src/validators/isKey.ts | 7 +++---- src/validators/isObject.ts | 4 +++- 19 files changed, 129 insertions(+), 23 deletions(-) create mode 100644 src/formatters/formatCamelCase.ts create mode 100644 src/random/randomObject.test.ts create mode 100644 src/random/randomObject.ts create mode 100644 src/random/randomValue.ts create mode 100644 src/types/Function.ts create mode 100644 src/validators/isBuffer.test.ts create mode 100644 src/validators/isBuffer.ts create mode 100644 src/validators/isFile.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 530f8b9..f16bccd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # deverything +## 0.44.0 + +### Minor Changes + +- randomObject isFile and many more + ## 0.43.0 ### Minor Changes diff --git a/README.md b/README.md index beecec2..f1d7378 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,14 @@ Contributions always welcome! - `isArray()` - `isBoolean()` - `isBrowser()` to detect if you are on the browser +- `isBuffer()` - `isClient()` to detect if you are ont the browser/client - `isEmail()` this is a relaxed check, use your own validation if you need to be strict - ⭐ `isEmpty()` to check for empty object, empty array, empty string, null or undefined - `isEmptyString()` trims the string and checks if something is left - `isEmptyArray()` - `isEmptyObject()` +- `isFile()` - `isFunction()` - `isJsDate()` if it's a **valid** javascript's Date - `isFutureDate()` @@ -98,6 +100,7 @@ Contributions always welcome! ### Formatters +- `formatCamelCase()` - `formatNumber()` 1000 => "1,000" or "1K" or 0.112 => "11.2%" - `stringToUnicode()` "hello" => "\u0068\u0065\u006c\u006c\u006f" - `stringToCSSUnicode()` "hello" => "\000068\000065\00006c\00006c\00006f" use this for CSS @@ -127,6 +130,7 @@ These functions are optimized for low entropy random data generation useful for - `randomEnumValue()` enum FRUIT { APPLE = 1, PEAR = 3 } => 3 - `randomFile()` - `randomFloat()` +- `randomObject()` - `randomHandle()` useful for social identifiers, or slugs - `randomHexColor()` - `randomHexValue()` @@ -149,6 +153,7 @@ These functions are optimized for low entropy random data generation useful for - `randomPhoneNumber()` - `randomString()` - `randomUUID()` lightweight uuid generation, passing UUID validation +- `randomValue()` - `randomWord()` ### Checks @@ -167,20 +172,21 @@ Checks are functions that throw an error, if the validation fails - `MaybePromiseOrValue<>` - `MaybePromiseOrValueArray<>` - `NonUndefined` +- `Key` - `ObjectKey<>` - `ObjectKeys<>` - `ObjectValue<>` - `ObjectValues<>` +- `ObjectEntry<>` - `ObjectEntries<>` - ⭐ `PlainObject` use this instead of `Record<,>` or `extends object`, also makes sure it's not an array - `Point` -- `PrismaSelect<>` - `HashMap<>` -- `HashMapKey` -- `NumberMap` -- `StringMap` -- `BoolMap` -- `TrueMap` + - `BoolMap` + - `NumberMap` + - `StringMap` + - `TrueMap` +- `VoidFn` ## Development diff --git a/package.json b/package.json index 6ccfa4e..1c2980e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "deverything", - "version": "0.43.0", + "version": "0.44.0", "description": "Everything you need for Dev", "main": "./dist/index.js", "module": "./dist/index.mjs", diff --git a/src/formatters/formatCamelCase.ts b/src/formatters/formatCamelCase.ts new file mode 100644 index 0000000..bac93be --- /dev/null +++ b/src/formatters/formatCamelCase.ts @@ -0,0 +1,7 @@ +export const formatCamelCase = (str: string) => { + return str + .toLowerCase() + .replace(/[-_\s]([a-z\d])(\w*)/g, function replacer(_m, p1, p2) { + return p1.toUpperCase() + p2; + }); +}; diff --git a/src/formatters/index.ts b/src/formatters/index.ts index 5dc2a82..1a2c1f2 100644 --- a/src/formatters/index.ts +++ b/src/formatters/index.ts @@ -1,3 +1,4 @@ +export * from "./formatCamelCase"; export * from "./formatNumber"; -export * from "./stringToUnicode"; export * from "./stringToCSSUnicode"; +export * from "./stringToUnicode"; diff --git a/src/helpers/serialize.ts b/src/helpers/serialize.ts index c953eb9..08dd040 100644 --- a/src/helpers/serialize.ts +++ b/src/helpers/serialize.ts @@ -1,7 +1,7 @@ import { PlainObject } from "../types"; /** - * Serialize plain object to a deterministic string, + * Serialize shallow object to a deterministic string, * for nested objects use [json-stable-stringify](https://www.npmjs.com/package/json-stable-stringify) * * @example diff --git a/src/random/randomObject.test.ts b/src/random/randomObject.test.ts new file mode 100644 index 0000000..13de7df --- /dev/null +++ b/src/random/randomObject.test.ts @@ -0,0 +1,9 @@ +import { describe, it, expect } from "@jest/globals"; +import { keysLength } from "../helpers"; +import { randomObject } from "./randomObject"; + +describe(`randomObject`, () => { + it(`works`, () => { + expect(keysLength(randomObject())).toBeGreaterThan(0); + }); +}); diff --git a/src/random/randomObject.ts b/src/random/randomObject.ts new file mode 100644 index 0000000..7f10d3b --- /dev/null +++ b/src/random/randomObject.ts @@ -0,0 +1,19 @@ +import { array } from "../helpers"; +import { PlainObject } from "../types"; +import { randomInt } from "./randomInt"; +import { randomValue } from "./randomValue"; +import { randomNoun } from "./randomWord"; + +export const randomObject = ({ maxDepth = 5 }: { maxDepth?: number } = {}) => { + const getRandomObject = (depth: number): PlainObject => { + if (depth >= maxDepth) return {}; + + const keys = array(randomInt(1, 5), randomNoun); + return keys.reduce((partial, key) => { + partial[key] = randomValue() || getRandomObject(depth + 1); + return partial; + }, {} as PlainObject); + }; + + return getRandomObject(0); +}; diff --git a/src/random/randomValue.ts b/src/random/randomValue.ts new file mode 100644 index 0000000..df1737a --- /dev/null +++ b/src/random/randomValue.ts @@ -0,0 +1,16 @@ +import { randomArrayItem } from "./randomArrayItem"; +import { randomBool } from "./randomBool"; +import { randomDate } from "./randomDate"; +import { randomInt } from "./randomInt"; +import { randomString } from "./randomString"; + +export const randomValue = () => { + return randomArrayItem([ + randomBool(), + randomString(), + randomInt(), + randomDate(), + undefined, + null, + ]); +}; diff --git a/src/types/Function.ts b/src/types/Function.ts new file mode 100644 index 0000000..63d3336 --- /dev/null +++ b/src/types/Function.ts @@ -0,0 +1 @@ +export type VoidFn = () => void; diff --git a/src/types/HashMap.ts b/src/types/HashMap.ts index 9e9a0dd..dfd7977 100644 --- a/src/types/HashMap.ts +++ b/src/types/HashMap.ts @@ -1,7 +1,8 @@ +import { Key } from "./Object"; + // I don't like the Dict keyword, but it's a possibility... -export type HashMapKey = string | number | symbol; -export type HashMap = Record; -export type NumberMap = Record; -export type StringMap = Record; -export type BoolMap = Record; -export type TrueMap = Record; +export type HashMap = Record; +export type NumberMap = Record; +export type StringMap = Record; +export type BoolMap = Record; +export type TrueMap = Record; diff --git a/src/types/Object.ts b/src/types/Object.ts index 5b643eb..d158bd1 100644 --- a/src/types/Object.ts +++ b/src/types/Object.ts @@ -1,6 +1,7 @@ +export type Key = string | number | symbol; export type ObjectKey = keyof T; export type ObjectKeys = ObjectKey[]; export type ObjectValue = T[keyof T]; export type ObjectValues = ObjectValue[]; -// ObjectEntry needed? -export type ObjectEntries = { [K in keyof T]: [K, T[K]] }[keyof T][]; +export type ObjectEntry = { [K in keyof T]: [K, T[K]] }[keyof T]; +export type ObjectEntries = ObjectEntry[]; diff --git a/src/types/PlainObject.ts b/src/types/PlainObject.ts index cda52c2..1636c25 100644 --- a/src/types/PlainObject.ts +++ b/src/types/PlainObject.ts @@ -1 +1,9 @@ -export type PlainObject = Record & { length?: never }; // Excludes arrays +import { Key } from "./Object"; + +/** + * A plain object is an object that is not an array, does not have a length property, and is not a function. + * Would have been nice to call it just Object, but that's already taken by the built-in type. + */ +export type PlainObject = Record & { + length?: never; +}; // Excludes arrays diff --git a/src/validators/index.ts b/src/validators/index.ts index 86468b0..6c1c73c 100644 --- a/src/validators/index.ts +++ b/src/validators/index.ts @@ -2,9 +2,11 @@ export * from "./isArray"; export * from "./isArrayIncluded"; export * from "./isBoolean"; export * from "./isBrowser"; +export * from "./isBuffer"; export * from "./isClient"; export * from "./isEmail"; export * from "./isEmpty"; +export * from "./isFile"; export * from "./isFunction"; export * from "./isFutureDate"; export * from "./isJsDate"; diff --git a/src/validators/isBuffer.test.ts b/src/validators/isBuffer.test.ts new file mode 100644 index 0000000..1c53483 --- /dev/null +++ b/src/validators/isBuffer.test.ts @@ -0,0 +1,15 @@ +import { describe, expect, test } from "@jest/globals"; +import { isBuffer } from "./isBuffer"; + +describe("isBuffer", () => { + test("mixed", async () => { + const buffer = Buffer.from("test"); + expect(isBuffer(buffer)).toBe(true); + + const arraybuffer = new Uint8Array([1, 2, 3]).buffer; + expect(isBuffer(arraybuffer)).toBe(false); + + const notBuffer = { byteLength: 3, slice: () => {} }; + expect(isBuffer(notBuffer)).toBe(false); + }); +}); diff --git a/src/validators/isBuffer.ts b/src/validators/isBuffer.ts new file mode 100644 index 0000000..24999af --- /dev/null +++ b/src/validators/isBuffer.ts @@ -0,0 +1,11 @@ +import { isFunction } from "./isFunction"; +import { isValue } from "./isValue"; + +export const isBuffer = (val?: any): boolean => { + return ( + isValue(val) && + isValue(val.constructor) && + isFunction(val.constructor.isBuffer) && + val.constructor.isBuffer(val) + ); +}; diff --git a/src/validators/isFile.ts b/src/validators/isFile.ts new file mode 100644 index 0000000..71757ae --- /dev/null +++ b/src/validators/isFile.ts @@ -0,0 +1,2 @@ +export const isFile = (arg?: any): arg is File => + Object.prototype.toString.call(arg) === "[object File]"; diff --git a/src/validators/isKey.ts b/src/validators/isKey.ts index 1718b51..740bbc2 100644 --- a/src/validators/isKey.ts +++ b/src/validators/isKey.ts @@ -1,6 +1,5 @@ -export const isKey = ( - key: string | number | symbol, - obj: T -): key is keyof T => +import { Key } from "../types/Object"; + +export const isKey = (key: Key, obj: T): key is keyof T => obj.hasOwnProperty(key) && // makes sure the prop is not in the prototype chain obj.propertyIsEnumerable(key); // makes sure the prop is not a getter/setter diff --git a/src/validators/isObject.ts b/src/validators/isObject.ts index e57d917..f2281d0 100644 --- a/src/validators/isObject.ts +++ b/src/validators/isObject.ts @@ -1,2 +1,4 @@ -export const isObject = (arg?: any): arg is Record => +import { PlainObject } from "../types"; + +export const isObject = (arg?: any): arg is PlainObject => Object.prototype.toString.call(arg) === "[object Object]";