Generating the documentation for your project is as simple as:
doc-holiday.conf
file to your project as described in the Configuration docmentationEven if you have not formatted descriptions, or parameter / return comments yet, your source code should still be documented according to its code signature. Check the output and see what you ended up with.
Note that only code exported with the export
keyword may be visible in the output docs (depending on your config choices).
Doc-holiday assumes each file is to be treated as a module. Only code entities that are exported from the module with the ‘export’ keyword ( or else with an explicit @public notation in the comment block) will be marked public and may not appear in the output otherwise (depending upon your output engine and template choices).
Unless you are using JSDoc HTML output (without a template that hides private entities anyway), you will not see private entities in your rendered documentation. Consult the documentation for the JSDoc engine and/or template you are using.
Follow the guidelines below for how to best document each of your code entities:
The first lines of the module – starting with the top line – are considered the module description. No @ - style prefix tags are needed to identify this as the module description. Any comment lines that appear here are considered to be the description of the module itself.
There may be multiple lines in contiguous comment block to form this module description.
At least one blank line following the comment block must precede any other code in the file.
For example, consider a module file named “UserModule.ts”:
/*
This is the description of the UserModule module.
It exports functions and data types related to the User login and status.
*/
import fs from 'fs'
...
This description will appear in the docs for UserModule (module). Any exported code entities that follow in the sources will appear within this section of the documentation.
If you do not wish to include a module description, you must leave at least one blank line at the top of the file.
Note that if the first line of a module contains a “shebang” line (starting with #!), then the module description may start on the follwing line
There are several supported ways to declare and document a function.
First, if we simply declare an exported function:
export function add(num1, num2) {
return num1+num2
}
It will get documented, similar to this:
Kind: inner method of exampleModule
Access: public
Param | Type |
---|---|
num1 | * |
num2 | * |
Which is nice, but what we really want is to include our own description and specifications.
We can describe the function, like this:
/*
Adds two numbers and returns the result
*/
export function add(num1, num2) {
return num1+num2
}
or, perhaps like this:
//
// Adds two numbers and returns the result
//
export function add(num1, num2) {
return num1+num2
}
Both forms will render as something like this:
Adds two numbers and returns the result
Kind: inner method of exampleModule
Access: public
Param | Type |
---|---|
num1 | * |
num2 | * |
Which is better, but we’d like our parameters and return values documented also.
Many code editors will produce a JSDoc comment block if you simply enter /** (return) above the function. These tools will autogenerate the @param tags for the parameters found in the function signature, like this:
/**
*
* @param num1
* @param num2
*/
Allowing us to add descriptions and types to this. We can also document our return value by adding a @return tag, as JSDoc convention provides:
/**
* Adds two numbers and returns the result
* @param {number} num1 The first number to be added
* @param {number} num2 The second number to be added
*
* @return {number} The result of the addition
*/
export function add(num1, num2) {
return num1+num2
}
and this gives us a more complete documentation rendering:
Adds two numbers and returns the result
Kind: inner method of exampleModule
Access: public
Param | Type |
---|---|
num1 | number |
num2 | number |
Which is fine, but this is all just what one gets with JSDoc. So What?
Let’s look at these examples again, though, from a Typescript perspective.
If we simply define a function (we’ll give it a description here, too), we can let the declaration syntax typescript requires of us already to document the parameters and return.
// Adds two numbers and returns the results
export function add(num1:number, num2:number):number {
return num1+num2
}
Even with this rather minimalist declaration, we will get documentation like this:
Adds two numbers and returns the results
Kind: inner method of exampleModule
Access: public
Param | Type |
---|---|
num1 | number |
num2 | number |
and if we want to be more descriptive, we could write this as:
/*
Adds two numbers and returns the result
*/
export function add(
num1:number, // The first number to add
num2:number // The second number to add
): number // the resulting sum of the addition.
{
return num1+num2
}
And get all of the members documented without having to have created a redundant JSDoc block for that.
Adds two numbers and returns the result
Kind: inner method of exampleModule
Returns: number
- <p>the resulting sum of the addition.</p>
Access: public
Param | Type | Description |
---|---|---|
num1 | number |
<p>The first number to add</p> |
num2 | number |
<p>The second number to add</p> |
If you declare parameter and/or return values in both a JSDoc comment block and use Typescript types and/or comments, the Typescript types and the associated comments will be used instead of the JSDoc entries. The JSDoc entries will be used if there is not a typescript type or associated comment for the parameter or return.
Note that variations on the comment block style shown above are allowed. Multiple lines (either successive // lines or a /* */ block are allowed, etc.)
functions may also be declared by assignment, either classically, or via the arrow operator:
// assigned classic function
export const assignedClassic = function(a,b,c) {
return ''
}
// an arrow function
export const assignedArrow = (foo:string, bar:number):string /* returns a value */ => {return ''}
Note that spreading whitespace among multiple lines is allowed for the above forms, too.
Anonymous functions are also allowed, as long as they are assigned.
// an anonymous function
export const anonymous = (function (a,b,c) {})
Generator functions are fine. You can use the @yield JSDoc tag to document the yield type:
// a generator function
// @yields {number} each call to next() returns the successive number
export function* indexGenerator(){
var index = 0;
while(true) {
yield index++;
}
}
Or you can specify the return as a Generator or Iterator in Typescript to achieve the same result
export function* indexGeneratorTS() : Generator<number>/* generates numbers */ {
var index = 0;
while(true) {
yield index++;
}
}
Prefix keywords such as async
are recognized and reflected in the rendered docs.
Your module may have an exported property you wish to document. You can do this much the same as how you document a function.
// Holds the ISO 639 code for the language and locale the user prefers
export let preferrredLanguage;
Or, you may use a side-comment for this:
export let preferrredLanguage; // Holds the ISO 639 code for the language and locale the user prefers
You can use let
, var
, or const
to declare your properties. You may also assign a value:
Or, you may use a side-comment for this:
export const supportedLanguage = 'en-US' // all we support for right now
Produces:
all we support for right now
Kind: inner constant of exampleModule
Default: "'en-US'"
Access: public
Something that is not supported by Doc-Holiday is a multiple declaration or assignment, such as either of the following:
export let a, b, c
or
export let a=1, b=2, c=3
These attempts will only capture the first declaration (a).
Avoid using these types of declarations if you wish these to be properly documented.
Enumerations are supported by Typescript and Doc-Holiday will document these appropriately.
For example, the following enumeration
// Constants for direction
enum Direction {
Up , // vertical ascend
Down, // vertical descend
Left, // westward if facing north
Right, // eastward if facing north
}
Would be represented as follows:
Constants for direction
Kind: inner enum of exampleModule
Read only: true
Properties
Name | Type | Default | Description |
---|---|---|---|
Up | number |
Up |
<p>vertical ascend (value = 0)</p> |
Down | number |
Down |
<p>vertical descend (value = 1)</p> |
Left | number |
Left |
<p>westward if facing north (value = 2)</p> |
Right | number |
Right |
<p>eastward if facing north (value = 3)</p> |
Note: To document a enum in plain Javascript, which does not support the enum keyword, create your enum as a class with properties and apply the @enum JSDoc tag directly, using the } extension, like this:
// Constants for direction
// }
export class Direction {
Up = 0 // vertical ascend
Down = 1 // vertical descend
Left = 2 // westward if facing north
Right = 3 // eastward if facing north
}
When you document a class, the documentation will reflect the aspects and comments of the class itself, as well as all of the inner properties, functions, and inner classes.
For example, consider this simple made up class declaration:
// The Foo class demonstrates
// how a simple class is documented
export class Foo {
name:string
readonly seed:string = "aklafg783yd8jccide-dkhei7s"
// This class is scoped within the Foo class
InnerClass = class {
prop1:string // a property of InnerClass
prop2:number // another InnerClass property
// a method of InnerClass
method() {
}
}
// Compute the sequence over the given time
compute(
time:number // number of seconds <positive, integer>
): number {
// blah blah
return 0
}
}
would render the following:
The Foo class demonstrates how a simple class is documented
Kind: inner class of example
Access: public
Properties
Name | Type | Default | Description |
---|---|---|---|
name | string |
<ul> <li></li> </ul> | |
seed | string |
"aklafg783yd8jccide-dkhei7s" |
<ul> <li></li> </ul> |
Foo.InnerClass | class |
<p>This class is scoped within the Foo class</p> | |
InnerClass.Foo.InnerClass | string |
<p>a property of InnerClass</p> | |
InnerClass.Foo.property | string |
<p>another InnerClass property</p> | |
InnerClass.Foo.method | method |
<p>a method of InnerClass</p> |
Compute the sequence over the given time
Kind: instance method of Foo
Returns: number
- <p>blah blah</p>
Access: public
Param | Type | Description |
---|---|---|
time | number |
<p>number of seconds</p> <ul class="doc-constraints" style="font-style:italic; margin-top: 0; margin-left: 33px"> <li>number must be an integer</li> <li>number must be positive</li> </ul> |
Note how the properties and methods of an inner class are represented within the properties block of the parent class itself rather than being represented in their own rendered blocks like the first-order entities of the containing class. This is how JSDoc is equipped to handle inner classes.
Documenting an interface is much the same as documenting a class.
The example below imagines two functional interfaces and an implementing class that uses them.
// Interface for providing print capability
export interface PrintAction {
print(device:string, orientation:PrinterOrientation, pages:number): boolean
}
// Interface providing persistence capability
export interface SaveAction {
save(device:string):boolean
}
// An example of implemented interfaces
export class PrintExample implements PrintAction, SaveAction {
// Local function to print Example.
exmpleLocal(foo:string // device if not default
):boolean {
const device = foo || 'default'
return this.save(device) && this.print(device, PrinterOrientation.Portrait, 1)
}
// implementation of primt
print(device:string, orientation:PrinterOrientation, pages:number): boolean { return true }
// implementation of save
save(device:string):boolean { return true }
}
resulting in the following rendered documentation:
Interface for providing print capability
Kind: inner interface of example
Access: public
Kind: instance method of PrintAction
Access: public
Param | Type |
---|---|
device | string |
orientation | PrinterOrientation |
pages | number |
Interface providing persistence capability
Kind: inner interface of example
Access: public
Kind: instance method of SaveAction
Access: public
Param | Type |
---|---|
device | string |
Local function to print Example.
Kind: instance method of PrintExample
Access: public
Param | Type | Description |
---|---|---|
foo | string |
<p>device if not default</p> |
implementation of primt
Kind: instance method of PrintExample
Returns: boolean
- <p>implementation of save</p>
Access: public
Param | Type |
---|---|
device | string |
orientation | PrinterOrientation |
pages | number |
implementation of save
Kind: instance method of PrintExample
Access: public
Param | Type |
---|---|
device | string |
If you are not using Typescript, you may not be able to use the interface
and
implements
keywords. Javascript has long had the ability to mix properties into
a functional object as a way to emulate interfaces or multiple-inheritance
behaviors. The so-called “Mix-In” pattern,
as documented by this example from MDN
is recognized and supported by Doc-Holiday:
// used in mix-in example from MDN
export let calculatorMixin = Base => class extends Base {
calc() { }
};
// used in mix-in example from MDN
export let randomizerMixin = Base => class extends Base {
randomize() { }
};
// used in mix-in example from MDN
export class Foo { }
// This is the class that extends Foo and implements the 2 mixins
export class MixInExample extends calculatorMixin(randomizerMixin(Foo)) { }
The mixins will be identified as such in the documentation, per JSDoc tag support,
and the MixInExample
class that uses them will list these under mixes
.
used in mix-in example from MDN
Kind: inner class of example
Access: public
Kind: inner class of example
Extends: Foo
Mixes: calculatorMixin
, randomizerMixin
Access: public
Kind: inner mixin of example
Extends: Base
Access: public
Kind: instance method of calculatorMixin
Access: public
Kind: inner mixin of example
Extends: Base
Access: public
Kind: instance method of randomizerMixin
Access: public
Type definitions are very useful code constructs, as they allow us to define our own types to suit the data we use in our applications in the way we think of them.
Type definitions are supported in TypeScript using the type
keyword.
For example, we might like to define a type that may consist of any of a number of types, like this one:
// used to define multi-type aliases
export type NumberLike = string|number
or to define a type that must be one of a constant set of values, like these:
// used to define acceptable string values
export type Office = "Seattle" | "Los Angeles" | "New York" | "London" | "Paris"
// used to define acceptable number values
export type ValueSet = 0 | 1 | 2 | 4 | 8 | 12 | 16
Often, we use a type definition to define the structure of an object, as an alternative to declaring a class to define the type.
// used to define a complex type
export type Complex = {
name:string, // name of person
age: NumberLike, // age of person
office:Office, // which office
value: ValueSet // which value
}
Some geospatial libraries define a Latitude, Longitude coordinate a variety of ways. Sometimes as a object with properties, and other times simply as an array with values in a defined order. Such a case can be handled by type definitions handily:
// lat, lon as object props
export type LocObj = {lat:number, lon:number}
// lon, lat as a 2-element array, in that order
export type LLTuple = [lon:number, lat:number]
The rendered documentation for the typedef examples above would appear like this:
used to define multi-type aliases
Kind: inner typedef of example
used to define acceptable string values
Kind: inner typedef of example
used to define acceptable number values
Kind: inner typedef of example
used to define a complex type
Kind: inner typedef of example
Properties
Name | Type | Description |
---|---|---|
name | string |
<p>name of person</p> |
age | NumberLike |
<p>age of person</p> |
office | Office |
<p>which office</p> |
value | string |
<p>which value</p> |
lat, lon as object props
Kind: inner typedef of example
Properties
Name | Type | Description |
---|---|---|
lat | number |
<ul> <li></li> </ul> |
lon | number |
<ul> <li></li> </ul> |
lon, lat as a 2-element array, in that order
Kind: inner typedef of example
Properties
Name | Type | Description |
---|---|---|
lon | number |
<ul> <li></li> </ul> |
lat | number |
<ul> <li></li> </ul> |
An interface is a kind of type, so in Typescript we can declare a combination of interfaces as its own type definition. Consider the following:
// used for intersection example
export interface Hunter {
hunt(speed: number): number;
}
// used for intersection example
export interface Gatherer {
gather(speed: number): number;
}
// assign intersection type definition to alias interface combo
export type HunterGatherer = Hunter & Gatherer;
This form is recognized and supported by Doc-Holiday so the output would appear as you might expect:
used for intersection example
Kind: inner class of example
Access: public
Kind: instance method of Hunter
Access: public
Param | Type |
---|---|
speed | number |
used for intersection example
Kind: inner class of example
Access: public
Kind: instance method of Gatherer
Access: public
Param | Type |
---|---|
speed | number |
assign intersection type definition to alias interface combo
Kind: inner typedef of example
Implements: Hunter
, Gatherer
It is helpful to define a type for a callback so that code can avoid simply declaring an “any” type here as poorly documented and error-prone catch-all. Although there are a couple ways in which a function type can be declared, the preferred method supported by Doc-Holiday is as follows:
// function typedef (callback)
export type MyFunction = (str:string, num:number) => boolean
You can also document the parameters and return of such a callback declaration:
// commented version
export type TheCallbck = (
str:string, // the string to process
num:number // the number to process it with
) => boolean // false to abort further processing
function typedef (callback)
Kind: inner typedef of example
Param | Type |
---|---|
str | string |
num | number |
commented version
Kind: inner typedef of focus
Returns: boolean
- <p>false to abort further processing</p>
Param | Type | Description |
---|---|---|
str | string |
<p>the string to process</p> |
num | number |
<p>the number to process it with</p> |