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
For more information about writing code comments in JavaScript, see Manual:Coding conventions/JavaScript.

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 examples

edit

If a class declaration has many tags for both the class and the constructor, group the class tags and the constructor tags together, and separate them with a line break.

/**
 * ContentEditable MediaWiki alien block extension node.
 *
 * @class
 * @abstract
 * @extends ve.ce.MWBlockExtensionNode
 * @mixes ve.ce.MWAlienExtensionNode
 *
 * @constructor
 * @param {ve.dm.MWAlienBlockExtensionNode} model Model to observe
 * @param {Object} [config] Configuration options
 */
ve.ce.MWAlienBlockExtensionNode = function VeCeMWAlienBlockExtensionNode() {

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,
};
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).

Types

edit

In addition to the types supported by JSDoc, the JSDoc WMF theme supports string literals in type definitions using the syntax used by TypeScript (and recognized by TypeScript in JSDoc comments). For example: @param {'a'|'b'} param.

Chainable

edit

The JSDoc WMF theme supports the @chainable tag to indicate chainable methods.

Configuration parameters

edit

When supplying an options object (or config or similar) as a parameter, document it using @param {Type} options.key

/**
 * Creates an ve.ui.MWCategoryItemWidget object.
 *
 * @param {Object} config
 * @param {Object} config.item Category item
 * @param {string} config.item.name Category name
 * @param {string} config.item.value
 * @param {string} [config.item.sortKey='']
 * @param {ve.dm.MWCategoryMetaItem} config.item.metaItem
 * @param {boolean} [config.hidden] Whether the category is hidden or not
 * @param {boolean} [config.missing] Whether the category's description page is missing
 * @param {string} [config.redirectTo] The name of the category this category's page redirects to.
 */
ve.ui.MWCategoryItemWidget = function VeUiMWCategoryItemWidget( config ) {

Code examples

edit

You can include examples in JSDoc by using the @example tag (with an optional <caption></caption>) or by using Markdown syntax (a line with ``` before and after the example). Markdown syntax is useful when you want to include multiple examples with text in between.

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, check the box for "Build core documentation" on the patch demo form, and 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.

Configuration example

edit

The below configuration example needs at least jsdoc-wmf-theme version 1.1.0 installed:

{
	"opts": {
		"destination": "docs/js",
		"pedantic": true,
		"readme": "README.md",
		"recurse": true,
		"template": "node_modules/jsdoc-wmf-theme"
	},
	"plugins": [
		"node_modules/jsdoc-wmf-theme/plugins/default"
	],
	"source": {
		"include": [ "modules", "resources" ],
		"exclude": [ ]
	},
	"templates": {
		"cleverLinks": true,
		"default": {
			"useLongnameInNav": true
		},
		"wmf": {
			"maintitle": "My Project",
			"repository": "https://gerrit.wikimedia.org/g/MyProject",
			"siteMap": {
				"sections": true
			},
			"linkMap": {}
		}
	}
}
edit

Certain objects outside your repo will be automatically hyperlinked by the JSDoc WMF theme:

Any objects outside your repo not defined by the theme will need to be defined manually, either using a linkMap or a prefixMap. See code examples below. Failing to define these will trigger "unknown link" warnings when running npm run doc.

{
    ...
    "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"
            }
        }
    }
}
{
    ...
    "templates": {
        "wmf": {
            "prefixMap": {
                "mw.": "https://doc.wikimedia.org/mediawiki-core/master/js/{type}.html"
            }
        }
    }
}

To unregister a default prefix, set the prefix to false in your JSDoc config. To override a default prefix with local links, set the prefix to true in your JSDoc config; for example, the OOUI documentation uses the below configuration to override the default prefix with links to the OOUI docs:

{
    ...
    "templates": {
        "wmf": {
            "prefixMap": {
                "OO.ui.": 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 false, the navigation displays only the last segment of an item's name (for example: clientPrefs).

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

By adding plugins: [ "node_modules/jsdoc-wmf-theme/plugins/default" ] to your config file as suggested above, you will enable these plugins:

Plugin Description
allow-dots-in-modules Supports module names that include periods
betterlinks Supports external links without a @link tag and Phabricator short links
externals Map links to URLs using a pattern instead of hard-coding each URL
jsdoc-class-hierarchy Adds a floating class hierarchy box when your repo contains @extends statements. To enable this plugin, add "class-hierarchy": {"showList": true} to the opts section of your JSDoc config.
markdown Supports Markdown formatting in descriptions
summarize Creates a summary field for each element based on its description

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.

Allowing globals

edit

Although globals are not recommended, you can configure the JSDoc WMF theme to allow specific globals using the opts.allowedGlobals option.

For example, to allow the global initReferencePreviewsInstrumentation method:

"opts": {
		"allowedGlobals": [
			"initReferencePreviewsInstrumentation"
		]
}

Custom navigation

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
  1. Create a script named doc in your package.json file that runs jsdoc -c jsdoc.json. If you want to include private symbols in the docs, use jsdoc -c jsdoc.json -p.
  2. The script should also be invoked as part of test, such as ... && npm run doc && .... This will cause JSDoc console warnings thrown during the npm run doc process to fail in CI, preventing regressions and making sure your doc site is able to generate.
  3. Add the latest JSDoc release and jsdoc-wmf-theme release to devDependencies.
    1. npm install --save-dev jsdoc
    2. npm install --save-dev jsdoc-wmf-theme

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

See #Previewing your changes.

4. Publish on doc.wikimedia.org

edit

To add the documentation to https://doc.wikimedia.org:

  1. Get consensus from the repo's maintainers (for example, via a Phabricator ticket)
  2. Make sure npm run doc is configured and working in package.json
  3. Create a patch for the repo integration/config that enables doc generation and upload for your repository in zuul/layout.yaml. (example)
  4. Create a patch for the repo integration/docroot that adds a section to wikimedia/doc/opensource.yaml (example)

To unpublish from doc.wikimedia.org, do the reverse. More details can be found in Continuous integration/Documentation generation and wikitech:doc.wikimedia.org.

ESLint

edit

There are different ways to write JSDoc-compatible docblocks. For example, @return vs @returns, or {string} vs {String}. Wikimedia has coding conventions for this. You can make sure your repo is following Wikimedia's JSDoc coding conventions by:

  1. Installing eslint-config-wikimedia. npm install eslint-config-wikimedia, then...
  2. Configuring it to use one of the JavaScript "client" or "server" rulesets.
    	"extends": [
    		"wikimedia/client/es6"
    	],
    

Converting from JSDuck to JSDoc

edit

Wikimedia used to use JSDuck to generate /docs/ pages, but is now transitioning to JSDoc. There are certain block tags that occur in JSDuck but never occur in JSDoc. These should be refactored, and avoided in new code.

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. You can also configure the theme to allow specific globals.

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 as module: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.

References

edit

See also

edit