UNPKG

@jovian/type-tools

Version:

TypeTools is a Typescript library for providing extensible tooling runtime validations and type helpers.

178 lines (158 loc) 5.88 kB
/* Jovian (c) 2020, License: MIT */ import { spotfull, StackUtilSourceMapEnv } from "./stack.util"; declare var process; declare var window; export const isNodeJs = (typeof process !== 'undefined') && (process.release.name === 'node'); export const debugLogHead = `\n-------------------------------- DEBUG_LOG_START --------------------------------\n`; export const debugLogTail = `\n-------------------------------- DEBUG_LOG_END --------------------------------\n`; const colorWhite = '\x1b[37m%s\x1b[0m'; const colorYellow = '\x1b[33m%s\x1b[0m'; const colorGray = '\x1b[90m%s\x1b[0m'; const colorEnd = `\x1b[0m`; export const dpColor = { colorEnabled: false, color: colorWhite, metaColorEnabled: isNodeJs, metaColor: colorGray, end: colorEnd, }; export const ansiColorMap = { // black: { fg: 30, bg: 40 } white: { fg: 37, bg: 47, normal: colorWhite }, yellow: { fg: 33, bg: 43, normal: colorYellow }, }; // function getColor(color) function dpDisplay(source: string, color: keyof typeof ansiColorMap, sectioned: boolean, args: any[]) { let activeColor: string; if (color && !activeColor) { activeColor = ansiColorMap?.[color]?.normal; } if (!activeColor) { activeColor = dpColor.color; } sectioned ? console.group() : null; if (!StackUtilSourceMapEnv.isBrowser) { dpColor.metaColorEnabled ? console.log(dpColor.metaColor, `${sectioned ? debugLogHead : ''}src: ${source}${sectioned ? '\n' : ''}`, dpColor.end) : console.log(`${sectioned ? debugLogHead : ''}src: ${source}${sectioned ? '\n' : ''}`); console.group(); } else { console.group(`${sectioned ? debugLogHead : ''}src: ${source}${sectioned ? '\n' : ''}`); } dpColor.colorEnabled ? console.log(activeColor, ...args, dpColor.end) : console.log(...args); console.groupEnd(); dpColor.metaColorEnabled ? console.log(dpColor.metaColor, `${sectioned ? debugLogTail : ''}`, dpColor.end) : sectioned ? console.log(debugLogTail) : null; sectioned ? console.groupEnd() : null; } const dptRegistry: {[name: string]: { start?: number; iterationCount?: number } } = {}; /** * Debug print timer */ export function dpt(name?: string, iterationCount?: number, ...args) { if (!name) { name = 'unnamed'; } const t = Date.now(); if (!dptRegistry[name]) { dptRegistry[name] = { start: t, iterationCount }; args.unshift(`dpt timer '${name}' started`); dpDisplay(spotfull(new Error, 2), null, false, args); } else { const reg = dptRegistry[name]; const startT = reg.start; const iterationCount = reg.iterationCount; delete dptRegistry[name]; const delta = t - startT; const perItemDuration = iterationCount ? ` (${delta * 1000 / iterationCount} us/count)` : ''; args.unshift(`dpt timer '${name}' ended; total ${delta} ms taken${perItemDuration}`); dpDisplay(spotfull(new Error, 2), null, false, args); } } /** * Debug print */ export function dpa(...args) { dpDisplay(new Error().stack, null, false, args); } /** * Debug print */ export function dp(...args) { dpDisplay(spotfull(new Error, 2), null, false, args); } /** * Debug print */ export function dp2(...args) { dpDisplay(spotfull(new Error, 3), null, false, args); } /** * Debug print */ export function dp3(...args) { dpDisplay(spotfull(new Error, 4), null, false, args); } /** * Debug print */ export function dp4(...args) { dpDisplay(spotfull(new Error, 5), null, false, args); } /** * Debug print section */ export function dphead(headerSectionName: string) { const sectionDivider = '================================================================'; dpDisplay(spotfull(new Error, 2), null, false, [ colorYellow, `${sectionDivider}\n\n ${headerSectionName}\n\n${sectionDivider}`, colorEnd, ]); } let displayClassSettings = false; let showClassSettingsStack = false; let withinClassSettingsCall = false; const classSettingsSources: Error[] = []; export const ClassSettings = { display: () => { displayClassSettings = true; const e = new Error(`[ClassSetting] display`); showClassSettingsStack ? dp2(e) : dp2(e.message); }, showStack: () => { displayClassSettings = true; showClassSettingsStack = true; const e = new Error(`[ClassSettings] showStack`); classSettingsSources.push(e); dp2(e); }, set: (fn: Function) => { if (withinClassSettingsCall) { throw new Error(`[ClassSettings] Cannot ClassSettings.set within ClassSettings.set`); } withinClassSettingsCall = true; if (displayClassSettings) { const e = new Error(`[ClassSettings] modified: ${fn}`); classSettingsSources.push(e); showClassSettingsStack ? dp2(e) : dp2(e.message); } let settingError: Error; try { fn(); } catch (e) { settingError = e; } withinClassSettingsCall = false; if (settingError) { throw settingError; } }, protect: <T>(type: T, ...settings: (keyof T)[]) => { const protectedList: (keyof T)[] = []; if (settings.length === 0) { settings = Object.keys(type) as any; } for (const setting of settings) { const settingValue = type[setting] as any; if (settingValue && settingValue.call && settingValue.apply) { continue; } protectSetting(type, setting); protectedList.push(setting); } return protectedList; } }; Object.freeze(ClassSettings); function protectSetting<T>(type: T, setting: keyof T) { let settingValue = type[setting]; const typename = (type as any).name; const settingPath = typename ? `${typename}.${String(setting)}` : setting; Object.defineProperty(type, setting, { get() { return settingValue; }, set(newValue) { if (!withinClassSettingsCall) { throw new Error(`[ClassSettings] Cannot change protected config '${String(settingPath)}' outside ClassSettings.set`); } settingValue = newValue; }, }); }