- v0.14 version bump (not done yet) - clean up of projbook project files on disk - fix in path read in @snippet statement - added references to System.Collections.Immutable to several projects as it's indirectly loaded and will make docnet fail at runtime if missingtags/v0.14
@@ -7,11 +7,11 @@ | |||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> | |||
<dependentAssembly> | |||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> | |||
<bindingRedirect oldVersion="0.0.0.0-1.3.0.0" newVersion="1.3.0.0" /> | |||
<bindingRedirect oldVersion="0.0.0.0-1.4.1.0" newVersion="1.4.1.0" /> | |||
</dependentAssembly> | |||
<dependentAssembly> | |||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> | |||
<bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0" /> | |||
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" /> | |||
</dependentAssembly> | |||
</assemblyBinding> | |||
</runtime> |
@@ -33,11 +33,15 @@ | |||
<WarningLevel>4</WarningLevel> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> | |||
<HintPath>..\..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath> | |||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> | |||
<HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System" /> | |||
<Reference Include="System.Collections.Immutable, Version=1.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\..\packages\System.Collections.Immutable.1.3.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.Configuration" /> | |||
<Reference Include="System.Core" /> | |||
<Reference Include="System.Web" /> | |||
@@ -72,6 +76,9 @@ | |||
<Name>MarkdownDeep</Name> | |||
</ProjectReference> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<WCFMetadata Include="Service References\" /> | |||
</ItemGroup> | |||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||
Other similar extension points exist, see Microsoft.Common.targets. | |||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices; | |||
// You can specify all the values or you can default the Build and Revision Numbers | |||
// by using the '*' as shown below: | |||
// [assembly: AssemblyVersion("1.0.*")] | |||
[assembly: AssemblyVersion("0.13.2.0")] | |||
[assembly: AssemblyFileVersion("0.13.2")] | |||
[assembly: AssemblyVersion("0.14.0.0")] | |||
[assembly: AssemblyFileVersion("0.14.0")] |
@@ -68,7 +68,7 @@ namespace Docnet | |||
this.MarkdownFromFile = File.ReadAllText(sourceFile, Encoding.UTF8); | |||
// Check if the content contains @@include tag | |||
content = Utils.IncludeProcessor(this.MarkdownFromFile, Utils.MakeAbsolutePath(activeConfig.Source, activeConfig.IncludeFolder)); | |||
content = Utils.ConvertMarkdownToHtml(content, Path.GetDirectoryName(destinationFile), activeConfig.Destination, _relativeH2LinksOnPage); | |||
content = Utils.ConvertMarkdownToHtml(content, Path.GetDirectoryName(destinationFile), activeConfig.Destination, sourceFile, _relativeH2LinksOnPage); | |||
} | |||
else | |||
{ | |||
@@ -90,7 +90,7 @@ namespace Docnet | |||
defaultMarkdown.AppendFormat("* [{0}]({1}{2}){3}", sibling.Name, relativePathToRoot, HttpUtility.UrlPathEncode(sibling.TargetURL), Environment.NewLine); | |||
} | |||
defaultMarkdown.Append(Environment.NewLine); | |||
content = Utils.ConvertMarkdownToHtml(defaultMarkdown.ToString(), Path.GetDirectoryName(destinationFile), activeConfig.Destination, _relativeH2LinksOnPage); | |||
content = Utils.ConvertMarkdownToHtml(defaultMarkdown.ToString(), Path.GetDirectoryName(destinationFile), activeConfig.Destination, string.Empty, _relativeH2LinksOnPage); | |||
} | |||
else | |||
{ | |||
@@ -39,15 +39,17 @@ namespace Docnet | |||
private static Regex includeRegex = new Regex(@"@@include\((.*)\)", RegexOptions.IgnoreCase | RegexOptions.Compiled); | |||
#endregion | |||
/// <summary> | |||
/// Converts the markdown to HTML. | |||
/// </summary> | |||
/// <param name="toConvert">The markdown string to convert.</param> | |||
/// <param name="documentPath">The document path (without the document filename).</param> | |||
/// <param name="siteRoot">The site root.</param> | |||
/// <param name="createdAnchorCollector">The created anchor collector, for ToC sublinks for H2 headers.</param> | |||
/// <returns></returns> | |||
public static string ConvertMarkdownToHtml(string toConvert, string documentPath, string siteRoot, List<Tuple<string, string>> createdAnchorCollector) | |||
/// <summary> | |||
/// Converts the markdown to HTML. | |||
/// </summary> | |||
/// <param name="toConvert">The markdown string to convert.</param> | |||
/// <param name="destinationDocumentPath">The document path (without the document filename).</param> | |||
/// <param name="siteRoot">The site root.</param> | |||
/// <param name="sourceDocumentFilename">the filename of the source markdown file</param> | |||
/// <param name="createdAnchorCollector">The created anchor collector, for ToC sublinks for H2 headers.</param> | |||
/// <returns></returns> | |||
public static string ConvertMarkdownToHtml(string toConvert, string destinationDocumentPath, string siteRoot, string sourceDocumentFilename, | |||
List<Tuple<string, string>> createdAnchorCollector) | |||
{ | |||
var parser = new MarkdownDeep.Markdown | |||
{ | |||
@@ -56,8 +58,9 @@ namespace Docnet | |||
AutoHeadingIDs = true, | |||
NewWindowForExternalLinks = true, | |||
DocNetMode = true, | |||
DocumentLocation = documentPath, | |||
DestinationDocumentLocation = destinationDocumentPath, | |||
DocumentRoot = siteRoot, | |||
SourceDocumentFilename = sourceDocumentFilename, | |||
HtmlClassTitledImages = "figure", | |||
}; | |||
@@ -1,4 +1,5 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<packages> | |||
<package id="Newtonsoft.Json" version="8.0.2" targetFramework="net461" /> | |||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> | |||
<package id="System.Collections.Immutable" version="1.3.0" targetFramework="net461" /> | |||
</packages> |
@@ -1533,7 +1533,7 @@ namespace MarkdownDeep | |||
} | |||
// extract the snippet, then build the fenced block to return. | |||
var fullFilename = Path.Combine(Path.GetDirectoryName(m_markdown.DocumentLocation) ?? string.Empty, filename); | |||
var fullFilename = Path.Combine(Path.GetDirectoryName(m_markdown.SourceDocumentFilename) ?? string.Empty, filename); | |||
var snippetText = extractor.Extract(fullFilename, pattern) ?? string.Empty; | |||
b.BlockType = BlockType.codeblock; | |||
b.Data = language; | |||
@@ -299,7 +299,7 @@ namespace MarkdownDeep | |||
return false; | |||
// Work out base location | |||
string str = url.StartsWith("/") ? DocumentRoot : DocumentLocation; | |||
string str = url.StartsWith("/") ? DocumentRoot : DestinationDocumentLocation; | |||
if (String.IsNullOrEmpty(str)) | |||
return false; | |||
@@ -909,15 +909,19 @@ namespace MarkdownDeep | |||
set; | |||
} | |||
// Local file system location of the current document. Used to locate relative | |||
// Local file system location of the current destination document. Used to locate relative | |||
// path images for image size. | |||
// Typical value: c:\inetpub\www\wwwroot\subfolder | |||
public string DocumentLocation | |||
public string DestinationDocumentLocation | |||
{ | |||
get; | |||
set; | |||
} | |||
public string SourceDocumentFilename { get; set; } | |||
// Limit the width of images (0 for no limit) | |||
public int MaxImageWidth | |||
{ | |||
@@ -44,6 +44,8 @@ | |||
<WarningLevel>4</WarningLevel> | |||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> | |||
<Prefer32Bit>false</Prefer32Bit> | |||
<DocumentationFile> | |||
</DocumentationFile> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||
<DebugType>pdbonly</DebugType> | |||
@@ -111,6 +113,9 @@ | |||
<Name>Projbook.Extension</Name> | |||
</ProjectReference> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Include="app.config" /> | |||
</ItemGroup> | |||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||
<PropertyGroup> | |||
<PostBuildEvent> | |||
@@ -0,0 +1,15 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<configuration> | |||
<runtime> | |||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> | |||
<dependentAssembly> | |||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> | |||
<bindingRedirect oldVersion="0.0.0.0-1.4.1.0" newVersion="1.4.1.0" /> | |||
</dependentAssembly> | |||
<dependentAssembly> | |||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> | |||
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" /> | |||
</dependentAssembly> | |||
</assemblyBinding> | |||
</runtime> | |||
</configuration> |
@@ -51,6 +51,10 @@ | |||
<HintPath>..\..\packages\NUnit.2.5.10.11092\lib\pnunit.framework.dll</HintPath> | |||
</Reference> | |||
<Reference Include="System" /> | |||
<Reference Include="System.Collections.Immutable, Version=1.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\..\packages\System.Collections.Immutable.1.3.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.Core"> | |||
<RequiredTargetFramework>3.5</RequiredTargetFramework> | |||
</Reference> | |||
@@ -10,4 +10,16 @@ | |||
<add key="ApartmentState" value="STA" /> | |||
</TestRunner> | |||
</NUnit> | |||
<runtime> | |||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> | |||
<dependentAssembly> | |||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> | |||
<bindingRedirect oldVersion="0.0.0.0-1.4.1.0" newVersion="1.4.1.0" /> | |||
</dependentAssembly> | |||
<dependentAssembly> | |||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> | |||
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" /> | |||
</dependentAssembly> | |||
</assemblyBinding> | |||
</runtime> | |||
</configuration> |
@@ -1,4 +1,5 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<packages> | |||
<package id="NUnit" version="2.5.10.11092" /> | |||
<package id="System.Collections.Immutable" version="1.3.0" targetFramework="net461" /> | |||
</packages> |
@@ -1,90 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | |||
<PropertyGroup> | |||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||
<ProjectGuid>{F5431901-29AC-46D4-A717-DE2A9114E82D}</ProjectGuid> | |||
<OutputType>Library</OutputType> | |||
<AppDesignerFolder>Properties</AppDesignerFolder> | |||
<RootNamespace>Projbook.Extension.CSharpExtractor</RootNamespace> | |||
<AssemblyName>Projbook.Extension.CSharpExtractor</AssemblyName> | |||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> | |||
<FileAlignment>512</FileAlignment> | |||
<TargetFrameworkProfile /> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||
<DebugSymbols>true</DebugSymbols> | |||
<DebugType>full</DebugType> | |||
<Optimize>false</Optimize> | |||
<OutputPath>bin\Debug\</OutputPath> | |||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||
<DebugType>pdbonly</DebugType> | |||
<Optimize>true</Optimize> | |||
<OutputPath>bin\Release\</OutputPath> | |||
<DefineConstants>TRACE</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Reference Include="Microsoft.CodeAnalysis, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Microsoft.CodeAnalysis.CSharp, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System" /> | |||
<Reference Include="System.Collections.Immutable, Version=1.1.37.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.Core" /> | |||
<Reference Include="System.Reflection.Metadata, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.Xml.Linq" /> | |||
<Reference Include="System.Data.DataSetExtensions" /> | |||
<Reference Include="Microsoft.CSharp" /> | |||
<Reference Include="System.Data" /> | |||
<Reference Include="System.Net.Http" /> | |||
<Reference Include="System.Xml" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Include="Projbook\Extension\CSharp\CSharpExtractionMode.cs" /> | |||
<Compile Include="Projbook\Extension\CSharp\CSharpMatchingRule.cs" /> | |||
<Compile Include="Projbook\Extension\CSharp\CSharpSnippetExtractor.cs" /> | |||
<Compile Include="Projbook\Extension\CSharp\CSharpSyntaxMatchingNode.cs" /> | |||
<Compile Include="Projbook\Extension\CSharp\CSharpSyntaxWalkerMatchingBuilder.cs" /> | |||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\Projbook.Extension\Projbook.Extension.csproj"> | |||
<Project>{8338b756-0519-4d20-ba04-3a8f4839237a}</Project> | |||
<Name>Projbook.Extension</Name> | |||
</ProjectReference> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Include="packages.config"> | |||
<SubType>Designer</SubType> | |||
</None> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.Analyzers.dll" /> | |||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" /> | |||
</ItemGroup> | |||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||
Other similar extension points exist, see Microsoft.Common.targets. | |||
<Target Name="BeforeBuild"> | |||
</Target> | |||
<Target Name="AfterBuild"> | |||
</Target> | |||
--> | |||
</Project> |
@@ -1,23 +0,0 @@ | |||
namespace Projbook.Extension.CSharpExtractor | |||
{ | |||
/// <summary> | |||
/// Represents the extraction mode. | |||
/// </summary> | |||
public enum CSharpExtractionMode | |||
{ | |||
/// <summary> | |||
/// Full member: Do not process the snippet and print it as it. | |||
/// </summary> | |||
FullMember, | |||
/// <summary> | |||
/// Content only: Extract the code block and print this part only. | |||
/// </summary> | |||
ContentOnly, | |||
/// <summary> | |||
/// Block structure only: Remove the block content and print the code structure only. | |||
/// </summary> | |||
BlockStructureOnly | |||
} | |||
} |
@@ -1,80 +0,0 @@ | |||
using Projbook.Extension.Exception; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text.RegularExpressions; | |||
namespace Projbook.Extension.CSharpExtractor | |||
{ | |||
/// <summary> | |||
/// Represents a matching rule for referencing a C# member. | |||
/// </summary> | |||
public class CSharpMatchingRule | |||
{ | |||
/// <summary> | |||
/// The matching chunk to identify which member are the snippet targets. | |||
/// </summary> | |||
public string[] MatchingChunks { get; private set; } | |||
/// <summary> | |||
/// The snippet extraction mode. | |||
/// </summary> | |||
public CSharpExtractionMode ExtractionMode { get; private set; } | |||
/// <summary> | |||
/// Defines rule regex used to parse the snippet into chunks. | |||
/// Expected input format: Path/File.cs [My.Name.Space.Class.Method][(string, string)] | |||
/// * The first chunk is the file name and will be loaded in <seealso cref="TargetFile"/> | |||
/// * The optional second chunks are all full qualified name to the member separated by "." | |||
/// * The optional last chunk is the method parameters if matching a method. | |||
/// </summary> | |||
private static Regex ruleRegex = new Regex(@"^([-=])?([^(]+)?\s*(\([^)]*\s*\))?\s*$", RegexOptions.Compiled); | |||
/// <summary> | |||
/// Parses the token | |||
/// </summary> | |||
/// <param name="pattern"></param> | |||
/// <returns></returns> | |||
public static CSharpMatchingRule Parse(string pattern) | |||
{ | |||
// Try to match the regex | |||
pattern = Regex.Replace(pattern, @"\s", string.Empty); | |||
Match match = CSharpMatchingRule.ruleRegex.Match(pattern); | |||
if (!match.Success || string.IsNullOrWhiteSpace(match.Groups[0].Value)) | |||
{ | |||
throw new SnippetExtractionException("Invalid extraction rule", pattern); | |||
} | |||
// Retrieve values from the regex matching | |||
string extractionOption = match.Groups[1].Value; | |||
string rawMember = match.Groups[2].Value.Trim(); | |||
string rawParameters = match.Groups[3].Value.Trim(); | |||
// Build The matching chunk with extracted data | |||
List<string> matchingChunks = new List<string>(); | |||
matchingChunks.AddRange(rawMember.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries)); | |||
if (rawParameters.Length >= 1) | |||
{ | |||
matchingChunks.Add(rawParameters); | |||
} | |||
// Read extraction mode | |||
CSharpExtractionMode extractionMode = CSharpExtractionMode.FullMember; | |||
switch (extractionOption) | |||
{ | |||
case "-": | |||
extractionMode = CSharpExtractionMode.ContentOnly; | |||
break; | |||
case "=": | |||
extractionMode = CSharpExtractionMode.BlockStructureOnly; | |||
break; | |||
} | |||
// Build the matching rule based on the regex matching | |||
return new CSharpMatchingRule | |||
{ | |||
MatchingChunks = matchingChunks.ToArray(), | |||
ExtractionMode = extractionMode | |||
}; | |||
} | |||
} | |||
} |
@@ -1,368 +0,0 @@ | |||
using EnsureThat; | |||
using Microsoft.CodeAnalysis; | |||
using Microsoft.CodeAnalysis.CSharp; | |||
using Microsoft.CodeAnalysis.CSharp.Syntax; | |||
using Microsoft.CodeAnalysis.Text; | |||
using Projbook.Extension.Exception; | |||
using Projbook.Extension.Spi; | |||
using System; | |||
using System.IO.Abstractions; | |||
using System.Linq; | |||
using System.Text; | |||
namespace Projbook.Extension.CSharpExtractor | |||
{ | |||
/// <summary> | |||
/// Extractor in charge of browsing source directories. load file content and extract requested member. | |||
/// </summary> | |||
[Syntax(name: "csharp")] | |||
public class CSharpSnippetExtractor : DefaultSnippetExtractor | |||
{ | |||
/// <summary> | |||
/// Represents the matching trie used for member matching. | |||
/// Because of the cost of building the Trie, this value is lazy loaded and kept for future usages. | |||
/// </summary> | |||
private CSharpSyntaxMatchingNode syntaxTrie; | |||
/// <summary> | |||
/// Extracts a snippet from a given rule pattern. | |||
/// </summary> | |||
/// <param name="fileSystemInfo">The file system info.</param> | |||
/// <param name="memberPattern">The member pattern to extract.</param> | |||
/// <returns>The extracted snippet.</returns> | |||
public override Model.Snippet Extract(FileSystemInfoBase fileSystemInfo, string memberPattern) | |||
{ | |||
// Return the entire code if no member is specified | |||
if (string.IsNullOrWhiteSpace(memberPattern)) | |||
{ | |||
return base.Extract(fileSystemInfo, memberPattern); | |||
} | |||
// Parse the matching rule from the pattern | |||
CSharpMatchingRule rule = CSharpMatchingRule.Parse(memberPattern); | |||
// Load the trie for pattern matching | |||
if (null == this.syntaxTrie) | |||
{ | |||
// Load file content | |||
string sourceCode = base.LoadFile(this.ConvertToFile(fileSystemInfo)); | |||
// Build a syntax tree from the source code | |||
SyntaxTree tree = CSharpSyntaxTree.ParseText(sourceCode); | |||
SyntaxNode root = tree.GetRoot(); | |||
// Visit the syntax tree for generating a Trie for pattern matching | |||
CSharpSyntaxWalkerMatchingBuilder syntaxMatchingBuilder = new CSharpSyntaxWalkerMatchingBuilder(); | |||
syntaxMatchingBuilder.Visit(root); | |||
// Retrieve the Trie root | |||
this.syntaxTrie = syntaxMatchingBuilder.Root; | |||
} | |||
// Match the rule from the syntax matching Trie | |||
CSharpSyntaxMatchingNode matchingTrie = syntaxTrie.Match(rule.MatchingChunks); | |||
if (null == matchingTrie) | |||
{ | |||
throw new SnippetExtractionException("Cannot find member", memberPattern); | |||
} | |||
// Build a snippet for extracted syntax nodes | |||
return this.BuildSnippet(matchingTrie.MatchingSyntaxNodes, rule.ExtractionMode); | |||
} | |||
/// <summary> | |||
/// Builds a snippet from extracted syntax nodes. | |||
/// </summary> | |||
/// <param name="nodes">The exctracted nodes.</param> | |||
/// <param name="extractionMode">The extraction mode.</param> | |||
/// <returns>The built snippet.</returns> | |||
private Model.Snippet BuildSnippet(SyntaxNode[] nodes, CSharpExtractionMode extractionMode) | |||
{ | |||
// Data validation | |||
Ensure.That(() => nodes).IsNotNull(); | |||
Ensure.That(() => nodes).HasItems(); | |||
// Extract code from each snippets | |||
StringBuilder stringBuilder = new StringBuilder(); | |||
bool firstSnippet = true; | |||
foreach (SyntaxNode node in nodes) | |||
{ | |||
// Write line return between each snippet | |||
if (!firstSnippet) | |||
{ | |||
stringBuilder.AppendLine(); | |||
stringBuilder.AppendLine(); | |||
} | |||
// Write each snippet line | |||
string[] lines = node.GetText().Lines.Select(x => x.ToString()).ToArray(); | |||
int contentPosition = this.DetermineContentPosition(node); | |||
this.WriteAndCleanupSnippet(stringBuilder, lines, extractionMode, contentPosition); | |||
// Flag the first snippet as false | |||
firstSnippet = false; | |||
} | |||
// Create the snippet from the exctracted code | |||
return new Model.PlainTextSnippet(stringBuilder.ToString()); | |||
} | |||
/// <summary> | |||
/// Determines the content's block position depending on the node type. | |||
/// </summary> | |||
/// <param name="node">The node to extract the content position from.</param> | |||
/// <returns>The determined content position or 0 if not found.</returns> | |||
private int DetermineContentPosition(SyntaxNode node) | |||
{ | |||
// Data validation | |||
Ensure.That(() => node).IsNotNull(); | |||
// Select the content node element depending on the node type | |||
TextSpan? contentTextSpan = null; | |||
switch (node.Kind()) | |||
{ | |||
// Accessor list content | |||
case SyntaxKind.PropertyDeclaration: | |||
case SyntaxKind.IndexerDeclaration: | |||
case SyntaxKind.EventDeclaration: | |||
AccessorListSyntax accessorList = node.DescendantNodes().OfType<AccessorListSyntax>().FirstOrDefault(); | |||
if (null != accessorList) | |||
{ | |||
contentTextSpan = accessorList.FullSpan; | |||
} | |||
break; | |||
// Contains children | |||
case SyntaxKind.NamespaceDeclaration: | |||
case SyntaxKind.InterfaceDeclaration: | |||
case SyntaxKind.ClassDeclaration: | |||
SyntaxToken token = node.ChildTokens().Where(x => x.Kind() == SyntaxKind.OpenBraceToken).FirstOrDefault(); | |||
if (null != token) | |||
{ | |||
contentTextSpan = token.FullSpan; | |||
} | |||
break; | |||
// Block content | |||
case SyntaxKind.ConstructorDeclaration: | |||
case SyntaxKind.DestructorDeclaration: | |||
case SyntaxKind.MethodDeclaration: | |||
case SyntaxKind.GetAccessorDeclaration: | |||
case SyntaxKind.SetAccessorDeclaration: | |||
case SyntaxKind.AddAccessorDeclaration: | |||
case SyntaxKind.RemoveAccessorDeclaration: | |||
BlockSyntax block = node.DescendantNodes().OfType<BlockSyntax>().FirstOrDefault(); | |||
if (null != block) | |||
{ | |||
contentTextSpan = block.FullSpan; | |||
} | |||
break; | |||
// Not processed by projbook csharp extractor | |||
default: | |||
break; | |||
} | |||
// Compute a line break insensitive position based on the fetched content text span if any is found | |||
if (null != contentTextSpan) | |||
{ | |||
int relativeTextSpanStart = contentTextSpan.Value.Start - node.FullSpan.Start; | |||
return node | |||
.ToFullString() | |||
.Substring(0, relativeTextSpanStart) | |||
.Replace("\r\n", "") | |||
.Replace("\n", "").Length; | |||
} | |||
// Otherwise return 0 as default value | |||
return 0; | |||
} | |||
/// <summary> | |||
/// Writes and cleanup line snippets. | |||
/// Snippets are moved out of their context, for this reason we need to trim lines aroung and remove a part of the indentation. | |||
/// </summary> | |||
/// <param name="stringBuilder">The string builder used as output.</param> | |||
/// <param name="lines">The lines to process.</param> | |||
/// <param name="extractionMode">The extraction mode.</param> | |||
/// <param name="contentPosition">The content position.</param> | |||
private void WriteAndCleanupSnippet(StringBuilder stringBuilder, string[] lines, CSharpExtractionMode extractionMode, int contentPosition) | |||
{ | |||
// Data validation | |||
Ensure.That(() => stringBuilder).IsNotNull(); | |||
Ensure.That(() => lines).IsNotNull(); | |||
// Do not process if lines are empty | |||
if (0 >= lines.Length) | |||
{ | |||
return; | |||
} | |||
// Compute the index of the first selected line | |||
int startPos = 0; | |||
int skippedCharNumber = 0; | |||
if (CSharpExtractionMode.ContentOnly == extractionMode) | |||
{ | |||
// Compute the content position index in the first processed line | |||
int contentPositionFirstLineIndex = 0; | |||
for (int totalLinePosition = 0; startPos < lines.Length; ++startPos) | |||
{ | |||
// Compute the content position in the current line | |||
string line = lines[startPos]; | |||
int relativePosition = contentPosition - totalLinePosition; | |||
int contentPositionInLine = relativePosition < line.Length ? relativePosition: -1; | |||
// In expected in the current line | |||
if (contentPositionInLine >= 0) | |||
{ | |||
// Look for the relative index in the current line | |||
// Save the found index and break the iteration if any open bracket is found | |||
int indexOf = line.IndexOf('{', contentPositionInLine); | |||
if (0 <= indexOf) | |||
{ | |||
contentPositionFirstLineIndex = indexOf; | |||
break; | |||
} | |||
} | |||
// Move the total line position after the processed line | |||
totalLinePosition += lines[startPos].Length; | |||
} | |||
// Extract block code if any opening bracket has been found | |||
if (startPos < lines.Length) | |||
{ | |||
int openingBracketPos = lines[startPos].IndexOf('{', contentPositionFirstLineIndex); | |||
if (openingBracketPos >= 0) | |||
{ | |||
// Extract the code before the curly bracket | |||
if (lines[startPos].Length > openingBracketPos) | |||
{ | |||
lines[startPos] = lines[startPos].Substring(openingBracketPos + 1); | |||
} | |||
// Skip the current line if empty | |||
if (string.IsNullOrWhiteSpace(lines[startPos]) && lines.Length > 1 + startPos) | |||
{ | |||
++startPos; | |||
} | |||
} | |||
} | |||
} | |||
else | |||
{ | |||
// Skip leading whitespace lines and keep track of the amount of skipped char | |||
for (; startPos < lines.Length; ++startPos) | |||
{ | |||
// Break on non whitespace line | |||
string line = lines[startPos]; | |||
if (line.Trim().Length > 0) | |||
{ | |||
break; | |||
} | |||
// Record skipped char number | |||
skippedCharNumber += line.Length; | |||
} | |||
} | |||
// Compute the index of the lastselected line | |||
int endPos = -1 + lines.Length; | |||
if (CSharpExtractionMode.ContentOnly == extractionMode) | |||
{ | |||
for (; 0 <= endPos && !lines[endPos].ToString().Contains('}'); --endPos); | |||
// Extract block code if any closing bracket has been found | |||
if (0 <= endPos) | |||
{ | |||
int closingBracketPos = lines[endPos].IndexOf('}'); | |||
if (closingBracketPos >= 0) | |||
{ | |||
// Extract the code before the curly bracket | |||
if (lines[endPos].Length > closingBracketPos) | |||
lines[endPos] = lines[endPos].Substring(0, closingBracketPos).TrimEnd(); | |||
} | |||
// Skip the current line if empty | |||
if (string.IsNullOrWhiteSpace(lines[endPos]) && lines.Length > -1 + endPos) | |||
{ | |||
--endPos; | |||
} | |||
} | |||
} | |||
else | |||
{ | |||
for (; 0 <= endPos && lines[endPos].ToString().Trim().Length == 0; --endPos); | |||
} | |||
// Compute the padding to remove for removing a part of the indentation | |||
int leftPadding = int.MaxValue; | |||
for (int i = startPos; i <= endPos; ++i) | |||
{ | |||
// Ignore empty lines in the middle of the snippet | |||
if (!string.IsNullOrWhiteSpace(lines[i])) | |||
{ | |||
// Adjust the left padding with the available whitespace at the beginning of the line | |||
leftPadding = Math.Min(leftPadding, lines[i].ToString().TakeWhile(Char.IsWhiteSpace).Count()); | |||
} | |||
} | |||
// Write selected lines to the string builder | |||
bool firstLine = true; | |||
for (int i = startPos; i <= endPos; ++i) | |||
{ | |||
// Write line return between each line | |||
if (!firstLine) | |||
{ | |||
stringBuilder.AppendLine(); | |||
} | |||
// Remove a part of the indentation padding | |||
if (lines[i].Length > leftPadding) | |||
{ | |||
string line = lines[i].Substring(leftPadding); | |||
// Process the snippet depending on the extraction mode | |||
switch (extractionMode) | |||
{ | |||
// Extract the block structure only | |||
case CSharpExtractionMode.BlockStructureOnly: | |||
// Compute the content position in the current line | |||
int relativePosition = contentPosition - skippedCharNumber; | |||
int contentPositionInLine = relativePosition < line.Length + leftPadding ? relativePosition : -1; | |||
// Look for open bracket from the content position in line | |||
int openingBracketPos = -1; | |||
if (contentPositionInLine >= 0) | |||
{ | |||
openingBracketPos = line.IndexOf('{', Math.Max(0, contentPositionInLine - leftPadding)); | |||
} | |||
// Anonymize code content if an open bracket is found | |||
if (openingBracketPos >= 0) | |||
{ | |||
// Extract the code before the curly bracket | |||
if (line.Length > openingBracketPos) | |||
line = line.Substring(0, 1 + openingBracketPos); | |||
// Replace the content and close the block | |||
line += string.Format("{0} // ...{0}}}", Environment.NewLine); | |||
// Stop the iteration | |||
endPos = i; | |||
} | |||
break; | |||
} | |||
// Append the line | |||
stringBuilder.Append(line); | |||
skippedCharNumber += lines[i].Length; | |||
} | |||
// Flag the first line as false | |||
firstLine = false; | |||
} | |||
} | |||
} | |||
} |
@@ -1,201 +0,0 @@ | |||
using EnsureThat; | |||
using Microsoft.CodeAnalysis; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
namespace Projbook.Extension.CSharpExtractor | |||
{ | |||
/// <summary> | |||
/// Represents a syntax matching node. | |||
/// Thie node is used to build a Trie representing possible matching. | |||
/// Each node contians children and matching syntax nodes. | |||
/// </summary> | |||
public class CSharpSyntaxMatchingNode | |||
{ | |||
/// <summary> | |||
/// The public Matching SyntaxNodes. | |||
/// </summary> | |||
public SyntaxNode[] MatchingSyntaxNodes | |||
{ | |||
get | |||
{ | |||
// Return empty array id the nodes are empty | |||
if (null == this.matchingSyntaxNodes) | |||
{ | |||
return new SyntaxNode[0]; | |||
} | |||
// Return the matching syntax nodes | |||
return this.matchingSyntaxNodes.ToArray(); | |||
} | |||
} | |||
/// <summary> | |||
/// The node's children. | |||
/// </summary> | |||
private Dictionary<string, CSharpSyntaxMatchingNode> children; | |||
/// <summary> | |||
/// The node's maching syntax node. | |||
/// </summary> | |||
private List<SyntaxNode> matchingSyntaxNodes; | |||
/// <summary> | |||
/// Finds a node from syntax chunk. | |||
/// </summary> | |||
/// <param name="chunks">The chunks to match.</param> | |||
/// <returns></returns> | |||
public CSharpSyntaxMatchingNode Match(string[] chunks) | |||
{ | |||
// Data validation | |||
Ensure.That(() => chunks).IsNotNull(); | |||
// Browse the Trie until finding a matching | |||
CSharpSyntaxMatchingNode matchingNode = this; | |||
foreach (string fragment in chunks) | |||
{ | |||
// Could not find any matching | |||
if (null == matchingNode.children || !matchingNode.children.TryGetValue(fragment, out matchingNode)) | |||
{ | |||
return null; | |||
} | |||
} | |||
// Return the matching node | |||
return matchingNode; | |||
} | |||
/// <summary> | |||
/// Lookup a node from children and return it. if the node doesn't exist, a new one will be created and added to the children. | |||
/// </summary> | |||
/// <param name="name">The node name.</param> | |||
/// <returns>The node matching the requested name.</returns> | |||
public CSharpSyntaxMatchingNode EnsureNode(string name) | |||
{ | |||
// Data validation | |||
Ensure.That(() => name).IsNotNullOrWhiteSpace(); | |||
// Fetch a node from existing children and return it if any is found | |||
CSharpSyntaxMatchingNode firstLevelNode; | |||
if (null != this.children && this.children.TryGetValue(name, out firstLevelNode)) | |||
{ | |||
return firstLevelNode; | |||
} | |||
// Otherwise create a new node and return it | |||
else | |||
{ | |||
// Lazu create the dictionary for storing children | |||
if (null == this.children) | |||
{ | |||
this.children = new Dictionary<string, CSharpSyntaxMatchingNode>(); | |||
} | |||
// Assign and return the new node | |||
return this.children[name] = new CSharpSyntaxMatchingNode(); | |||
} | |||
} | |||
/// <summary> | |||
/// Adds a syntax node as matching node. | |||
/// </summary> | |||
/// <param name="node"></param> | |||
public void AddSyntaxNode(SyntaxNode node) | |||
{ | |||
// Data validation | |||
Ensure.That(() => node).IsNotNull(); | |||
// Lazy create the syntax node list | |||
if (null == this.matchingSyntaxNodes) | |||
{ | |||
this.matchingSyntaxNodes = new List<SyntaxNode>(); | |||
} | |||
// Add the node to the known matching node | |||
this.matchingSyntaxNodes.Add(node); | |||
} | |||
/// <summary> | |||
/// Copies to a given node. | |||
/// </summary> | |||
/// <param name="targetNode">The node wherer to copy.</param> | |||
/// <param name="name">The node name.</param> | |||
public void CopyTo(CSharpSyntaxMatchingNode targetNode, string name) | |||
{ | |||
// Data validation | |||
Ensure.That(() => name).IsNotNullOrWhiteSpace(); | |||
Ensure.That(() => targetNode).IsNotNull(); | |||
// Ensure and retrieve a node the the copy | |||
CSharpSyntaxMatchingNode newNode = targetNode.EnsureNode(name); | |||
// Add syntax node to the created node | |||
if (null != this.matchingSyntaxNodes) | |||
{ | |||
// Lazy create the syntax nodes | |||
if (null == newNode.matchingSyntaxNodes) | |||
{ | |||
newNode.matchingSyntaxNodes = new List<SyntaxNode>(); | |||
} | |||
// Merge syntax nodes | |||
int[] indexes = newNode.matchingSyntaxNodes.Select(x => x.Span.Start).ToArray(); | |||
newNode.matchingSyntaxNodes.AddRange(this.matchingSyntaxNodes.Where(x => !indexes.Contains(x.Span.Start))); | |||
} | |||
// Recurse for applying copy to the children | |||
if (null != this.children && this.children.Count > 0) | |||
{ | |||
string[] childrenName = this.children.Keys.ToArray(); | |||
foreach (string childName in childrenName) | |||
{ | |||
this.children[childName].CopyTo(newNode, childName); | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// Overrides ToString to renger the internal Trie to a string. | |||
/// </summary> | |||
/// <returns>The rendered Trie as string.</returns> | |||
public override string ToString() | |||
{ | |||
StringBuilder strinbBuilder = new StringBuilder(); | |||
this.Write(strinbBuilder, null, 0); | |||
return strinbBuilder.ToString(); | |||
} | |||
/// <summary> | |||
/// Writes a node to a string builder and recurse to the children. | |||
/// </summary> | |||
/// <param name="stringBuilder">The string builder used as output.</param> | |||
/// <param name="name">The node name.</param> | |||
/// <param name="level">The node level.</param> | |||
private void Write(StringBuilder stringBuilder, string name, int level) | |||
{ | |||
// Print the node only if the name is not null in order to ignore the root node for more clarity | |||
int nextLevel = level; | |||
if (null != name) | |||
{ | |||
++nextLevel; | |||
stringBuilder.AppendLine(string.Format("{0}{1}", new string('-', level), name)); | |||
} | |||
// Print each matching syntax node | |||
foreach (var matchingSyntaxNode in this.MatchingSyntaxNodes) | |||
{ | |||
stringBuilder.AppendLine(string.Format("{0}[{1}]", new string('-', level), matchingSyntaxNode.GetType().Name)); | |||
} | |||
// Recurse to children | |||
if (null != this.children) | |||
{ | |||
foreach (string childName in this.children.Keys) | |||
{ | |||
this.children[childName].Write(stringBuilder, childName, nextLevel); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,329 +0,0 @@ | |||
using Microsoft.CodeAnalysis; | |||
using Microsoft.CodeAnalysis.CSharp; | |||
using Microsoft.CodeAnalysis.CSharp.Syntax; | |||
using System; | |||
using System.Linq; | |||
namespace Projbook.Extension.CSharpExtractor | |||
{ | |||
/// <summary> | |||
/// Implements a syntax walker generating a Trie for pattern matching. | |||
/// </summary> | |||
public class CSharpSyntaxWalkerMatchingBuilder : CSharpSyntaxWalker | |||
{ | |||
/// <summary> | |||
/// The current Trie root available from the outside. | |||
/// </summary> | |||
public CSharpSyntaxMatchingNode Root { get; private set; } | |||
/// <summary> | |||
/// The Trie root referencing the root without any reference change. | |||
/// </summary> | |||
private CSharpSyntaxMatchingNode internalInvariantRoot; | |||
/// <summary> | |||
/// Initializes a new instance of <see cref="CSharpSyntaxWalkerMatchingBuilder"/>. | |||
/// </summary> | |||
public CSharpSyntaxWalkerMatchingBuilder() | |||
{ | |||
this.internalInvariantRoot = new CSharpSyntaxMatchingNode(); | |||
this.Root = this.internalInvariantRoot; | |||
} | |||
/// <summary> | |||
/// Visits a namespace declaration. | |||
/// A namespace may be composed with different segment dot separated, each segment has to be represented by a different node. | |||
/// However the syntax node is attached to the last node only. | |||
/// </summary> | |||
/// <param name="node">The namespace declaration node to visit.</param> | |||
public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) | |||
{ | |||
// Retrieve the namespace name and split segments | |||
string name = node.Name.ToString(); | |||
string[] namespaces = name.Split('.'); | |||
// Keep track of the initial node the restore the root after the visit | |||
CSharpSyntaxMatchingNode initialNode = this.Root; | |||
// Browse all namespaces and generate intermediate node for each segment for the copy to the root | |||
CSharpSyntaxMatchingNode firstNamespaceNode = null; | |||
foreach (string currentNamespace in namespaces) | |||
{ | |||
// Create the node and keep track of the first one | |||
this.Root = this.Root.EnsureNode(currentNamespace); | |||
if (null == firstNamespaceNode) | |||
{ | |||
firstNamespaceNode = this.Root; | |||
} | |||
} | |||
// Add the syntax node the last segment | |||
this.Root.AddSyntaxNode(node); | |||
// Triger member visiting | |||
base.VisitNamespaceDeclaration(node); | |||
// Copy the generated sub tree to the Trie root | |||
firstNamespaceNode.CopyTo(this.internalInvariantRoot, namespaces[0]); | |||
// Restore the initial root | |||
this.Root = initialNode; | |||
} | |||
/// <summary> | |||
/// Visits a class declaration. | |||
/// </summary> | |||
/// <param name="node">The class declaration to visit.</param> | |||
public override void VisitClassDeclaration(ClassDeclarationSyntax node) | |||
{ | |||
// Visit | |||
this.Visit<ClassDeclarationSyntax>( | |||
node: node, | |||
typeParameterList: node.TypeParameterList, | |||
exctractName: n => node.Identifier.ValueText, | |||
targetNode: n => n, | |||
visit: base.VisitClassDeclaration); | |||
} | |||
/// <summary> | |||
/// Visits an interface declaration. | |||
/// </summary> | |||
/// <param name="node">The class declaration to visit.</param> | |||
public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) | |||
{ | |||
// Visit | |||
this.Visit<InterfaceDeclarationSyntax>( | |||
node: node, | |||
typeParameterList: node.TypeParameterList, | |||
exctractName: n => node.Identifier.ValueText, | |||
targetNode: n => n, | |||
visit: base.VisitInterfaceDeclaration); | |||
} | |||
/// <summary> | |||
/// Visits an enum declaration. | |||
/// </summary> | |||
/// <param name="node">The enum declaration to visit.</param> | |||
public override void VisitEnumDeclaration(EnumDeclarationSyntax node) | |||
{ | |||
// Visit | |||
this.Visit<EnumDeclarationSyntax>( | |||
node: node, | |||
typeParameterList: null, | |||
exctractName: n => node.Identifier.ValueText, | |||
targetNode: n => n, | |||
visit: base.VisitEnumDeclaration); | |||
} | |||
/// <summary> | |||
/// Visits an enum member declaration. | |||
/// </summary> | |||
/// <param name="node">The enum member declaration to visit.</param> | |||
public override void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) | |||
{ | |||
// Visit | |||
this.Visit<EnumMemberDeclarationSyntax>( | |||
node: node, | |||
typeParameterList: null, | |||
exctractName: n => node.Identifier.ValueText, | |||
targetNode: n => n, | |||
visit: base.VisitEnumMemberDeclaration); | |||
} | |||
/// <summary> | |||
/// Visits a property declaration. | |||
/// </summary> | |||
/// <param name="node">The property declaration to visit.</param> | |||
public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) | |||
{ | |||
// Visit | |||
this.Visit<PropertyDeclarationSyntax>( | |||
node: node, | |||
typeParameterList: null, | |||
exctractName: n => n.Identifier.ValueText, | |||
targetNode: n => n, | |||
visit: base.VisitPropertyDeclaration); | |||
} | |||
/// <summary> | |||
/// Visits a field declaration. | |||
/// </summary> | |||
/// <param name="node">The field declaration to visit.</param> | |||
public override void VisitFieldDeclaration(FieldDeclarationSyntax node) | |||
{ | |||
// Visit each variable declaration | |||
foreach(VariableDeclaratorSyntax variableDeclarationSyntax in node.Declaration.Variables) | |||
{ | |||
this.Visit<FieldDeclarationSyntax>( | |||
node: node, | |||
typeParameterList: null, | |||
exctractName: n => variableDeclarationSyntax.Identifier.ValueText, | |||
targetNode: n => n, | |||
visit: base.VisitFieldDeclaration); | |||
} | |||
} | |||
/// <summary> | |||
/// Visits an indexter declaration. | |||
/// </summary> | |||
/// <param name="node">The indexter declaration to visit.</param> | |||
public override void VisitIndexerDeclaration(IndexerDeclarationSyntax node) | |||
{ | |||
// Compute suffix for representing generics | |||
string memberName = string.Empty; | |||
if (null != node.ParameterList) | |||
{ | |||
memberName = string.Format( | |||
"[{0}]", | |||
string.Join(",", node.ParameterList.Parameters.Select(x => x.Type.ToString()))); | |||
} | |||
// Visit | |||
this.Visit<IndexerDeclarationSyntax>( | |||
node: node, | |||
typeParameterList: null, | |||
exctractName: n => memberName, | |||
targetNode: n => n, | |||
visit: base.VisitIndexerDeclaration); | |||
} | |||
/// <summary> | |||
/// Visits an event declaration. | |||
/// </summary> | |||
/// <param name="node">The event declaration to visit.</param> | |||
public override void VisitEventDeclaration(EventDeclarationSyntax node) | |||
{ | |||
// Visit | |||
this.Visit<EventDeclarationSyntax>( | |||
node: node, | |||
typeParameterList: null, | |||
exctractName: n => n.Identifier.ValueText, | |||
targetNode: n => n, | |||
visit: base.VisitEventDeclaration); | |||
} | |||
/// <summary> | |||
/// Visits an accessor declaration. | |||
/// </summary> | |||
/// <param name="node">The accessor declaration to visit.</param> | |||
public override void VisitAccessorDeclaration(AccessorDeclarationSyntax node) | |||
{ | |||
// Visit | |||
this.Visit<AccessorDeclarationSyntax>( | |||
node: node, | |||
typeParameterList: null, | |||
exctractName: n => n.Keyword.ValueText, | |||
targetNode: n => n, | |||
visit: base.VisitAccessorDeclaration); | |||
} | |||
/// <summary> | |||
/// Visits a method declaration. | |||
/// </summary> | |||
/// <param name="node">The method declaration to visit.</param> | |||
public override void VisitMethodDeclaration(MethodDeclarationSyntax node) | |||
{ | |||
// Visit | |||
this.Visit<MethodDeclarationSyntax>( | |||
node: node, | |||
typeParameterList: node.TypeParameterList, | |||
exctractName: n => n.Identifier.ValueText, | |||
targetNode: n => n, | |||
visit: base.VisitMethodDeclaration); | |||
} | |||
/// <summary> | |||
/// Visits a constructor declaration. | |||
/// </summary> | |||
/// <param name="node">The constructor declaration to visit.</param> | |||
public override void VisitConstructorDeclaration(ConstructorDeclarationSyntax node) | |||
{ | |||
// Visit | |||
this.Visit<ConstructorDeclarationSyntax>( | |||
node: node, | |||
typeParameterList: null, | |||
exctractName: n => "<Constructor>", | |||
targetNode: n => n, | |||
visit: base.VisitConstructorDeclaration); | |||
} | |||
/// <summary> | |||
/// Visits a destructor declaration. | |||
/// </summary> | |||
/// <param name="node">The destructor declaration to visit.</param> | |||
public override void VisitDestructorDeclaration(DestructorDeclarationSyntax node) | |||
{ | |||
// Visit | |||
this.Visit<DestructorDeclarationSyntax>( | |||
node: node, | |||
typeParameterList: null, | |||
exctractName: n => "<Destructor>", | |||
targetNode: n => n, | |||
visit: base.VisitDestructorDeclaration); | |||
} | |||
/// <summary> | |||
/// Visits parameter list. | |||
/// </summary> | |||
/// <param name="node">The parameter list to visit.</param> | |||
public override void VisitParameterList(ParameterListSyntax node) | |||
{ | |||
// Skip parameter list when the parent is a lambda | |||
if ( | |||
SyntaxKind.SimpleLambdaExpression == node.Parent.Kind() || | |||
SyntaxKind.ParenthesizedLambdaExpression == node.Parent.Kind()) | |||
{ | |||
return; | |||
} | |||
// Visit | |||
this.Visit<ParameterListSyntax>( | |||
node: node, | |||
typeParameterList: null, | |||
exctractName: n => string.Format("({0})", string.Join(",", node.Parameters.Select(x => x.Type.ToString()))), | |||
targetNode: n => n.Parent, | |||
visit: base.VisitParameterList); | |||
} | |||
/// <summary> | |||
/// Visits a member. | |||
/// </summary> | |||
/// <typeparam name="T">The syntax node type to visit.</typeparam> | |||
/// <param name="node">The node to visit.</param> | |||
/// <param name="exctractName">Extract the node name.</param> | |||
/// <param name="typeParameterList">The type parameter list.</param> | |||
/// <param name="targetNode">Resolved the target node.</param> | |||
/// <param name="visit">Visit sub nodes.</param> | |||
private void Visit<T>(T node, Func<T, string> exctractName, TypeParameterListSyntax typeParameterList , Func<T, SyntaxNode> targetNode, Action<T> visit) where T : CSharpSyntaxNode | |||
{ | |||
// Retrieve the accessor name | |||
string name = exctractName(node); | |||
// Compute suffix for representing generics | |||
if (null != typeParameterList) | |||
{ | |||
name = string.Format( | |||
"{0}{{{1}}}", | |||
name, | |||
string.Join(",", typeParameterList.Parameters.Select(x => x.ToString()))); | |||
} | |||
// Keep track of the initial node the restore the root after the visit | |||
CSharpSyntaxMatchingNode initialNode = this.Root; | |||
// Create and add the node | |||
this.Root = this.Root.EnsureNode(name); | |||
this.Root.AddSyntaxNode(targetNode(node)); | |||
// Trigger member visiting | |||
visit(node); | |||
// Copy the class sub tree to the Trie root | |||
this.Root.CopyTo(this.internalInvariantRoot, name); | |||
// Restore the initial root | |||
this.Root = initialNode; | |||
} | |||
} | |||
} |
@@ -1,36 +0,0 @@ | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
using System.Runtime.InteropServices; | |||
// General Information about an assembly is controlled through the following | |||
// set of attributes. Change these attribute values to modify the information | |||
// associated with an assembly. | |||
[assembly: AssemblyTitle("Projbook.Extension.CSharpExtractor")] | |||
[assembly: AssemblyDescription("")] | |||
[assembly: AssemblyConfiguration("")] | |||
[assembly: AssemblyCompany("")] | |||
[assembly: AssemblyProduct("Projbook.Extension.CSharpExtractor")] | |||
[assembly: AssemblyCopyright("Copyright © 2016")] | |||
[assembly: AssemblyTrademark("")] | |||
[assembly: AssemblyCulture("")] | |||
// Setting ComVisible to false makes the types in this assembly not visible | |||
// to COM components. If you need to access a type in this assembly from | |||
// COM, set the ComVisible attribute to true on that type. | |||
[assembly: ComVisible(false)] | |||
// The following GUID is for the ID of the typelib if this project is exposed to COM | |||
[assembly: Guid("f5431901-29ac-46d4-a717-de2a9114e82d")] | |||
// Version information for an assembly consists of the following four values: | |||
// | |||
// Major Version | |||
// Minor Version | |||
// Build Number | |||
// Revision | |||
// | |||
// You can specify all the values or you can default the Build and Revision Numbers | |||
// by using the '*' as shown below: | |||
// [assembly: AssemblyVersion("1.0.*")] | |||
[assembly: AssemblyVersion("1.0.0.0")] | |||
[assembly: AssemblyFileVersion("1.0.0.0")] |
@@ -1,9 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<packages> | |||
<package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net45" /> | |||
<package id="Microsoft.CodeAnalysis.Common" version="1.3.2" targetFramework="net45" /> | |||
<package id="Microsoft.CodeAnalysis.CSharp" version="1.3.2" targetFramework="net45" /> | |||
<package id="System.Collections.Immutable" version="1.1.37" targetFramework="net45" /> | |||
<package id="System.IO.Abstractions" version="2.0.0.136" targetFramework="net45" /> | |||
<package id="System.Reflection.Metadata" version="1.2.0" targetFramework="net45" /> | |||
</packages> |
@@ -1,68 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | |||
<PropertyGroup> | |||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||
<ProjectGuid>{BC3E43EB-2263-49B4-883A-B720EDDF9298}</ProjectGuid> | |||
<OutputType>Library</OutputType> | |||
<AppDesignerFolder>Properties</AppDesignerFolder> | |||
<RootNamespace>Projbook.Extension.XmlExtractor</RootNamespace> | |||
<AssemblyName>Projbook.Extension.XmlExtractor</AssemblyName> | |||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> | |||
<FileAlignment>512</FileAlignment> | |||
<TargetFrameworkProfile /> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||
<DebugSymbols>true</DebugSymbols> | |||
<DebugType>full</DebugType> | |||
<Optimize>false</Optimize> | |||
<OutputPath>bin\Debug\</OutputPath> | |||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||
<DebugType>pdbonly</DebugType> | |||
<Optimize>true</Optimize> | |||
<OutputPath>bin\Release\</OutputPath> | |||
<DefineConstants>TRACE</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Reference Include="System" /> | |||
<Reference Include="System.Core" /> | |||
<Reference Include="System.IO.Abstractions, Version=2.0.0.136, Culture=neutral, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.IO.Abstractions.2.0.0.136\lib\net40\System.IO.Abstractions.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.Xml.Linq" /> | |||
<Reference Include="System.Data.DataSetExtensions" /> | |||
<Reference Include="Microsoft.CSharp" /> | |||
<Reference Include="System.Data" /> | |||
<Reference Include="System.Net.Http" /> | |||
<Reference Include="System.Xml" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Include="Projbook\Extension\Xml\XmlSnippetExtractor.cs" /> | |||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\Projbook.Extension\Projbook.Extension.csproj"> | |||
<Project>{8338b756-0519-4d20-ba04-3a8f4839237a}</Project> | |||
<Name>Projbook.Extension</Name> | |||
</ProjectReference> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Include="packages.config" /> | |||
</ItemGroup> | |||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||
Other similar extension points exist, see Microsoft.Common.targets. | |||
<Target Name="BeforeBuild"> | |||
</Target> | |||
<Target Name="AfterBuild"> | |||
</Target> | |||
--> | |||
</Project> |
@@ -1,159 +0,0 @@ | |||
using System; | |||
using Projbook.Extension.Exception; | |||
using Projbook.Extension.Spi; | |||
using System.IO.Abstractions; | |||
using System.Text; | |||
using System.Text.RegularExpressions; | |||
using System.Xml; | |||
namespace Projbook.Extension.XmlExtractor | |||
{ | |||
/// <summary> | |||
/// Extractor in charge of browsing source directories. load file content and extract requested member. | |||
/// </summary> | |||
[Syntax(name: "xml")] | |||
public class XmlSnippetExtractor : DefaultSnippetExtractor | |||
{ | |||
/// <summary> | |||
/// The regex extracting the document namespaces | |||
/// </summary> | |||
private Regex regex = new Regex(@"xmlns:([^=]+)=""([^""]*)""", RegexOptions.Compiled); | |||
/// <summary> | |||
/// The lazy loaded xml document. | |||
/// </summary> | |||
private XmlDocument xmlDocument; | |||
/// <summary> | |||
/// The lazy loaded namespace manager. | |||
/// </summary> | |||
private XmlNamespaceManager xmlNamespaceManager; | |||
/// <summary> | |||
/// Extracts a snippet from a given rule pattern. | |||
/// </summary> | |||
/// <param name="fileSystemInfo">The file system info.</param> | |||
/// <param name="memberPattern">The member pattern to extract.</param> | |||
/// <returns>The extracted snippet.</returns> | |||
public override Extension.Model.Snippet Extract(FileSystemInfoBase fileSystemInfo, string memberPattern) | |||
{ | |||
// Return the entire code if no member is specified | |||
if (string.IsNullOrWhiteSpace(memberPattern)) | |||
{ | |||
return base.Extract(fileSystemInfo, memberPattern); | |||
} | |||
// Load the xml document for xpath execution | |||
if (null == this.xmlDocument) | |||
{ | |||
// Load file content | |||
string sourceCode = base.LoadFile(this.ConvertToFile(fileSystemInfo)); | |||
// Remove default avoiding to define and use a prefix for the default namespace | |||
// This is not strictly correct in a xml point of view but it's closest to most needs | |||
sourceCode = Regex.Replace(sourceCode, @"xmlns\s*=\s*""[^""]*""", string.Empty); | |||
// Parse the file as xml | |||
this.xmlDocument = new XmlDocument(); | |||
try | |||
{ | |||
// Initialize the document and the namespace manager | |||
this.xmlDocument.LoadXml(sourceCode); | |||
this.xmlNamespaceManager = new XmlNamespaceManager(this.xmlDocument.NameTable); | |||
// Match namespace declaration for filling the namespace manager | |||
Match match = this.regex.Match(sourceCode); | |||
while (match.Success) | |||
{ | |||
// Collect prefix and namespace value | |||
string prefix = match.Groups[1].Value.Trim(); | |||
string ns = match.Groups[2].Value.Trim(); | |||
// Add namespace declaration to the namespace manager | |||
xmlNamespaceManager.AddNamespace(prefix, ns); | |||
// Mode to the next matching | |||
match = match.NextMatch(); | |||
} | |||
} | |||
// Throw an exception is the file is not loadable as xml document | |||
catch (System.Exception exception) | |||
{ | |||
throw new SnippetExtractionException("Cannot parse xml file", exception.Message); | |||
} | |||
} | |||
// Execute Xpath query | |||
XmlNodeList xmlNodeList = null; | |||
try | |||
{ | |||
xmlNodeList = this.xmlDocument.SelectNodes(memberPattern, this.xmlNamespaceManager); | |||
} | |||
catch | |||
{ | |||
throw new SnippetExtractionException("Invalid extraction rule", memberPattern); | |||
} | |||
// Ensure we found a result | |||
if (xmlNodeList.Count <= 0) | |||
{ | |||
throw new SnippetExtractionException("Cannot find member", memberPattern); | |||
} | |||
// Build a snippet for extracted nodes | |||
return this.BuildSnippet(xmlNodeList); | |||
} | |||
/// <summary> | |||
/// Builds a snippet from xml node. | |||
/// </summary> | |||
/// <param name="xmlNodeList">The xml node list.</param> | |||
/// <returns>The built snippet.</returns> | |||
private Extension.Model.Snippet BuildSnippet(XmlNodeList xmlNodeList) | |||
{ | |||
// Data validation | |||
if(xmlNodeList == null) | |||
{ | |||
throw new ArgumentNullException(nameof(xmlNodeList)); | |||
} | |||
// Extract code from each snippets | |||
StringBuilder stringBuilder = new StringBuilder(); | |||
bool firstSnippet = true; | |||
for (int i = 0; i < xmlNodeList.Count; ++i) | |||
{ | |||
// Get the current node | |||
XmlNode node = xmlNodeList.Item(i); | |||
// Write line return between each snippet | |||
if (!firstSnippet) | |||
{ | |||
stringBuilder.AppendLine(); | |||
stringBuilder.AppendLine(); | |||
} | |||
// Write each snippet | |||
XmlWriterSettings settings = new XmlWriterSettings(); | |||
settings.Indent = true; | |||
settings.OmitXmlDeclaration = true; | |||
settings.NewLineOnAttributes = true; | |||
using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder, settings)) | |||
{ | |||
node.WriteTo(xmlWriter); | |||
} | |||
// Flag the first snippet as false | |||
firstSnippet = false; | |||
} | |||
// Remove all generate namespace declaration | |||
// This is produce some output lacking of namespace declaration but it's what is relevant for a xml document extraction | |||
string output = stringBuilder.ToString(); | |||
output = Regex.Replace(output, @" ?xmlns\s*(:[^=]+)?\s*=\s*""[^""]*""", string.Empty); | |||
// Create the snippet from the extracted code | |||
return new Model.PlainTextSnippet(output); | |||
} | |||
} | |||
} |
@@ -1,36 +0,0 @@ | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
using System.Runtime.InteropServices; | |||
// General Information about an assembly is controlled through the following | |||
// set of attributes. Change these attribute values to modify the information | |||
// associated with an assembly. | |||
[assembly: AssemblyTitle("Projbook.Extension.XmlExtractor")] | |||
[assembly: AssemblyDescription("")] | |||
[assembly: AssemblyConfiguration("")] | |||
[assembly: AssemblyCompany("")] | |||
[assembly: AssemblyProduct("Projbook.Extension.XmlExtractor")] | |||
[assembly: AssemblyCopyright("Copyright © 2016")] | |||
[assembly: AssemblyTrademark("")] | |||
[assembly: AssemblyCulture("")] | |||
// Setting ComVisible to false makes the types in this assembly not visible | |||
// to COM components. If you need to access a type in this assembly from | |||
// COM, set the ComVisible attribute to true on that type. | |||
[assembly: ComVisible(false)] | |||
// The following GUID is for the ID of the typelib if this project is exposed to COM | |||
[assembly: Guid("bc3e43eb-2263-49b4-883a-b720eddf9298")] | |||
// Version information for an assembly consists of the following four values: | |||
// | |||
// Major Version | |||
// Minor Version | |||
// Build Number | |||
// Revision | |||
// | |||
// You can specify all the values or you can default the Build and Revision Numbers | |||
// by using the '*' as shown below: | |||
// [assembly: AssemblyVersion("1.0.*")] | |||
[assembly: AssemblyVersion("1.0.0.0")] | |||
[assembly: AssemblyFileVersion("1.0.0.0")] |
@@ -1,5 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<packages> | |||
<package id="Ensure.That" version="5.0.0" targetFramework="net45" /> | |||
<package id="System.IO.Abstractions" version="2.0.0.136" targetFramework="net45" /> | |||
</packages> |
@@ -11,9 +11,9 @@ | |||
public string Pattern { get; private set; } | |||
/// <summary> | |||
/// Initializes a new instance of <see cref="ProjbookEngine"/>. | |||
/// Initializes a new instance of <see cref="SnippetExtractionException"/>. | |||
/// </summary> | |||
/// <param name="message">Initializes the required <see cref="Message"/>.</param> | |||
/// <param name="message">Initializes the required message.</param> | |||
/// <param name="pattern">Initializes the required <see cref="Pattern"/>.</param> | |||
public SnippetExtractionException(string message, string pattern) | |||
: base(message) | |||
@@ -23,7 +23,7 @@ namespace Projbook.Extension.CSharpExtractor | |||
/// <summary> | |||
/// Defines rule regex used to parse the snippet into chunks. | |||
/// Expected input format: Path/File.cs [My.Name.Space.Class.Method][(string, string)] | |||
/// * The first chunk is the file name and will be loaded in <seealso cref="TargetFile"/> | |||
/// * The first chunk is the file name and will be loaded in TargetFile | |||
/// * The optional second chunks are all full qualified name to the member separated by "." | |||
/// * The optional last chunk is the method parameters if matching a method. | |||
/// </summary> | |||
@@ -21,6 +21,7 @@ | |||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
<DocumentationFile>bin\Debug\Projbook.Extension.XML</DocumentationFile> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||
<DebugType>pdbonly</DebugType> | |||
@@ -40,14 +41,15 @@ | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System" /> | |||
<Reference Include="System.Collections.Immutable, Version=1.1.37.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll</HintPath> | |||
<Reference Include="System.Collections.Immutable, Version=1.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\..\packages\System.Collections.Immutable.1.3.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.ComponentModel.Composition" /> | |||
<Reference Include="System.Core" /> | |||
<Reference Include="Microsoft.CSharp" /> | |||
<Reference Include="System.Reflection.Metadata, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath> | |||
<Reference Include="System.Reflection.Metadata, Version=1.4.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\..\packages\System.Reflection.Metadata.1.4.1\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.Threading.Thread, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
@@ -1,15 +1,15 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<configuration> | |||
<runtime> | |||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> | |||
<dependentAssembly> | |||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/> | |||
<bindingRedirect oldVersion="0.0.0.0-1.3.0.0" newVersion="1.3.0.0"/> | |||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> | |||
<bindingRedirect oldVersion="0.0.0.0-1.4.1.0" newVersion="1.4.1.0" /> | |||
</dependentAssembly> | |||
<dependentAssembly> | |||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/> | |||
<bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0"/> | |||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> | |||
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" /> | |||
</dependentAssembly> | |||
</assemblyBinding> | |||
</runtime> | |||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/></startup></configuration> | |||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" /></startup></configuration> |
@@ -3,14 +3,14 @@ | |||
<package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net451" /> | |||
<package id="Microsoft.CodeAnalysis.Common" version="1.3.2" targetFramework="net451" /> | |||
<package id="Microsoft.CodeAnalysis.CSharp" version="1.3.2" targetFramework="net451" /> | |||
<package id="System.Collections" version="4.0.0" targetFramework="net451" /> | |||
<package id="System.Collections.Immutable" version="1.1.37" targetFramework="net451" /> | |||
<package id="System.Diagnostics.Debug" version="4.0.0" targetFramework="net451" /> | |||
<package id="System.Globalization" version="4.0.0" targetFramework="net451" /> | |||
<package id="System.Linq" version="4.0.0" targetFramework="net451" /> | |||
<package id="System.Reflection.Metadata" version="1.2.0" targetFramework="net451" /> | |||
<package id="System.Resources.ResourceManager" version="4.0.0" targetFramework="net451" /> | |||
<package id="System.Runtime" version="4.0.0" targetFramework="net451" /> | |||
<package id="System.Runtime.Extensions" version="4.0.0" targetFramework="net451" /> | |||
<package id="System.Threading" version="4.0.0" targetFramework="net451" /> | |||
<package id="System.Collections" version="4.3.0" targetFramework="net451" /> | |||
<package id="System.Collections.Immutable" version="1.3.0" targetFramework="net451" /> | |||
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net451" /> | |||
<package id="System.Globalization" version="4.3.0" targetFramework="net451" /> | |||
<package id="System.Linq" version="4.3.0" targetFramework="net451" /> | |||
<package id="System.Reflection.Metadata" version="1.4.1" targetFramework="net451" /> | |||
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net451" /> | |||
<package id="System.Runtime" version="4.3.0" targetFramework="net451" /> | |||
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net451" /> | |||
<package id="System.Threading" version="4.3.0" targetFramework="net451" /> | |||
</packages> |