The following is a simplistic and certainly buggy parser script for HeaderDoc comments (tested only on. itself). No attempt is made to clean up the fields or to apply optimizations. I let you do the rest
(*!
@header
HeaderDoc AppleScript Parser
@abstract
Extracts (a subset of) HeaderDoc comments from an AppleScript source.
@version 0.0.0
@copyright 2011 Use At Your Own Risk :)
*)
(*! @property |TAB|
@abstract The tabulation character. *)
property |TAB| : string id 9
(*! @abstract New line character. *)
property LF : string id 10
property SP : string id 32
set {sourcename, sourcepath} to chooseFile("Please choose an AppleScript source file:", "com.apple.applescript.text", path to scripts folder from user domain)
set source to readFile(sourcepath)
set comments to textBetween(source, "(*!", "*)")
set theCommentDataStructure to {} -- A list of (heterogeneous) records containing the information extracted from the source code
repeat with comment in (a reference to comments)
-- Parse comment
if comment contains "@header" then
set header to getHeaderDocUniqueField(comment, "@header") -- text
set abstract to getHeaderDocUniqueField(comment, "@abstract") -- text
set discussion to getHeaderDocUniqueField(comment, "@discussion") -- text
set theVersion to getHeaderDocUniqueField(comment, "@version") -- text
set copyright to getHeaderDocUniqueField(comment, "@copyright") -- text
set the end of (a reference to theCommentDataStructure) to {header:header, abstract:abstract, discussion:discussion, |version|:theVersion, copyright:copyright}
else
set function to getHeaderDocUniqueField(comment, "@function") -- text
set theClass to getHeaderDocUniqueField(comment, "@class") -- text
set theProperty to getHeaderDocUniqueField(comment, "@property") -- text
set abstract to getHeaderDocUniqueField(comment, "@abstract") -- text
set discussion to getHeaderDocUniqueField(comment, "@discussion") -- text
set params to getHeaderDocField(comment, "@param") -- List of parameters
set theResult to getHeaderDocUniqueField(comment, "@result") -- text
set throws to getHeaderDocField(comment, "@throws") -- List of exceptions
set seealso to getHeaderDocField(comment, "@seealso") -- List of cross-references
-- The following assumes that the commented element
-- comes on the line immediately following the comment (no empty lines allowed)
set commentedElement to textBetween(source, "(*!" & comment & "*)" & LF, LF)
if function is not missing value then
set type to "handler"
else if theClass is not missing value then
set type to "script"
else if theProperty is not missing value then
set type to "property"
else
set type to "missing value"
end if
-- Parse parameters
set paramList to {} -- List of records of the form {|name|: <value>, |description|: <value> }
repeat with param in (a reference to params)
set x to split(param, {SP, LF, |TAB|})
set the end of (a reference to paramList) to {|name|:the first item of x, |description|:join(the rest of x, SP)}
end repeat
set the end of (a reference to theCommentDataStructure) to {type:type, abstract:abstract, discussion:discussion, params:paramList, |result|:theResult, throws:throws, seealso:seealso, signature:commentedElement}
end if
end repeat
return theCommentDataStructure
------------------------------------
-- HeaderDoc-specific handlers
------------------------------------
(*!
@abstract Gets the value of the specified HeaderDoc tag.
@discussion This handler parses a HeaderDoc comment and returns a list of values for the specified tag name. A tag is defined as whatever text there is between the tag name and the first occurrence of another HeaderDoc tag or AppleScript's end-of-comment tag (whatever comes first). Note, in particular, that escaped <tt>@</tt> characters (that is, <tt>\@</tt>) will confuse this handler.
@param comment The text of the comment.
@param tag The name of a HeaderDoc tag.
@result A list of values for the given field.
*)
on getHeaderDocField(comment, tag)
textBetween(comment & "*)", {tag & SP, tag & LF, tag & |TAB|}, {"*)", "@"})
end getHeaderDocField
(*!
@abstract Returns the (unique) value associated to the given tag.
@discussion This handler assumes that there is a unique occurrence of the given tag within the comment.
*)
on getHeaderDocUniqueField(comment, tag)
try
the first item of textBetween(comment & "*)", {tag & SP, tag & LF, tag & |TAB|}, {"*)", "@"})
on error -- Field not present
missing value
end try
end getHeaderDocUniqueField
-----------------------------------
-- File manipulation
-----------------------------------
on chooseFile(msg, type, defaultLocation)
set theAlias to choose file with prompt msg of type {type} ¬
default location defaultLocation ¬
without invisibles, multiple selections allowed and showing package contents
{basename(theAlias), theAlias}
end chooseFile
(*! @function basename
@abstract
Gets the basename from a path.
@param pathname A (POSIX) path.
@result
The base filename of the given path. Example: basename("HD:Users:me:Downloads:filename.txt") is "filename".
*)
on basename(pathname)
set bn to split(last item of split(POSIX path of pathname, "/"), ".")
if (count bn) > 1 then return join(items 1 thru -2 of bn, ".")
return bn as text
end basename
on readFile(thePath)
read (POSIX file (POSIX path of thePath) as alias) from 1 to eof as text
end readFile
---------------------------
-- Text-related handlers
---------------------------
on split(theText, theDelim)
set {tid, AppleScript's text item delimiters} to {AppleScript's text item delimiters, theDelim}
set theResult to the text items of theText
set AppleScript's text item delimiters to tid
return theResult
end split
on join(theList, theDelim)
set {tid, AppleScript's text item delimiters} to {AppleScript's text item delimiters, theDelim}
set theResult to theList as text
set AppleScript's text item delimiters to tid
return theResult
end join
(*!
@abstract
Finds all substrings enclosed between the given delimiters.
@result
A list of the occurrences in the given text that are enclosed by the given delimiters. Note that the delimiters <strong>must be distinct</strong>.
*)
on textBetween(theText, leftDelim, rightDelim)
set t to the rest of split(theText, leftDelim)
set theResult to {}
repeat with rec in t
set s to split(rec, rightDelim)
if length of s > 1 then set the end of theResult to the first item of s
end repeat
theResult
end textBetween