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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@simplysf/simply-document

v0.3.6

Published

Utilities for generating project documentation

Readme

@simplysf/simply-document

NPM Downloads/week License: Apache-2.0

Install

sf plugins install @simplysf/simply-document

Issues

Please report any issues at https://github.com/SimplySF/simply-node/issues

Contributing

This package is part of the @simplysf/simply monorepo. See CONTRIBUTING.md for what's specific to this package, and the repo's root CONTRIBUTING.md for repo structure, setup, commit conventions, and how to submit a pull request. Please also read our Code of Conduct.

Commands

sf simply document diff

Generate a change report between two git refs.

USAGE
  $ sf simply document diff --from-tag <value> --to-tag <value> [--json] [--flags-dir <value>] [--output-file <value>]
    [--template-file <value>] [--output-format html]

FLAGS
  --from-tag=<value>        (required) The starting git ref for the diff report.
  --output-file=<value>     Path to write the generated report to.
  --output-format=<option>  [default: html] Output format to render the report in.
                            <options: html>
  --template-file=<value>   Path to a custom Handlebars template to render instead of the built-in one.
  --to-tag=<value>          (required) The ending git ref for the diff report.

GLOBAL FLAGS
  --flags-dir=<value>  Import flag values from a directory.
  --json               Format output as json.

DESCRIPTION
  Generate a change report between two git refs.

  Runs `git diff --name-status` between two git refs (tags, branches, or commits) in the current working directory,
  groups the changed files by Salesforce metadata component type, and renders a Confluence-storage-format change report
  suitable for pasting into a release or change-management page.

EXAMPLES
  $ sf simply document diff --from-tag v1.0.0 --to-tag v1.1.0

  $ sf simply document diff --from-tag v1.0.0 --to-tag v1.1.0 --output-file change-report.html

  $ sf simply document diff --from-tag v1.0.0 --to-tag v1.1.0 --template-file my-change-report.hbs

FLAG DESCRIPTIONS
  --output-file=<value>  Path to write the generated report to.

    When specified, the generated report is written to this path instead of being printed to the terminal.

  --output-format=html  Output format to render the report in.

    Currently only `html` is supported. Reserved for future formats (e.g. Markdown).

  --template-file=<value>  Path to a custom Handlebars template to render instead of the built-in one.

    When specified, this template is rendered with the same data the built-in report template receives, and can reuse
    the built-in `changeTable` partial. See this package's README "Custom Templates" section for the data shape and
    available partials.

See code: lib/commands/simply/document/diff.js

sf simply document generate

Generate a technical design document for a Salesforce project.

USAGE
  $ sf simply document generate -d <value> --output-file <value> [--json] [--flags-dir <value>] [--template-file <value>]
    [--output-format html]

FLAGS
  -d, --directory=<value>       (required) Salesforce project source directory to scan.
      --output-file=<value>     (required) Path to write the generated document to.
      --output-format=<option>  [default: html] Output format to render the document in.
                                <options: html>
      --template-file=<value>   Path to a custom Handlebars template to render instead of the built-in one.

GLOBAL FLAGS
  --flags-dir=<value>  Import flag values from a directory.
  --json               Format output as json.

DESCRIPTION
  Generate a technical design document for a Salesforce project.

  Scans a Salesforce DX project's source directory for metadata (objects, fields, Apex, Lightning components, flows,
  permissions, and more) and renders a Confluence-storage-format technical design document covering the data model,
  security model, groups/queues/permissions, solution inventory, and custom code inventory.

EXAMPLES
  $ sf simply document generate --directory force-app --output-file technical-design-document.html

  $ sf simply document generate --directory force-app --output-file technical-design-document.html --template-file my-tdd-template.hbs

FLAG DESCRIPTIONS
  --output-format=html  Output format to render the document in.

    Currently only `html` is supported. Reserved for future formats (e.g. Markdown).

  --template-file=<value>  Path to a custom Handlebars template to render instead of the built-in one.

    When specified, this template is rendered with the same scanned project data the built-in technical design document
    template receives, and can reuse the built-in `loud` helper. See this package's README "Custom Templates" section
    for the data shape.

See code: lib/commands/simply/document/generate.js

Custom Templates

Both commands render a built-in Handlebars template by default. Pass --template-file to render your own template instead — it's compiled against the exact same Handlebars instance as the built-in template, so it can use any partial or helper the built-in template uses, and receives the exact same data.

