Skip to content

tools.wrendoc

Camilo edited this page Feb 17, 2021 · 6 revisions

Code structure and organization is a matter of pride for developers. Clear and consistent code signifies clear and consistent thought.

Even though the compiler lacks a discerning palate when it comes to naming, whitespace, or documentation, it makes all the difference for human collaborators.

WrenDoc takes inspiration from Swift-flavored Markdown and Jazzy to extract documentation markup from special comments inside Wren source-code. Creating Markdown files.


Since the early '00s, Headerdoc has been Apple's preferred documentation standard.

Starting off as little more than a Perl script that parsed trumped-up Javadoc comments, Headerdoc would eventually be the engine behind Apple's developer documentation online and in Xcode.

But like so much of the Apple developer ecosystem, Swift changed everything. In the spirit of "Out with the old, in with the new", Xcode 7 traded Headerdoc for fan favorite Markdown --- specifically, Swift-flavored Markdown.

Usage

WrenDoc is a simple Python script that reads .wren files and parse them looking for /** comments. Then it extract the comment contents and store them inside a Markdown file.

You just need Python 3 installed (MacOS and Linux provides a Python installation by default in most cases).

$ cd tools/docs
$ python3 . ../
✨ Jobs Done!: found 9 files. parsed 6 comments. docs saved in `./docs`

Take a peek at a WrenDoc-generated documentation for the emoji.wren class.

Config

A small configuration file is provided.

  • repo: The base for generating header links to the source code. e.g. "github.com/ninjascl/domepunk"
  • branch: The url related to the branch in the source code. e.g. "blob/main"
  • docs: Tells the directory name for generating the files e.g. "docs"

Special Comments

There are some special comments that could be used at the beginning of the file. Only one command per line is supported.

  • /** doc-disable */: This command will disable parsing the file.

  • /** doc-name: MyFilename */: This command will overwrite the filename of the generated markdown file. By default WrenDoc uses the following format:

# e.g domepunk-misc-emoji-emoji.wren.md
f"{pathToFile}".lower().strip().replace("/", "-").replace("\\", "-") + ".md"`
  • /** doc-header */: This is a special comment that will append its contents on the header of the document.

Example:

/** doc-header
This markdown will append before any other comment.
Useful for giving context.
*/

Documentation Comments & Swift-Flavored Markdown

Even if you've never written a line of Markdown before, you can get up to speed in just a few minutes. Here's pretty much everything you need to know:

Basic Markup

Documentation comments look like normal comments, but with a little something extra.

Multi-line documentation comments have an extra star in their opening delimiter (/** ... */).

Standard Markdown rules apply inside documentation comments:

  • Paragraphs are separated by blank lines.
  • Unordered lists are marked by bullet characters (-, +, *, or ).
  • Ordered lists use numerals (1, 2, 3, ...) followed by either a period (1.) or a right parenthesis (1)).
  • Headers are preceded by # signs or underlined with = or -.
  • Both links and images work.
/**
    # Lists

    You can apply *italic*, **bold**, or `code` inline styles.

    ## Unordered Lists

    - Lists are great,
    - but perhaps don't nest;
    - Sub-list formatting...

      - ...isn't the best.

    ## Ordered Lists

    1. Ordered lists, too,
    2. for things that are sorted;
    3. Arabic numerals
    4. are the only kind supported.
*/

Summary & Description

The leading paragraph of a documentation comment becomes the documentation Summary. Any additional content is grouped together into the Discussion section.

If a documentation comment starts with anything other than a paragraph, all of its content is put into the Discussion.

Parameters & Return Values

  • Parameters: Start the line with Parameter <param name>: and the description of the parameter.
  • Return values: Start the line with Returns: and information about the return value.
  • Thrown errors: Start the line with Throws: and a description of the errors that can be thrown. it's especially important to document errors properly.
/**
 Creates a personalized greeting for a recipient.

 - Parameter recipient: The person being greeted.

 - Signature: func greeting(recipient:String) -> String

 - Throws: `MyError.invalidRecipient`
           if `recipient` is "Derek"
           (he knows what he did).

 - Returns: A new string saying hello to `recipient`.
 */
  greeting(recipient) {
    if (recipient == "Derek") {
      return Fiber.abort("MyError.invalidRecipient")
    }
    return "Greetings, %(recipient)!"
  }

Additional Fields

In addition to Parameters, Throws and Returns, Swift-flavored Markdown defines a handful of other fields, which can be loosely organized in the following way:

Algorithm/Safety Information
Precondition
Postcondition
Requires
Invariant
Complexity
Important
Warning
Metadata
Author
Authors
Copyright
Date
SeeAlso
Since
Version
General Notes & Exhortations
Attention
Bug
Experiment
Note
Remark
ToDo

WrenDoc Additions

Some fields were added in order to better document Wren code.

Signature

Since Wren does not have a syntax for type signature. Is recommended to use Swift syntax to document better the signature for properties and methods.

The main difference would be using Wren value types for params and method returns instead Swift's.

Examples

The signature for a method that will return the string "hello, world".

  • Code:
  sayHelloWorld() {
    return "hello, world"
  }
  • Signature:
func sayHelloWorld() -> String

The signature for a static property name with the string "Camilo".

  • Code:
  static name { "Camilo" }
  • Signature:
  static var name: String

The signature for a method with an optional parameter. That returns a Data object.

  • Code:
  download(useCache) {
    // implementation
  }
  • Signature:
  func download(useCache:Bool?) -> Object

The signature for a method with an optional parameter and default value that does not returns a value.

  • Code:
  paint(color, times) {
    // implementation
  }
  • Signature:
  func paint(color:String? = "#ffffff", times:Num? = 1) -> Void

Refer to the Swift Language Guide for more details.

Code blocks

Demonstrate the proper usage or implementation details of a function by embedding code blocks. Inset code blocks by at least four spaces:

/**
    The area of the `Shape` instance.

    Computation depends on the shape of the instance.
    For a triangle, `area` is equivalent to:

        var height = triangle.calculateHeight()
        var area = triangle.base * height / 2
*/
area{_area}

Fenced code blocks are also recognized, delimited by either three backticks (`) or tildes (~):

/**
    The perimeter of the `Shape` instance.

    Computation depends on the shape of the instance, and is
    equivalent to:

    ~~~
    // Circles:
    var perimeter = circle.radius * 2 * Num.pi
    ~~~
*/
perimeter { _perimeter }

MARK / TODO / FIXME

In Objective-C, the preprocessor directive #pragma mark is used to divide functionality into meaningful, easy-to-navigate sections. In Swift, the same can be accomplished with the comment // MARK:. Thus we recommend implementing it in your code too.

The following comments are :

  • // MARK:
  • // TODO:
  • // FIXME:

As with #pragma, marks followed by a single dash (-) are preceded with a horizontal divider. Additionally there are others conventional comment tags, such as NOTE and XXX.

WrenDoc does not recognize this type of comments. But they are useful for separating different sections of the code. In the future it may obtain information to generate better docs.


Although the tooling and documentation around Wren is still developing, one would be wise to adopt good habits early, by using the new Markdown capabilities for documentation, as well as MARK: comments in Wren code going forward.

Thanks

Links