Skip to content

Commit 534bd61

Browse files
committed
Add ability to add scripts based on wildcard patterns. Closes #60
1 parent 3ddc128 commit 534bd61

10 files changed

+173
-9
lines changed

src/React.Core/FileSystemBase.cs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
* of patent rights can be found in the PATENTS file in the same directory.
88
*/
99

10+
using System.Collections.Generic;
1011
using System.IO;
12+
using System.Linq;
1113
using System.Text;
1214

1315
namespace React
@@ -17,19 +19,35 @@ namespace React
1719
/// </summary>
1820
abstract public class FileSystemBase : IFileSystem
1921
{
22+
/// <summary>
23+
/// Prefix for relative paths
24+
/// </summary>
25+
public const string RELATIVE_PREFIX = "~/";
26+
2027
/// <summary>
2128
/// Converts a path from an application relative path (~/...) to a full filesystem path
2229
/// </summary>
2330
/// <param name="relativePath">App-relative path of the file</param>
2431
/// <returns>Full path of the file</returns>
2532
public abstract string MapPath(string relativePath);
2633

34+
/// <summary>
35+
/// Converts a path from a full filesystem path to anan application relative path (~/...)
36+
/// </summary>
37+
/// <param name="absolutePath">Full path of the file</param>
38+
/// <returns>App-relative path of the file</returns>
39+
public virtual string ToRelativePath(string absolutePath)
40+
{
41+
var root = MapPath(RELATIVE_PREFIX);
42+
return absolutePath.Replace(root, RELATIVE_PREFIX).Replace('\\', '/');
43+
}
44+
2745
/// <summary>
2846
/// Reads the contents of a file as a string.
2947
/// </summary>
3048
/// <param name="relativePath">App-relative path of the file</param>
3149
/// <returns>Contents of the file</returns>
32-
public string ReadAsString(string relativePath)
50+
public virtual string ReadAsString(string relativePath)
3351
{
3452
return File.ReadAllText(MapPath(relativePath), Encoding.UTF8);
3553
}
@@ -39,7 +57,7 @@ public string ReadAsString(string relativePath)
3957
/// </summary>
4058
/// <param name="relativePath">App-relative path of the file</param>
4159
/// <param name="contents">Contents of the file</param>
42-
public void WriteAsString(string relativePath, string contents)
60+
public virtual void WriteAsString(string relativePath, string contents)
4361
{
4462
File.WriteAllText(MapPath(relativePath), contents, Encoding.UTF8);
4563
}
@@ -49,9 +67,21 @@ public void WriteAsString(string relativePath, string contents)
4967
/// </summary>
5068
/// <param name="relativePath">App-relative path of the file</param>
5169
/// <returns><c>true</c> if the file exists</returns>
52-
public bool FileExists(string relativePath)
70+
public virtual bool FileExists(string relativePath)
5371
{
5472
return File.Exists(MapPath(relativePath));
5573
}
74+
75+
/// <summary>
76+
/// Gets all the file paths that match the specified pattern
77+
/// </summary>
78+
/// <param name="glob">Pattern to search for (eg. "~/Scripts/*.js")</param>
79+
/// <returns>File paths that match the pattern</returns>
80+
public virtual IEnumerable<string> Glob(string glob)
81+
{
82+
var path = MapPath(Path.GetDirectoryName(glob));
83+
var searchPattern = Path.GetFileName(glob);
84+
return Directory.EnumerateFiles(path, searchPattern).Select(ToRelativePath);
85+
}
5686
}
5787
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (c) 2014-2015, 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.IO;
11+
12+
namespace React
13+
{
14+
/// <summary>
15+
/// Extension methods relating to file system paths.
16+
/// </summary>
17+
public static class FileSystemExtensions
18+
{
19+
/// <summary>
20+
/// Determines if the specified string is a glob pattern that can be used with
21+
/// <see cref="Directory.GetFiles(string, string)"/>.
22+
/// </summary>
23+
/// <param name="input">String</param>
24+
/// <returns><c>true</c> if the specified string is a glob pattern</returns>
25+
public static bool IsGlobPattern(this string input)
26+
{
27+
return input.Contains("*") || input.Contains("?");
28+
}
29+
}
30+
}

