npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@cparra/apexdocs

v3.7.2

Published

Library with CLI capabilities to generate documentation for Salesforce Apex classes.

Downloads

7,894

Readme

ApexDocs

CI License npm

ApexDocs is a non-opinionated documentation generator for Salesforce Apex classes. It can output documentation in Markdown format, which allows you to use the Static Site Generator of your choice to create a documentation site that fits your needs, hosted in any static web hosting service.

👀 Examples

ApexDocs generates Markdown files, which can be integrated into any Static Site Generation (SSG) engine, (e.g. Jekyll, Vitepress, Hugo, Docosaurus, etc.) to create a documentation site that fits your needs.

This gives you the flexibility to create beautiful sites by leveraging your preferred SSG engine, which usually provides a wide range of themes, dark mode support, and other features out of the box.

These are examples of documentation sites generated using Vitepress. Head over to the examples/vitepress folder to see the code.

The extra flexibility also lets you integrate the output documentation with your existing documentation site, allowing you to match the look and feel of your existing site.

OpenApi REST definitions can be visualized using a tool like ReDoc, Swagger UI, or any other OpenApi viewer.

This repo contains several other example implementations in the examples directory, showcasing how to integrate with different tools.

In the wild

Here are some live projects using ApexDocs:

🚀 Features

  • Generate documentation for Salesforce Apex classes as Markdown files
  • Generate an OpenApi REST specification based on @RestResource classes
  • Generate a changelog based on the differences between two versions of your Salesforce Apex classes
  • Support for grouping blocks of related code within a class
  • Support for ignoring files and members from being documented
  • Namespace support
  • Configuration file support
  • Single line ApexDoc Blocks
  • Custom tag support
  • And much, much more!

💿 Installation

npm i -g @cparra/apexdocs

⚡ Quick Start

CLI

Markdown

Run the following command to generate markdown files for your global Salesforce Apex classes and custom objects:

apexdocs markdown -s force-app

OpenApi

Run the following command to generate an OpenApi REST specification for your Salesforce Apex classes annotated with @RestResource:

apexdocs openapi -s force-app

Changelog

Run the following command to generate a changelog for your Salesforce Apex classes:

apexdocs changelog --previousVersionDir force-app-previous --currentVersionDir force-app

▶️ Available Commands

Markdown

markdown

Flags

| Flag | Alias | Description | Default | Required | |----------------------------|-------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|----------| | --sourceDir | -s | The directory where the source files are located. | N/A | Yes | | --targetDir | -t | The directory where the generated files will be placed. | docs | No | | --scope | -p | A list of scopes to document. Values should be separated by a space, e.g --scope global public namespaceaccessible. | global | No | | --defaultGroupName | N/A | The default group name to use when a group is not specified. | Miscellaneous | No | | --namespace | N/A | The package namespace, if any. If provided, it will be added to the generated files. | N/A | No | | --sortAlphabetically | N/A | Sorts files appearing in the Reference Guide alphabetically, as well as the members of a class, interface or enum alphabetically. If false, the members will be displayed in the same order as the code. | false | No | | --includeMetadata | N/A | Whether to include the file's meta.xml information: Whether it is active and and the API version | false | No | | --linkingStrategy | N/A | The strategy to use when linking to other classes. Possible values are relative, no-link, and none | relative | No | | --customObjectsGroupName | N/A | The name under which custom objects will be grouped in the Reference Guide | Custom Objects | No |

Linking Strategy

The linking strategy determines how ApexDocs will link to other classes in your documentation. For example, if I have class A that links through class B (e.g. through an {@link B} tag, the @see tag, takes it as a param, returns it from a method, etc.), the linking strategy will determine how the link to class B is created.

These are the possible values for the linkingStrategy flag:

  • relative

Create a relative link to the class file. So if both classes are in the same directory, the link will be created as [B](B.md). If the classes are in different directories, the link will be created as [B](../path/to/B.md)

  • no-link

Does not create a link at all. The class name will be displayed as plain text.

  • none

Does not apply any kind of logic. Instead, the links will be determined by the path to the file from the root of the documentation site OR by whatever path you have returned in the transformReference hook for the file.

Sample Usage

apexdocs markdown -s force-app -t docs -p global public namespaceaccessible -n MyNamespace

OpenApi

openapi

Flags

| Flag | Alias | Description | Default | Required | |----------------|-------|-------------------------------------------------------------------------------|-----------------|----------| | --sourceDir | -s | The directory where the source files are located. | N/A | Yes | | --targetDir | -t | The directory where the generated files will be placed. | docs | No | | --fileName | N/A | The name of the OpenApi file. | openapi.json | No | | --namespace | N/A | The package namespace, if any. This will be added to the API file Server Url. | N/A | No | | --title | N/A | The title of the OpenApi file. | Apex REST API | No | | --apiVersion | N/A | The version of the API. | 1.0.0 | No |

