JSDuck is formally unmaintained and seems abandonware by now. It is hurting our ability to properly document our code.
- Examples of problems:
- No support for @interface
- No support for namespaced events (change:title is invalid)
- No support for ES6 (T156469)
- Links that show it is unmaintained:
- Last beta was in 2013: https://github.com/senchalabs/jsduck/issues/633
- See the pulse graphs, barely any activity since end of 2013
- Formal announcement on readme
- Proposed alternatives:
- Use real JSDoc from npm
- Use documentationjs
Requirements for alternative
What are blockers for adopting JSDoc3 and/or a custom theme? In other words, compared to viewing code comments directly, what added value do we want our generated documentation to have for consumers?
TDB, see T187672: Create Wikimedia theme for JSDoc3 (version 1)
Acceptance criteria
- Usage of jsduck is dropped in favor of jsdoc in MobileFrontend
- Usage of jsduck is dropped in favor of jsdoc in Minerva
- Usage of jsduck is dropped in favor of jsdoc in core
- Usage of jsduck is dropped in favor of jsdoc in VisualEditor
- Usage of jsduck is dropped in favor of jsdoc in ContentTranslation
- Usage of jsduck is dropped in favor of jsdoc in Kartographer
- Usage of jsduck is dropped in favor of jsdoc in Wikibase
Checklist for each migration
- Code documentation works fine, fix any problems
- Docs get properly published to docs.wikimedia.org e.g. https://doc.wikimedia.org/MobileFrontend/master/js/
- CI lints documentation properly with jenkins-bot on patches
- Documentation about how to run documentation in mw.org, README, etc is updated to point to the new instructions if any change
Migration guide
JSDoc configuration:
- Filename is jsdoc.json.
- Don't forget the tabs.
- Update destination to wherever the autogenerated JavaScript documentation output is. This should be ignored in a .gitignore.
- Try hard to enable pedantic.
- If you have a JS-specific readme, update the readme option.
- If you do not have many externals, try to enable the Wikimedia template. See T250022 if this is blocking adoption. It's better to have pedantic than a theme.
- Update source.include as needed.
- Output should most probably be available on doc.wikimedia.org since you've taken the trouble to write it.
{ "opts": { "destination": "docs/js", "package": "package.json", "pedantic": true, "readme": "README.md", "recurse": true, "template": "node_modules/jsdoc-wmf-theme" }, "plugins": [ "plugins/markdown" ], "source": { "include": [ "resources", "src" ] }, "templates": { "cleverLinks": true, "default": { "useLongnameInNav": true } } }
NPM configuration:
- If a separate NPM script is added, the script should be called jsdoc to avoid confusion with other languages like PHP. Invocation can be inline though too.
- Invocation looks like jsdoc -c jsdoc.json.
- Script should be invoked as part of test like ... && npm -s run jsdoc && ....
- Add the latest JSDoc release (v3.6.4 at time of writing) and jsdoc-wmf-theme (v0.0.3, at time of writing) to devDependencies.
- All jsduck references should be clean (e.g., rg jsduck).
{ ..., "scripts": { ..., "test": "npm -s run build && npm -s run doc", "doc": "jsdoc -c jsdoc.json && npm run build-storybook", ..., }, "devDependencies": { ..., "jsdoc": "3.6.4", "jsdoc-wmf-theme": "0.0.3", ..., } }
JSDuck to JSDoc mapping:
- Try to comply with:
- TypeScript supported JSDoc tags (other tags are simply ignored). This enables type checking for participating repos. Supported tags are:
- @type
- @param / @arg / @argument
- @returns / @return
- @typedef
- @callback
- @template
- @class / @constructor
- @this
- @extends / @augments
- @enum
- eslint-config-wikimedia style preferences. The linter improves the consistency of code across Wikimedia for participating repos.
- TypeScript supported JSDoc tags (other tags are simply ignored). This enables type checking for participating repos. Supported tags are:
- Type definitions themselves appear to be compatible as both JSDuck type definitions and JSDoc type definitions use Google Closure compiler type expressions. However, garbage in = garbage out.
- Many JSDuck types support optional descriptions on subsequent lines.
- Ironically, neither JSDoc nor JSDuck is as well documented as one would like.
JSDuck tag | JSDoc tag and notes |
@abstract | @abstract |
@accessor | Unsupported. Only used by ExtJSBase. |
@alias prefix.name | @alias <aliasNamepath> |
@alternateClassName OtherClassName | What to do? @alias <aliasNamepath>? @typedef [<type>] <namepath>? Sparse usage. |
@aside <name> | Unsupported. No usage. |
@author Some name... | @author <name> [<emailAddress>] |
@cfg, @cfg name, @cfg {Type} name, @cfg {Type} [name="default value"], @cfg {Type} name.subproperty | What to do? |
@chainable | What to do? Custom tag? |
@class, @class ClassName | @class [<type> <name>] |
@constructor | @return [{type}] [description]. |
@deprecated | @deprecated. |
@docauthor Some name... | Unsupported and unused. |
@enum, @enum {Type}, @enum {Type} EnumName, @enum [EnumName=alias.*] | @enum [<type>] |
@event, @event name | @event <className>#[event:]<eventName>. |
@evented | Unsupported. Only used by ExtJSBase. |
@example | @example. |
@experimental, @experimental 2.0 Some description... | @experimental |
@extends ParentClassName | @extends <namepath> |
@fires eventName (in 5.x beta) | @fires <className>#[event:]<eventName> |
@ftype name | Unsupported. No usage. |
@hide | Unsupported. Only used by ExtJSBase. |
@ignore | What to do? @ignore but move to end of block? |
@inheritable | What to do? Delete? |
@inheritdoc, @inheritdoc ClassName, @inheritdoc #memberName, @inheritdoc ClassName#memberName, @inheritdoc ClassName#static-type-memberName | What to do? If no value, @inheritdoc. If value, @extends <value>? |
@localdoc This documentation is only visible inside this class/member. (in 5.x beta) | What to do? Delete? |
@markdown | Unsupported. No usage. |
@member ClassName | What to do? @member [<type>] [<name>], @memberof <parentNamepath> @memberof! <parentNamepath>, or something else? |
@method, @method name | @method [<FunctionName>] |
@mixins ClassName | @mixin [<MixinName>] |
@new | Unsupported. No usage. |
@override OverriddenClassName | @override |
@param name, @param {Type} name, @param {Type} [name], @param {Type} [name="default-value"], @param {Type} name.subproperty | @param [<type>] [<name>] [<description> |
@preventable | Unsupported. Only used by ExtJSBase. |
@private | @private [{typeExpression}] |
@property, @property name, @property {Type} name, @property {Type} [name="default value"], @property {Type} name.subproperty | @property [<type>] [<name>] [<description> |
@protected | @protected [{typeExpression}] |
@ptype name | Unsupported. No usage. |
@readonly | @readonly |
@removed, @removed 2.0 Some description... | Unsupported. One usage in SemanticMediaWiki and otherwise only used by ExtJSBase. |
@requires ClassName | @requires <someModuleName> |
@return {Type}, @return {Type} return.subproperty | @return [{type}] [description] |
@scss-mixin | Unsupported. No usage. |
@since Ext JS 4.0 beta | @since <versionDescription> |
@singleton | What to do? Custom tag? |
@static | @static |
@template | @template |
@throws, @throws {Type} | @throws {<type>} [free-form description] |
@type {Type}, @type Type | @type {<type>} [free-form description] |
@uses ClassName | @see <namepath> or @see <text>. Mapping isn't one-to-one. |
@var, @var $some-name, @var {Type} $some-name, @var {Type} [$some-name="default value"] | @member [<type>] [<name>] |
@xtype | Unsupported. One usage in ExtTab and otherwise only uses by ExtJSBase. |
{@link Class#member link text} | {@link namepathOrURL}, [link text]{@link namepathOrURL}, {@link namepathOrURL%7clink text}, {@link namepathOrURL link text (after the first space)} |
{@img path/to/image.png alt text} | Usupported. Only used by ExtJSBase. |
{@video vimeo 465123 Some description here...} | Unsupported. No usage. |