' DocGeneratorCS class
'
' Generates html and markdown documentation for C# code from compiler-generated xml files based on three-slash ( /// ) code comments.
'
' Four base tags are supported: summary, parameters, returns, and remarks. Within these tags, html tags are allowed, although Markdown typically does not render all html tags.
'
' Note: When changes are made to source-code comments, the code must be compiled again in order for new .xml files to be generated, before running the doc-generator script.
'
' Note: Html tags may result in malformed markdown table rows when there is whitespace between adjacent tags.
'
Class DocGeneratorCS
Private xml 'MSXML2.DomDocument.6.0 object
Private html 'text stream object for writing
Private md 'text stream object for writing
Private xmlFile 'filespec
Private outFile_ 'partial filespec
Private htmlFile 'filespec of html output file
Private mdFile 'filespec of markdown output file
Private fso 'Scripting.FileSystemObject object
Private sh 'WScript.Shell object
Private f 'VBScripting.StringFormatter object
Private ForWriting, CreateNew 'faux constants for OpenTextFile
Sub Class_Initialize
Set fso = CreateObject( "Scripting.FileSystemObject" )
Set sh = CreateObject( "WScript.Shell" )
Set f = CreateObject( "VBScripting.StringFormatter" )
Set xml = CreateObject( "MSXML2.DomDocument.6.0" )
With CreateObject( "VBScripting.Includer" )
ExecuteGlobal .Read( "EscapeMd" )
End With
xml.Async = False
ForWriting = 2
CreateNew = True
End Sub
Sub Class_Terminate
Set xml = Nothing
On Error Resume Next
html.Close
md.Close
On Error Goto 0
Set html = Nothing
Set md = Nothing
Set fso = Nothing
Set sh = Nothing
Set f = Nothing
End Sub
'Property XmlFolder
'Parameter: folder
'Returns: folder
'Remarks: Required. Sets (or gets) the folder containing the .xml files autogenerated by the C# compiler. Relative paths and environment variables are supported.
Property Get XmlFolder
XmlFolder = sh.ExpandEnvironmentStrings(xmlFolder_)
End Property
Property Let XmlFolder(newFolder)
xmlFolder_ = newFolder
ValidateXmlFolder
End Property
Private xmlFolder_
'Property OutputFile
'Parameters: filespec
'Returns: filespec
'Remarks: Required. Sets (or gets) the path and base name of the output files. Do not include the .html or .md extension name: they will be added automatically. Older versions, if any, will be overwritten. Relative paths and environment variables are supported.
Property Get OutputFile
OutputFile = Expand(outFile_)
End Property
Property Let OutputFile(newValue)
outFile_ = newValue
htmlFile = Expand(outFile_) & ".html"
mdFile = Expand(outFile_) & ".md"
End Property
Function Expand(path)
Expand = sh.ExpandEnvironmentStrings(path)
End Function
'Method Generate
'Remarks: Generates html and markdown code documentation. Requires .xml files to have been generated by the C# compiler.
Sub Generate
ValidateXmlFolder
WriteHtmlHeader
WriteMarkdownHeader
Dim file
For Each file In fso.GetFolder(xmlFolder_).Files
GenerateTable file.Path
Next
WriteHtmlFooter
End Sub
'Method ViewHtml
'Remarks: Opens the html document with the default viewer.
Sub ViewHtml
sh.Run """" & htmlFile & """"
End Sub
'Method ViewMarkdown
'Remarks: Opens the markdown document with the default viewer.
Sub ViewMarkdown
sh.Run """" & mdFile & """"
End Sub
Sub GenerateTable(xmlFile)
Dim member 'xml node object for a C# class member
If Not "xml" = LCase(fso.GetExtensionName(xmlFile)) Then
Exit Sub
End If
xml.Load xmlFile
If xml.ParseError.ErrorCode Then
Err.Raise xml.ParseError.ErrorCode,, xml.ParseError.Reason & vbLf & "File: " & xmlFile
End If
GenerateHtmlTableHeader xmlFile
GenerateMarkdownTableHeader xmlFile
For Each member In xml.getElementsByTagName( "member" )
GenerateRow member
Next
html.WriteLine ""
End Sub
Sub GenerateHtmlTableHeader(xmlFile)
html.WriteLine ""
html.WriteLine "
" & fso.GetBaseName(xmlFile) & "
"
html.WriteLine ""
html.WriteLine " "
html.WriteLine " | Member name | "
html.WriteLine " Remarks | "
html.WriteLine " Returns | "
html.WriteLine " Parameters | "
html.WriteLine " Kind | "
html.WriteLine " Member of | "
html.WriteLine " Namespace | "
html.WriteLine "
"
End Sub
Sub GenerateMarkdownTableHeader(xmlFile)
md.WriteLine ""
md.WriteLine "## " & fso.GetBaseName(xmlFile)
md.WriteLine ""
md.WriteLine "| Member name | Remarks | Returns | Parameters | Kind | Member of | Namespace |"
md.WriteLine "| :---------- | :------ | :------ | :--------- | :--- | :-------- | :-------- |"
End Sub
Sub GenerateRow(member)
Dim info : Set info = GetMemberInfo(member)
If Len(Trim(info.Summary & info.Remarks)) < 3 And 0 = Len(Trim(info.Returns)) Then
Exit Sub
End If
GenerateHtmlRow info
GenerateMarkdownRow info
End Sub
Sub GenerateHtmlRow(info)
html.WriteLine " "
html.WriteLine f(Array(" | %s | ", info.Name))
html.WriteLine f(Array(" %s | ", info.Summary & " " & info.Remarks))
html.WriteLine f(Array(" %s | ", info.Returns))
html.WriteLine f(Array(" %s | ", info.Parameters))
html.WriteLine f(Array(" %s | ", info.Kind))
If "Type" = info.Kind Then
html.WriteLine " | "
Else
html.WriteLine f(Array(" %s | ", info.MemberOf))
End If
html.WriteLine f(Array(" %s | ", info.NamespaceName))
html.WriteLine "
"
End Sub
Sub GenerateMarkdownRow(info)
md.Write f(Array("| %s ", info.Name))
md.Write f(Array("| %s ", EscapeMd2(info.Summary & " " & info.Remarks)))
md.Write f(Array("| %s ", info.Returns))
md.Write f(Array("| %s ", info.Parameters))
md.Write f(Array("| %s ", info.Kind))
If "Type" = info.Kind Then
md.Write "| "
Else
md.Write f(Array("| %s ", info.MemberOf))
End If
md.Write f(Array("| %s ", info.NamespaceName))
md.WriteLine "|"
End Sub
'Return a MemberInfo object suitable for use in creating a row in the html or markdown table. The argument "member" is an xml node/object.
Function GetMemberInfo(member)
Dim info 'MemberInfo object
Dim child 'xml dom object
Dim attribute 'xml attribute object
Dim rawName 'string
Set info = New MemberInfo
For Each attribute In member.attributes
If "name" = attribute.name Then
rawName = attribute.text
End If
Next
info.Kind = GetKind(rawName)
info.NamespaceName = GetNamespaceName(rawName)
info.MemberOf = GetTypeName(rawName)
If "Type" = info.Kind Then
info.Name = info.MemberOf
info.MemberOf = ""
Else info.Name = GetName(rawName)
End If
If "#ctor" = info.Name Then
info.Name = "(Constructor)"
End If
Set GetMemberInfo = info
If Not member.hasChildNodes Then
Exit Function
End If
For Each child In member.childNodes
Select case child.nodeName
Case "summary" info.Summary = innerHTML(child)
Case "remarks" info.Remarks = innerHTML(child)
Case "parameters" info.Parameters = innerHTML(child)
Case "returns" info.Returns = innerHTML(child)
End Select
Next
Set GetMemberInfo = info
End Function
Function innerHTML(child)
Dim str 'string of xml to be parsed
Dim tag 'xml tag name
str = child.xml
tag = child.nodeName
str = Replace(str, f(Array("<%s>", tag)), "")
innerHTML = Trim(Replace(str, f(Array("%s>", tag)), ""))
End Function
Function GetKind(rawName) 'ByRef by default
Select Case Left(rawName, 1)
Case "T" : GetKind = "Type"
Case "P" : GetKind = "Property"
Case "M" : GetKind = "Method"
Case "F" : GetKind = "Field"
End Select
rawName = Right(rawName, Len(rawName) - 2)
End Function
Function GetNamespaceName(rawName) 'ByRef by default
GetNamespaceName = Left(rawName, InStr(rawName, ".") - 1)
rawName = Right(rawName, Len(rawName) - Len(GetNamespaceName) - 1)
End Function
Function GetTypeName(rawName)
If InStr(rawName, ".") Then
GetTypeName = Left(rawName, InStr(rawName, ".") - 1)
rawName = Right(rawName, Len(rawName) - Len(GetTypeName) - 1)
Else GetTypeName = rawName
rawName = ""
End If
End Function
Function GetName(rawName)
If InStr(rawName, "(") Then
GetName = Left(rawName, InStr(rawName, "(") - 1)
Else GetName = rawName
End If
End Function
Sub WriteHtmlHeader
On Error Resume Next
Set html = fso.OpenTextFile(htmlFile, ForWriting, CreateNew)
If Err Then
MsgBox "Use the OutputFile property to set the output file.", vbInformation, "DocGeneratorCS class"
Class_Terminate
WScript.Quit 'for .vbs or .wsf script
Self.Close 'for .hta
End If
On Error Goto 0
html.WriteLine ""
html.WriteLine ""
html.WriteLine ""
html.WriteLine ""
html.WriteLine ""
html.WriteLine " C# Classes Documentation
"
End Sub
Sub WriteMarkdownHeader
Dim file 'file object
Dim baseName 'string: partial filename
On Error Resume Next
Set md = fso.OpenTextFile(mdFile, ForWriting, CreateNew)
If Err Then
MsgBox "Use the OutputFile property to set the output file.", vbInformation, "DocGeneratorCS class"
Class_Terminate
WScript.Quit 'for .vbs or .wsf script
Self.Close 'for .hta
End If
On Error Goto 0
md.WriteLine "# C# Classes Documentation"
md.WriteLine ""
md.WriteLine "### Contents"
md.WriteLine ""
For Each file In fso.GetFolder(xmlFolder_).Files
If "xml" = LCase(fso.GetExtensionName(file.Name)) Then
baseName = fso.GetBaseName(file.Name)
md.WriteLine f(Array("[%s](#%s) ", baseName, LCase(baseName)))
End If
Next
md.WriteLine ""
End Sub
Sub WriteHtmlFooter
html.WriteLine ""
html.WriteLine ""
html.WriteLine ""
html.WriteLine ""
End Sub
Sub ValidateXmlFolder
If Not fso.FolderExists(xmlFolder_) Then
Err.Raise 505, "DocGeneratorCS.ValidateXmlFolder", "Set the XmlFolder property to the location of the .xml files."
End If
End Sub
End Class
Class MemberInfo
Public Kind 'Type, Method, Property, Field
Public NamespaceName
Public MemberOf 'type name or, for types, namespace name
Public Name
Public Summary
Public Parameters
Public Returns
Public Remarks
End Class