A template file is just Handlebars source (typically saved with an .hbs extension, though the extension itself doesn't matter — the file is read as plain text). Nothing is auto-escaped as Confluence storage format or any other target; you control the entire output, so a custom template can produce plain HTML, Markdown, or anything else Handlebars can produce as text.

sf simply document diff --template-file

The data passed to the template is a plain object keyed by component type, where each value is an array of changed-component records. A key is present only if at least one changed file mapped to that component type — check for a key's existence with {{#if someKey}} before iterating it, the same way the built-in template does.

Each entry in a component type's array has this shape:

| Field | Type | Description | | ------------------- | ------ | ---------------------------------------------------------------------------------- | | componentName | string | The component's name (e.g. MyClass, MyObject__c). | | componentType | string | The component type key this entry is grouped under (same as its parent key). | | changeType | string | One of Added, Modified, Renamed, Deleted, Copied. | | changeDescription | string | Renamed from <oldPath> / Copied from <oldPath> for renames/copies, else empty. | | path | string | The changed file's path, as reported by git diff. |

The possible top-level keys are:

standardObjects, customObjects, customSettings, customMetadataTypes, customMetadata, platformEvents,
apexClasses, apexTriggers, visualforcePages, lightningComponents, auraComponents, flows, flexipages,
approvalProcesses, customApplications, customLabels, staticResources, dashboards, reports, emailTemplates,
digitalExperienceBundles, experienceBundles, groups, queues, permissionSets, permissionSetGroups, sharingRules

A changeTable partial is pre-registered and available to your template — pass it any one of the arrays above to render the same table the built-in template uses:

<h1>My Custom Change Report</h1>

<h2>Apex Classes</h2>
{{#if apexClasses}}
  {{> changeTable apexClasses}}
{{else}}
  <p>No Apex class changes.</p>
{{/if}}

sf simply document generate --template-file

The data passed to the template is a single object with one array-valued field per metadata category (every field is always present, though it may be empty). Every array item at minimum has a name field (or, for a few types noted below, an equivalent identifying field); most other fields are optional and only populated when the underlying metadata has a value.

| Field | Item type | | -------------------------- | -------------------------------------------------------------------- | | standardObjects | Object | | customObjects | Object | | customSettings | Object | | customMetadataTypes | Object | | platformEvents | Object | | customMetadata | { name, label? } | | apexClasses | { name, status?, apiVersion? } | | apexTriggers | { name, status?, apiVersion? } | | visualforcePages | { name, label?, description?, apiVersion? } | | lightningComponents | { name, description?, apiVersion? } | | auraComponents | { name, description?, apiVersion? } | | flows | { name, label?, processType?, description? } | | flexipages | { name, masterLabel?, type? } | | approvalProcesses | { name, label?, active?, description? } | | customApplications | { name, label?, description? } | | customLabels | { fullName?, shortDescription? } | | staticResources | { name, contentType?, cacheControl?, description? } | | dashboards | { name, folderName?, description? } | | reports | { name, folderName?, description? } | | emailTemplates | { apiName, label?, type?, description? } | | digitalExperienceBundles | { name } | | experienceBundles | { name } | | groups | { apiName?, label?, doesIncludeBosses? } | | queues | { name, label?, doesSendEmailToMembers?, queueObjects?: string[] } | | permissionSets | { name, label?, description? } | | permissionSetGroups | { name, label?, description? } | | sharingRules | { label?, fullName?, object?, type?, accessLevel?, description? } |

Object item

standardObjects, customObjects, customSettings, customMetadataTypes, and platformEvents all share this shape (they're all backed by CustomObject-family metadata):

| Field | Type | Description | | ---------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | name | string | API name. | | label | string? | Label. | | miniDescription | string? | The object's description, with the org's description: ... usage notes: ... convention stripped down to just the description portion (or the raw description, if that convention wasn't used). | | sharingModel | string? | Internal sharing model (custom objects only). | | externalSharingModel | string? | External sharing model (custom objects only). | | customSettingsType | string? | Set only for custom settings (List or Hierarchy). | | eventType | string? | Set only for platform events. | | publishBehavior | string? | Set only for platform events. | | recordTypes | RecordTypeItem[]? | { fullName, label?, active?, description? } | | layouts | LayoutItem[]? | { nameOnly? } | | customFields | CustomFieldItem[]? | See below. | | fieldSets | FieldSetItem[]? | { fullName, label?, description?, displayedFields?: Array<{ field? }> } | | validationRules | ValidationRuleItem[]? | { fullName, active?, description? } |

A field in customFields has this shape:

| Field | Type | Description | | ----------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | fullName | string | API name. | | label | string? | Label. | | type | string? | Display type — for LongTextArea/Lookup/MasterDetail/Number/Text fields this is already formatted as e.g. Lookup(Account), Number(18,0), ready to render as-is. | | required | string? | "true"/"false" (a string, not a boolean, matching the underlying metadata). | | externalId | string? | "true"/"false". | | unique | string? | "true"/"false". | | miniDescription | string? | Same convention as the object's miniDescription. |

A loud helper is pre-registered and available to your template — it upper-cases a string, handy for rendering the "true"/"false" string fields above the way the built-in template does ({{#if this.required}}{{loud this.required}}{{else}}FALSE{{/if}}):

<h1>My Custom Technical Design Document</h1>

<h2>Apex Classes</h2>
<ul>
  {{#each apexClasses}}
    <li>{{this.name}} ({{loud this.status}})</li>
  {{/each}}
</ul>

<h2>Custom Objects</h2>
{{#each customObjects}}
  <h3>{{this.label}}</h3>
  {{#each this.customFields}}
    <p>{{this.label}} — {{this.type}}</p>
  {{/each}}
{{/each}}

License

Licensed under the Apache-2.0 license.