|  | 
|  | 1 | +/* global caml_named_value, caml_global_data, caml_string_of_jsstring | 
|  | 2 | + */ | 
|  | 3 | + | 
|  | 4 | +//Provides: caml_wrap_exception const (const) | 
|  | 5 | +//Requires: caml_global_data,caml_string_of_jsstring,caml_named_value | 
|  | 6 | +//Requires: caml_return_exn_constant | 
|  | 7 | +function caml_wrap_exception(e) { | 
|  | 8 | +  if (e instanceof Array) return e; | 
|  | 9 | +  if (e instanceof globalThis.Error && caml_named_value('jsError')) | 
|  | 10 | +    return [0, caml_named_value('jsError'), e]; | 
|  | 11 | +  //fallback: wrapped in Failure | 
|  | 12 | +  return [0, caml_global_data.Failure, caml_string_of_jsstring(String(e))]; | 
|  | 13 | +} | 
|  | 14 | + | 
|  | 15 | +//Provides: caml_raise_with_string (const, const) | 
|  | 16 | +function caml_raise_with_string(tag, msg) { | 
|  | 17 | +  throw globalThis.Error(msg.c); | 
|  | 18 | +} | 
|  | 19 | + | 
|  | 20 | +//Provides: custom_reraise_exn | 
|  | 21 | +function custom_reraise_exn(exn, fallbackMessage) { | 
|  | 22 | +  // this handles the common case of a JS Error reraised by OCaml | 
|  | 23 | +  // in that case, the error will first be wrapped in OCaml with "caml_wrap_exception" | 
|  | 24 | +  // (defined in js_of_ocaml-compiler / jslib.js) | 
|  | 25 | +  // which results in [0, caml_named_value("jsError"), err] | 
|  | 26 | +  var err = exn[2]; | 
|  | 27 | +  if (err instanceof globalThis.Error) { | 
|  | 28 | +    throw err; | 
|  | 29 | +  } else { | 
|  | 30 | +    throw Error(fallbackMessage); | 
|  | 31 | +  } | 
|  | 32 | +} | 
|  | 33 | + | 
|  | 34 | +/** | 
|  | 35 | + * This overrides the handler for uncaught exceptions in js_of_ocaml, | 
|  | 36 | + * fixing the flaw that by default, no actual `Error`s are thrown, | 
|  | 37 | + * but other objects (arrays) which are missing an error trace. | 
|  | 38 | + * This override should make it much easier to find the source of an error. | 
|  | 39 | + */ | 
|  | 40 | +//Provides: caml_fatal_uncaught_exception | 
|  | 41 | +function caml_fatal_uncaught_exception(err) { | 
|  | 42 | +  // first, we search for an actual error inside `err`, | 
|  | 43 | +  // since this is the best thing to throw | 
|  | 44 | +  function throw_errors(err) { | 
|  | 45 | +    if (err instanceof Error) throw err; | 
|  | 46 | +    else if (Array.isArray(err)) { | 
|  | 47 | +      err.forEach(throw_errors); | 
|  | 48 | +    } | 
|  | 49 | +  } | 
|  | 50 | +  throw_errors(err); | 
|  | 51 | +  // if this didn't throw an error, let's log whatever we got | 
|  | 52 | +  console.dir(err, { depth: 20 }); | 
|  | 53 | +  // now, try to collect all strings in the error and throw that | 
|  | 54 | +  function collect_strings(err, acc) { | 
|  | 55 | +    var str = undefined; | 
|  | 56 | +    if (typeof err === 'string') { | 
|  | 57 | +      str = err; | 
|  | 58 | +    } else if (err && err.constructor && err.constructor.name === 'MlBytes') { | 
|  | 59 | +      str = err.c; | 
|  | 60 | +    } else if (Array.isArray(err)) { | 
|  | 61 | +      err.forEach(function (e) { | 
|  | 62 | +        collect_strings(e, acc); | 
|  | 63 | +      }); | 
|  | 64 | +    } | 
|  | 65 | +    if (!str) return acc.string; | 
|  | 66 | +    if (acc.string === undefined) acc.string = str; | 
|  | 67 | +    else acc.string = acc.string + '\n' + str; | 
|  | 68 | +    return acc.string; | 
|  | 69 | +  } | 
|  | 70 | +  var str = collect_strings(err, {}); | 
|  | 71 | +  if (str !== undefined) throw globalThis.Error(str); | 
|  | 72 | +  // otherwise, just throw an unhelpful error | 
|  | 73 | +  console.dir(err, { depth: 10 }); | 
|  | 74 | +  throw globalThis.Error('Unknown error thrown from OCaml'); | 
|  | 75 | +} | 
0 commit comments