UNPKG

ran-boilerplate

Version:

React . Apollo (GraphQL) . Next.js Toolkit

163 lines (142 loc) 4.49 kB
/** * Copyright 2017 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Standardized Firebase Error. * * Usage: * * // Typescript string literals for type-safe codes * type Err = * 'unknown' | * 'object-not-found' * ; * * // Closure enum for type-safe error codes * // at-enum {string} * var Err = { * UNKNOWN: 'unknown', * OBJECT_NOT_FOUND: 'object-not-found', * } * * let errors: Map<Err, string> = { * 'generic-error': "Unknown error", * 'file-not-found': "Could not find file: {$file}", * }; * * // Type-safe function - must pass a valid error code as param. * let error = new ErrorFactory<Err>('service', 'Service', errors); * * ... * throw error.create(Err.GENERIC); * ... * throw error.create(Err.FILE_NOT_FOUND, {'file': fileName}); * ... * // Service: Could not file file: foo.txt (service/file-not-found). * * catch (e) { * assert(e.message === "Could not find file: foo.txt."); * if (e.code === 'service/file-not-found') { * console.log("Could not read file: " + e['file']); * } * } */ export type ErrorList<T> = { [code: string]: string }; const ERROR_NAME = 'FirebaseError'; export interface StringLike { toString: () => string; } let captureStackTrace: (obj: Object, fn?: Function) => void = (Error as any) .captureStackTrace; // Export for faking in tests export function patchCapture(captureFake?: any): any { let result: any = captureStackTrace; captureStackTrace = captureFake; return result; } export interface FirebaseError { // Unique code for error - format is service/error-code-string code: string; // Developer-friendly error message. message: string; // Always 'FirebaseError' name: string; // Where available - stack backtrace in a string stack: string; } export class FirebaseError implements FirebaseError { public stack: string; public name: string; constructor(public code: string, public message: string) { let stack: string; // We want the stack value, if implemented by Error if (captureStackTrace) { // Patches this.stack, omitted calls above ErrorFactory#create captureStackTrace(this, ErrorFactory.prototype.create); } else { let err = Error.apply(this, arguments); this.name = ERROR_NAME; // Make non-enumerable getter for the property. Object.defineProperty(this, 'stack', { get: function() { return err.stack; } }); } } } // Back-door inheritance FirebaseError.prototype = Object.create(Error.prototype) as FirebaseError; FirebaseError.prototype.constructor = FirebaseError; (FirebaseError.prototype as any).name = ERROR_NAME; export class ErrorFactory<T extends string> { // Matches {$name}, by default. public pattern = /\{\$([^}]+)}/g; constructor( private service: string, private serviceName: string, private errors: ErrorList<T> ) { // empty } create(code: T, data?: { [prop: string]: StringLike }): FirebaseError { if (data === undefined) { data = {}; } let template = this.errors[code as string]; let fullCode = this.service + '/' + code; let message: string; if (template === undefined) { message = 'Error'; } else { message = template.replace(this.pattern, (match, key) => { let value = data![key]; return value !== undefined ? value.toString() : '<' + key + '?>'; }); } // Service: Error message (service/code). message = this.serviceName + ': ' + message + ' (' + fullCode + ').'; let err = new FirebaseError(fullCode, message); // Populate the Error object with message parts for programmatic // accesses (e.g., e.file). for (let prop in data) { if (!data.hasOwnProperty(prop) || prop.slice(-1) === '_') { continue; } (err as any)[prop] = data[prop]; } return err; } }