CesiumJS's reference documentation is one of the most popular sections of the CesiumJS website, and a critical resource for developers.
This guide describes best practices for writing reference doc.
Always include doc for new identifiers (classes, functions, properties, constants) in the public CesiumJS API.
Generally, just follow the patterns that are already in comparable parts of the code, e.g., if you are documenting a new utility function in Core
, look at a function in Core
such as binarySearch
; likewise, if you are documenting a new class in Scene
, look at a similar class such as Model
.
- Building the Doc
- Basics
- Parameters
options
Parameters- Exceptions
- Examples
- References
- Classes
- Properties and Constants
- Functions and Callbacks
- Private
- Layout Reference
- TypeScript type definitions
The reference doc is written in JavaScript code comments using JSDoc3 tags. At the command line, build the doc from the root CesiumJS directory by running the following:
npm run generateDocumentation
This creates a Build/Documentation
directory with the built HTML files.
Alternatively, you can build documentation in watch mode
npm run generateDocumentation-watch
and have it generated automatically when source files change.
There is a link to the doc from CesiumJS's main index.html
when running
npm start
Consider one of the simplest functions in CesiumJS, defined
:
/**
* @function
*
* @param {*} value The object.
* @returns {Boolean} Returns true if the object is defined, returns false otherwise.
*
* @example
* if (Cesium.defined(positions)) {
* doSomething();
* } else {
* doSomethingElse();
* }
*/
function defined(value) {
return value !== undefined;
}
- The doc for
defined
is in the comment starting with/**
. JSDoc tags begin with@
. @function
tells JSDoc that this is a function.@param
describes the function's parameters, and@returns
describes the function's return value.@example
describes a code sample.
The above reference doc is built into the following:
This guide describes best practices for writing doc. For complete details on JSDoc tags, see their documentation.
- Document all function parameters.
- Use
[]
for optional parameters and include the default value, e.g.,
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
- Omit the default value if it is
undefined
, e.g.,
* @param {Cartesian3} [result] The object on which to store the result.
- If a parameter can be more than one type, use
|
to separate the types, e.g.,
* @param {GeometryInstance[]|GeometryInstance} [options.geometryInstances] The geometry instances - or a single geometry instance - to render.
As a complete example,
/**
* Computes a Matrix4 instance from a Matrix3 representing the rotation
* and a Cartesian3 representing the translation.
*
* @param {Matrix3} rotation The upper left portion of the matrix representing the rotation.
* @param {Cartesian3} [translation=Cartesian3.ZERO] The upper right portion of the matrix representing the translation.
* @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
*/
Matrix4.fromRotationTranslation = function(rotation, translation, result) {
// ..
generates
The CesiumJS classes in the Type
column are links to their doc.
Each property of an options
parameter (see the Coding Guide) should be documented with a separate @param
tag, e.g.,
* @param {Object} [options] Object with the following properties:
* @param {Number} [options.length=10000000.0] The length of the axes in meters.
* @param {Number} [options.width=2.0] The width of the axes in pixels.
* @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 matrix that defines the reference frame, i.e., origin plus axes, to visualize.
* @param {Boolean} [options.show=true] Determines if this primitive will be shown.
* @param {Object} [options.id] A user-defined object to return when the instance is picked with {@link Scene#pick}
generates
If all options
properties are optional, also mark the options
object optional.
- Document exceptions after the
@param
/@returns
section using@exception
, e.g.,
/**
* ...
*
* @exception {DeveloperError} aspectRatio must be greater than zero.
*/
Matrix4.computePerspectiveFieldOfView = function(fovY, aspectRatio, near, far, result) {
//>>includeStart('debug', pragmas.debug);
if (aspectRatio <= 0.0) {
throw new DeveloperError('aspectRatio must be greater than zero.');
}
// ...
- Do not document exceptions for missing parameters; it is implicit in the
@param
tag because the parameter is not optional, e.g.,
/**
* Computes a Matrix4 instance from a column-major order array.
*
* @param {Number[]} values The column-major order array.
* @param {Matrix4} [result] The object in which the result will be stored. If undefined a new instance will be created.
* @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
*/
Matrix4.fromColumnMajorArray = function (values, result) {
//>>includeStart('debug', pragmas.debug);
if (!defined(values)) {
throw new DeveloperError("values is required.");
}
//>>includeEnd('debug');
return Matrix4.clone(values, result);
};
Developers almost always jump to an example before reading the doc. Provide concise but instructive code examples with enough context whenever possible.
Useful examples:
/**
* ...
*
* @example
* const n = Cesium.Math.lerp(0.0, 2.0, 0.5); // returns 1.0
*/
CesiumMath.lerp = function(p, q, time) {
// ...
/**
* ...
*
* @example
* // Apply non-uniform scale to node LOD3sp
* const node = model.getNode('LOD3sp');
* node.matrix = Cesium.Matrix4.fromScale(new Cesium.Cartesian3(5.0, 1.0, 1.0), node.matrix);
*/
Model.prototype.getNode = function(name) {
// ...
Unnecessary example:
/**
* ..
*
* @example
* const f = Cesium.Math.EPSILON1;
*/
CesiumMath.EPSILON1 = 0.1;
- Use the Cesium namespace (
Cesium.
) in examples. - Limit code in
@example
tags to 80 lines so it does not overflow.
- Use
@see
sparingly to link to related classes, functions, and online resources., e.g.,
/**
* Provides terrain or other geometry for the surface of an ellipsoid. The surface geometry is
* organized into a pyramid of tiles according to a {@link TilingScheme}. This type describes an
* interface and is not intended to be instantiated directly.
*
* @alias TerrainProvider
* @constructor
*
* @see EllipsoidTerrainProvider
* @see CesiumTerrainProvider
*/
function TerrainProvider() {
/* ... */
}
- Use
#
to reference an instance member (e.g., one that is assigned to the prototype); use.
to access a static member, e.g.,
@see Class
@see Class#instanceMember
@see Class.staticMember
- Use
{@link className}
to link to another documented type. This is not required for@param
tags when the type is provided. - Use
<code> </code>
tags when referring to parameters or other variable names and values within a description. - Use
{@link URL|title}
to link to external sites.
Define a class with @alias
and @constructor
tags on the constructor function, e.g.,
/**
* A 3D Cartesian point.
*
* @alias Cartesian3
* @constructor
*
* ...
*/
function Cartesian3(x, y, z) {
// ...
- Use
@type
and@default
(whenever possible, except when the default isundefined
) to document properties, e.g.,
function Cartesian3(x, y) {
/**
* The X component.
*
* @type {Number}
* @default 0.0
*/
this.x = defaultValue(x, 0.0);
// ...
- Use
@memberOf
when documenting property getter/setters, e.g.,
Object.defineProperties(Entity.prototype, {
/**
* Gets or sets whether this entity should be displayed. When set to true,
* the entity is only displayed if the parent entity's show property is also true.
*
* @memberof Entity.prototype
* @type {Boolean}
*/
show : {
get : function() {
// ...
},
set : function(value) {
// ...
}
},
// ...
- Use
@readonly
to indicate read-only properties, e.g.,
Object.defineProperties(Entity.prototype, {
/**
* Gets the unique ID associated with this object.
*
* @memberof Entity.prototype
* @type {String}
* @readonly
*/
id : {
get : function() {
return this._id;
}
},
// ...
- The description for readonly properties should start with "Gets", and the description for read/write properties should start with "Gets or sets."
- Document constants with
@constant
, e.g.,
/**
* An immutable Cartesian3 instance initialized to (0.0, 0.0, 0.0).
*
* @type {Cartesian3}
* @constant
*/
Cartesian3.ZERO = Object.freeze(new Cartesian3(0.0, 0.0, 0.0));
- Use
@function
when JSDoc can't infer that an identifier is a function because the JavaScriptfunction
keyword isn't used, e.g.,
/**
* Creates a Cartesian4 from four consecutive elements in an array.
* @function
*
* @param {Number[]} array The array whose four consecutive elements correspond to the x, y, z, and w components, respectively.
* @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to the x component.
* @param {Cartesian4} [result] The object on which to store the result.
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
*
* @example
* // Create a Cartesian4 with (1.0, 2.0, 3.0, 4.0)
* const v = [1.0, 2.0, 3.0, 4.0];
* const p = Cesium.Cartesian4.fromArray(v);
*
* // Create a Cartesian4 with (1.0, 2.0, 3.0, 4.0) using an offset into an array
* const v2 = [0.0, 0.0, 1.0, 2.0, 3.0, 4.0];
* const p2 = Cesium.Cartesian4.fromArray(v2, 2);
*/
Cartesian4.fromArray = Cartesian4.unpack;
- Use
@callback
to document a function signature, e.g.,
/**
* Sort the items in the queue in-place.
*
* @param {Queue.Comparator} compareFunction A function that defines the sort order.
*/
Queue.prototype.sort = function (compareFunction) {
if (this._offset > 0) {
//compact array
this._array = this._array.slice(this._offset);
this._offset = 0;
}
this._array.sort(compareFunction);
};
/**
* A function used to compare two items while sorting a queue.
* @callback Queue.Comparator
*
* @param {*} a An item in the array.
* @param {*} b An item in the array.
* @returns {Number} Returns a negative value if <code>a</code> is less than <code>b</code>,
* a positive value if <code>a</code> is greater than <code>b</code>, or
* 0 if <code>a</code> is equal to <code>b</code>.
*
* @example
* function compareNumbers(a, b) {
* return a - b;
* }
*/
Documentation is not generated for private members that start with _
. It is often useful to still write doc comments for them for maintainability (see the Coding Guide).
If a member or function doesn't start with _
, but is intended to be private, use the @private
tag at the bottom of the documentation, e.g.,
/**
* A tween is an animation that interpolates the properties of two objects using an {@link EasingFunction}. Create
* one using {@link Scene#tweens} and {@link TweenCollection#add} and related add functions.
*
* @alias Tween
* @constructor
*
* @private
*/
function Tween(/* ... */) {
/* ... */
}
If no documentation comments are provided, the identifier will not be documented. In this case, @private
is not strictly needed, but we use it anyway so it is clear that documentation was not forgotten, e.g.,
/**
* @private
*/
function appendForwardSlash(url) {
/* ... */
}
Documentation for private elements can be generated by running the following:
npm run generateDocumentation -- --private
There's a general flow to each documentation block that makes it easy to read. Tags are always in the same order with the same spacing.
DESCRIPTION.
@alias NAME
@constructor
@param {TYPE} NAME DESCRIPTION.
@param {TYPE|OTHER_TYPE} NAME DESCRIPTION WITH LONG
WRAPPING LINES.
@exception {TYPE} DESCRIPTION.
@see TYPE
@see TYPE#INSTANCE_MEMBER
@see TYPE.STATIC_MEMBER
@example
[@private]
DESCRIPTION.
@param {TYPE} NAME DESCRIPTION.
@param {TYPE|OTHER_TYPE} NAME DESCRIPTION WITH LONG
WRAPPING LINES.
@returns {TYPE} DESCRIPTION.
@exception {TYPE} DESCRIPTION.
@see TYPE
@see TYPE#INSTANCE_MEMBER
@see TYPE.STATIC_MEMBER
@example
[@private]
DESCRIPTION.
@type {TYPE}
[@constant]
[@default DEFAULT_VALUE]
[@readonly]
@exception {TYPE} DESCRIPTION.
@see TYPE
@see TYPE#INSTANCE_MEMBER
@see TYPE.STATIC_MEMBER
@example
[@private]
DESCRIPTION.
@memberof CLASS_NAME.prototype
@type {TYPE}
[@default DEFAULT_VALUE]
[@readonly]
@exception {TYPE} DESCRIPTION.
@see TYPE
@see TYPE#INSTANCE_MEMBER
@see TYPE.STATIC_MEMBER
@example
[@private]
DESCRIPTION.
@function
@param {TYPE} NAME DESCRIPTION.
@param {TYPE|OTHER_TYPE} NAME DESCRIPTION WITH LONG
WRAPPING LINES.
@returns {TYPE} DESCRIPTION.
@exception {TYPE} DESCRIPTION.
@see TYPE
@see TYPE#INSTANCE_MEMBER
@see TYPE.STATIC_MEMBER
@example
[@private]
We also use JSDoc to build official TypeScript type definitions. Normally this behavior is transparent to the developer and happens as part of CI, however incorrect or non-standard JSDoc can lead to failures. If CI is failing because of the build-ts
step, you can debug it locally by running:
npm run build-ts
In most cases, the TypeScript compiler will provide a very obvious error and line number which will help you track down the offending, most likely incorrect, JSDoc.