@@ -161,22 +161,298 @@ Error MustacheHTMLGenerator::generateDocs(
161161  return  Error::success ();
162162}
163163
164+ static  json::Value
165+ extractValue (const  Location &L,
166+              std::optional<StringRef> RepositoryUrl = std::nullopt ) {
167+   Object Obj = Object ();
168+   //  TODO: Consider using both Start/End line numbers to improve location report
169+   Obj.insert ({" LineNumber" StartLineNumber });
170+   Obj.insert ({" Filename" Filename });
171+ 
172+   if  (!L.IsFileInRootDir  || !RepositoryUrl)
173+     return  Obj;
174+   SmallString<128 > FileURL (*RepositoryUrl);
175+   sys::path::append (FileURL, sys::path::Style::posix, L.Filename );
176+   FileURL += " #" std::to_string (L.StartLineNumber );
177+   Obj.insert ({" FileURL" 
178+ 
179+   return  Obj;
180+ }
181+ 
182+ static  json::Value extractValue (const  Reference &I,
183+                                 StringRef CurrentDirectory) {
184+   SmallString<64 > Path = I.getRelativeFilePath (CurrentDirectory);
185+   sys::path::append (Path, I.getFileBaseName () + " .html" 
186+   sys::path::native (Path, sys::path::Style::posix);
187+   Object Obj = Object ();
188+   Obj.insert ({" Link" 
189+   Obj.insert ({" Name" Name });
190+   Obj.insert ({" QualName" QualName });
191+   Obj.insert ({" ID" toHex (toStringRef (I.USR ))});
192+   return  Obj;
193+ }
194+ 
195+ static  json::Value extractValue (const  TypedefInfo &I) {
196+   //  Not Supported
197+   return  nullptr ;
198+ }
199+ 
200+ static  json::Value extractValue (const  CommentInfo &I) {
201+   assert ((I.Kind  == " BlockCommandComment" Kind  == " FullComment" 
202+           I.Kind  == " ParagraphComment" Kind  == " TextComment" 
203+          " Unknown Comment type in CommentInfo." 
204+ 
205+   Object Obj = Object ();
206+   json::Value Child = Object ();
207+ 
208+   //  TextComment has no children, so return it.
209+   if  (I.Kind  == " TextComment" 
210+     Obj.insert ({" TextComment" Text });
211+     return  Obj;
212+   }
213+ 
214+   //  BlockCommandComment needs to generate a Command key.
215+   if  (I.Kind  == " BlockCommandComment" 
216+     Child.getAsObject ()->insert ({" Command" Name });
217+ 
218+   //  Use the same handling for everything else.
219+   //  Only valid for:
220+   //   - BlockCommandComment
221+   //   - FullComment
222+   //   - ParagraphComment
223+   json::Value ChildArr = Array ();
224+   auto  &CARef = *ChildArr.getAsArray ();
225+   CARef.reserve (I.Children .size ());
226+   for  (const  auto  &C : I.Children )
227+     CARef.emplace_back (extractValue (*C));
228+   Child.getAsObject ()->insert ({" Children" 
229+   Obj.insert ({I.Kind , Child});
230+ 
231+   return  Obj;
232+ }
233+ 
234+ static  void  maybeInsertLocation (std::optional<Location> Loc,
235+                                 const  ClangDocContext &CDCtx, Object &Obj) {
236+   if  (!Loc)
237+     return ;
238+   Location L = *Loc;
239+   Obj.insert ({" Location" extractValue (L, CDCtx.RepositoryUrl )});
240+ }
241+ 
242+ static  void  extractDescriptionFromInfo (ArrayRef<CommentInfo> Descriptions,
243+                                        json::Object &EnumValObj) {
244+   if  (Descriptions.empty ())
245+     return ;
246+   json::Value DescArr = Array ();
247+   json::Array &DescARef = *DescArr.getAsArray ();
248+   for  (const  CommentInfo &Child : Descriptions)
249+     DescARef.emplace_back (extractValue (Child));
250+   EnumValObj.insert ({" EnumValueComments" 
251+ }
252+ 
253+ static  json::Value extractValue (const  FunctionInfo &I, StringRef ParentInfoDir,
254+                                 const  ClangDocContext &CDCtx) {
255+   Object Obj = Object ();
256+   Obj.insert ({" Name" Name });
257+   Obj.insert ({" ID" toHex (toStringRef (I.USR ))});
258+   Obj.insert ({" Access" getAccessSpelling (I.Access ).str ()});
259+   Obj.insert ({" ReturnType" extractValue (I.ReturnType .Type , ParentInfoDir)});
260+ 
261+   json::Value ParamArr = Array ();
262+   json::Array &ParamARef = *ParamArr.getAsArray ();
263+   for  (const  auto  Val : enumerate(I.Params )) {
264+     json::Value V = Object ();
265+     auto  &VRef = *V.getAsObject ();
266+     VRef.insert ({" Name" value ().Name });
267+     VRef.insert ({" Type" value ().Type .Name });
268+     VRef.insert ({" End" index () + 1  == I.Params .size ()});
269+     ParamARef.emplace_back (V);
270+   }
271+   Obj.insert ({" Params" 
272+ 
273+   maybeInsertLocation (I.DefLoc , CDCtx, Obj);
274+   return  Obj;
275+ }
276+ 
277+ static  json::Value extractValue (const  EnumInfo &I,
278+                                 const  ClangDocContext &CDCtx) {
279+   Object Obj = Object ();
280+   std::string EnumType = I.Scoped  ? " enum class " " enum " 
281+   EnumType += I.Name ;
282+   bool  HasComment = std::any_of (
283+       I.Members .begin (), I.Members .end (),
284+       [](const  EnumValueInfo &M) { return  !M.Description .empty (); });
285+   Obj.insert ({" EnumName" 
286+   Obj.insert ({" HasComment" 
287+   Obj.insert ({" ID" toHex (toStringRef (I.USR ))});
288+   json::Value EnumArr = Array ();
289+   json::Array &EnumARef = *EnumArr.getAsArray ();
290+   for  (const  EnumValueInfo &M : I.Members ) {
291+     json::Value EnumValue = Object ();
292+     auto  &EnumValObj = *EnumValue.getAsObject ();
293+     EnumValObj.insert ({" Name" Name });
294+     if  (!M.ValueExpr .empty ())
295+       EnumValObj.insert ({" ValueExpr" ValueExpr });
296+     else 
297+       EnumValObj.insert ({" Value" Value });
298+ 
299+     extractDescriptionFromInfo (M.Description , EnumValObj);
300+     EnumARef.emplace_back (EnumValue);
301+   }
302+   Obj.insert ({" EnumValues" 
303+ 
304+   extractDescriptionFromInfo (I.Description , Obj);
305+   maybeInsertLocation (I.DefLoc , CDCtx, Obj);
306+ 
307+   return  Obj;
308+ }
309+ 
310+ static  void  extractScopeChildren (const  ScopeChildren &S, Object &Obj,
311+                                  StringRef ParentInfoDir,
312+                                  const  ClangDocContext &CDCtx) {
313+   json::Value NamespaceArr = Array ();
314+   json::Array &NamespaceARef = *NamespaceArr.getAsArray ();
315+   for  (const  Reference &Child : S.Namespaces )
316+     NamespaceARef.emplace_back (extractValue (Child, ParentInfoDir));
317+ 
318+   if  (!NamespaceARef.empty ())
319+     Obj.insert ({" Namespace" " Links" 
320+ 
321+   json::Value RecordArr = Array ();
322+   json::Array &RecordARef = *RecordArr.getAsArray ();
323+   for  (const  Reference &Child : S.Records )
324+     RecordARef.emplace_back (extractValue (Child, ParentInfoDir));
325+ 
326+   if  (!RecordARef.empty ())
327+     Obj.insert ({" Record" " Links" 
328+ 
329+   json::Value FunctionArr = Array ();
330+   json::Array &FunctionARef = *FunctionArr.getAsArray ();
331+ 
332+   json::Value PublicFunctionArr = Array ();
333+   json::Array &PublicFunctionARef = *PublicFunctionArr.getAsArray ();
334+ 
335+   json::Value ProtectedFunctionArr = Array ();
336+   json::Array &ProtectedFunctionARef = *ProtectedFunctionArr.getAsArray ();
337+ 
338+   for  (const  FunctionInfo &Child : S.Functions ) {
339+     json::Value F = extractValue (Child, ParentInfoDir, CDCtx);
340+     AccessSpecifier Access = Child.Access ;
341+     if  (Access == AccessSpecifier::AS_public)
342+       PublicFunctionARef.emplace_back (F);
343+     else  if  (Access == AccessSpecifier::AS_protected)
344+       ProtectedFunctionARef.emplace_back (F);
345+     else 
346+       FunctionARef.emplace_back (F);
347+   }
348+ 
349+   if  (!FunctionARef.empty ())
350+     Obj.insert ({" Function" " Obj" 
351+ 
352+   if  (!PublicFunctionARef.empty ())
353+     Obj.insert ({" PublicFunction" " Obj" 
354+ 
355+   if  (!ProtectedFunctionARef.empty ())
356+     Obj.insert ({" ProtectedFunction" " Obj" 
357+ 
358+   json::Value EnumArr = Array ();
359+   auto  &EnumARef = *EnumArr.getAsArray ();
360+   for  (const  EnumInfo &Child : S.Enums )
361+     EnumARef.emplace_back (extractValue (Child, CDCtx));
362+ 
363+   if  (!EnumARef.empty ())
364+     Obj.insert ({" Enums" " Obj" 
365+ 
366+   json::Value TypedefArr = Array ();
367+   auto  &TypedefARef = *TypedefArr.getAsArray ();
368+   for  (const  TypedefInfo &Child : S.Typedefs )
369+     TypedefARef.emplace_back (extractValue (Child));
370+ 
371+   if  (!TypedefARef.empty ())
372+     Obj.insert ({" Typedefs" " Obj" 
373+ }
374+ 
164375static  json::Value extractValue (const  NamespaceInfo &I,
165376                                const  ClangDocContext &CDCtx) {
166377  Object NamespaceValue = Object ();
378+   std::string InfoTitle = I.Name .empty () ? " Global Namespace" 
379+                                          : (Twine (" namespace " Name ).str ();
380+ 
381+   SmallString<64 > BasePath = I.getRelativeFilePath (" " 
382+   NamespaceValue.insert ({" NamespaceTitle" 
383+   NamespaceValue.insert ({" NamespacePath" 
384+ 
385+   extractDescriptionFromInfo (I.Description , NamespaceValue);
386+   extractScopeChildren (I.Children , NamespaceValue, BasePath, CDCtx);
167387  return  NamespaceValue;
168388}
169389
170390static  json::Value extractValue (const  RecordInfo &I,
171391                                const  ClangDocContext &CDCtx) {
172392  Object RecordValue = Object ();
393+   extractDescriptionFromInfo (I.Description , RecordValue);
394+   RecordValue.insert ({" Name" Name });
395+   RecordValue.insert ({" FullName" FullName });
396+   RecordValue.insert ({" RecordType" getTagType (I.TagType )});
397+ 
398+   maybeInsertLocation (I.DefLoc , CDCtx, RecordValue);
399+ 
400+   SmallString<64 > BasePath = I.getRelativeFilePath (" " 
401+   extractScopeChildren (I.Children , RecordValue, BasePath, CDCtx);
402+   json::Value PublicMembers = Array ();
403+   json::Array &PubMemberRef = *PublicMembers.getAsArray ();
404+   json::Value ProtectedMembers = Array ();
405+   json::Array &ProtMemberRef = *ProtectedMembers.getAsArray ();
406+   json::Value PrivateMembers = Array ();
407+   json::Array &PrivMemberRef = *PrivateMembers.getAsArray ();
408+   for  (const  MemberTypeInfo &Member : I.Members ) {
409+     json::Value MemberValue = Object ();
410+     auto  &MVRef = *MemberValue.getAsObject ();
411+     MVRef.insert ({" Name" Name });
412+     MVRef.insert ({" Type" Type .Name });
413+     extractDescriptionFromInfo (Member.Description , MVRef);
414+ 
415+     if  (Member.Access  == AccessSpecifier::AS_public)
416+       PubMemberRef.emplace_back (MemberValue);
417+     else  if  (Member.Access  == AccessSpecifier::AS_protected)
418+       ProtMemberRef.emplace_back (MemberValue);
419+     else  if  (Member.Access  == AccessSpecifier::AS_private)
420+       ProtMemberRef.emplace_back (MemberValue);
421+   }
422+   if  (!PubMemberRef.empty ())
423+     RecordValue.insert ({" PublicMembers" " Obj" 
424+   if  (!ProtMemberRef.empty ())
425+     RecordValue.insert ({" ProtectedMembers" " Obj" 
426+   if  (!PrivMemberRef.empty ())
427+     RecordValue.insert ({" PrivateMembers" " Obj" 
428+ 
173429  return  RecordValue;
174430}
175431
176432static  Error setupTemplateValue (const  ClangDocContext &CDCtx, json::Value &V,
177433                                Info *I) {
178-   return  createStringError (inconvertibleErrorCode (),
179-                            " setupTemplateValue is unimplemented" 
434+   V.getAsObject ()->insert ({" ProjectName" ProjectName });
435+   json::Value StylesheetArr = Array ();
436+   auto  InfoPath = I->getRelativeFilePath (" " 
437+   SmallString<128 > RelativePath = computeRelativePath (" " 
438+   sys::path::native (RelativePath, sys::path::Style::posix);
439+   for  (const  auto  &FilePath : CDCtx.UserStylesheets ) {
440+     SmallString<128 > StylesheetPath = RelativePath;
441+     sys::path::append (StylesheetPath, sys::path::Style::posix,
442+                       sys::path::filename (FilePath));
443+     StylesheetArr.getAsArray ()->emplace_back (StylesheetPath);
444+   }
445+   V.getAsObject ()->insert ({" Stylesheets" 
446+ 
447+   json::Value ScriptArr = Array ();
448+   for  (auto  Script : CDCtx.JsScripts ) {
449+     SmallString<128 > JsPath = RelativePath;
450+     sys::path::append (JsPath, sys::path::Style::posix,
451+                       sys::path::filename (Script));
452+     ScriptArr.getAsArray ()->emplace_back (JsPath);
453+   }
454+   V.getAsObject ()->insert ({" Scripts" 
455+   return  Error::success ();
180456}
181457
182458Error MustacheHTMLGenerator::generateDocForInfo (Info *I, raw_ostream &OS,
@@ -187,6 +463,7 @@ Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
187463        extractValue (*static_cast <clang::doc::NamespaceInfo *>(I), CDCtx);
188464    if  (auto  Err = setupTemplateValue (CDCtx, V, I))
189465      return  Err;
466+     assert (NamespaceTemplate && " NamespaceTemplate is nullptr." 
190467    NamespaceTemplate->render (V, OS);
191468    break ;
192469  }
0 commit comments