src/React.Core/IFileSystem.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* of patent rights can be found in the PATENTS file in the same directory.
88
*/
99

10+
using System.Collections.Generic;
11+
1012
namespace React
1113
{
1214
/// <summary>
@@ -21,6 +23,13 @@ public interface IFileSystem
2123
/// <returns>Full path of the file</returns>
2224
string MapPath(string relativePath);
2325

26+
/// <summary>
27+
/// Converts a path from a full filesystem path to anan application relative path (~/...)
28+
/// </summary>
29+
/// <param name="absolutePath">Full path of the file</param>
30+
/// <returns>App-relative path of the file</returns>
31+
string ToRelativePath(string absolutePath);
32+
2433
/// <summary>
2534
/// Reads the contents of a file as a string.
2635
/// </summary>
@@ -41,5 +50,12 @@ public interface IFileSystem
4150
/// <param name="relativePath">App-relative path of the file</param>
4251
/// <returns><c>true</c> if the file exists</returns>
4352
bool FileExists(string relativePath);
53+
54+
/// <summary>
55+
/// Gets all the files that match the specified pattern
56+
/// </summary>
57+
/// <param name="glob">Pattern to search for (eg. "~/Scripts/*.js")</param>
58+
/// <returns>File names that match the pattern</returns>
59+
IEnumerable<string> Glob(string glob);
4460
}
4561
}

src/React.Core/IReactSiteConfiguration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,13 @@ public interface IReactSiteConfiguration
4646
/// Gets a list of all the scripts that have been added to this configuration and require JSX
4747
/// transformation to be run.
4848
/// </summary>
49-
IList<string> Scripts { get; }
49+
IEnumerable<string> Scripts { get; }
5050

5151
/// <summary>
5252
/// Gets a list of all the scripts that have been added to this configuration and do not
5353
/// require JSX transformation to be run.
5454
/// </summary>
55-
IList<string> ScriptsWithoutTransform { get; }
55+
IEnumerable<string> ScriptsWithoutTransform { get; }
5656

5757
/// <summary>
5858
/// A value indicating if es6 syntax should be rewritten.

src/React.Core/React.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
</Compile>
9191
<Compile Include="AssemblyRegistration.cs" />
9292
<Compile Include="Exceptions\ReactNotInitialisedException.cs" />
93+
<Compile Include="FileSystemExtensions.cs" />
9394
<Compile Include="JavaScriptEngineUtils.cs" />
9495
<Compile Include="VroomJsEngine.cs" />
9596
<Compile Include="Exceptions\ClearScriptV8InitialisationException.cs" />

src/React.Core/ReactSiteConfiguration.cs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Newtonsoft.Json;
1111
using System.Collections.Generic;
1212
using System.Collections.ObjectModel;
13+
using System.Linq;
1314

1415
namespace React
1516
{
@@ -83,21 +84,43 @@ public IReactSiteConfiguration AddScriptWithoutTransform(string filename)
8384
return this;
8485
}
8586

