{"action":"created","comment":{"url":"https://api.github.com/repos/dotnet/docfx/pulls/comments/93933992","pull_request_review_id":14465270,"id":93933992,"diff_hunk":"@@ -0,0 +1,186 @@\n+﻿// Copyright (c) Microsoft. All rights reserved.\n+// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n+\n+namespace Microsoft.DocAsCode.Build.Common\n+{\n+    using System;\n+    using System.Collections;\n+    using System.Collections.Concurrent;\n+    using System.Reflection;\n+\n+    using Microsoft.DocAsCode.DataContracts.Common.Attributes;\n+    using System.Linq;\n+    using System.Collections.Generic;\n+    using System.Collections.Immutable;\n+    using Plugins;\n+\n+    public class MarkdownContentHandler : IModelAttributeHandler\n+    {\n+        private readonly static ConcurrentDictionary<Type, MarkdownContentHandlerImpl> _cache = new ConcurrentDictionary<Type, MarkdownContentHandlerImpl>();\n+\n+        public void Handle(object obj, HandleModelAttributesContext context)\n+        {\n+            if (obj == null)\n+            {\n+                return;\n+            }\n+\n+            if (context == null)\n+            {\n+                throw new ArgumentNullException(nameof(context));\n+            }\n+\n+            if (context.host == null)\n+            {\n+                throw new ArgumentNullException(nameof(context.host));\n+            }\n+\n+            var type = obj.GetType();\n+            _cache.GetOrAdd(type, new MarkdownContentHandlerImpl(type, this)).Handle(obj, context);\n+        }\n+\n+        private sealed class MarkdownContentHandlerImpl : BaseModelAttributeHandler<MarkdownContentAttribute>\n+        {\n+            private const string ContentPlaceholder = \"*content\";\n+            private string placeholderContentAfterMarkup = null;\n+\n+            public MarkdownContentHandlerImpl(Type type, IModelAttributeHandler handler) : base(type, handler)\n+            {\n+            }\n+\n+            protected override void HandleCurrentProperty(object declaringObject, PropertyInfo currentPropertyInfo, HandleModelAttributesContext context)\n+            {\n+                var obj = currentPropertyInfo.GetValue(declaringObject);\n+                if (obj == null)\n+                {\n+                    return;\n+                }\n+\n+                var val = obj as string;\n+                if (val != null)\n+                {\n+                    var marked = Markup(val, context);\n+                    currentPropertyInfo.SetValue(declaringObject, marked);\n+                }\n+                else\n+                {\n+                    throw new NotSupportedException($\"Type {obj.GetType()} is NOT a supported type for {nameof(MarkdownContentAttribute)}\");\n+                }\n+            }\n+\n+            protected override PropInfo[] GetProps(Type type)\n+            {\n+                return (from prop in ReflectionHelper.GetSettableProperties(type)\n+                        let attr = prop.GetCustomAttribute<MarkdownContentAttribute>()\n+                        select new PropInfo\n+                        {\n+                            Prop = prop,\n+                            Attr = attr\n+                        }).ToArray();\n+            }\n+\n+            protected override bool ShouldHandle(PropInfo currentPropInfo, object declaringObject, HandleModelAttributesContext context)\n+            {\n+                if (context.SkipMarkup)\n+                {\n+                    return false;\n+                }\n+\n+                // MarkdownContent will be marked and set back to the property, so the property type must be assignable from string\n+                if (!currentPropInfo.Prop.PropertyType.IsAssignableFrom(typeof(string)))\n+                {\n+                    if (currentPropInfo.Attr != null)\n+                    {\n+                        throw new NotSupportedException($\"Type {declaringObject.GetType()} is NOT a supported type for {nameof(MarkdownContentAttribute)}\");\n+                    }\n+                    return false;\n+                }\n+\n+                if (context.EnableContentPlaceholder)\n+                {\n+                    var currentValue = currentPropInfo.Prop.GetValue(declaringObject) as string;\n+                    if (currentValue != null && IsPlaceholderContent(currentValue))\n+                    {\n+                        return true;\n+                    }\n+                }\n+\n+                return currentPropInfo.Attr != null;","path":"src/Microsoft.DocAsCode.Build.Common/ModelAttributeHandlers/Handlers/MarkdownContentHandler.cs","position":108,"original_position":108,"commit_id":"c16eac3e0bc70821f81b253889f7e7dbf23424f7","original_commit_id":"c16eac3e0bc70821f81b253889f7e7dbf23424f7","user":{"login":"hellosnow","id":1836885,"avatar_url":"https://avatars.githubusercontent.com/u/1836885?v=3","gravatar_id":"","url":"https://api.github.com/users/hellosnow","html_url":"https://github.com/hellosnow","followers_url":"https://api.github.com/users/hellosnow/followers","following_url":"https://api.github.com/users/hellosnow/following{/other_user}","gists_url":"https://api.github.com/users/hellosnow/gists{/gist_id}","starred_url":"https://api.github.com/users/hellosnow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hellosnow/subscriptions","organizations_url":"https://api.github.com/users/hellosnow/orgs","repos_url":"https://api.github.com/users/hellosnow/repos","events_url":"https://api.github.com/users/hellosnow/events{/privacy}","received_events_url":"https://api.github.com/users/hellosnow/received_events","type":"User","site_admin":false},"body":"need this line call base.ShouldHandle() instead?","created_at":"2016-12-27T14:06:20Z","updated_at":"2016-12-27T14:06:20Z","html_url":"https://github.com/dotnet/docfx/pull/1064#discussion_r93933992","pull_request_url":"https://api.github.com/repos/dotnet/docfx/pulls/1064","_links":{"self":{"href":"https://api.github.com/repos/dotnet/docfx/pulls/comments/93933992"},"html":{"href":"https://github.com/dotnet/docfx/pull/1064#discussion_r93933992"},"pull_request":{"href":"https://api.github.com/repos/dotnet/docfx/pulls/1064"}}},"pull_request":{"url":"https://api.github.com/repos/dotnet/docfx/pulls/1064","id":99420816,"html_url":"https://github.com/dotnet/docfx/pull/1064","diff_url":"https://github.com/dotnet/docfx/pull/1064.diff","patch_url":"https://github.com/dotnet/docfx/pull/1064.patch","issue_url":"https://api.github.com/repos/dotnet/docfx/issues/1064","number":1064,"state":"open","locked":false,"title":"Add MarkdownContentAttribute","user":{"login":"vicancy","id":668244,"avatar_url":"https://avatars.githubusercontent.com/u/668244?v=3","gravatar_id":"","url":"https://api.github.com/users/vicancy","html_url":"https://github.com/vicancy","followers_url":"https://api.github.com/users/vicancy/followers","following_url":"https://api.github.com/users/vicancy/following{/other_user}","gists_url":"https://api.github.com/users/vicancy/gists{/gist_id}","starred_url":"https://api.github.com/users/vicancy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vicancy/subscriptions","organizations_url":"https://api.github.com/users/vicancy/orgs","repos_url":"https://api.github.com/users/vicancy/repos","events_url":"https://api.github.com/users/vicancy/events{/privacy}","received_events_url":"https://api.github.com/users/vicancy/received_events","type":"User","site_admin":false},"body":"And support *content","created_at":"2016-12-27T08:55:29Z","updated_at":"2016-12-27T14:06:20Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a7d0e96aa00f397d2c0d365b32d5604134e63822","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/dotnet/docfx/pulls/1064/commits","review_comments_url":"https://api.github.com/repos/dotnet/docfx/pulls/1064/comments","review_comment_url":"https://api.github.com/repos/dotnet/docfx/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dotnet/docfx/issues/1064/comments","statuses_url":"https://api.github.com/repos/dotnet/docfx/statuses/c16eac3e0bc70821f81b253889f7e7dbf23424f7","head":{"label":"vicancy:mdattr","ref":"mdattr","sha":"c16eac3e0bc70821f81b253889f7e7dbf23424f7","user":{"login":"vicancy","id":668244,"avatar_url":"https://avatars.githubusercontent.com/u/668244?v=3","gravatar_id":"","url":"https://api.github.com/users/vicancy","html_url":"https://github.com/vicancy","followers_url":"https://api.github.com/users/vicancy/followers","following_url":"https://api.github.com/users/vicancy/following{/other_user}","gists_url":"https://api.github.com/users/vicancy/gists{/gist_id}","starred_url":"https://api.github.com/users/vicancy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vicancy/subscriptions","organizations_url":"https://api.github.com/users/vicancy/orgs","repos_url":"https://api.github.com/users/vicancy/repos","events_url":"https://api.github.com/users/vicancy/events{/privacy}","received_events_url":"https://api.github.com/users/vicancy/received_events","type":"User","site_admin":false},"repo":{"id":77111138,"name":"docfx","full_name":"vicancy/docfx","owner":{"login":"vicancy","id":668244,"avatar_url":"https://avatars.githubusercontent.com/u/668244?v=3","gravatar_id":"","url":"https://api.github.com/users/vicancy","html_url":"https://github.com/vicancy","followers_url":"https://api.github.com/users/vicancy/followers","following_url":"https://api.github.com/users/vicancy/following{/other_user}","gists_url":"https://api.github.com/users/vicancy/gists{/gist_id}","starred_url":"https://api.github.com/users/vicancy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vicancy/subscriptions","organizations_url":"https://api.github.com/users/vicancy/orgs","repos_url":"https://api.github.com/users/vicancy/repos","events_url":"https://api.github.com/users/vicancy/events{/privacy}","received_events_url":"https://api.github.com/users/vicancy/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/vicancy/docfx","description":"Tools for building and publishing API documentation for .NET projects","fork":true,"url":"https://api.github.com/repos/vicancy/docfx","forks_url":"https://api.github.com/repos/vicancy/docfx/forks","keys_url":"https://api.github.com/repos/vicancy/docfx/keys{/key_id}","collaborators_url":"https://api.github.com/repos/vicancy/docfx/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/vicancy/docfx/teams","hooks_url":"https://api.github.com/repos/vicancy/docfx/hooks","issue_events_url":"https://api.github.com/repos/vicancy/docfx/issues/events{/number}","events_url":"https://api.github.com/repos/vicancy/docfx/events","assignees_url":"https://api.github.com/repos/vicancy/docfx/assignees{/user}","branches_url":"https://api.github.com/repos/vicancy/docfx/branches{/branch}","tags_url":"https://api.github.com/repos/vicancy/docfx/tags","blobs_url":"https://api.github.com/repos/vicancy/docfx/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/vicancy/docfx/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/vicancy/docfx/git/refs{/sha}","trees_url":"https://api.github.com/repos/vicancy/docfx/git/trees{/sha}","statuses_url":"https://api.github.com/repos/vicancy/docfx/statuses/{sha}","languages_url":"https://api.github.com/repos/vicancy/docfx/languages","stargazers_url":"https://api.github.com/repos/vicancy/docfx/stargazers","contributors_url":"https://api.github.com/repos/vicancy/docfx/contributors","subscribers_url":"https://api.github.com/repos/vicancy/docfx/subscribers","subscription_url":"https://api.github.com/repos/vicancy/docfx/subscription","commits_url":"https://api.github.com/repos/vicancy/docfx/commits{/sha}","git_commits_url":"https://api.github.com/repos/vicancy/docfx/git/commits{/sha}","comments_url":"https://api.github.com/repos/vicancy/docfx/comments{/number}","issue_comment_url":"https://api.github.com/repos/vicancy/docfx/issues/comments{/number}","contents_url":"https://api.github.com/repos/vicancy/docfx/contents/{+path}","compare_url":"https://api.github.com/repos/vicancy/docfx/compare/{base}...{head}","merges_url":"https://api.github.com/repos/vicancy/docfx/merges","archive_url":"https://api.github.com/repos/vicancy/docfx/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/vicancy/docfx/downloads","issues_url":"https://api.github.com/repos/vicancy/docfx/issues{/number}","pulls_url":"https://api.github.com/repos/vicancy/docfx/pulls{/number}","milestones_url":"https://api.github.com/repos/vicancy/docfx/milestones{/number}","notifications_url":"https://api.github.com/repos/vicancy/docfx/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/vicancy/docfx/labels{/name}","releases_url":"https://api.github.com/repos/vicancy/docfx/releases{/id}","deployments_url":"https://api.github.com/repos/vicancy/docfx/deployments","created_at":"2016-12-22T04:09:13Z","updated_at":"2016-12-22T04:09:20Z","pushed_at":"2016-12-27T08:54:30Z","git_url":"git://github.com/vicancy/docfx.git","ssh_url":"git@github.com:vicancy/docfx.git","clone_url":"https://github.com/vicancy/docfx.git","svn_url":"https://github.com/vicancy/docfx","homepage":"http://dotnet.github.io/docfx/","size":155563,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"dev"}},"base":{"label":"dotnet:dev","ref":"dev","sha":"a8987e897d9fec604078550e916b52f556b28b33","user":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars.githubusercontent.com/u/9141961?v=3","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"repo":{"id":38007053,"name":"docfx","full_name":"dotnet/docfx","owner":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars.githubusercontent.com/u/9141961?v=3","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dotnet/docfx","description":"Tools for building and publishing API documentation for .NET projects","fork":false,"url":"https://api.github.com/repos/dotnet/docfx","forks_url":"https://api.github.com/repos/dotnet/docfx/forks","keys_url":"https://api.github.com/repos/dotnet/docfx/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dotnet/docfx/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dotnet/docfx/teams","hooks_url":"https://api.github.com/repos/dotnet/docfx/hooks","issue_events_url":"https://api.github.com/repos/dotnet/docfx/issues/events{/number}","events_url":"https://api.github.com/repos/dotnet/docfx/events","assignees_url":"https://api.github.com/repos/dotnet/docfx/assignees{/user}","branches_url":"https://api.github.com/repos/dotnet/docfx/branches{/branch}","tags_url":"https://api.github.com/repos/dotnet/docfx/tags","blobs_url":"https://api.github.com/repos/dotnet/docfx/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dotnet/docfx/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dotnet/docfx/git/refs{/sha}","trees_url":"https://api.github.com/repos/dotnet/docfx/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dotnet/docfx/statuses/{sha}","languages_url":"https://api.github.com/repos/dotnet/docfx/languages","stargazers_url":"https://api.github.com/repos/dotnet/docfx/stargazers","contributors_url":"https://api.github.com/repos/dotnet/docfx/contributors","subscribers_url":"https://api.github.com/repos/dotnet/docfx/subscribers","subscription_url":"https://api.github.com/repos/dotnet/docfx/subscription","commits_url":"https://api.github.com/repos/dotnet/docfx/commits{/sha}","git_commits_url":"https://api.github.com/repos/dotnet/docfx/git/commits{/sha}","comments_url":"https://api.github.com/repos/dotnet/docfx/comments{/number}","issue_comment_url":"https://api.github.com/repos/dotnet/docfx/issues/comments{/number}","contents_url":"https://api.github.com/repos/dotnet/docfx/contents/{+path}","compare_url":"https://api.github.com/repos/dotnet/docfx/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dotnet/docfx/merges","archive_url":"https://api.github.com/repos/dotnet/docfx/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dotnet/docfx/downloads","issues_url":"https://api.github.com/repos/dotnet/docfx/issues{/number}","pulls_url":"https://api.github.com/repos/dotnet/docfx/pulls{/number}","milestones_url":"https://api.github.com/repos/dotnet/docfx/milestones{/number}","notifications_url":"https://api.github.com/repos/dotnet/docfx/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dotnet/docfx/labels{/name}","releases_url":"https://api.github.com/repos/dotnet/docfx/releases{/id}","deployments_url":"https://api.github.com/repos/dotnet/docfx/deployments","created_at":"2015-06-24T19:43:53Z","updated_at":"2016-12-27T08:53:20Z","pushed_at":"2016-12-27T08:55:30Z","git_url":"git://github.com/dotnet/docfx.git","ssh_url":"git@github.com:dotnet/docfx.git","clone_url":"https://github.com/dotnet/docfx.git","svn_url":"https://github.com/dotnet/docfx","homepage":"http://dotnet.github.io/docfx/","size":155561,"stargazers_count":501,"watchers_count":501,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":145,"mirror_url":null,"open_issues_count":92,"forks":145,"open_issues":92,"watchers":501,"default_branch":"dev"}},"_links":{"self":{"href":"https://api.github.com/repos/dotnet/docfx/pulls/1064"},"html":{"href":"https://github.com/dotnet/docfx/pull/1064"},"issue":{"href":"https://api.github.com/repos/dotnet/docfx/issues/1064"},"comments":{"href":"https://api.github.com/repos/dotnet/docfx/issues/1064/comments"},"review_comments":{"href":"https://api.github.com/repos/dotnet/docfx/pulls/1064/comments"},"review_comment":{"href":"https://api.github.com/repos/dotnet/docfx/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dotnet/docfx/pulls/1064/commits"},"statuses":{"href":"https://api.github.com/repos/dotnet/docfx/statuses/c16eac3e0bc70821f81b253889f7e7dbf23424f7"}}}}
{"actor":{"display_login":"hellosnow"}}