Saltarelle / SaltarelleCompiler

C# to JavaScript compiler – Now http://bridge.net
http://saltarelle-compiler.com
Other
297 stars 74 forks source link

Provide toString override for Exception class, otherwise uncaught exceptions will end up logged as [object Object] #443

Open thecoderok opened 8 years ago

thecoderok commented 8 years ago

The default object's toString is to return [object Object] instances of Exception class are just regular objects and because of that they are logged with this exact message. Example:

public class Program
    {
        public static void Main()
        {
            DoOne();
        }

        public static void DoOne()
        {
            DoTwo();
        }

        public static void DoTwo()
        {
            DoThree();
        }

        public static void DoThree()
        {
            throw new Exception("Blah blah");
        }
    }

Will be logged as:

saltarelle2.js:21 Uncaught [object Object]

Error message is lost. Here is how it can be fixed:


 [Mixin("ss.Exception.prototype")]
    [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1300:ElementMustBeginWithUpperCaseLetter",
        Justification = "overriding toString method.")]
    internal static class ExceptionExtensions
    {
        /// <summary>
        /// Mixin to show more informative error messages. In our code we use new Exception(message) to raise exceptions.
        /// However ss.Exception is yet another JS object for JS runtime and it does not know how to nicely get message from it.
        /// So it is using default toString implementation, which just returns '[object Object]'. 
        /// This mixin will override default toString for ss.Exception prototype so it will return message. 
        /// If message is not available, it will return type name which sometimes can be helpful. 
        /// Fallback - return [object Exception]
        /// </summary>
        /// <returns>string representation of the Saltarelle's exception object</returns>
        [PreserveName]
        private static string toString()
        {
            Exception exception = GetThis();
            Debug.Assert(Script.IsValue(exception), "Unable to get exception (this)");
            string message = exception.Message;

            if (string.IsNullOrEmpty(message))
            {
                // That is ok, for example throw new NotImplementedException();
                if (Script.IsValue(exception.GetType()) 
                    && Script.IsValue(exception.GetType().FullName))
                {
                    message = exception.GetType().FullName;
                }
                else
                {
                    // Fallback really, at least more useful than object Object
                    message = "[object Exception]";
                    Debug.Assert(false, "Unable to get both error message and type");
                }
            }

            return message;
        }

        [InlineCode("this")]
        private static Exception GetThis()
        {
            return null;
        }
    }