UNPKG

vike

Version:

The Framework *You* Control - Next.js & Nuxt alternative for unprecedented flexibility and dependability.

192 lines (191 loc) 6.46 kB
export { assert }; export { assertUsage }; export { assertWarning }; export { assertInfo }; export { getProjectError }; export { addOnBeforeLogHook }; export { getAssertErrMsg }; export { overwriteAssertProductionLogger }; export { isBug }; export { setAlwaysShowStackTrace }; import { assertSingleInstance_onAssertModuleLoad } from './assertSingleInstance.js'; import { createErrorWithCleanStackTrace } from './createErrorWithCleanStackTrace.js'; import { getGlobalObject } from './getGlobalObject.js'; import { isObject } from './isObject.js'; import { PROJECT_VERSION } from './PROJECT_VERSION.js'; import pc from '@brillout/picocolors'; const globalObject = getGlobalObject('utils/assert.ts', { alreadyLogged: new Set(), // Production logger. Overwritten by loggerNotProd.ts in non-production environments. logger(msg, logType) { if (logType === 'info') { console.log(msg); } else { console.warn(msg); } }, showStackTraceList: new WeakSet(), }); assertSingleInstance_onAssertModuleLoad(); const projectTag = `[vike]`; const projectTagWithVersion = `[vike@${PROJECT_VERSION}]`; const bugTag = 'Bug'; const numberOfStackTraceLinesToRemove = 2; function assert(condition, debugInfo) { if (condition) return; const debugStr = (() => { if (!debugInfo) { return null; } const debugInfoSerialized = typeof debugInfo === 'string' ? debugInfo : JSON.stringify(debugInfo); return pc.dim(`Debug info for Vike maintainers (you can ignore this): ${debugInfoSerialized}`); })(); const link = pc.underline('https://github.com/vikejs/vike/issues/new?template=bug.yml'); let errMsg = [ `You stumbled upon a Vike bug. Go to ${link} and copy-paste this error. A maintainer will fix the bug (usually within 24 hours).`, debugStr, ] .filter(Boolean) .join(' '); errMsg = addWhitespace(errMsg); errMsg = addPrefixAssertType(errMsg, bugTag); errMsg = addPrefixProjectName(errMsg, true); const internalError = createErrorWithCleanStackTrace(errMsg, numberOfStackTraceLinesToRemove); globalObject.onBeforeLog?.(); throw internalError; } function assertUsage(condition, errMsg, { showStackTrace, exitOnError } = {}) { if (condition) return; showStackTrace = showStackTrace || globalObject.alwaysShowStackTrace; errMsg = addWhitespace(errMsg); errMsg = addPrefixAssertType(errMsg, 'Wrong Usage'); errMsg = addPrefixProjectName(errMsg); const usageError = createErrorWithCleanStackTrace(errMsg, numberOfStackTraceLinesToRemove); if (showStackTrace) { globalObject.showStackTraceList.add(usageError); } globalObject.onBeforeLog?.(); if (!exitOnError) { throw usageError; } else { console.error(showStackTrace ? usageError : errMsg); process.exit(1); } } function getProjectError(errMsg) { errMsg = addWhitespace(errMsg); errMsg = addPrefixAssertType(errMsg, 'Error'); errMsg = addPrefixProjectName(errMsg); const projectError = createErrorWithCleanStackTrace(errMsg, numberOfStackTraceLinesToRemove); return projectError; } function assertWarning(condition, msg, { onlyOnce, showStackTrace }) { if (condition) return; showStackTrace = showStackTrace || globalObject.alwaysShowStackTrace; msg = addWhitespace(msg); msg = addPrefixAssertType(msg, 'Warning'); msg = addPrefixProjectName(msg); if (onlyOnce) { const { alreadyLogged } = globalObject; const key = onlyOnce === true ? msg : onlyOnce; if (alreadyLogged.has(key)) return; alreadyLogged.add(key); } globalObject.onBeforeLog?.(); if (showStackTrace) { const err = createErrorWithCleanStackTrace(msg, numberOfStackTraceLinesToRemove); globalObject.showStackTraceList.add(err); globalObject.logger(err, 'warn'); } else { globalObject.logger(msg, 'warn'); } } function assertInfo(condition, msg, { onlyOnce }) { if (condition) { return; } msg = addWhitespace(msg); msg = addPrefixProjectName(msg); if (onlyOnce) { const { alreadyLogged } = globalObject; const key = msg; if (alreadyLogged.has(key)) { return; } else { alreadyLogged.add(key); } } globalObject.onBeforeLog?.(); globalObject.logger(msg, 'info'); } function addOnBeforeLogHook(onBeforeLog) { globalObject.onBeforeLog = onBeforeLog; } function addPrefixAssertType(msg, tag) { let prefix = `[${tag}]`; const color = tag === 'Warning' ? 'yellow' : 'red'; prefix = pc.bold(pc[color](prefix)); return `${prefix}${msg}`; } function addWhitespace(msg) { if (msg.startsWith('[')) { return msg; } else { return ` ${msg}`; } } function addPrefixProjectName(msg, showProjectVersion = false) { const prefix = showProjectVersion ? projectTagWithVersion : projectTag; return `${prefix}${msg}`; } function getAssertErrMsg(thing) { let errMsg; let errStack; if (typeof thing === 'string') { errMsg = thing; } else if (isObject(thing) && typeof thing.message === 'string' && typeof thing.stack === 'string') { errMsg = thing.message; errStack = thing.stack; } else { return null; } for (const tag of [projectTagWithVersion, projectTag]) { const showVikeVersion = tag === projectTagWithVersion; const errStackPrefix = `Error: ${tag}`; if (errStack?.startsWith(errStackPrefix)) { if (globalObject.showStackTraceList.has(thing) || isBug(thing)) { const assertMsg = errStack.slice(errStackPrefix.length); return { assertMsg, showVikeVersion }; } } else if (errStack?.includes(tag)) { throw new Error('Internal Vike error'); } if (errMsg?.startsWith(tag)) { const assertMsg = errMsg.slice(tag.length); return { assertMsg, showVikeVersion }; } } return null; } function overwriteAssertProductionLogger(logger) { globalObject.logger = logger; } function isBug(err) { return String(err).includes(`[${bugTag}]`); } // Called upon `DEBUG=vike:error` function setAlwaysShowStackTrace() { globalObject.alwaysShowStackTrace = true; }