| // Copyright (c) 2022, Compiler Explorer Authors |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // * Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| // POSSIBILITY OF SUCH DAMAGE. |
| |
| import {isString} from '../lib/common-utils'; |
| import stacktrace from '../lib/stacktrace'; |
| |
| // This file defines three assert utilities: |
| // assert(condition, message?, extra_info...?): asserts condition |
| // unwrap(x: T | undefined | null, message?, extra_info...?): T |
| // assert_type(x, class, message?, extra_info...?) |
| |
| function get_diagnostic() { |
| const e = new Error(); // eslint-disable-line unicorn/error-message |
| const trace = stacktrace.parse(e); |
| if (trace.length >= 4) { |
| const invoker_frame = trace[3]; |
| if (invoker_frame.fileName && invoker_frame.lineNumber) { |
| return { |
| file: invoker_frame.fileName, |
| line: invoker_frame.lineNumber, |
| }; |
| } |
| } |
| } |
| |
| function fail(fail_message: string, user_message: string | undefined, args: any[]): never { |
| // Assertions will look like: |
| // Assertion failed |
| // Assertion failed: Foobar |
| // Assertion failed: Foobar, [{"foo": "bar"}] |
| let assert_line = fail_message; |
| if (user_message) { |
| assert_line += `: ${user_message}`; |
| } |
| if (args.length > 0) { |
| try { |
| assert_line += ', ' + JSON.stringify(args); |
| } catch (e) {} |
| } |
| |
| const diagnostic = get_diagnostic(); |
| if (diagnostic) { |
| throw new Error(assert_line + `, at ${diagnostic.file}:${diagnostic.line}`); |
| } else { |
| throw new Error(assert_line); |
| } |
| } |
| |
| export function assert<C>(c: C, message?: string, ...extra_info: any[]): asserts c { |
| if (!c) { |
| fail('Assertion failed', message, extra_info); |
| } |
| } |
| |
| export function unwrap<T>(x: T | undefined | null, message?: string, ...extra_info: any[]): T { |
| if (x === undefined || x === null) { |
| fail('Unwrap failed', message, extra_info); |
| } |
| return x; |
| } |
| |
| // This mainly a utility for JQuery.val(): string | number | string[] | undefined, in our code we typically want a |
| // single string. |
| // T is syntax sugar for unwrapping to a string union |
| export function unwrapString<T extends string>(x: any, message?: string, ...extra_info: any[]): T { |
| if (!isString(x)) { |
| fail('String unwrap failed', message, extra_info); |
| } |
| return x as T; |
| } |