Sample Usage

apexdocs openapi -s force-app -t docs -n MyNamespace --title "My Custom OpenApi Title"

Changelog

changelog

Flags

| Flag | Alias | Description | Default | Required | |------------------------|-------|--------------------------------------------------------------------|-------------|----------| | --previousVersionDir | -p | The directory location of the previous version of the source code. | N/A | Yes | | --currentVersionDir | -t | The directory location of the current version of the source code. | N/A | Yes | | --targetDir | -t | The directory location where the changelog file will be generated. | ./docs/ | No | | --fileName | N/A | The name of the changelog file to be generated. | changelog | No | | --scope | N/A | The list of scope to respect when generating the changelog. | ['global'] | No | | --skipIfNoChanges | N/A | Whether to skip generating the changelog if there are no changes. | true | No |

Sample Usage

apexdocs changelog -p force-app-previous -t force-app

🔬 Defining a configuration file

You can also use a configuration file to define the parameters that will be used when generating the documentation.

Configuration files are the main way to integrate the generated documentation with the Static Site Generator of your choice and your build process, as well as configuring any custom behavior and the output of the generated files.

Overview

Apexdocs uses cosmiconfig to load the configuration file, which means it supports the following formats (plus anything else supported by cosmiconfig):

  • A package.json property, e.g. { "apexdocs": { "sourceDir": "src", "targetDir": "docs" } }
  • A .apexdocsrc file, written in YAML or JSON, with optional extensions: .yaml/.yml/.json/.js
  • An apexdocs.config.js (or .mjs) file that exports an object
  • A apexdocs.config.ts file that exports an object

The configuration file should be placed in the root directory of your project.

Note that when using a configuration file, you can still override any of the parameters by passing them through the CLI.

Configuration file

When defining a configuration file, it is recommended to use ES modules syntax. The config file should default export an object with the parameters you want to use.:

export default {
  sourceDir: 'force-app',
  targetDir: 'docs',
  scope: ['global', 'public'],
  ...
}

Every property in the configuration file is optional, and if not provided, either the value provided through the CLI will be used, or the default value will be used.

Config Intellisense

Using the defineMarkdownConfig (or the defineOpenApiConfig for OpenApi documentation) helper will provide Typescript-powered intellisense for the configuration file options. This should work with both Javascript and Typescript files.

import { defineMarkdownConfig } from "@cparra/apexdocs";

export default defineMarkdownConfig({
  sourceDir: 'force-app',
  targetDir: 'docs',
  scope: ['global', 'public'],
  ...
});

Generating Different Types of Documentation

You might want to generate different types of documentation using a single command. For example, if you are releasing a new version of your project, you might want to generate updated documentation Markdown files, and at the same time generate a changelog listing everything new.

You can do this by providing a configuration file that exports a configuration object which keys are the type of documentation you want to generate.

import { defineMarkdownConfig, defineChangelogConfig } from '@cparra/apexdocs';

export default {
  markdown: defineMarkdownConfig({
    sourceDir: 'force-app',
    targetDir: 'docs',
    scope: ['global', 'public'],
    ...
  }),
  changelog: defineChangelogConfig({
    previousVersionDir: 'force-app-previous',
    currentVersionDir: 'force-app',
    targetDir: 'docs',
    scope: ['global', 'public'],
  })
};

Then you only need to run the top level apexdocs command, and it will generate both types of documentation.

Note that you can still run the individual commands if you only want to generate one type of documentation by providing the subcommand, e.g apexdocs markdown or apexdocs changelog.

Excluding Files from Being Documented

Any pattern included in the .forceignore file will be excluded from the documentation.

Additionally, you can exclude one or multiple files from being documented by providing a list of glob patterns to the exclude property in the configuration file.

import { defineMarkdownConfig } from "@cparra/apexdocs";

export default defineMarkdownConfig({
  sourceDir: 'force-app',
  targetDir: 'docs',
  scope: ['global', 'public'],
  exclude: ['**/MyClass.cls', '**/MyOtherClass.cls'],
  ...
});

Excluding Tags from Appearing in the Documentation

Note: Only works for Markdown documentation.

You can exclude tags from appearing in the documentation by using the excludeTags property in the configuration file, which allow you to pass a list of tags that you want to exclude from the documentation.

import { defineMarkdownConfig } from "@cparra/apexdocs";

export default defineMarkdownConfig({
  sourceDir: 'force-app',
  targetDir: 'docs',
  scope: ['global', 'public'],
  excludeTags: ['internal', 'ignore'],
  ...
});

