Skip to content

Commit 7fe48f8

Browse files
committed
Move JSX Transformer to separate class
1 parent 9bfa992 commit 7fe48f8

File tree

9 files changed

+228
-68
lines changed

9 files changed

+228
-68
lines changed

src/React.Sample.Cassette/React.Sample.Cassette.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@
211211
</FlavorProperties>
212212
</VisualStudio>
213213
</ProjectExtensions>
214-
<Target Name="Bundle" AfterTargets="Build">
214+
<Target Name="Bundle" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
215215
<Exec Command="&quot;$(msbuildtoolspath)\msbuild.exe&quot; $(ProjectDirectory)cassette.targets /p:OutputPath=$(OutputPath) /t:Bundle /nr:false" />
216216
</Target>
217217
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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 Moq;
11+
using Xunit;
12+
13+
namespace React.Tests.Core
14+
{
15+
public class JsxTransformerTests
16+
{
17+
[Fact]
18+
public void ShouldNotTransformJsxIfNoAnnotationPresent()
19+
{
20+
var environment = new Mock<IReactEnvironment>();
21+
var cache = new Mock<ICache>();
22+
var fileSystem = new Mock<IFileSystem>();
23+
var jsxTransformer = new JsxTransformer(
24+
environment.Object,
25+
cache.Object,
26+
fileSystem.Object
27+
);
28+
const string input = "<div>Hello World</div>";
29+
30+
var output = jsxTransformer.TransformJsx(input);
31+
Assert.Equal(input, output);
32+
}
33+
34+
[Fact]
35+
public void ShouldTransformJsxIfAnnotationPresent()
36+
{
37+
var environment = new Mock<IReactEnvironment>();
38+
var cache = new Mock<ICache>();
39+
var fileSystem = new Mock<IFileSystem>();
40+
var jsxTransformer = new JsxTransformer(
41+
environment.Object,
42+
cache.Object,
43+
fileSystem.Object
44+
);
45+
const string input = "/** @jsx React.DOM */ <div>Hello World</div>";
46+
jsxTransformer.TransformJsx(input);
47+
48+
environment.Verify(x => x.ExecuteWithLargerStackIfRequired<string>(
49+
@"global.JSXTransformer.transform(""/** @jsx React.DOM */ <div>Hello World</div>"").code"
50+
));
51+
}
52+
}
53+
}

