Skip to content

Commit f13c0e5

Browse files
committed
Include more detail in error messages. Closes #17
1 parent 60cba90 commit f13c0e5

File tree

8 files changed

+215
-17
lines changed

8 files changed

+215
-17
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (c) 2014, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
using System;
11+
using System.Runtime.Serialization;
12+
13+
namespace React.Exceptions
14+
{
15+
/// <summary>
16+
/// Thrown when an error is encountered while loading a JavaScript file.
17+
/// </summary>
18+
[Serializable]
19+
public class ReactScriptLoadException : ReactException
20+
{
21+
/// <summary>
22+
/// Initializes a new instance of the <see cref="ReactScriptLoadException"/> class.
23+
/// </summary>
24+
/// <param name="message">The message that describes the error.</param>
25+
public ReactScriptLoadException(string message) : base(message) { }
26+
27+
/// <summary>
28+
/// Initializes a new instance of the <see cref="ReactScriptLoadException"/> class.
29+
/// </summary>
30+
/// <param name="message">The error message that explains the reason for the exception.</param>
31+
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>
32+
public ReactScriptLoadException(string message, Exception innerException)
33+
: base(message, innerException) { }
34+
35+
/// <summary>
36+
/// Used by deserialization
37+
/// </summary>
38+
protected ReactScriptLoadException(SerializationInfo info, StreamingContext context)
39+
: base(info, context) { }
40+
}
41+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (c) 2014, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
using System;
11+
using System.Runtime.Serialization;
12+
13+
namespace React.Exceptions
14+
{
15+
/// <summary>
16+
/// Thrown when an error occurs during server rendering of a React component.
17+
/// </summary>
18+
[Serializable]
19+
public class ReactServerRenderingException : ReactException
20+
{
21+
/// <summary>
22+
/// Initializes a new instance of the <see cref="ReactInvalidComponentException"/> class.
23+
/// </summary>
24+
/// <param name="message">The message that describes the error.</param>
25+
public ReactServerRenderingException(string message) : base(message) { }
26+
27+
/// <summary>
28+
/// Initializes a new instance of the <see cref="ReactInvalidComponentException"/> class.
29+
/// </summary>
30+
/// <param name="message">The error message that explains the reason for the exception.</param>
31+
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>
32+
public ReactServerRenderingException(string message, Exception innerException)
33+
: base(message, innerException) { }
34+
35+
/// <summary>
36+
/// Used by deserialization
37+
/// </summary>
38+
protected ReactServerRenderingException(SerializationInfo info, StreamingContext context)
39+
: base(info, context) { }
40+
}
41+
}

src/React/IReactEnvironment.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ public interface IReactEnvironment
4141
/// <returns>Result of the JavaScript code</returns>
4242
T Execute<T>(string code);
4343

44+
/// <summary>
45+
/// Executes the provided JavaScript function, returning a result of the specified type.
46+
/// </summary>
47+
/// <typeparam name="T">Type to return</typeparam>
48+
/// <param name="function">JavaScript function to execute</param>
49+
/// <param name="args">Arguments to pass to function</param>
50+
/// <returns>Result of the JavaScript code</returns>
51+
T Execute<T>(string function, params object[] args);
52+
4453
/// <summary>
4554
/// Attempts to execute the provided JavaScript code using the current engine. If an
4655
/// exception is thrown, retries the execution using a new thread (and hence a new engine)

src/React/JsxTransformer.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,19 @@ public string TransformJsxFile(string filename, bool? useHarmony = null)
9898
}
9999

100100
// 3. Not cached, perform the transformation
101-
return TransformJsxWithHeader(contents, hash, useHarmony);
101+
try
102+
{
103+
return TransformJsxWithHeader(contents, hash, useHarmony);
104+
}
105+
catch (JsxException ex)
106+
{
107+
// Add the filename to the error message
108+
throw new JsxException(string.Format(
109+
"In file \"{0}\": {1}",
110+
filename,
111+
ex.Message
112+
));
113+
}
102114
}
103115
);
104116
}

src/React/React.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@
8383
<Link>Properties\SharedAssemblyVersionInfo.cs</Link>
8484
</Compile>
8585
<Compile Include="AssemblyRegistration.cs" />
86+
<Compile Include="Exceptions\ReactScriptLoadException.cs" />
87+
<Compile Include="Exceptions\ReactServerRenderingException.cs" />
8688
<Compile Include="SystemEnvironmentUtils.cs" />
8789
<Compile Include="Exceptions\JsxUnsupportedEngineException.cs" />
8890
<Compile Include="Exceptions\ReactConfigurationException.cs" />

src/React/ReactComponent.cs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
using System.Linq;
1111
using System.Text.RegularExpressions;
12+
using JavaScriptEngineSwitcher.Core;
1213
using Newtonsoft.Json;
1314
using React.Exceptions;
1415