Configuration Hooks

When defining a .js or .ts configuration file, your object export can also make use of different hooks that will be called at different stages of the documentation generation process.

All hooks can be async functions, allowing you to make asynchronous operations, like calling an external API.

There are hooks for both Markdown and Changelog operations (but not for OpenApi).

Markdown Hooks

transformReferenceGuide

Allows changing the Allows changing the frontmatter and content of the reference guide, or even if creating a reference guide page should be skipped.

Type

type TransformReferenceGuide = (referenceGuide: ReferenceGuidePageData) => Partial<ReferenceGuidePageData> | Skip | Promise<Partial<ReferenceGuidePageData> | Skip>;

Example: Updating the frontmatter

export default {
  transformReferenceGuide: (referenceGuide) => {
    return {
      // The frontmatter can either be an object, of the frontmatter string itself
      frontmatter: { example: 'example' }
    };
  }
};

Example: skipping the reference guide

// The skip function is imported from the package
import { defineMarkdownConfig, skip } from "@cparra/apexdocs";

export default defineMarkdownConfig({
  transformReferenceGuide: (referenceGuide) => {
    return skip();
  }
});
transformDocs

The main purpose of this hook is to allow you to skip the generation of specific pages, by returning a filtered array of DocPageData objects.

If you want to modify the contents or frontmatter of the docs, use the transformDocPage hook instead.

Type

type TransformDocs = (docs: DocPageData[]) => DocPageData[] | Promise<DocPageData[]>

Example

export default {
  transformDocs: (docs) => {
    return docs.filter(doc => doc.name !== 'MyClass');
  }
};
transformDocPage

Allows changing the frontmatter and content of the doc page.

Type

type TransformDocPage = (
  doc: DocPageData,
) => Partial<ConfigurableDocPageData> | Promise<Partial<ConfigurableDocPageData>>

Example

export default {
  transformDocPage: (doc) => {
    return {
      frontmatter: { example: 'example' }
    };
  }
};
transformReference

Allows changing where the files are written to and how files are linked to each other.

Type

type TransformReference = (
  reference: DocPageReference,
) => Partial<ConfigurableDocPageReference> | Promise<ConfigurableDocPageReference>;

Example

export default {
  // Notice how we are setting the linking strategy to none, so that nothing is done
  // to the links by the tool when it tries to link to other classes
  linkingStrategy: 'none',
  transformReference: (reference) => {
    return {
      // Link to the class in Github instead to its doc page.
      referencePath: `https://github.com/MyOrg/MyRepo/blob/main/src/classes/${reference.name}.cls`
    };
  }
};

Changelog Hooks

transformChangeLogPage

Allows changing the frontmatter and content of the changelog page.

Type

type TransformChangeLogPage = (
  changelog: ChangeLogPageData,
) => Partial<ChangeLogPageData> | Promise<Partial<ChangeLogPageData>>

// Supporting types

type ChangeLogPageData = {
  source: SourceChangelog;
  frontmatter: string | Record<string, any>;
  content: string;
  outputDocPath: string;
};

type SourceChangelog = {
  fileChanges: FileChange[];
};

type FileChange = {
  name: string;
  fileType: 'apex' | 'customobject';
  changeType: 'added' | 'removed' | 'changed';
  changes?: {
    addedMethods?: string[];
    removedMethods?: string[];
    addedFields?: string[];
    removedFields?: string[];
    addedProperties?: string[];
    removedProperties?: string[];
    addedCustomFields?: string[];
    removedCustomFields?: string[];
    addedSubtypes?: string[];
    removedSubtypes?: string[];
    addedEnumValues?: string[];
    removedEnumValues?: string[];
  };
};

Example

export default {
  transformChangeLogPage: (changelog) => {
    return {
      frontmatter: { example: 'example' }
    };
  }
};

⤵︎ Importing to your project

Reflection

If you are just interested in the Apex parsing capabilities, you can use the standalone Apex Reflection Library which is what gets used by this library behind the scenes to generate the documentation files.

Processing

If you would like to use the processing capabilities of ApexDocs directly from Javascript/Typescript instead of using the CLI, you can import the process function from the library.

import { process } from '@cparra/apexdocs';

process({
  sourceDir: 'force-app',
  targetDir: 'docs',
  scope: ['global', 'public'],
  ...
});

👨‍💻 Typescript

If using Typescript, ApexDocs provides all necessary type definitions.

📖 Documentation Guide

See the wiki for an in-depth guide on how to document your Apex code to get the most out of ApexDocs.

📄 Generating OpenApi REST Definitions

ApexDocs can also generate OpenApi REST definitions for your Salesforce Apex classes annotated with @RestResource.

See the wiki for more information.