UNPKG

@naturalcycles/js-lib

Version:

Standard library for universal (browser + Node.js) javascript

123 lines (122 loc) 4.34 kB
import { _deepEquals } from '../object/deepEquals.js'; import { _stringify } from '../string/stringify.js'; import { _isBackendErrorResponseObject, _isErrorObject, AssertionError } from './error.util.js'; /** * Evaluates the `condition` (casts it to Boolean). * Expects it to be truthy, otherwise throws AppError. * * Should be used NOT for "expected" / user-facing errors, but * vice-versa - for completely unexpected and 100% buggy "should never happen" cases. * * It'll result in http 500 on the server (cause that's the right code for "unexpected" errors). * Pass { backendResponseStatusCode: x } at errorData argument to override the http code (will be picked up by backend-lib). * * API is similar to Node's assert(), except: * 1. Throws js-lib's AppError * 2. Has a default message, if not provided * * Since 2024-07-10 it no longer sets `userFriendly: true` by default. */ export function _assert(condition, // will be evaluated as Boolean message, errorData) { if (!condition) { throw new AssertionError(message || 'condition failed', { ...errorData, }); } } /** * Like _assert(), but prints more helpful error message. * API is similar to Node's assert.equals(). * * Does SHALLOW, but strict equality (===), use _assertDeepEquals() for deep equality. */ export function _assertEquals(actual, expected, message, errorData) { if (actual !== expected) { const msg = message || ['not equal', `expected: ${_stringify(expected)}`, `got : ${_stringify(actual)}`] .filter(Boolean) .join('\n'); throw new AssertionError(msg, { ...errorData, }); } } /** * Like _assert(), but prints more helpful error message. * API is similar to Node's assert.deepEquals(). * * Does DEEP equality via _deepEquals() */ export function _assertDeepEquals(actual, expected, message, errorData) { if (!_deepEquals(actual, expected)) { const msg = message || ['not deeply equal', `expected: ${_stringify(expected)}`, `got : ${_stringify(actual)}`] .filter(Boolean) .join('\n'); throw new AssertionError(msg, { ...errorData, }); } } export function _assertIsError(err, errorClass = Error) { if (!(err instanceof errorClass)) { throw new AssertionError(`Expected to be instanceof ${errorClass.name}, actual typeof: ${typeof err}`); } } /** * Asserts that passed object is indeed an Error of defined ErrorClass. * If yes - returns peacefully (with TypeScript assertion). * In not - throws (re-throws) that error up. */ export function _assertErrorClassOrRethrow(err, errorClass) { if (!(err instanceof errorClass)) { // re-throw throw err; } } export function _assertIsErrorObject(obj) { if (!_isErrorObject(obj)) { throw new AssertionError(`Expected to be ErrorObject, actual typeof: ${typeof obj}`); } } export function _assertIsBackendErrorResponseObject(obj) { if (!_isBackendErrorResponseObject(obj)) { throw new AssertionError(`Expected to be BackendErrorResponseObject, actual typeof: ${typeof obj}`); } } export function _assertIsString(v, message) { _assertTypeOf(v, 'string', message); } export function _assertIsNumber(v, message) { _assertTypeOf(v, 'number', message); } export function _assertTypeOf(v, expectedType, message) { if (typeof v !== expectedType) { const msg = message || `Expected typeof ${expectedType}, actual typeof: ${typeof v}`; throw new AssertionError(msg); } } /** * Casts an arbitrary number as UnixTimestamp. * Right now does not perform any validation (unlike `asUnixTimestamp2000`), * but only type casting. */ export function asUnixTimestamp(n) { return n; } const TS_2500 = 16725225600; // 2500-01-01 const TS_2000 = 946684800; // 2000-01-01 /** * Casts an arbitrary number as UnixTimestamp2000. * Throws if the number is not inside 2000-01-01 and 2500-01-01 time interval, * which would indicate a bug. */ export function asUnixTimestamp2000(n) { if (!n || n < TS_2000 || n > TS_2500) { throw new AssertionError(`Number is not a valid UnixTimestamp2000: ${n}`, { fingerprint: 'asUnixTimestamp2000', }); } return n; }