src/React.Tests/Core/ReactEnvironmentTest.cs

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,6 @@ namespace React.Tests.Core
1616
{
1717
public class ReactEnvironmentTest
1818
{
19-
[Fact]
20-
public void ShouldNotTransformJsxIfNoAnnotationPresent()
21-
{
22-
var mocks = new Mocks();
23-
var environment = mocks.CreateReactEnvironment();
24-
var input = "<div>Hello World</div>";
25-
26-
var output = environment.TransformJsx(input);
27-
Assert.Equal(input, output);
28-
}
29-
30-
[Fact]
31-
public void ShouldTransformJsxIfAnnotationPresent()
32-
{
33-
var mocks = new Mocks();
34-
var environment = mocks.CreateReactEnvironment();
35-
36-
const string input = "/** @jsx React.DOM */ <div>Hello World</div>";
37-
environment.TransformJsx(input);
38-
39-
mocks.Engine.Verify(x => x.Evaluate<string>(
40-
@"global.JSXTransformer.transform(""/** @jsx React.DOM */ <div>Hello World</div>"").code"
41-
));
42-
}
43-
4419
[Fact]
4520
public void ExecuteWithLargerStackIfRequiredWithNoNewThread()
4621
{

src/React.Tests/React.Tests.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<DefineConstants>DEBUG;TRACE</DefineConstants>
2121
<ErrorReport>prompt</ErrorReport>
2222
<WarningLevel>4</WarningLevel>
23-
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
23+
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
2424
<NoWarn>1607</NoWarn>
2525
</PropertyGroup>
2626
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
@@ -67,6 +67,7 @@
6767
<Link>Properties\SharedAssemblyVersionInfo.cs</Link>
6868
</Compile>
6969
<Compile Include="Core\JavaScriptEngineFactoryTest.cs" />
70+
<Compile Include="Core\JsxTransformerTests.cs" />
7071
<Compile Include="Core\ReactComponentTest.cs" />
7172
<Compile Include="Properties\AssemblyInfo.cs" />
7273
<Compile Include="Core\ReactEnvironmentTest.cs" />

src/React/IJsxTransformer.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
namespace React
11+
{
12+
/// <summary>
13+
/// Handles compiling JSX to JavaScript.
14+
/// </summary>
15+
public interface IJsxTransformer
16+
{
17+
/// <summary>
18+
/// Loads a JSX file. Results of the JSX to JavaScript transformation are cached.
19+
/// </summary>
20+
/// <param name="filename">Name of the file to load</param>
21+
/// <returns>File contents</returns>
22+
string LoadJsxFile(string filename);
23+
24+
/// <summary>
25+
/// Transforms JSX into regular JavaScript. The result is not cached. Use
26+
/// <see cref="JsxTransformer.LoadJsxFile"/> if loading from a file since this will cache the result.
27+
/// </summary>
28+
/// <param name="input">JSX</param>
29+
/// <returns>JavaScript</returns>
30+
string TransformJsx(string input);
31+
}
32+
}

src/React/IReactEnvironment.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ public interface IReactEnvironment
2929
/// <returns>Result of the JavaScript code</returns>
3030
T Execute<T>(string code);
3131

32+
/// <summary>
33+
/// Attempts to execute the provided JavaScript code using the current engine. If an
34+
/// exception is thrown, retries the execution using a new thread (and hence a new engine)
35+
/// with a larger maximum stack size.
36+
/// This is required because JSXTransformer uses a huge stack which ends up being larger
37+
/// than what ASP.NET allows by default (256 KB).
38+
/// </summary>
39+
/// <typeparam name="T">Type to return from JavaScript call</typeparam>
40+
/// <param name="code">JavaScript code to execute</param>
41+
/// <returns>Result returned from JavaScript code</returns>
42+
T ExecuteWithLargerStackIfRequired<T>(string code);
43+
3244
/// <summary>
3345
/// Determines if the specified variable exists in the JavaScript engine
3446
/// </summary>

src/React/JsxTransformer.cs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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.Diagnostics;
12+
using Newtonsoft.Json;
13+
using React.Exceptions;
14+
15+
namespace React
16+
{
17+
/// <summary>
18+
/// Handles compiling JSX to JavaScript.
19+
/// </summary>
20+
public class JsxTransformer : IJsxTransformer
21+
{
22+
/// <summary>
23+
/// Cache key for JSX to JavaScript compilation
24+
/// </summary>
25+
private const string JSX_CACHE_KEY = "JSX_{0}";
26+
27+
/// <summary>
28+
/// Environment this JSX Transformer has been created in
29+
/// </summary>
30+
private readonly IReactEnvironment _environment;
31+
/// <summary>
32+
/// Cache used for storing compiled JSX
33+
/// </summary>
34+
private readonly ICache _cache;
35+
/// <summary>
36+
/// File system wrapper
37+
/// </summary>
38+
private readonly IFileSystem _fileSystem;
39+
40+
/// <summary>
41+
/// Initializes a new instance of the <see cref="JsxTransformer"/> class.
42+
/// </summary>
43+
/// <param name="environment">The ReactJS.NET environment</param>
44+
/// <param name="cache">The cache to use for JSX compilation</param>
45+
/// <param name="fileSystem">File system wrapper</param>
46+
public JsxTransformer(IReactEnvironment environment, ICache cache, IFileSystem fileSystem)
47+
{
48+
_environment = environment;
49+
_cache = cache;
50+
_fileSystem = fileSystem;
51+
}
52+
53+
/// <summary>
54+
/// Loads a JSX file. Results of the JSX to JavaScript transformation are cached.
55+
/// </summary>
56+
/// <param name="filename">Name of the file to load</param>
57+
/// <returns>File contents</returns>
58+
public string LoadJsxFile(string filename)
59+
{
60+
var fullPath = _fileSystem.MapPath(filename);
61+
62+
return _cache.GetOrInsert(
63+
key: string.Format(JSX_CACHE_KEY, filename),
64+
slidingExpiration: TimeSpan.FromMinutes(30),
65+
cacheDependencyFiles: new[] { fullPath },
66+
getData: () =>
67+
{
68+
Trace.WriteLine(string.Format("Parsing JSX from {0}", filename));
69+
var contents = _fileSystem.ReadAsString(filename);
70+
return TransformJsx(contents);
71+
}
72+
);
73+
}
74+
75+
/// <summary>
76+
/// Transforms JSX into regular JavaScript. The result is not cached. Use
77+
/// <see cref="LoadJsxFile"/> if loading from a file since this will cache the result.
78+
/// </summary>
79+
/// <param name="input">JSX</param>
80+
/// <returns>JavaScript</returns>
81+
public string TransformJsx(string input)
82+
{
83+
// Just return directly if there's no JSX annotation
84+
if (!input.Contains("@jsx"))
85+
{
86+
return input;
87+
}
88+
89+
try
90+
{
91+
var encodedInput = JsonConvert.SerializeObject(input);
92+
var output = _environment.ExecuteWithLargerStackIfRequired<string>(string.Format(
93+
"global.JSXTransformer.transform({0}).code",
94+
encodedInput
95+
));
96+
return output;
97+
}
98+
catch (Exception ex)
99+
{
100+
throw new JsxException(ex.Message, ex);
101+
}
102+
}
103+
}
104+
}

src/React/React.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,14 @@
8383
<Compile Include="ICache.cs" />
8484
<Compile Include="IFileSystem.cs" />
8585
<Compile Include="IJavaScriptEngineFactory.cs" />
86+
<Compile Include="IJsxTransformer.cs" />
8687
<Compile Include="Initializer.cs" />
8788
<Compile Include="IReactComponent.cs" />
8889
<Compile Include="IReactEnvironment.cs" />
8990
<Compile Include="IReactSiteConfiguration.cs" />
9091
<Compile Include="Exceptions\JsxException.cs" />
9192
<Compile Include="JavaScriptEngineFactory.cs" />
93+
<Compile Include="JsxTransformer.cs" />
9294
<Compile Include="NullCache.cs" />
9395
<Compile Include="Properties\AssemblyInfo.cs" />
9496
<Compile Include="ReactComponent.cs" />

0 commit comments

Comments
 (0)