Module index

March 16, 2025 · View on GitHub

category:jsdocplugin

Defines a JSDoc plugin that adds custom properties to doclets and provides a new category tag.

Source file

Functions

defineTags()

modifier: public modifier: static

Defines a new JSDoc tag 'category' that accepts a text value. This adds a corresponding 'category' property on the corresponding doclet.

Examples

@category Model

extractTypeExpression(string) ► string

modifier: private

Extracts the type expression from a comment string

ParametersTypeDescription
stringstringthe comment string
returnstringthe type expression

extractParametersInfo(line) ► Doclet

modifier: private

Extracts the type, name and description of the 'param' tag.

ParametersTypeDescription
linestringthe comment line
returnDocletlist of parameters

extractTagInfo(line, tag) ► Doclet

modifier: private

Extracts the type and description of the specified tag.

ParametersTypeDescription
linestringthe comment line
tag'return'the specified tag
returnDocletlist of parameters

populateFunctionInfo(doclet)

modifier: private

Tries to populate 'params' and 'return' type and description on the specified doclet if not provided but found through comment

ParametersTypeDescription
docletDocletthe doclet to process

populateMemberInfo(doclet)

modifier: private

Tries to populate type and description on the specified doclet if not provided but found through comment

ParametersTypeDescription
docletDocletthe doclet to process

getFilePath(d) ► string

modifier: private

Gets the absolute file path corresponding to the specified doclet.

ParametersTypeDescription
dDocletthe specified doclet
returnstringthe absolute file path

getModuleName(filename, folderPath) ► string

modifier: private

Get the module name corresponding to the given filename and path. In case of index.js the folder name is used.

ParametersTypeDescription
filenamestringthe given filename
folderPathstringthe given folder path containing the file
returnstringthe module name

defaultProcess(cf, k) ► function

modifier: private

Defines the default process on doclet: applying the 'value' function defined on the configuration object to the specified key/property of the doclet instance.

ParametersTypeDescription
cfobjectthe configuration object
kstringthe key/property of the object
returnfunctiona function that takes a doclet as input and sets the corresponding key/property with the 'value' function

processDoclet(doclet) ► Doclet

modifier: private

Processes the specified doclet to add or modify properties based on the processConfig object.

ParametersTypeDescription
docletDocletthe specified doclet to modify
returnDocletthe modified doclet

processDoclets(doclets)

modifier: private

Processes the parsed doclets to provide a better hierarchy.

ParametersTypeDescription
docletsArray.<Doclet>the array of parsed doclets

Members

handlers

modifier: public modifier: static

Defines the event handlers of the JSDoc plugin.


Constants

config

modifier: private

The configuration of the JSDoc plugin.

Value

{
  rootFolder: env.pwd,
  docFolder: env.opts.destination,
  includes: (env.opts.includes || 'public,protected,private').toLowerCase().replace(' ', '').split(','),
  badgecolors:
    (env.conf &&
      env.conf.templates &&
      env.conf.templates.markdown &&
      env.conf.templates.markdown.badgecolors) ||
    {}
}

processConfig

modifier: private

The configuration of the doclet processing. Each key of the configuration object defines a process:

  • either explicitly if the 'process' function is defined,
  • either implictly if the 'value' function is defined : in such case the process consists of applying a value to the corresponding key property of the doclet instance.
  • In both cases, the process is executed if there is no 'condition' function, or if the 'condition' function evaluates to true.

