@onivoro/isomorphic-common
v24.33.4
Published
Common utilities, functions, types, and constants shared between browser and server environments in the Onivoro monorepo. This library provides essential building blocks for TypeScript applications with a focus on type safety and consistent behavior acros
Readme
@onivoro/isomorphic-common
Common utilities, functions, types, and constants shared between browser and server environments in the Onivoro monorepo. This library provides essential building blocks for TypeScript applications with a focus on type safety and consistent behavior across different runtime environments.
Installation
npm install @onivoro/isomorphic-commonFeatures
- Isomorphic Design: Works identically in browser and Node.js environments
- String Manipulation: Case conversion, formatting, sanitization, and validation utilities
- Array Operations: Chunking, sorting, deduplication, and transformation functions
- Date/Time Utilities: Calendar operations, offset calculations, and time constants
- Financial Functions: Currency formatting and money calculations
- Type Utilities: TypeScript type helpers and interfaces
- Validation Functions: Data validation and parsing utilities
- Testing Helpers: Mock functions and test arrangement utilities
- Constants: Authentication headers, regex patterns, and time constants
- Object Utilities: Property extraction and conversion functions
- JSON Utilities: Safe parsing and stringifying operations
Constants
Authentication Headers
import { apiKeyHeader, apiIdHeader, authCookieName } from '@onivoro/isomorphic-common';
// Use in HTTP requests
const headers = {
[apiKeyHeader]: 'your-api-key', // 'x-api-key'
[apiIdHeader]: 'api-identifier' // 'x-api-id'
};
// Cookie name for authentication
document.cookie = `${authCookieName}=your-token`; // 'token'Time Constants
import { MILLIS_PER_DAY, MILLIS_PER_HOUR, MILLIS_PER_MINUTE } from '@onivoro/isomorphic-common';
// Time constants (calculated from MILLIS_PER_MINUTE base)
const hoursInDay = MILLIS_PER_DAY / MILLIS_PER_HOUR; // 24
const minutesInHour = MILLIS_PER_HOUR / MILLIS_PER_MINUTE; // 60
// Set timeouts
setTimeout(() => {}, MILLIS_PER_MINUTE); // 1 minute timeoutRegular Expressions
import {
email,
phone,
zip,
v4,
dateIso8601,
numeric,
ssn,
ein
} from '@onivoro/isomorphic-common';
// Validate email
const isValidEmail = email.test('[email protected]'); // true
// Validate phone number (format: 123-456-7890)
const isValidPhone = phone.test('123-456-7890'); // true
// Validate ZIP code (5 digits)
const isValidZip = zip.test('12345'); // true
// Validate UUID v4
const isValidUuid = v4.test('550e8400-e29b-41d4-a716-446655440000'); // true
// Validate ISO date (YYYY-MM-DD)
const isValidDate = dateIso8601.test('2023-12-31'); // true
// Validate numeric values
const isNumeric = numeric.test('12345'); // true
// Validate SSN (format: XXX-XX-XXXX)
const isValidSSN = ssn.test('123-45-6789'); // true
// Validate EIN (format: XX-XXXXXXX)
const isValidEIN = ein.test('12-3456789'); // trueString Functions
Case Conversion
import { camelCase, kebabCase, snakeCase } from '@onivoro/isomorphic-common';
// camelCase(string: string): string
camelCase('hello world'); // 'helloWorld'
camelCase('--foo-bar--'); // 'fooBar'
camelCase('__FOO_BAR__'); // 'fooBar'
// kebabCase(string: string): string
kebabCase('Hello World'); // 'hello-world'
kebabCase('fooBar'); // 'foo-bar'
// snakeCase(string: string): string
snakeCase('Hello World'); // 'hello_world'
snakeCase('fooBar'); // 'foo_bar'String Utilities
import {
toString,
getTag,
sanitizeFilename,
fromBooleanString,
toBooleanString
} from '@onivoro/isomorphic-common';
// toString(value: any): string
toString(null); // 'null'
toString([1, 2, 3]); // '1,2,3'
toString({foo: 'bar'}); // '[object Object]'
// getTag(value: any): string
getTag([]); // '[object Array]'
getTag(new Date()); // '[object Date]'
// sanitizeFilename(filename: string): string
sanitizeFilename('file:name?.txt'); // 'filename.txt'
sanitizeFilename('invalid/file\\name'); // 'invalidfilename'
// fromBooleanString(value: string): boolean
fromBooleanString('true'); // true
fromBooleanString('false'); // false
// toBooleanString(value: boolean): string
toBooleanString(true); // 'true'
toBooleanString(false); // 'false'Array Functions
Array Manipulation
import {
chunk,
removeElementAtIndex,
toUniqueArray,
mapEnumToOptions,
mapEnumToLookupArray,
mapEnumToArrayOfValues
} from '@onivoro/isomorphic-common';
// chunk<T>(array: T[], numDivisions: number): T[][]
// Divides array into N divisions (NOT chunks of size N)
chunk([1, 2, 3, 4, 5, 6], 3); // [[1, 2], [3, 4], [5, 6]] - 3 divisions
chunk([1, 2, 3, 4, 5], 2); // [[1, 2, 3], [4, 5]] - 2 divisions
// removeElementAtIndex<T>(array: T[], indexToRemove: number): T[]
removeElementAtIndex(['a', 'b', 'c'], 1); // ['a', 'c']
// toUniqueArray<TElement>(elements: TElement[]): TElement[]
toUniqueArray([1, 2, 2, 3, 3, 4]); // [1, 2, 3, 4]Sorting Functions
import {
sortByName,
sortById,
sortNumbers,
sortByPropertyFactory,
sortByNumericPropertyFactory
} from '@onivoro/isomorphic-common';
// sortByName<TEntity extends { name: string }>(a: TEntity, b: TEntity): number
const users = [{ name: 'Bob' }, { name: 'Alice' }];
users.sort(sortByName); // [{ name: 'Alice' }, { name: 'Bob' }]
// sortById<TEntity extends { id: string }>(a: TEntity, b: TEntity): number
const items = [{ id: '3' }, { id: '1' }, { id: '2' }];
items.sort(sortById); // [{ id: '1' }, { id: '2' }, { id: '3' }]
// sortNumbers(a: number, b: number): number
const numbers = [3, 1, 4, 1, 5];
numbers.sort(sortNumbers); // [1, 1, 3, 4, 5]
// sortByPropertyFactory<TEntity>(property: keyof TEntity): (a: TEntity, b: TEntity) => number
const sortByAge = sortByPropertyFactory<{age: number}>('age');
const people = [{age: 30}, {age: 20}, {age: 25}];
people.sort(sortByAge); // [{age: 20}, {age: 25}, {age: 30}]
// sortByNumericPropertyFactory<TEntity>(property: keyof TEntity): (a: TEntity, b: TEntity) => number
const sortByScore = sortByNumericPropertyFactory<{score: number}>('score');Date/Time Functions
Date Operations
import {
addOffset,
subtractOffset,
getDateRangeForMonth,
getDateLastMonth,
tryParseDate,
useDate
} from '@onivoro/isomorphic-common';
// addOffset(input: string | Date | undefined | null): Date | undefined
const date = new Date('2023-01-15');
const withOffset = addOffset(date); // Adds timezone offset
// subtractOffset(input: string | Date | undefined | null): Date | undefined
const withoutOffset = subtractOffset(date); // Subtracts timezone offset
// getDateRangeForMonth(year: number, month: number): {startDate: Date, endDate: Date}
const { startDate, endDate } = getDateRangeForMonth(2023, 0); // January 2023 (month 0-indexed)
// getDateLastMonth(): string
const lastMonth = getDateLastMonth(); // Returns date string for last month
// tryParseDate(value: any): Date | null
const parsedDate = tryParseDate('2023-01-15'); // Date object
const failedParse = tryParseDate('invalid'); // null
// useDate(dateString: string | Date): Date
const ensuredDate = useDate('2023-01-15'); // Always returns Date objectDate Utilities
import {
isValidDate,
parseBool
} from '@onivoro/isomorphic-common';
// isValidDate(dateString: string | Date): Date | undefined
const validDate = isValidDate('2023-01-15'); // Date object
const invalidDate = isValidDate('invalid'); // undefined
// parseBool(asc: string | boolean | null | undefined): boolean
parseBool('true'); // true
parseBool('false'); // false
parseBool(true); // true
parseBool(null); // falseFinancial Functions
import {
formatUsd,
money,
toDollarsAndCents,
round
} from '@onivoro/isomorphic-common';
// formatUsd(rawAmount?: number | string): string
formatUsd(1234.56); // '$1,234.56'
formatUsd('1234.56'); // '$1,234.56'
formatUsd(); // '$0.00'
// money(rawValue: number | string): string | undefined
money(19.99); // '$19.99'
money('abc'); // undefined
// toDollarsAndCents(input: string | number): string
toDollarsAndCents(19.99); // 'nineteen dollars and ninety-nine cents'
toDollarsAndCents(20); // 'twenty dollars'
// round(numberToRound: number, scalingFactor: number): number
round(19.999, 100); // 20.00 (rounds to nearest cent)
round(19.994, 100); // 19.99Object Utilities
import {
propertiesToArray,
convertObjectToLiteral,
toDecimalBase
} from '@onivoro/isomorphic-common';
// propertiesToArray(obj: any, parentKey?: string): string[]
const obj = { a: { b: { c: 1 } }, d: 2 };
propertiesToArray(obj); // ['a.b.c', 'd']
// convertObjectToLiteral(obj: any): string
const literal = convertObjectToLiteral({ foo: 'bar', num: 42 });
// Returns string representation of object
// toDecimalBase(num: string | number, base: number): number
toDecimalBase('FF', 16); // 255
toDecimalBase('101', 2); // 5Data Transformation
Enum Utilities
import {
mapEnumToOptions,
mapEnumToLookupArray,
mapEnumToArrayOfValues
} from '@onivoro/isomorphic-common';
enum Status {
ACTIVE = 'active',
INACTIVE = 'inactive',
PENDING = 'pending'
}
// mapEnumToOptions<TEntity extends object>(enumeration: TEntity, includeBlank = true)
const options = mapEnumToOptions(Status);
// [{ display: '', value: '' }, { display: 'ACTIVE', value: 'active' }, ...]
const optionsNoBlank = mapEnumToOptions(Status, false);
// [{ display: 'ACTIVE', value: 'active' }, ...]
// mapEnumToLookupArray<TEntity extends object>(enumeration: TEntity)
const lookupArray = mapEnumToLookupArray(Status);
// Array of lookup objects with display/value pairs
// mapEnumToArrayOfValues<TEntity extends object>(enumeration: TEntity)
const values = mapEnumToArrayOfValues(Status);
// ['active', 'inactive', 'pending']Entity Utilities
import { getUserFullName } from '@onivoro/isomorphic-common';
// getUserFullName(user: TNameable | undefined): string
const user = { firstName: 'John', lastName: 'Doe' };
getUserFullName(user); // 'John Doe'
getUserFullName(undefined); // 'undefined undefined'JSON Utilities
import {
tryJsonParse,
tryJsonStringify
} from '@onivoro/isomorphic-common';
// tryJsonParse<T>(parseable: string | null | undefined): T | null
const parsed = tryJsonParse<{name: string}>('{"name":"John"}'); // {name: 'John'}
const failed = tryJsonParse('invalid json'); // null
// tryJsonStringify<T>(object: T | null | undefined, fmtr?: any, spaces?: number): string | null
const json = tryJsonStringify({name: 'John'}); // '{"name":"John"}'
const formatted = tryJsonStringify({name: 'John'}, null, 2); // Pretty formatted JSONTesting Utilities
import {
arrangeActAssert,
mockCalls
} from '@onivoro/isomorphic-common';
// arrangeActAssert<T>(arrange: () => T, act: (arranged: T) => any, assert: (arranged: T, acted: any) => any)
arrangeActAssert(
() => ({ value: 5 }), // arrange
(arranged) => arranged.value * 2, // act
(arranged, result) => expect(result).toBe(10) // assert
);
// mockCalls(mockFn: jest.Mock): any[]
const mock = jest.fn();
mock('first');
mock('second');
const calls = mockCalls(mock); // ['first', 'second']Utility Functions
import { sleep } from '@onivoro/isomorphic-common';
// sleep(milliseconds = 0): Promise<void>
await sleep(1000); // Wait 1 second
await sleep(); // Wait 0 milliseconds (next tick)Type Definitions
Core Interfaces
import {
ILookup,
TNameable,
IAccessToken,
TCreateable,
TKeysOf,
IEntityProvider,
IAxiosWrappedNestException
} from '@onivoro/isomorphic-common';
// Lookup interface for key-value pairs
const lookup: ILookup<string, number> = {
display: 'Option 1',
value: 1
};
// Nameable type
const user: TNameable = {
firstName: 'John',
lastName: 'Doe'
};
// Access token interface
const token: IAccessToken = {
token: 'jwt-token-here',
expires: 1234567890
};
// Createable type with timestamp
const entity: TCreateable = {
createdAt: new Date()
};
// Type utility for extracting keys with specific value types
type StringKeys = TKeysOf<{a: string, b: number, c: string}, string>; // 'a' | 'c'
// Entity provider interface
const provider: IEntityProvider = {
// Implementation details depend on usage
};
// Axios error wrapper for NestJS
const error: IAxiosWrappedNestException = {
// Error structure for HTTP exception handling
};License
This library is licensed under the MIT License. See the LICENSE file in this package for details.
