diff --git a/src/.editorconfig b/src/.editorconfig
new file mode 100644
index 000000000..a127657e3
--- /dev/null
+++ b/src/.editorconfig
@@ -0,0 +1,13 @@
+# editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+end_of_line = crlf
+indent_size = 4
+indent_style = tab
+insert_final_newline = true
+
+[*.json]
+indent_size = 2
+indent_style = space
\ No newline at end of file
diff --git a/src/React.Core/Babel.cs b/src/React.Core/Babel.cs
index b42892473..9c816a5ca 100644
--- a/src/React.Core/Babel.cs
+++ b/src/React.Core/Babel.cs
@@ -350,12 +350,37 @@ string filename
)
{
var outputPath = GetOutputPath(filename);
- var sourceMapPath = GetSourceMapOutputPath(filename);
var contents = _fileSystem.ReadAsString(filename);
+ if (CacheIsValid(contents, outputPath))
+ return outputPath;
+
var result = TransformWithHeader(filename, contents, null);
+
+ var sourceMapPath = GetSourceMapOutputPath(filename);
_fileSystem.WriteAsString(outputPath, result.Code);
- _fileSystem.WriteAsString(sourceMapPath, result.SourceMap == null ? string.Empty : result.SourceMap.ToJson());
+ _fileSystem.WriteAsString(sourceMapPath, result.SourceMap == null ? string.Empty : result.SourceMap.ToJson());
+
return outputPath;
}
+
+ ///
+ /// Checks whether an input file (given as inputFileContents) should be transpiled
+ /// by calculating the hash and comparing it to the hash value stored
+ /// in the file given by outputPath. If the outputPath file does not
+ /// exist the input file should always be transpiled.
+ ///
+ /// The contents of the input file.
+ /// The output path of the (possibly previously) generated file.
+ /// Returns false if the file should be transpiled, true otherwise.
+ public virtual bool CacheIsValid(string inputFileContents, string outputPath)
+ {
+ if (!_fileSystem.FileExists(outputPath))
+ return false;
+
+ var hashForInputFile = _fileCacheHash.CalculateHash(inputFileContents);
+ var existingOutputContents = _fileSystem.ReadAsString(outputPath);
+ var fileHasNotChanged = _fileCacheHash.ValidateHash(existingOutputContents, hashForInputFile);
+ return fileHasNotChanged;
+ }
}
}
diff --git a/src/React.Tests/Core/BabelTransformerTests.cs b/src/React.Tests/Core/BabelTransformerTests.cs
index ed25300ce..f281ee677 100644
--- a/src/React.Tests/Core/BabelTransformerTests.cs
+++ b/src/React.Tests/Core/BabelTransformerTests.cs
@@ -32,6 +32,10 @@ public void SetUp()
_fileSystem = new Mock();
_fileSystem.Setup(x => x.MapPath(It.IsAny())).Returns(x => x);
+ // Per default the output file should not exist, then individual tests
+ // can choose otherwise.
+ _fileSystem.Setup(x => x.FileExists(It.IsAny())).Returns(false);
+
_fileCacheHash = new Mock();
_babel = new Babel(
@@ -152,6 +156,29 @@ public void ShouldSaveTransformationResult()
StringAssert.EndsWith("React.DOM.div('Hello World')", result);
}
+ [Test]
+ public void ShouldSkipTransformationIfCacheIsValid()
+ {
+ _fileSystem.Setup(x => x.ReadAsString("foo.jsx")).Returns("Hello World
");
+ _fileSystem.Setup(x => x.FileExists(It.IsAny())).Returns(true);
+ _fileCacheHash.Setup(x => x.ValidateHash(It.IsAny(), It.IsAny())).Returns(true);
+ _environment.Setup(x => x.ExecuteWithBabel(
+ "ReactNET_transform_sourcemap",
+ It.IsAny(),
+ It.IsAny(), // Babel config
+ "foo.jsx" // File name
+ )).Returns(new JavaScriptWithSourceMap { Code = "React.DOM.div('Hello World')" });
+
+ string result = null;
+ _fileSystem.Setup(x => x.WriteAsString("foo.generated.js", It.IsAny())).Callback(
+ (string filename, string contents) => result = contents
+ );
+
+ var resultFilename = _babel.TransformAndSaveFile("foo.jsx");
+ Assert.AreEqual("foo.generated.js", resultFilename);
+ Assert.IsNull(result, "There should be no result. Cached result should have been used.");
+ }
+
private void SetUpEmptyCache()
{
_cache.Setup(x => x.Get("JSX_v3_foo.jsx", null)).Returns((JavaScriptWithSourceMap)null);