@@ -68,15 +69,27 @@ public ReactComponent(IReactEnvironment environment, string componentName, strin
6869
public string RenderHtml()
6970
{
7071
EnsureComponentExists();
71-
var html = _environment.Execute<string>(
72-
string.Format("React.renderComponentToString({0})", GetComponentInitialiser())
73-
);
74-
// TODO: Allow changing of the wrapper tag element from a DIV to something else
75-
return string.Format(
76-
"<div id=\"{0}\">{1}</div>",
77-
_containerId,
78-
html
79-
);
72+
try
73+
{
74+
var html = _environment.Execute<string>(
75+
string.Format("React.renderComponentToString({0})", GetComponentInitialiser())
76+
);
77+
// TODO: Allow changing of the wrapper tag element from a DIV to something else
78+
return string.Format(
79+
"<div id=\"{0}\">{1}</div>",
80+
_containerId,
81+
html
82+
);
83+
}
84+
catch (JsRuntimeException ex)
85+
{
86+
throw new ReactServerRenderingException(string.Format(
87+
"Error while rendering \"{0}\" to \"{2}\": {1}",
88+
_componentName,
89+
ex.Message,
90+
_containerId
91+
));
92+
}
8093
}
8194

8295
/// <summary>

src/React/ReactEnvironment.cs

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using System.Text;
1515
using System.Threading;
1616
using JavaScriptEngineSwitcher.Core;
17+
using React.Exceptions;
1718

1819
namespace React
1920
{
@@ -169,7 +170,18 @@ private void EnsureUserScriptsLoaded()
169170
foreach (var file in _config.Scripts)
170171
{
171172
var contents = JsxTransformer.TransformJsxFile(file);
172-
Execute(contents);
173+
try
174+
{
175+
Execute(contents);
176+
}
177+
catch (JsRuntimeException ex)
178+
{
179+
throw new ReactScriptLoadException(string.Format(
180+
"Error while loading \"{0}\": {1}",
181+
file,
182+
ex.Message
183+
));
184+
}
173185
}
174186
Engine.SetVariableValue(USER_SCRIPTS_LOADED_KEY, true);
175187
}
@@ -180,7 +192,14 @@ private void EnsureUserScriptsLoaded()
180192
/// <param name="code">JavaScript to execute</param>
181193
public void Execute(string code)
182194
{
183-
Engine.Execute(code);
195+
try
196+
{
197+
Engine.Execute(code);
198+
}
199+
catch (JsRuntimeException ex)
200+
{
201+
throw WrapJavaScriptRuntimeException(ex);
202+
}
184203
}
185204

186205
/// <summary>
@@ -191,7 +210,33 @@ public void Execute(string code)
191210
/// <returns>Result of the JavaScript code</returns>
192211
public T Execute<T>(string code)
193212
{
194-
return Engine.Evaluate<T>(code);
213+
try
214+
{
215+
return Engine.Evaluate<T>(code);
216+
}
217+
catch (JsRuntimeException ex)
218+
{
219+
throw WrapJavaScriptRuntimeException(ex);
220+
}
221+
}
222+
223+
/// <summary>
224+
/// Executes the provided JavaScript function, returning a result of the specified type.
225+
/// </summary>
226+
/// <typeparam name="T">Type to return</typeparam>
227+
/// <param name="function">JavaScript function to execute</param>
228+
/// <param name="args">Arguments to pass to function</param>
229+
/// <returns>Result of the JavaScript code</returns>
230+
public T Execute<T>(string function, params object[] args)
231+
{
232+
try
233+
{
234+
return Engine.CallFunction<T>(function, args);
235+
}
236+
catch (JsRuntimeException ex)
237+
{
238+
throw WrapJavaScriptRuntimeException(ex);
239+
}
195240
}
196241

197242
/// <summary>
@@ -201,7 +246,14 @@ public T Execute<T>(string code)
201246
/// <returns><c>true</c> if the variable exists; <c>false</c> otherwise</returns>
202247
public bool HasVariable(string name)
203248
{
204-
return Engine.HasVariable(name);
249+
try
250+
{
251+
return Engine.HasVariable(name);
252+
}
253+
catch (JsRuntimeException ex)
254+
{
255+
throw WrapJavaScriptRuntimeException(ex);
256+
}
205257
}
206258

207259
/// <summary>
@@ -278,7 +330,7 @@ public T ExecuteWithLargerStackIfRequired<T>(string function, params object[] ar
278330
{
279331
try
280332
{
281-
return Engine.CallFunction<T>(function, args);
333+
return Execute<T>(function, args);
282334
}
283335
catch (Exception)
284336
{
@@ -292,7 +344,7 @@ public T ExecuteWithLargerStackIfRequired<T>(string function, params object[] ar
292344
try
293345
{
294346
// New engine will be created here (as this is a new thread)
295-
result = Engine.CallFunction<T>(function, args);
347+
result = Execute<T>(function, args);
296348
}
297349
catch (Exception threadEx)
298350
{
@@ -336,5 +388,29 @@ public void Dispose()
336388
{
337389
_engineFactory.DisposeEngineForCurrentThread();
338390
}
391+
392+
/// <summary>
393+
/// Updates the Message of a <see cref="JsRuntimeException"/> to be more useful, containing
394+
/// the line and column numbers.
395+
/// </summary>
396+
/// <param name="ex">Original exception</param>
397+
/// <returns>New exception</returns>
398+
private JsRuntimeException WrapJavaScriptRuntimeException(JsRuntimeException ex)
399+
{
400+
return new JsRuntimeException(string.Format(
401+
"{0}\r\nLine: {1}\r\nColumn:{2}",
402+
ex.Message,
403+
ex.LineNumber,
404+
ex.ColumnNumber
405+
), ex.EngineName, ex.EngineVersion)
406+
{
407+
ErrorCode = ex.ErrorCode,
408+
Category = ex.Category,
409+
LineNumber = ex.LineNumber,
410+
ColumnNumber = ex.ColumnNumber,
411+
SourceFragment = ex.SourceFragment,
412+
Source = ex.Source,
413+
};
414+
}
339415
}
340416
}

src/React/Resources/shims.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,9 @@ if (!Object.freeze) {
2020
}
2121

2222
function ReactNET_transform(input, harmony) {
23-
return global.JSXTransformer.transform(input, { harmony: !!harmony }).code;
23+
try {
24+
return global.JSXTransformer.transform(input, { harmony: !!harmony }).code;
25+
} catch (ex) {
26+
throw new Error(ex.message + " (at line " + ex.lineNumber + " column " + ex.column + ")");
27+
}
2428
}

0 commit comments

Comments
 (0)