All Downloads are FREE. Search and download functionalities are using the official Maven repository.

japgolly.scalajs.react.util.ConsoleHijack.scala Maven / Gradle / Ivy

The newest version!
package japgolly.scalajs.react.util

import scala.scalajs.js

final class ConsoleHijack(val config: ConsoleHijack.Config) {
  import ConsoleHijack._
  import ConsoleHijack.Internals._

  def ++(b: ConsoleHijack): ConsoleHijack =
    new ConsoleHijack(config ++ b.config)

  /** Install these hijacks into `console`, execute the given procedure,
    * then restore `console` to the state that it was before this is called.
    */
  def apply[A](a: => A): A = {
    val undo = new js.Array[() => Unit]
    try {
      _install(undo)
      a
    } finally
      undo.foreach(_())
  }

  /** Install these hijacks into `console`.
    *
    * @return A procedure to restore `console` to the state that it was before this is called.
    */
  def install(): () => Unit = {
    val undo = new js.Array[() => Unit]
    _install(undo)
    () => undo.foreach(_())
  }

  private def _install(undo: js.Array[() => Unit]): Unit = {
    val console = js.Dynamic.global.console

    def setHandler(m: Method, h: JsVarargsFn): () => Unit = () => {
      console.updateDynamic(m.name)(h)
    }

    config.foreach { case (method, handler) =>
      val orig = console.selectDynamic(method.name).asInstanceOf[JsVarargsFn]
      undo.push(setHandler(method, orig))
      setHandler(method, mkHandler(handler, orig))()
    }
  }
}

object ConsoleHijack {

  lazy val fatalReactWarnings: ConsoleHijack =
    Error.handleWith { i =>
      if (i.msg.startsWith("Warning: "))
        i.throwException()
      else
        i.fallthrough()
    }

  def apply(cfg: (Method, Handler)*): ConsoleHijack =
    apply(cfg.toMap)

  def apply(cfg: Config): ConsoleHijack =
    new ConsoleHijack(cfg)

  type Config = Map[Method, Handler]

  sealed abstract class Method(final val name: String) {
    final def handleWith(h: Handler): ConsoleHijack =
      ConsoleHijack(this -> h)

    final def throwException =
      handleWith(Handler.throwException)
  }

  case object Debug extends Method("debug")
  case object Error extends Method("error")
  case object Info  extends Method("info")
  case object Log   extends Method("log")
  case object Warn  extends Method("warn")
  case object Trace extends Method("trace")

  final case class Intercept(args: Seq[Any], fallthrough: () => Unit) {
    override def toString = msg

    lazy val msg: String =
      if (args.isEmpty)
        ""
      else {
        @inline def default = args.mkString
        args.head match {
          case fmt: String =>
            try
              Internals.vsprintf(fmt, js.Array(args.tail: _*))
            catch {
              case _: Throwable => default
            }
          case _ => default
        }
      }

    def throwException(): Nothing =
      throw new js.JavaScriptException(msg)
  }

  type Handler = Intercept => Unit

  object Handler {
    @inline def apply(h: Handler): Handler = h

    def throwException: Handler =
      apply(_.throwException())
  }

  private object Internals {

    type VsprintfFn = js.Function2[String, js.Array[Any], String]

    lazy val vsprintf: VsprintfFn = {
      // https://github.com/alexei/sprintf.js/blob/master/dist/sprintf.min.js
      val code = """
        !function(){"use strict";var g={not_string:/[^s]/,not_bool:/[^t]/,not_type:/[^T]/,not_primitive:/[^v]/,number:/[diefg]/,numeric_arg:/[bcdiefguxX]/,json:/[j]/,not_json:/[^j]/,text:/^[^\x25]+/,modulo:/^\x25{2}/,placeholder:/^\x25(?:([1-9]\d*)\$|\(([^)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-gijostTuvxX])/,key:/^([a-z_][a-z_\d]*)/i,key_access:/^\.([a-z_][a-z_\d]*)/i,index_access:/^\[(\d+)\]/,sign:/^[+-]/};function y(e){return function(e,t){var r,n,i,s,a,o,p,c,l,u=1,f=e.length,d="";for(n=0;n>>0).toString(8);break;case"s":r=String(r),r=s.precision?r.substring(0,s.precision):r;break;case"t":r=String(!!r),r=s.precision?r.substring(0,s.precision):r;break;case"T":r=Object.prototype.toString.call(r).slice(8,-1).toLowerCase(),r=s.precision?r.substring(0,s.precision):r;break;case"u":r=parseInt(r,10)>>>0;break;case"v":r=r.valueOf(),r=s.precision?r.substring(0,s.precision):r;break;case"x":r=(parseInt(r,10)>>>0).toString(16);break;case"X":r=(parseInt(r,10)>>>0).toString(16).toUpperCase()}g.json.test(s.type)?d+=r:(!g.number.test(s.type)||c&&!s.sign?l="":(l=c?"+":"-",r=r.toString().replace(g.sign,"")),o=s.pad_char?"0"===s.pad_char?"0":s.pad_char.charAt(1):" ",p=s.width-(l+r).length,a=s.width&&0
      val i = Intercept(args, () => orig(args: _*))
      f(i)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy