JSDuck is [[ https://github.com/senchalabs/jsduck/commit/febef5558ecd05da25f5c260365acc3afd0cafd8#diff-04c6e90faac2675aa89e2176d2eec7d8 | 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
** [[ https://github.com/senchalabs/jsduck/commit/febef5558ecd05da25f5c260365acc3afd0cafd8#diff-04c6e90faac2675aa89e2176d2eec7d8 | Formal announcement on readme ]]
# **Proposed alternatives:**
** {icon check color=green} Use real JSDoc from npm
*** https://jsdoc.app/
*** https://www.npmjs.com/package/jsdoc
** {icon times color=red} Use documentationjs
*** http://documentation.js.org/
*** https://github.com/documentationjs/documentation
## 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}
## Acceptance criteria
[x] {T188261}
[x] Usage of jsduck is dropped in favor of jsdoc in Minerva
[] Usage of jsduck is dropped in favor of jsdoc in core
[] {T250843}
[] Usage of jsduck is dropped in favor of jsdoc in ContentTranslation
[x] {T342864}
[] {T342905}
## 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
//See also https://www.mediawiki.org/wiki/JSDoc //
### 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 [[ https://doc.wikimedia.org/ | doc.wikimedia.org ]] since you've taken the trouble to write it.
```lang=json,name=jsdoc.json
{
"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// [[ https://github.com/jsdoc/jsdoc/releases | JSDoc release ]] ([[ https://github.com/jsdoc/jsdoc/releases/tag/3.6.4 | v3.6.4 ]] at time of writing) and [[ https://github.com/wikimedia/jsdoc-wmf-theme/releases | jsdoc-wmf-theme ]] ([[ https://github.com/wikimedia/jsdoc-wmf-theme/releases/tag/0.0.3 | v0.0.3 ]], at time of writing) to `devDependencies`.
- All `jsduck` references should be clean (e.g., `rg jsduck`).
```lang=json,name=Example package.json
{
...,
"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:
- [[ https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#supported-jsdoc | 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`
- [[ https://github.com/wikimedia/eslint-config-wikimedia/blob/fba89782a4a3028fbd80a8ae9cff48ed4a918c2d/common.json#L102 | eslint-config-wikimedia style preferences ]]. The linter improves the consistency of code across Wikimedia for participating repos.
- Type definitions themselves appear to be compatible as both [[ https://github.com/senchalabs/jsduck/wiki/Type-Definitions | JSDuck type definitions ]] and [[ https://jsdoc.app/tags-type.html | JSDoc type definitions ]] use [[ https://github.com/google/closure-compiler/wiki/Types-in-the-Closure-Type-System | 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.
| **[[ https://github.com/senchalabs/jsduck/wiki#syntax | JSDuck tag ]]** | **[[ https://jsdoc.app/ | JSDoc tag ]] and notes** |
| `@abstract` | `@abstract` |
| `@accessor` | {icon check color=green} Unsupported. Only used by ExtJSBase. |
| `@alias prefix.name` | `@alias <aliasNamepath>` |
| `@alternateClassName OtherClassName` | {icon times color=red} **What to do?** `@alias <aliasNamepath>`? `@typedef [<type>] <namepath>`? [[ https://codesearch.wmflabs.org/search/?q=%40alternateClassName&i=nope&files=&repos= | Sparse usage ]]. |
| `@aside <name>` | {icon check color=green} Unsupported. No usage. |
| `@author Some name...` | `@author <name> [<emailAddress>]` |
| `@cfg`, `@cfg name`, `@cfg {Type} name`, `@cfg {Type} [name="default value"]`, `@cfg {Type} name.subproperty` | {icon times color=red} **What to do?** |
| `@chainable` | {icon times color=red} **What to do?** Custom tag? |
| `@class`, `@class ClassName` | `@class [<type> <name>]` |
| `@constructor` | `@return [{type}] [description]`. |
| `@deprecated` | `@deprecated`. |
| `@docauthor Some name...` | {icon check color=green} Unsupported and unused. |
| `@enum`, `@enum {Type}`, `@enum {Type} EnumName`, `@enum [EnumName=alias.*]` | `@enum [<type>]` |
| `@event`, `@event name` | `@event <className>#[event:]<eventName>`. |
| `@evented` | {icon check color=green} 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` | {icon check color=green} Unsupported. No usage. |
| `@hide` |{icon check color=green} Unsupported. Only used by ExtJSBase. |
| `@ignore` | {icon times color=red} **What to do?** `@ignore` but move to end of block? |
| `@inheritable` | {icon times color=red} **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) | {icon times color=red} **What to do?** Delete? |
| `@markdown` | {icon check color=green} Unsupported. No usage. |
| `@member ClassName` | {icon times color=red} **What to do?** `@member [<type>] [<name>]`, `@memberof <parentNamepath>` `@memberof! <parentNamepath>`, or something else? |
| `@method`, `@method name` | `@method [<FunctionName>]` |
| `@mixins ClassName` | `@mixin [<MixinName>]` |
| `@new` | {icon check color=green} 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` | {icon check color=green} 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` | {icon check color=green} Unsupported. No usage. |
| `@readonly` | `@readonly` |
| `@removed`, `@removed 2.0 Some description...` | {icon check color=green} 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` | {icon check color=green} Unsupported. No usage. |
| `@since Ext JS 4.0 beta` | `@since <versionDescription>` |
| `@singleton` | {icon times color=red} **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` | {icon check color=green} 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...}` | {icon check color=green} Unsupported. [[ https://codesearch.wmflabs.org/search/?q=%40%7Bvideo&i=nope&files=&repos= | No usage. ]] |