Value


      d.kind === 'class' &&
      d.meta.code &&
      d.meta.code.name &&
      (d.meta.code.name.startsWith('export') || (d.tags && d.tags.some(t => t.title === 'export'))),
    process: d => {
      exportedClasses.push(d.name);
      return d;
    }
  },
  tocDescription: {
    // add 'tocDescription' property that represents the description of a module that appears in the toc
    condition: d => d.kind === 'module' && !d.tocDescription,
    value: d => d.description
  },
  valuecode: {
    // add 'valuecode' property that represents the source code of a constant
    condition: d => d.kind === 'constant',
    value: d => {
      const sourcefile = getFilePath(d);
      const source = fs.readFileSync(sourcefile, 'utf8');
      const indexedSource = lineColumn(source);
      const { loc } = d.meta.code.node;
      const code = source.slice(
        indexedSource.toIndex(loc.start.line, loc.start.column + 1),
        indexedSource.toIndex(loc.end.line, loc.end.column + 1)
      );
      return code.includes(' =') ? code.slice(code.indexOf(' =') + 3, -1) : code;
    }
  },
  screenshot: {
    // add 'screenshot' property that indicates if the documented has a related snapshot image?
    condition: d => {
      if (!['module', 'class'].includes(d.kind)) return false;
      // the relative path of the screenshot file
      const filename = `${d.kind}_${path.basename(d.meta.filename, path.extname(d.meta.filename))}.png`;
      const filepath = path.join(config.docFolder, 'images/screenshots', filename);
      return fs.existsSync(filepath);
    },
    value: d => `${d.kind}_${path.basename(d.meta.filename, path.extname(d.meta.filename))}.png`
  },
  category: {
    // modify the 'category' property: add a default value ('other') if none found
    condition: d => !d.category && ['module', 'class'].includes(d.kind),
    value: () => 'other'
  },
  categorycolor: {
    // add 'categorycolor' property
    value: d => config.badgecolors[d.category] || 'blue'
  },
  static: {
    // add 'relativepath' property that indicates if the documented object is static?
    value: d => d.scope === 'static'
  },
  hasParameters: {
    // add 'hasParameters' property that indicates if the documented object has @param or @returns tags?
    value: d => (d.params && d.params.length > 0) || (d.returns && d.returns.length > 0)
  },
  relativepath: {
    // add 'relativepath' property that indicates the relative path from the documentation to the source code
    value: d => {
      const filepath = getFilePath(d); // the absolute path of the source file
      return path.relative(config.docFolder, filepath).replaceAll(path.sep, path.posix.sep); // the relative path of the source file from the documentation folder
    }
  },
  fixDotPathForModule: {
    // fix a jsdoc issue: 'longname' and 'memberof' are corrupted when file path contains a dot: 'module' string appears in the middle of 'longname'
    condition: d => d.longname?.indexOf(tagModule) > 0 && d.kind === 'module',
    process: d => {
      d.name = d.longname.replace(tagModule, '');
      d.longname = tagModule + d.name;
      if (d.memberof) delete d.memberof;
      return d;
    }
  },
  fixDotPathForNonModule: {
    // fix a jsdoc issue: 'longname' and 'memberof' are corrupted when file path contains a dot: 'module' string appears in the middle of 'longname'
    condition: d => d.longname?.indexOf(tagModule) > 0 && d.kind !== 'module',
    process: d => {
      d.longname = tagModule + d.longname.replace(tagModule, '');
      d.memberof = tagModule + d.memberof.replace(tagModule, '');
      return d;
    }
  },
  memberof: {
    // modify the 'memberof' property: fix 'export default var'
    condition: d => d.kind !== 'module' && !d.memberof && d.longname && d.longname.startsWith(tagModule),
    value: d => d.longname
  },
  access: {
    // modify the 'access' property: add a default value ('private') if none found
    condition: d => !d.access,
    value: d => {
      if (d.memberof && exportedClasses.includes(d.memberof) && d.name.charAt(0) !== '_') return 'public';
      if (
        (d.kind === 'constant' || d.kind === 'function' || d.kind === 'member') &&
        d.meta.code &&
        d.meta.code.name &&
        d.meta.code.name.length > 0 &&
        (d.meta.code.name.startsWith('exports.') || d.meta.code.name === 'module.exports')
      ) {
        return 'public';
      }
      return 'private';
    }
  },
  included: {
    // add 'included' property that indicates if the comment is to be included in the doc
    value: d => ['module', 'class'].includes(d.kind) || config.includes.includes(d.access)
  },
  isDefault: {
    // add 'isDefault' property that indicates if the documented object is the default export of the module
    condition: d => d.kind !== 'module' && d.name && d.name.startsWith(tagModule),
    process: d => {
      d.isDefault = true;
      d.name = 'default';
      return d;
    }
  },
  fixUndocumented: {
    // fix a jsdoc regression: constructors are forced to undocumented on some conditions
    // so the publish handler has been modified to include also undocumented
    // and truly undocumented doclets are marked as 'included': false so that they can be removed
    condition: d => d.undocumented === true,
    process: d => {
      d.included = false;
      return d;
    }
  },
  acceptTypeScriptType: {
    // add 'type' property when type tag is expressed as some funky typescript expression
    // causing JSDoc to throw an error preventing type to be defined
    // but still can be retrieved from the comment property
    condition: d => d.comment?.length > 0,
    process: d => {
      if (d.kind === 'member' && !d.type) {
        populateMemberInfo(d);
      }
      if (d.kind === 'function' || d.kind === 'constant') {
        populateFunctionInfo(d);
      }
      return d;
    }
  }