87+
/// <summary>
88+
/// Gets all the file paths that match the specified pattern. If the pattern is a plain
89+
/// path, just returns that path verbatim.
90+
/// </summary>
91+
/// <param name="glob">
92+
/// Patterns to search for (eg. <c>~/Scripts/*.js</c> or <c>~/Scripts/Awesome.js</c>
93+
/// </param>
94+
/// <returns>File paths that match this pattern</returns>
95+
private IEnumerable<string> Glob(string glob)
96+
{
97+
if (!glob.IsGlobPattern())
98+
{
99+
return new[] {glob};
100+
}
101+
// Directly touching the IoC container is not ideal, but we only want to pull the FileSystem
102+
// dependency if it's absolutely necessary.
103+
var fileSystem = AssemblyRegistration.Container.Resolve<IFileSystem>();
104+
return fileSystem.Glob(glob);
105+
}
106+
86107
/// <summary>
87108
/// Gets a list of all the scripts that have been added to this configuration and require JSX
88109
/// transformation to be run.
89110
/// </summary>
90-
public IList<string> Scripts
111+
public IEnumerable<string> Scripts
91112
{
92-
get { return new ReadOnlyCollection<string>(_scriptFiles); }
113+
// TODO: It's a bit strange to do the globbing here, ideally this class should just be a simple
114+
// bag of settings with no logic.
115+
get { return _scriptFiles.SelectMany(Glob); }
93116
}
94117

95118
/// <summary>
96119
/// Gets a list of all the scripts that have been added to this configuration.
97120
/// </summary>
98-
public IList<string> ScriptsWithoutTransform
121+
public IEnumerable<string> ScriptsWithoutTransform
99122
{
100-
get { return new ReadOnlyCollection<string>(_scriptFilesWithoutTransform); }
123+
get { return _scriptFilesWithoutTransform.SelectMany(Glob); }
101124
}
102125

103126
/// <summary>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
<DefineConstants>TRACE</DefineConstants>
4545
<ErrorReport>prompt</ErrorReport>
4646
<WarningLevel>4</WarningLevel>
47+
<NoWarn>1607</NoWarn>
4748
</PropertyGroup>
4849
<ItemGroup>
4950
<Reference Include="AjaxMin, Version=4.84.4790.14405, Culture=neutral, PublicKeyToken=21ef50ce11b5d80f, processorArchitecture=MSIL">
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2014-2015, 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 NUnit.Framework;
11+
12+
namespace React.Tests.Core
13+
{
14+
[TestFixture]
15+
public class FileSystemBaseTests
16+
{
17+
[TestCase("~/Test.txt", "C:\\Test.txt")]
18+
[TestCase("~/Scripts/lol.js", "C:\\Scripts\\lol.js")]
19+
public void ToRelativePath(string expected, string input)
20+
{
21+
var fileSystem = new TestFileSystem();
22+
Assert.AreEqual(expected, fileSystem.ToRelativePath(input));
23+
}
24+
25+
private class TestFileSystem : FileSystemBase
26+
{
27+
public override string MapPath(string relativePath)
28+
{
29+
return "C:\\" + relativePath.Replace("~/", string.Empty);
30+
}
31+
}
32+
}
33+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2014-2015, 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 NUnit.Framework;
11+
12+
namespace React.Tests.Core
13+
{
14+
[TestFixture]
15+
public class FileSystemExtensionsTests
16+
{
17+
[TestCase("*.txt", true)]
18+
[TestCase("foo?.js", true)]
19+
[TestCase("first\\second\\third\\*.js", true)]
20+
[TestCase("lol.js", false)]
21+
[TestCase("", false)]
22+
[TestCase("hello\\world.js", false)]
23+
public void IsGlobPattern(string input, bool expected)
24+
{
25+
Assert.AreEqual(expected, input.IsGlobPattern());
26+
}
27+
}
28+
}

src/React.Tests/React.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@
9696
<Link>Properties\SharedAssemblyVersionInfo.cs</Link>
9797
</Compile>
9898
<Compile Include="Core\FileCacheHashTests.cs" />
99+
<Compile Include="Core\FileSystemBaseTests.cs" />
100+
<Compile Include="Core\FileSystemExtensionsTest.cs" />
99101
<Compile Include="Core\JavaScriptEngineFactoryTest.cs" />
100102
<Compile Include="Core\JavaScriptEngineUtilsTests.cs" />
101103
<Compile Include="Core\JsxTransformerTests.cs" />

0 commit comments

Comments
 (0)