- 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"> | <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> | ||||
<dependentAssembly> | <dependentAssembly> | ||||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> | <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> | ||||
<dependentAssembly> | <dependentAssembly> | ||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> | <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> | </dependentAssembly> | ||||
</assemblyBinding> | </assemblyBinding> | ||||
</runtime> | </runtime> |
@@ -33,11 +33,15 @@ | |||||
<WarningLevel>4</WarningLevel> | <WarningLevel>4</WarningLevel> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
<ItemGroup> | <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> | <Private>True</Private> | ||||
</Reference> | </Reference> | ||||
<Reference Include="System" /> | <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.Configuration" /> | ||||
<Reference Include="System.Core" /> | <Reference Include="System.Core" /> | ||||
<Reference Include="System.Web" /> | <Reference Include="System.Web" /> | ||||
@@ -72,6 +76,9 @@ | |||||
<Name>MarkdownDeep</Name> | <Name>MarkdownDeep</Name> | ||||
</ProjectReference> | </ProjectReference> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | |||||
<WCFMetadata Include="Service References\" /> | |||||
</ItemGroup> | |||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | <!-- 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. | 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 | // You can specify all the values or you can default the Build and Revision Numbers | ||||
// by using the '*' as shown below: | // by using the '*' as shown below: | ||||
// [assembly: AssemblyVersion("1.0.*")] | // [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); | this.MarkdownFromFile = File.ReadAllText(sourceFile, Encoding.UTF8); | ||||
// Check if the content contains @@include tag | // Check if the content contains @@include tag | ||||
content = Utils.IncludeProcessor(this.MarkdownFromFile, Utils.MakeAbsolutePath(activeConfig.Source, activeConfig.IncludeFolder)); | 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 | else | ||||
{ | { | ||||
@@ -90,7 +90,7 @@ namespace Docnet | |||||
defaultMarkdown.AppendFormat("* [{0}]({1}{2}){3}", sibling.Name, relativePathToRoot, HttpUtility.UrlPathEncode(sibling.TargetURL), Environment.NewLine); | defaultMarkdown.AppendFormat("* [{0}]({1}{2}){3}", sibling.Name, relativePathToRoot, HttpUtility.UrlPathEncode(sibling.TargetURL), Environment.NewLine); | ||||
} | } | ||||
defaultMarkdown.Append(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 | else | ||||
{ | { | ||||
@@ -39,15 +39,17 @@ namespace Docnet | |||||
private static Regex includeRegex = new Regex(@"@@include\((.*)\)", RegexOptions.IgnoreCase | RegexOptions.Compiled); | private static Regex includeRegex = new Regex(@"@@include\((.*)\)", RegexOptions.IgnoreCase | RegexOptions.Compiled); | ||||
#endregion | #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 | var parser = new MarkdownDeep.Markdown | ||||
{ | { | ||||
@@ -56,8 +58,9 @@ namespace Docnet | |||||
AutoHeadingIDs = true, | AutoHeadingIDs = true, | ||||
NewWindowForExternalLinks = true, | NewWindowForExternalLinks = true, | ||||
DocNetMode = true, | DocNetMode = true, | ||||
DocumentLocation = documentPath, | |||||
DestinationDocumentLocation = destinationDocumentPath, | |||||
DocumentRoot = siteRoot, | DocumentRoot = siteRoot, | ||||
SourceDocumentFilename = sourceDocumentFilename, | |||||
HtmlClassTitledImages = "figure", | HtmlClassTitledImages = "figure", | ||||
}; | }; | ||||
@@ -1,4 +1,5 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||
<packages> | <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> | </packages> |
@@ -1533,7 +1533,7 @@ namespace MarkdownDeep | |||||
} | } | ||||
// extract the snippet, then build the fenced block to return. | // 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; | var snippetText = extractor.Extract(fullFilename, pattern) ?? string.Empty; | ||||
b.BlockType = BlockType.codeblock; | b.BlockType = BlockType.codeblock; | ||||
b.Data = language; | b.Data = language; | ||||
@@ -299,7 +299,7 @@ namespace MarkdownDeep | |||||
return false; | return false; | ||||
// Work out base location | // Work out base location | ||||
string str = url.StartsWith("/") ? DocumentRoot : DocumentLocation; | |||||
string str = url.StartsWith("/") ? DocumentRoot : DestinationDocumentLocation; | |||||
if (String.IsNullOrEmpty(str)) | if (String.IsNullOrEmpty(str)) | ||||
return false; | return false; | ||||
@@ -909,15 +909,19 @@ namespace MarkdownDeep | |||||
set; | 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. | // path images for image size. | ||||
// Typical value: c:\inetpub\www\wwwroot\subfolder | // Typical value: c:\inetpub\www\wwwroot\subfolder | ||||
public string DocumentLocation | |||||
public string DestinationDocumentLocation | |||||
{ | { | ||||
get; | get; | ||||
set; | set; | ||||
} | } | ||||
public string SourceDocumentFilename { get; set; } | |||||
// Limit the width of images (0 for no limit) | // Limit the width of images (0 for no limit) | ||||
public int MaxImageWidth | public int MaxImageWidth | ||||
{ | { | ||||
@@ -44,6 +44,8 @@ | |||||
<WarningLevel>4</WarningLevel> | <WarningLevel>4</WarningLevel> | ||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> | <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> | ||||
<Prefer32Bit>false</Prefer32Bit> | <Prefer32Bit>false</Prefer32Bit> | ||||
<DocumentationFile> | |||||
</DocumentationFile> | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||||
<DebugType>pdbonly</DebugType> | <DebugType>pdbonly</DebugType> | ||||
@@ -111,6 +113,9 @@ | |||||
<Name>Projbook.Extension</Name> | <Name>Projbook.Extension</Name> | ||||
</ProjectReference> | </ProjectReference> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | |||||
<None Include="app.config" /> | |||||
</ItemGroup> | |||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||||
<PropertyGroup> | <PropertyGroup> | ||||
<PostBuildEvent> | <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> | <HintPath>..\..\packages\NUnit.2.5.10.11092\lib\pnunit.framework.dll</HintPath> | ||||
</Reference> | </Reference> | ||||
<Reference Include="System" /> | <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"> | <Reference Include="System.Core"> | ||||
<RequiredTargetFramework>3.5</RequiredTargetFramework> | <RequiredTargetFramework>3.5</RequiredTargetFramework> | ||||
</Reference> | </Reference> | ||||
@@ -10,4 +10,16 @@ | |||||
<add key="ApartmentState" value="STA" /> | <add key="ApartmentState" value="STA" /> | ||||
</TestRunner> | </TestRunner> | ||||
</NUnit> | </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> | </configuration> |
@@ -1,4 +1,5 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||
<packages> | <packages> | ||||
<package id="NUnit" version="2.5.10.11092" /> | <package id="NUnit" version="2.5.10.11092" /> | ||||
<package id="System.Collections.Immutable" version="1.3.0" targetFramework="net461" /> | |||||
</packages> | </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; } | public string Pattern { get; private set; } | ||||
/// <summary> | /// <summary> | ||||
/// Initializes a new instance of <see cref="ProjbookEngine"/>. | |||||
/// Initializes a new instance of <see cref="SnippetExtractionException"/>. | |||||
/// </summary> | /// </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> | /// <param name="pattern">Initializes the required <see cref="Pattern"/>.</param> | ||||
public SnippetExtractionException(string message, string pattern) | public SnippetExtractionException(string message, string pattern) | ||||
: base(message) | : base(message) | ||||
@@ -23,7 +23,7 @@ namespace Projbook.Extension.CSharpExtractor | |||||
/// <summary> | /// <summary> | ||||
/// Defines rule regex used to parse the snippet into chunks. | /// Defines rule regex used to parse the snippet into chunks. | ||||
/// Expected input format: Path/File.cs [My.Name.Space.Class.Method][(string, string)] | /// 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 second chunks are all full qualified name to the member separated by "." | ||||
/// * The optional last chunk is the method parameters if matching a method. | /// * The optional last chunk is the method parameters if matching a method. | ||||
/// </summary> | /// </summary> | ||||
@@ -21,6 +21,7 @@ | |||||
<DefineConstants>DEBUG;TRACE</DefineConstants> | <DefineConstants>DEBUG;TRACE</DefineConstants> | ||||
<ErrorReport>prompt</ErrorReport> | <ErrorReport>prompt</ErrorReport> | ||||
<WarningLevel>4</WarningLevel> | <WarningLevel>4</WarningLevel> | ||||
<DocumentationFile>bin\Debug\Projbook.Extension.XML</DocumentationFile> | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||||
<DebugType>pdbonly</DebugType> | <DebugType>pdbonly</DebugType> | ||||
@@ -40,14 +41,15 @@ | |||||
<Private>True</Private> | <Private>True</Private> | ||||
</Reference> | </Reference> | ||||
<Reference Include="System" /> | <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> | <Private>True</Private> | ||||
</Reference> | </Reference> | ||||
<Reference Include="System.ComponentModel.Composition" /> | |||||
<Reference Include="System.Core" /> | <Reference Include="System.Core" /> | ||||
<Reference Include="Microsoft.CSharp" /> | <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> | <Private>True</Private> | ||||
</Reference> | </Reference> | ||||
<Reference Include="System.Threading.Thread, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | <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> | <configuration> | ||||
<runtime> | <runtime> | ||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> | <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> | ||||
<dependentAssembly> | <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> | ||||
<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> | </dependentAssembly> | ||||
</assemblyBinding> | </assemblyBinding> | ||||
</runtime> | </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.Analyzers" version="1.1.0" targetFramework="net451" /> | ||||
<package id="Microsoft.CodeAnalysis.Common" version="1.3.2" 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="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> | </packages> |