const CLOSEBUTTON = ``; type MessageType = 'text' | 'html'; /** * These error codes are used to identify the type of error that occurred. * @see https://docs.pyscript.net/latest/reference/exceptions.html?highlight=errors */ export enum ErrorCode { GENERIC = 'PY0000', // Use this only for development then change to a more specific error code FETCH_ERROR = 'PY0001', FETCH_NAME_ERROR = 'PY0002', // Currently these are created depending on error code received from fetching FETCH_UNAUTHORIZED_ERROR = 'PY0401', FETCH_FORBIDDEN_ERROR = 'PY0403', FETCH_NOT_FOUND_ERROR = 'PY0404', FETCH_SERVER_ERROR = 'PY0500', FETCH_UNAVAILABLE_ERROR = 'PY0503', BAD_CONFIG = 'PY1000', MICROPIP_INSTALL_ERROR = 'PY1001', BAD_PLUGIN_FILE_EXTENSION = 'PY2000', NO_DEFAULT_EXPORT = 'PY2001', TOP_LEVEL_AWAIT = 'PY9000', } export class UserError extends Error { /** * `isinstance` doesn't work correctly across multiple realms. * Hence, `$$isUserError` flag / marker is used to identify a `UserError`. */ $$isUserError: boolean; constructor(public errorCode: ErrorCode, message: string, public messageType: MessageType = 'text') { super(`(${errorCode}): ${message}`); this.name = 'UserError'; this.$$isUserError = true; } } export class FetchError extends UserError { constructor(errorCode: ErrorCode, message: string) { super(errorCode, message); this.name = 'FetchError'; } } export class InstallError extends UserError { constructor(errorCode: ErrorCode, message: string) { super(errorCode, message); this.name = 'InstallError'; } } export function _createAlertBanner( message: string, level: 'error' | 'warning' = 'error', messageType: MessageType = 'text', logMessage = true, ) { switch (`log-${level}-${logMessage}`) { case 'log-error-true': console.error(message); break; case 'log-warning-true': console.warn(message); break; } const content = messageType === 'html' ? 'innerHTML' : 'textContent'; const banner = Object.assign(document.createElement('div'), { className: `alert-banner py-${level}`, [content]: message, }); if (level === 'warning') { const closeButton = Object.assign(document.createElement('button'), { id: 'alert-close-button', innerHTML: CLOSEBUTTON, }); banner.appendChild(closeButton).addEventListener('click', () => { banner.remove(); }); } document.body.prepend(banner); }