JSDoc
We are currently moving from JSDuck, as it is unmaintained. For more details on this work see JSDoc WMF theme. |
MediaWiki and related codebases use JSDoc annotations to document JavaScript code. This page contains information about setting up JSDoc, documenting code, and publishing a docs site.
Documenting your code edit
JSDoc reads descriptions and annotations from code comments in JavaScript files. In general, annotations begin with @
and must be separated by new lines. Annotation blocks that precede a function or symbol assume that the annotation belongs to the following code and use the name of that function or symbol.
For a complete list of tags supported by JSDoc, see the JSDoc documentation.
ES6 example edit
/**
* Description for MyClass.
*
* @extends MyParentClass
*/
class MyClass extends MyParentClass {
/**
* @param {Object} [config] Configuration options
* @param {string} [config.optionA] Description for optionA
* @param {string} [config.optionB] Description for optionB
*/
constructor( config ) {
// …
}
// …
}
export default MyClass;
When using ES6 classes, you do not need to use tags such as @class, @member, @constructor, and @module since the structure of your code already expresses this to JSDoc. Adding these tags might cause duplicate definitions.
If you use ECMAScript Modules and want to export the class, this must be a separate statement due to a bug in JSDoc.[1] In the above example, using export default MyClass { … }
will break the documentation. Instead, move the export default MyClass;
to a separate statement.
ES5 example edit
To document a class that uses ES5 syntax, with the class and constructor defined together as function MyClass(…) {…}
, use:
- a
@classdesc
tag to document the class - a
@description
tag to document the constructor
/**
* @classdesc Class description.
*
* @description Constructor description.
*
* @param {string} myParam
* @return {string} Description
*/
Resourceloader module example edit
/**
* Fetch and display a preview of the current editing area.
*
* @memberof module:mediawiki.page.preview
* @param {Object} config Configuration options
* @param {string} [config.summary=null] The edit summary
* @return {jQuery.Promise}
* @fires Hooks~'wikipage.content'
* @stable
*/
function doPreview( config ) {
// ...
}
/**
* Fetch and display a preview of the current editing area.
*
* @example
* var preview = require( 'mediawiki.page.preview' );
* preview.doPreview();
*
* @exports mediawiki.page.preview
*/
module.exports = {
doPreview: doPreview,
};
Links edit
Learn how to refer to other elements in your code by reading up on namepaths and the @link tag.
You can also use Markdown link syntax or a link enclosed in angle brackets. To link to a Phabricator task, use the task number (for example: T55555).
Reusable links edit
To create a reusable alias for a link or to set up a link for a type, add the link to the linkMap
in the JSDoc configuration file:
{
...
"templates": {
...
"wmf": {
"linkMap": {
"mw": "https://doc.wikimedia.org/mediawiki-core/master/js/mw.html",
"jQuery": "https://api.jquery.com/jQuery",
"Array": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array"
}
}
}
}
Previewing your changes edit
For MediaWiki core, you can generate a preview of the JSDoc site for a given patch using the patch demo tool. To view the JSDoc preview, select the JSDoc documentation link on the main page of the demo wiki.
To test the docs locally, run npm install
and npm run doc
.
To run the JSDoc WMF theme locally, see the local development instructions in the theme's code repository.
Setting up JSDoc edit
Once you've documented your code using JSDoc tags, follow these steps to build and publish the docs.
1. Configure JSDoc edit
Create a jsdoc.json
file in your project's repository to configure JSDoc. If you want to include comments, you can create your JSDoc config as a JavaScript file; see MediaWiki core for an example.
Configuration example edit
{
"opts": {
"destination": "docs",
"pedantic": true,
"readme": "README.md",
"recurse": true,
"template": "node_modules/jsdoc-wmf-theme"
},
"plugins": [
"plugins/markdown",
"node_modules/jsdoc-wmf-theme/plugins/summarize",
"node_modules/jsdoc-wmf-theme/plugins/betterlinks"
],
"source": {
"include": [ "resources", "src" ],
"exclude": [ "resources/libs", "resources/oldfile.js" ]
},
"templates": {
"cleverLinks": true,
"default": {
"useLongnameInNav": true
},
"wmf": {
"maintitle": "My Project",
"repository": "https://gerrit.wikimedia.org/g/MyProject",
"siteMap": {
"sections": true
}
}
}
}
Configuration options edit
Option | Description |
---|---|
opts.destination |
Location of the autogenerated JavaScript documentation output. This should be ignored in a .gitignore . If you're using the regular CI jobs for generating and publishing the documentation, this must be docs .
|
opts.pedantic |
Treat errors as fatal errors, and treat warnings as errors |
opts.readme |
Homepage content for the JSDoc site |
opts.recurse |
Recurse into subdirectories when scanning for source files and tutorials |
opts.template |
JSDoc theme. For Wikimedia codebases, use node_modules/jsdoc-wmf-theme
|
plugins |
Array of plugin names to execute after building the docs, executed in the order they are specified. Theme plugins should be prefixed with node_modules/jsdoc-wmf-theme/plugins/ ; JSDoc plugins should be prefixed with plugins/ . At a minimum, we recommend adding the plugins shown in the example above. For more options, see #Plugins.
|
source.include |
Array of paths that JSDoc should parse. You can also use includePattern and a regular expression.
|
source.exclude |
Array of paths that JSDoc should ignore. You can also use excludePattern and a regular expression.
|
templates.cleverLinks |
Sets link text formatting based on the type of link. Set to true .
|
templates.default.useLongnameInNav |
If set to true , the navigation sidebar displays the full name of each item, including ancestors (for example: mw.user.clientPrefs).
If set to |
templates.wmf.maintitle |
Title of the site, overrides name from package.json
|
templates.wmf.repository |
Link to the project's code repository, overrides repo from package.json
|
templates.wmf.linkMap |
Map of #Reusable links |
templates.wmf.hideSections |
Array of sections that will not appear in the sidebar, can include Modules, Externals, Namespaces, Classes, Interfaces, Events, Mixins, and Tutorials |
templates.wmf.siteMap |
Object that adds a sitemap page to the sidebar |
templates.wmf.siteMap.sections |
Set to true to split the sitemap into sections by category (modules, classes, namespaces, etc.), defaults to false
|
templates.wmf.siteMap.include |
Array of categories to include in the sitemap, can include modules, externals, namespaces, classes, interfaces, events, mixins, and tutorials. Must be lowercase. Defaults to all categories |
Plugins edit
You can enable plugins in the JSDoc configuration file. Here are some useful plugins from JSDoc and from the JSDoc WMF theme:
Plugin | Source | Description |
---|---|---|
markdown | JSDoc | Supports Markdown formatting in descriptions |
summarize | theme | Creates a summary field for each element based on its description |
betterlinks | theme | Supports external links without a @link tag and Phabricator short links
|
allow-dots-in-modules | theme | Supports module names that include periods |
Plugins are a great way to extend the functionality of JSDoc. You can contribute your own plugins to the theme by adding a file to the plugins directory. For more information about writing plugins, see the JSDoc documentation.
edit
The JSDoc WMF theme allows you to customize the navigation sidebar. This feature can help provide additional context for the docs and help larger projects reduce information overload.
In this example, this project has over 70 classes, so the Classes section in the sidebar is too long to navigate easily. Instead, the project uses the custom navigation feature to:
- Hide the Classes section from the sidebar, and rely on the list of classes on each namespace page to guide users.
- Rename the Namespaces section.
- Add a landing page to the Namespaces section to provide context about each namespace.
- Limit the Namespaces section to only the top-level namespaces.
{
"opts": {
"pages": {
"namespaces": {
"longname": "Frontend API",
"readme": "resources/src/frontend-api.md",
"depth": 1
}
}
},
"templates": {
"wmf": {
"hideSections": [ "Classes" ]
}
}
}
Option | Description |
---|---|
opts.pages |
Object that configures custom navigation. Can include configuration objects for modules, externals, namespaces, classes, interfaces, events, mixins, and tutorials |
opts.pages.CATEGORY_NAME.longname |
Name to use in the sidebar in place of the default name |
opts.pages.CATEGORY_NAME.readme |
Markdown file to use as a category's landing page |
opts.pages.CATEGORY_NAME.depth |
Limits the navigation items shown under a category by the number of elements in each item. For example, mw has a depth of 1; mw.Api has a depth of 2
|
2. Configure NPM edit
- Create a script named
doc
in your package.json file that runsjsdoc -c jsdoc.json
. If you want to include private symbols in the docs, usejsdoc -c jsdoc.json -p
. The script should also be invoked as part oftest
, such as... && npm -s run doc && ...
. - Add the latest JSDoc release and jsdoc-wmf-theme release to
devDependencies
. - Run
npm install
.
Configuration example edit
{
...,
"scripts": {
...,
"test": "grunt lint && npm run doc",
"doc": "jsdoc -c jsdoc.json",
...,
},
"devDependencies": {
...,
"jsdoc": "^x.x.x",
"jsdoc-wmf-theme": "^x.x.x",
...,
}
}
3. Preview your changes edit
4. Publish on doc.wikimedia.org edit
To add the documentation to https://doc.wikimedia.org:
- Create a patch for the repo integration/docroot that adds a section to wikimedia/doc/opensource.yaml (example)
- Create a patch for the repo integration/config that enables doc generation and upload for your repository in zuul/layout.yaml. (example)
More details can be found in Continuous integration/Documentation generation.
Troubleshooting edit
Globals edit
Error: Unexpected global detected
The JSDoc WMF theme does not allow global methods, events, or properties outside of the window
namespace. For recommended alternatives, see Manual:Coding conventions/JavaScript#Exporting. If the theme detects a global, JSDoc will fail with the error "Unexpected global detected" and list the relevant name and path.
To fix this issue, make sure the global is part of a module, namespace, or class.
Common causes:
- In an ES5-style class, you may need to add a
@memberof
tag with the class, namespace, or module name. Modules names should be formatted asmodule:name
. - In an ES6-style class, an unnecessary
@class
annotation can cause this error. - If the error relates to a method in an ECMAScript module, see the note under #ES6 example.