cesarparra / apexdocs Goto Github PK
View Code? Open in Web Editor NEWNode.js tool to generate documentation for your Salesforce Apex Classes.
Home Page: https://www.npmjs.com/package/@cparra/apexdocs
License: MIT License
Node.js tool to generate documentation for your Salesforce Apex Classes.
Home Page: https://www.npmjs.com/package/@cparra/apexdocs
License: MIT License
When generating documentation for our code it would be nice to apply code formatting to the output type of a method:
PS: ignore the description part that starts with the code formatted String
. I'll need to fix my description.
I really appreciate all of your hard work and mention that there's no need to rush a fix for this and to release a version immediately, this can definitely wait.
Cesar,
Again, thank you for your work on this and your responsiveness.
I've hit upon another bit of wonky parsing, and I'm not sure what to make of it. Here's the Apex method causing troubles
/**
* @description - Demonstrates how to use the Database.insert() method to persist a net-new
* record to the database.
* @param name name Passed through to the account created
* @param allOrNothing allOrNothing determines whether or not all accounts to be inserted must insert successfully
*/
public static void insertAccountsViaDatabaseMethod(
String name,
Boolean allOrNothing
) {
Account acct = new Account(name = name);
Account acct2 = new Account();
try {
if (CanTheUser.create(acct)) {
Database.insert(new List<Account>{ acct, acct2 }, allOrNothing);
}
} catch (DMLException DMLe) {
throw new CustomDMLException('Failed');
}
}
It's generating this markdown
---
## Methods
### `)` → ``
- Demonstrates how to use the Database.insert() method to persist a net-new record to the database.
#### Parameters
|Param|Description|
|-----|-----------|
|`name` | name Passed through to the account created |
|`allOrNothing` | allOrNothing determines whether or not all accounts to be inserted must insert successfully |
Specifically, it's not properly parsing the method name, and I'm not sure why. 4 methods in this file (I gave one example above) fail to parse, but the other ~5-6 work fine.
Seems not working on MacOS:
npm run apexdocs-generate
> [email protected] apexdocs-generate
> apexdocs-generate -s ./force-app/main/promoengine/selectors -r true -t ./docs
5/17/2022, 9:38:44 AM: Parsed 0 files
5/17/2022, 9:38:44 AM: index processed.
% ls ./force-app/main/promoengine/selectors
WebCartSelector.cls WebCartSelector.cls-meta.xml
When generating docs with a group, apexdocs automatically adds the Markdown Group to all the files. Is there a way to turn this off?
Running @cparra/[email protected]
, I'm trying to use the new @start-group/@end-group
directives added in v2.1.0 (and thanks for that!), but they don't seem to work. Here's the start of my class:
public with sharing class CodeControl {
// @start-group Picklist constant for Code_Control__mdt.Logging__c
public static final String LOGGING_CONTROL_NONE = 'None';
public static final String LOGGING_CONTROL_DEBUG = 'Debug';
public static final String LOGGING_CONTROL_ERROR = 'Error';
// @end-group
// @start-group Picklist constants for Code_Control__mdt.Enabled__c
public static final String TRIGGER_CONTROL_ENABLED = 'Yes';
public static final String TRIGGER_CONTROL_DISABLED = 'No';
public static final String FEATURE_CONTROL_ENABLED = 'Yes';
public static final String FEATURE_CONTROL_DISABLED = 'No';
// @end-group
/* Special MDT values */
public static final String WILDCARD_SOURCE = 'CodeControl_Default';
public static final String SYSTEM_WIDE_SOURCE = 'CodeControl_Override';
And here's the output:
---
## Properties
### `FEATURE_CONTROL_DISABLED` → `String`
### `FEATURE_CONTROL_ENABLED` → `String`
### `LOGGING_CONTROL_DEBUG` → `String`
### `LOGGING_CONTROL_ERROR` → `String`
### `LOGGING_CONTROL_NONE` → `String`
### `SYSTEM_WIDE_SOURCE` → `String`
### `TRIGGER_CONTROL_DISABLED` → `String`
### `TRIGGER_CONTROL_ENABLED` → `String`
### `WILDCARD_SOURCE` → `String`
---
## Methods
I tried wrapping the last two constants in a group just in case, but it had no effect.
Overview: We have a unique need to add a new annotation / tag to Apex docs. I think it would be good for the community at large, and rather than forking apex docs, I wanted to ask if you'd be ok with a PR? and if you could help me orient myself to it. I'm happy to do the work.
Specifics: We work in a highly regulated org. There are certain apex actions / settings and or configurations that we have to Justify the use of. For instance, we have to provide justification for the use of any query or DML that doesn't use 'WITH USER_MODE'. We would like to introduce a new, optional, tag @justification similar to @description. The key is, we need the doc generator to honor and publish that justification in the output.
Thoughts?
@cesarParra - love your work.
I'm looking to incorporate apexDocs into a CI action I'm building in ESM / node. I'd like to import Apexdoxs and execute the doc generation "in-band" rather than shelling out to the cli to run apex docs. I'm struggling, however, with how and what I can import.
I've tried
import Apexdocs from '@cparra/apexdocs';
and while that will import something... it doesn't have the .generate() method on it I was expecting from the cli.
I'm sure i'm missing something obvious, but I was wondering if you could provide an example of how to import Apex docs into a typescript / esm project as a library and call it's generate method? Please?
We are using sfdx unlocked packages to install some of our utility classes, and we recently started using the unpackaged metadata feature to move all of our test classes and test-only metadata out of the installed package. This results in a structure like this:
/package-root
+ /force-app
+ /main
+ /default
+ /classes
| ApexClass.cls
+ /unpackaged-test-metadata
+ /classes
| ApexClassTest.cls
I'd like to run apexdocs
once for both force-app/main/default/classes/
and unpackaged-test-metadata/classes
, since I'm using @see
in the class to reference the test class, and vice versa. I tried using the top-level project directory with recursion:
npm exec -- apexdocs-generate --s .
But that missed unpackaged-test-metadata
and picked up things in node_modules
. Then I tried specifying two directories:
npm exec -- apexdocs-generate -s force-app/ -s unpackaged-test-metadata
But that resulted in an (unsurprising) error:
node:internal/fs/utils:670
throw new ERR_INVALID_ARG_TYPE(propName, ['string', 'Buffer', 'URL'], path);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received an instance of Array
at Object.readdirSync (node:fs:1385:10)
at getClassesFromDirectory (/Users/jclark/Documents/dev/axia-core-utils/node_modules/@cparra/apexdocs/lib/Command/Generate.js:37:34)
at Object.generate (/Users/jclark/Documents/dev/axia-core-utils/node_modules/@cparra/apexdocs/lib/Command/Generate.js:29:21)
at Object.<anonymous> (/Users/jclark/Documents/dev/axia-core-utils/node_modules/@cparra/apexdocs/lib/cli/generate.js:52:41)
at Module._compile (node:internal/modules/cjs/loader:1097:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1149:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47 {
code: 'ERR_INVALID_ARG_TYPE'
}
Node.js v17.2.0
Note: You could argue that we don't need to document test classes, and I might agree - I'm still trying to decide best practices for apexdocs. However, the same issues will apply for any project which includes multiple packages. See for example this sample sfdx-project.json in the sfdx
docs, which contains 4 packages with dependencies.
When generating an open-API specification with a URL with v1/items
, the generated tag does not include slashes. It generates v1items
. Below is a snippet of the open-API specification file
"v1/items/": {
"get": {
"tags": ["Vitems"],
....
This Doc block
/**
* @description @HttpGet exposes a method to a GET request when the custom REST endpoint is called. A GET request allows us to return
* data from Salesforce. In this example, we're going to query a list of Accounts that were created and return them to the application that
* called the endpoint. When creating a response we can use the RestResponse class to specify certain fields of the payload that is
* sent. We are manually setting the statusCode as 200 for a successful get and 400 on error. In any other case, Salesforce will supply the error code.
*
* Note: This method has a false-positive PMD warning. Our Query
* includes the keyword 'WITH SECURITY_ENFORCED' which prevents this
* Query from accessing fields and objects that they don't have permission
* to access. This is a form of inline CRUD/FLS Check.
*
* The return statement is atomically serialized and returned in the responseBody.
* @return RestResponse A list of Accounts or the exception message
* @example
* curl -H "Authorization: Bearer <SessionID>" "https://<Org Base URL>/services/apexrest/IntegrationService"
*/
Results in the following Markdown:
@HttpGet exposes a method to a GET request when the custom REST endpoint is called. A GET request allows us to return data from Salesforce. In this example, we're going to query a list of Accounts that were created and return them to the application that called the endpoint. When creating a response we can use the RestResponse class to specify certain fields of the payload that is sent. We are manually setting the statusCode as 200 for a successful get and 400 on error. In any other case, Salesforce will supply the error code. Note: This method has a false-positive PMD warning. Our Query includes the keyword 'WITH SECURITY_ENFORCED' which prevents this Query from accessing fields and objects that they don't have permission to access. This is a form of inline CRUD/FLS Check. The return statement is atomically serialized and returned in the responseBody.
#### Example
```java
curl -H "Authorization: Bearer <SessionID>" "https:
When installing with -g
to make it available system-wide, the command fails with MODULE_NOT_FOUND.
internal/modules/cjs/loader.js:985
throw err;
^
Error: Cannot find module '../command/Generate'
Require stack:
- /usr/local/lib/node_modules/@cparra/apexdocs/lib/cli/generate.js
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:982:15)
at Function.Module._load (internal/modules/cjs/loader.js:864:27)
at Module.require (internal/modules/cjs/loader.js:1044:19)
at require (internal/modules/cjs/helpers.js:77:18)
at Object.<anonymous> (/usr/local/lib/node_modules/@cparra/apexdocs/lib/cli/generate.js:5:20)
at Module._compile (internal/modules/cjs/loader.js:1158:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)
at Module.load (internal/modules/cjs/loader.js:1002:32)
at Function.Module._load (internal/modules/cjs/loader.js:901:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/usr/local/lib/node_modules/@cparra/apexdocs/lib/cli/generate.js'
]
}
OS: Linux
Node Version: 12.16.1
NPM Version: 6.14.2
I suspect it may be due to case sensitivity on this OS. The actual Command
folder has a capital C
with the stracktrace showing it's trying to load a lowercase c
.
Would it be possible to have an option to customize the current # Classes
title in the result README.md file?
The use case is that I want to group all of my package classes into: Classes/Interfaces/Enums. But this standard Classes
title in the beginning doesn't seem to make sense in this case as it's the main header.
Expected result:
# My Custom Title
## Classes
### [Service](/Classes/Service.md)
Some service description
## Interfaces
### [IService](/Interfaces/IService.md)
Actual result:
# Classes
## Classes
### [Service](/Classes/Service.md)
Some service description
## Interfaces
### [IService](/Interfaces/IService.md)
Since configs passed through the CLI override whatever is configured in the configuration file, when the CLI arguments have a default, even when not specified explicitly when calling apexdocs-generate
, these defaults are still overriding whatever is in the configuration file.
Thanks for fixing the other issues like a super human 💯
I noticed that the tool does not create Markdown files for classes without access modifier.
Example:
@istest
class TestObjectFactory { ... }
Any return type, parameter type, etc, that uses angle bracket notations causes issues with the output, especially when the output is not in a code block as this will get picked up by most Markdown parsers as HTML instead and effectively render nothing.
It also causes issues if plugging this into other rendering systems that accept MDX.
If not within a code block, >
and <
can be used as an escape
defaultGroupName
Default: Miscellaneous
The generated output directories seems to actually be labelled "Misc" - not "Miscellaneous".
I notice in your source file: class-file-generatorHelper.ts , that is shows
return groupAnnotation?.body ?? 'Misc';
We had previously received result files in a sub-directory "Miscellaneous". Should we update to "Misc" or is this a bug?
Thanks!
On @start-group/@end-group:
This works fine:
// @start-group Special Metadata Names
public static final String WILDCARD_SOURCE = 'CodeControl_Default';
public static final String SYSTEM_WIDE_SOURCE = 'CodeControl_Override';
// @end-group
And produces:
SYSTEM_WIDE_SOURCE
→ String
WILDCARD_SOURCE
→ String
BUT, changing // @START-Group ... to /** start-group ... */ does not:
/** @start-group Special Metadata Names */
public static final String WILDCARD_SOURCE = 'CodeControl_Default';
public static final String SYSTEM_WIDE_SOURCE = 'CodeControl_Override';
/** @end-group */
That produces:
SYSTEM_WIDE_SOURCE
→ String
WILDCARD_SOURCE
→ String
Which is probably okay, but since all other directives work with the Javadoc prefix (/**) it is a bit of an exception.
Also @description does not work with either the constants or the group. For example:
// @start-group Special Metadata Names
/** @description Wildcard and Override Settings are only used for Logging and Trigger control.*/
public static final String WILDCARD_SOURCE = 'CodeControl_Default';
public static final String SYSTEM_WIDE_SOURCE = 'CodeControl_Override';
// @end-group
I suppose you could read that @description as either describing the group (which I'd prefer) or WILDCARD_SOURCE, but either way, it did not appear in the output. I tried several variations of comment styles and locations without success. My suggestion is to support two types of description - A description in the same comment block as @START-Group is a group-level description, and a standalone comment is a property-level description
/** @start-group Special Metadata Names
* @description Wildcard and Override Settings are only used for Logging and Trigger control.
*/
/** @description Overrides all metadata */
public static final String WILDCARD_SOURCE = 'CodeControl_Default';
/** @description Used if no matching metadata found */
public static final String SYSTEM_WIDE_SOURCE = 'CodeControl_Override';
/** @end-group */
would produce:
Wildcard and Override Settings are only used for Logging and Trigger control.
Overrides all metadata
SYSTEM_WIDE_SOURCE
→ String
WILDCARD_SOURCE
→ String
Or even better, allow in-line comments to appear in-line in the output:
/** @start-group Special Metadata Names
* @description Wildcard and Override Settings are only used for Logging and Trigger control.
*/
public static final String WILDCARD_SOURCE = 'CodeControl_Default'; /** @description Overrides all metadata */
public static final String SYSTEM_WIDE_SOURCE = 'CodeControl_Override'; /** @description Used if no matching metadata found */
/** @end-group */
Producing:
Wildcard and Override Settings are only used for Logging and Trigger control.
SYSTEM_WIDE_SOURCE
→ String
: Overrides all metadataWILDCARD_SOURCE
→ String
: Used if no matching metadata foundI'm using docsify for documentation. My docs
folder structure is the following:
docs/
| - examples/
| - types/
| - Classes/ # <-- This is the `Classes` group folder
| - README.md # <-- This is the documentation generated by `apexdocs` package
| - README.md
| - index.html # <-- This is the `docsify` index.html file
So, the problem I'm facing is that Apex classes documentation is not located in the root folder but when I generate it, the links are referencing relatively to the Apex classes README files in group folders:
## Classes
### [SomeService](/Classes/SomeService.md)
Some description
This doesn't work for docsify
, as my index.html
file is located one level above. It means that when I try to check the Apex Classes documentation from docsify
page, clicking on a particular class link, it tries to direct me to /Classes/SomeService.md
. But the actual URL in my case should be /types/Classes/SomeService.md
.
My current workaround is manually replacing links in the docs
folder with a sed
bash command but I was wondering what you think about this case and if this could be addressed with an additional option like rootFolder
or something.
Thanks in advance
First of all thanks for the great work that you do around this tool, this is really helpful.
When running apexdocs on the following code, the parser breaks the class description.
/**
* @description Demonstrates the @future syntax and usage
*/
public with sharing class AtFutureRecipes {
}
This generate the following doc:
---
layout: default
---
# AtFutureRecipes
Demonstrates the
**Future** syntax and usage
The problem is due to the fact that it attempts to parse the @future
annotation within the description.
Could we prevent nested annotations parsing?
Good afternoon. Just installed from npm @ v2.2.2
and tried importing into my nodejs script. The documentation indicates there's a docGenerator
function that should be part of the export but I wasn't able to find it anywhere:
If you are just interested in the documentation parsing capabilities, you can import ApexDocs into your own project.
Use the docGenerator function to create a list of ClassModel that includes all the parsed information from your .cls files [...]
If we add a space in the method return type (space between ,
and Object
here). The space breaks the documentation. the return type in the Markdown file only contains Object>
public static
Map<String, Object> getActiveSurveySettings(String surveyType){ ... }
If we remove the space it works as expected.
public static
Map<String,Object> getActiveSurveySettings(String surveyType){ ... }
Hi,
I wanted to make it work, but there is something I really don't understand.
When I'm executing the command, it throw this error.
In the end, in my project, I see that a new folder has been created "docs" (default), and a readme.md. But there is nothing inside the readme.md.
I'm not able to make it work, do you have any idea ? Below, the code where you can see the error.
Thanks a lot !
$ apexdocs-generate -s force-app/main/default/classes/
Processed 1 files
internal/fs/utils.js:314
throw err;
^
Error: EINVAL: invalid argument, mkdir 'docs\:'
at Object.mkdirSync (fs.js:1009:3)
at JekyllDocsProcessor.process (C:\Users\fabie\AppData\Roaming\npm\node_modules\@cparra\apexdocs\lib\MarkdownDocsProcessor.js:80:20)
at C:\Users\fabie\AppData\Roaming\npm\node_modules\@cparra\apexdocs\lib\FileManager.js:24:27
at Array.forEach (<anonymous>)
at FileManager.generate (C:\Users\fabie\AppData\Roaming\npm\node_modules\@cparra\apexdocs\lib\FileManager.js:23:23)
at Object.<anonymous> (C:\Users\fabie\AppData\Roaming\npm\node_modules\@cparra\apexdocs\lib\cli\generate.js:53:49)
at Module._compile (internal/modules/cjs/loader.js:1085:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:790:14) {
errno: -4071,
syscall: 'mkdir',
code: 'EINVAL',
path: 'docs\\:'
}
Is there a way to sort all the methods in an apex class alphabetically? This would be useful in some of the classes that have methods that are not alphabetical in the code itself.
When I have the following ApexDoc, I get the error below if the {@link ... }
is at the start of the comment:
/**
* A formatter which formats phone numbers as they are entered.
*
* <p>An AsYouTypeFormatter can be created by invoking
* {@link PhoneNumberUtil#getAsYouTypeFormatter}. After that, digits can be added by invoking
* {@link #inputDigit} on the formatter instance, and the partially formatted phone number will be
* returned each time a digit is added. {@link #clear} can be invoked before formatting a new
* number.
*
*/
2/18/2023, 2:57:45 AM: AsYouTypeFormatter - Doc comment parsing error. Level: Type
2/18/2023, 2:57:45 AM: Comment:
/**
* A formatter which formats phone numbers as they are entered.
*
* <p>An AsYouTypeFormatter can be created by invoking
* {@link PhoneNumberUtil#getAsYouTypeFormatter}. After that, digits can be added by invoking
* {@link #inputDigit} on the formatter instance, and the partially formatted phone number will be
* returned each time a digit is added. {@link #clear} can be invoked before formatting a new
* number.
*
*/
2/18/2023, 2:57:45 AM: Exception: Error parsing Apex doc. Line 5:3 - mismatched input '{@' expecting {NEWLINE, SPACE, JAVADOC_END}
2/18/2023, 2:57:45 AM: =================================
But if I add anything else before the {@link ... }
, then the error disappears:
/**
* A formatter which formats phone numbers as they are entered.
*
* <p>An AsYouTypeFormatter can be created by invoking
* test {@link PhoneNumberUtil#getAsYouTypeFormatter}. After that, digits can be added by invoking
* test {@link #inputDigit} on the formatter instance, and the partially formatted phone number will be
* returned each time a digit is added. {@link #clear} can be invoked before formatting a new
* number.
*
*/
It's me again, go figure haha. So since the most recent update I'm not able to get any output. It will iterate through the input files, say it's parsing, then say 0 files parsed. I don't know if its erroring on the files silently or for some reason considering them invalid? Not sure if there is a debug log or verbose mode that isn't documented but I'm not really sure how to debug this. I can send you my files that I'm trying to parse if that helps. It does generate the index.md file but it seems to be corrupt/incomplete. Let me know if there is any other info I can provide to help. Thanks!
Was wondering what would it take for this to generate Docusaurus site? I love how Docusaurus works, but never understood how to implement myself.
Fuzzy search looks particularly useful!
Cheers
I'd love a flag, or an option to have the docs also generate method blocks for private methods.
Hi,
Thanks for creating this CLI, it helps a lot. However, I have a suggestion about what's being printed in the .md file for an Apex class.
Doesn't matter what options and generators I use, I always get ApexClass meta information in the final markdown file. I don't really see much sense in printing this information as I've never seen in that somebody would expose and not delete an Apex class with Status: Inactive
. ApexClass API version is a bit more important but again, most of the time it's not required for a user to know the exact API version.
So, would it be possible to have at least a CLI option to disable that ApexClass meta information to be printed?
What I'm running:
npx apexdocs-generate -s ./src/main -t ./docs -p global -g docsify --defaultGroupName Classes
Example source file:
/**
* @description Some description
*/
global abstract class Service implements IService {}
Expected result .md file:
# Service
Some description
**Implemented types**
[IService](/Interfaces/IService.md)
Actual result .md file:
# Service
`APIVERSION: 55`
`STATUS: ACTIVE`
Some description
**Implemented types**
[IService](/Interfaces/IService.md)
I'm using @description
to label my constants, which works, but they are treated as properties, so they are all sorted by name. I'd like the ability to group them together with a single description for a group of constants, with sorting only within each group, or even disabled altogether within a group.
As an example, here is an excerpt of the constants from a utility class I am documenting. While I understand that @description
is intended to label only the item below it, I'm using it here as a "group description" just to illustrate what I'm looking for; I'm guessing a slightly different syntax would be needed. I'm ambivalent about the actual doc format, as long as the rendered output is what I need.
/** @description Picklist constants for Code_Control__mdt.Logging__c */
public static final String LOGGING_CONTROL_NONE = 'None';
public static final String LOGGING_CONTROL_DEBUG = 'Debug';
public static final String LOGGING_CONTROL_ERROR = 'Error';
/** @description Picklist constants for Code_Control__mdt.Enabled__c */
public static final String TRIGGER_CONTROL_ENABLED = 'Yes';
public static final String TRIGGER_CONTROL_DISABLED = 'No';
public static final String FEATURE_CONTROL_ENABLED = 'Yes';
public static final String FEATURE_CONTROL_DISABLED = 'No';
/** @description Wildcard and Override settings are only used for Logging and Trigger control.
* They are not used for feature control; the developer should create group-level
* defaults/overrides as separate features.
*/
public static final String WILDCARD_SOURCE = 'CodeControl_Default';
public static final String SYSTEM_WIDE_SOURCE = 'CodeControl_Override';
And here is what is output by apexdocs-generate
:
---
## Properties
### `FEATURE_CONTROL_DISABLED` → `String`
### `FEATURE_CONTROL_ENABLED` → `String`
### `LOGGING_CONTROL_DEBUG` → `String`
### `LOGGING_CONTROL_ERROR` → `String`
### `LOGGING_CONTROL_NONE` → `String`
Picklist constants for Code_Control__mdt.Logging__c
### `SYSTEM_WIDE_SOURCE` → `String`
### `TRIGGER_CONTROL_DISABLED` → `String`
### `TRIGGER_CONTROL_ENABLED` → `String`
Picklist constants for Code_Control__mdt.Enabled__c
### `WILDCARD_SOURCE` → `String`
Wildcard and Override settings are only used for Logging and Trigger control. They are not used for feature control; the developer should create group-level defaults/overrides as separate features.
---
As expected, the "group-level" descriptions have become single-constant descriptions. I could almost live with that by positioning the descriptions appropriately, but the sorting has re-arranged all of the constants, separating related constants such as SYSTEM_WIDE_SOURCE
and WILDCARD_SOURCE
Here's one idea for a new syntax, that allows for group-level and per-constant comments when needed:
/** @constants Picklist constants for Code_Control__mdt.Logging__c */
/** @description Record only Exceptions */
public static final String LOGGING_CONTROL_NONE = 'None';
/** @description Record debug, error, and exception level logging */
public static final String LOGGING_CONTROL_DEBUG = 'Debug';
/** @description Record error, and exception level logging */
public static final String LOGGING_CONTROL_ERROR = 'Error';
/** @end-constants **/
/** @constants Picklist constants for Code_Control__mdt.Enabled__c
* @description The `TRIGGER_CONTROL*` and `FEATURE_CONTROL*` constants are interchangeable; both names are provided for semantic purposes */
*/
public static final String TRIGGER_CONTROL_ENABLED = 'Yes';
public static final String TRIGGER_CONTROL_DISABLED = 'No';
public static final String FEATURE_CONTROL_ENABLED = 'Yes';
public static final String FEATURE_CONTROL_DISABLED = 'No';
/** @end-constants **/
With potential output:
## Constants
### Picklist constants for Code_Control__mdt.Logging__c
* `LOGGING_CONTROL_NONE` - Record only Exceptions
* `LOGGING_CONTROL_DEBUG` - Record debug, error, and exception level logging
* `LOGGING_CONTROL_ERROR` - Record error, and exception level logging
### Picklist constants for Code_Control__mdt.Enabled__c
The `TRIGGER_CONTROL*` and `FEATURE_CONTROL*` constants are interchangeable; both names are provided for semantic purposes
* `TRIGGER_CONTROL_ENABLED`
* `TRIGGER_CONTROL_DISABLED`
* `FEATURE_CONTROL_ENABLED`
* `FEATURE_CONTROL_DISABLED`
Me again :P
I am noticing an issue where the link generation from one document to another seems to be a little inconsistent or inaccurate. I've noticed two specific kinds of failures.
An @see tag is resolving the link to contain the folder name when both files are in the same folder. EX the source code for the file StripeAgreement.cls contains this tag.
@See StripeRESTService
Which when processed becomes a link
<a href="/Misc/StripeRESTService.md">StripeRESTService</a>
Which is incorrect as both StripeAgreement and StripeRestService are in the same folder (additionally they are being placed in a 'Misc' folder when they are both in the '@group Stripe_Integration', not sure why that is.
I'm unsure if this is intentional but when links are generated they prepended with a '/' which at least on my windows 10 machine with Chrome makes it want to resolve to absolute file path. EX
@See StripeRestServiceTest
Becomes
<a href="/Misc/StripeRESTServiceTest.md">StripeRESTServiceTest</a>
Which my browser then interprets as
file:///C:/Misc/StripeRESTServiceTest.md
When the actual path would be
file:///C:/Users/Kenji/Documents/SFDX%20Projects/ClientName/ApexDoc/docs/markdown/Misc/StripeRESTServiceTest.md
Maybe adding a flag to the command to either include or exclude that beginning slash? I know system file paths get weird and different OS handle them differently and probably even different browsers so I'm not sure if there is a one size fits all fix there but just thought you should know.
First,
Let me say GREAT work. I love this.
I've discovered an issue where it's unable to properly determine parameters when they are on multiple lines. This causes issues with the default prettier config that forces param lists to wrap to one-per-line if the overall line exceeds 80 characters.
Example code to reproduce:
/**
* @description - This method is where the actual work occurs. It's run once per batch.
* @param context - dependency injected by the system
* @param scope - a list of up to 200 SObject records to be processed
* in this batch. It's this mechanism of breaking a large number of records
* into smaller batches called scope (in this example) that make this easier
**/
public void execute(
Database.BatchableContext context,
List<Account> scope
) { }
This generates the following markdown:
---
## Methods
### `)` → ``
- This method is where the actual work occurs. It's run once per batch.
#### Parameters
|Param|Description|
|-----|-----------|
|`context` | - dependency injected by the system |
|`scope` | - a list of up to 200 SObject records to be processed |
Specifically, the issue is here:
### `)` → ``
First of all, thanks for this great tool. We're using it several project including the Apex Recipes sample app.
As part of our dev workflows we use lint-staged to automatically run some pre-commit scripts on files that are staged (not the entire repo):
It would be great if we could add apexdocs to this workflow. However, in order to achieve this and make apexdocs work with lint-staged, we need the apexdocs CLI to accept an individual source file instead of an entire source directory.
Is this a feature that you would consider?
Sometimes a method can have multiple @author
and @date
tags to show original and subsequent authors. Currently, the generated site only shows the last one.
This works perfectly:
public class ApexUtil {
// @start-group allOrNothing param values DML Operations
public static final Boolean ALLOW_PARTIAL_SUCCESS = false;
public static final Boolean ALL_OR_NOTHING = true;
// @end-group
// @start-group caseSensitive param values for ApexUtil.getPattern()
...
But if I add backticks (or single- or double-quotes) around the first word of the group description, it does not:
public class ApexUtil {
// @start-group 'allOrNothing' param values DML Operations
public static final Boolean ALLOW_PARTIAL_SUCCESS = false;
public static final Boolean ALL_OR_NOTHING = true;
// @end-group
// @start-group caseSensitive param values for ApexUtil.getPattern()
...
Resulting in:
7/8/2022, 9:15:47 AM: ApexUtil.cls - Parsing error Exception: Error parsing Apex Body. Line 14:4 - extraneous input '// @end-group' expecting {'abstract', 'after', 'before', 'class', 'enum', 'final', 'get', 'global', 'inherited', 'instanceof', 'interface', 'override', 'private', 'protected', 'public', 'set', 'sharing', 'static', 'switch', 'testmethod', 'transient', 'trigger', 'virtual', 'void', 'webservice', 'when', 'with', 'without', 'list', 'map', 'select', 'count', 'from', 'as', 'using', 'scope', 'where', 'order', 'by', 'limit', 'and', 'or', 'not', 'avg', 'count_distinct', 'min', 'max', 'sum', 'typeof', 'end', 'then', 'like', 'in', 'includes', 'excludes', 'asc', 'desc', 'nulls', 'first', 'last', 'group', 'all', 'rows', 'view', 'having', 'rollup', 'tolabel', 'offset', 'data', 'category', 'at', 'above', 'below', 'above_or_below', 'security_enforced', 'reference', 'cube', 'format', 'tracking', 'viewstat', 'custom', 'standard', 'calendar_month', 'calendar_quarter', 'calendar_year', 'day_in_month', 'day_in_week', 'day_in_year', 'day_only', 'fiscal_month', 'fiscal_quarter', 'fiscal_year', 'hour_in_day', 'week_in_month', 'week_in_year', 'converttimezone', 'yesterday', 'today', 'tomorrow', 'last_week', 'this_week', 'next_week', 'last_month', 'this_month', 'next_month', 'last_90_days', 'next_90_days', 'last_n_days', 'next_n_days', 'next_n_weeks', 'last_n_weeks', 'next_n_months', 'last_n_months', 'this_quarter', 'last_quarted', 'next_quarter', 'next_n_quarters', 'last_n_quarters', 'this_year', 'last_year', 'next_year', 'next_n_years', 'last_n_years', 'this_fiscal_quarter', 'last_fiscal_quarter', 'next_fiscal_quarter', 'next_n_fiscal_quarters', 'last_n_fiscal_quarters', 'this_fiscal_year', 'last_fiscal_year', 'next_fiscal_year', 'next_n_fiscal_years', 'last_n_fiscal_years',
If I insert any text before the quoted word, it's fine... I can even use backticks to get monospaced text as intended. It just seems to be the first non-space character after @start-group
that matters.
Is there an example to show the array reference for a custom class? The documentation reference shows custom schemas or is the parser automatically generates the array type?
global AddressDTO {
public String streetAddress { get; set; }
public String city { get; set; }
}
global class CustomerDTO {
/**
* @description Customer addressed
* @http-schema
* type: array
* items:
* $ref: "#/components/schemas/AddressDTO"
*/
public List<AddressDTO> addresses { get; set; }
}
Hello Cesar,
First of all thanks for sharing this plugin, what a very useful work ! I've stumbled upon what I believe to be an issue with the parsing of @return statements in the javadoc like structure. Here's the simple dummy class I wrote, and below the generate markdown. No configuration file is used. Happy to help solve this if you'd like, although I'm not sure where to start in the implementation you propose.
public class dummyTest {
/**
* @description Some description for the class.
* @param myParam Some input parameter
* @return a return value
*/
public String dummyMethod(Integer myParam) {
return '';
}
}
And the generated markdown :
--- layout: default --- # dummyTest class --- ## Methods ### `dummyMethod(Integer myParam)` → `String` Some description for the class. #### Parameters |Param|Description| |-----|-----------| |`myParam` | Some input parameter | ---
Thanks again for your work, I can definitely see this plugin gaining a lot of traction and interest seeing the void around proper Javadoc like support for Apex !
Hi @cesarParra this issue is a follow up on #88. I just realized that while you deployed a fix for escaped annotations within class-level comments, the issue persists on method/variable comments.
For example, generating doc for the following code:
/**
* @description Demonstrates the `@future` syntax and usage
* @group Async Apex Recipes
*/
public with sharing class AtFutureRecipes {
/**
* This class features a 'circuit breaker' variable. While this is not a
* pattern I routinely turn to, it is a valuable pattern for testing code
* that is otherwise hard to test. For instance, `@future` methods must be
* static void methods...
*/
@testVisible
private static Boolean testCircuitBreaker = false;
}
will crash with this error:
10/4/2023, 4:25:35 PM: AtFutureRecipes - Doc comment parsing error. Level: Field
10/4/2023, 4:25:35 PM: Comment:
/**
* This class features a 'circuit breaker' variable. While this is not a
* pattern I routinely turn to, it is a valuable pattern for testing code
* that is otherwise hard to test. For instance, `@future` methods must be
* static void methods...
*/
10/4/2023, 4:25:35 PM: Exception: Error parsing Apex doc. Line 4:53 - mismatched input '`@future`' expecting {NAME, NEWLINE, SPACE, TEXT_CONTENT, '*', '/', JAVADOC_END, '{@', '{', '}'}
I really like a lot this tool. So great what you have been doing.
How do you add the method access modifier (global, private, public) to the md file? Seems to be missing for me in the generated output.
apexdocs-generate -s force-app -t docs -r --scope global public private -g docsify --includeMetadata
Hey there, this may be a user issue but I don't really see a way to modify this behavior. When I generate markdown files the links that get created point to an invalid path. It seems to be trying to use the root path instead of a relative path. Example when viewing a file located at
file:///C:/ApexDoc/markdown/Forfeitures/BatchForfeitureEmailNotification.md
the link for the test class mentioned in the @see param pointed at
file:///C:/Forfeitures/BatchForfeitureEmailNotificationTest.md
When it really just needed to point to
../Forfeitures/BatchForfeitureEmailNotificationTest.md
I am using a Chrome extension for my markdown viewer so it's possible that is causing a problem, but then also using another utility to convert the generated markdown files to PDFs the link is also bad there so I think its just being generated using that incorrect path. Again this is probably on me somehow but I'm not quite sure how to fix. Thanks in advance!
It would be nice to have a feature where you could configure the output for jekyll to not just include the layout in the front matter, but also add the title.
For example, I'd like to be able to add the "title" to all the files with their filenames.
---
title: filename.cls
---
I'd like to have some longer form explanatory text at the top of my class files. With the recent addition of HTML support, this is (mostly) possible, but I'd prefer to use markdown. Markdown largely already works in apexdocs, but @description
treats all content as one long unformatted span (unless you add html tags). Here's a (shortened) example of a class header I'd like to use. Note that I could use <p>
, <ul>
, and <li>
tags for the beginning, but I still can't do a code block.
/**********************************************************
@class TriggerService
@testClass TriggerService_Test
@group core-utils
@description Simple Trigger Framework, integrated with <<CodeControl>>.
To use TriggerService for a given trigger,
1. Build a trigger handler class that extends <<TriggerHelperBase>>, implementing any trigger stages (e.g., beforeInsert, afterUpdate, etc)
needed by your trigger.
2. In the trigger, call `TriggerService.run()`, passing a new instance of your handler.
```
// TriggerHandler
public class AccountHandler extends TriggerHelperBase {
public override void afterInsert(List<SObject> newList) {
// ... do trigger things
}
}
// Trigger
trigger AccountTrigger on Account (after insert) {
TriggerService.run(new AccountHandler());
}
```
@author Jason Clark
@date 1/15/22
***********************************************************/
What I'd like is a way to specify the description is a block, and pass any standard markdown. Maybe @description-block
and @end-block
tags?
Decided to give the alpha I try (I could use the additional scope and annotation support), but I cannot get anything but an error:
> $ npm exec -- apexdocs-generate -s force-app/
node:internal/fs/utils:530
function getStatsFromBinding(stats, offset = 0) {
^
RangeError: Maximum call stack size exceeded
at getStatsFromBinding (node:internal/fs/utils:530:29)
at Object.statSync (node:fs:1537:10)
at DefaultFileSystem.isDirectory (/Users/jclark/Documents/dev/axia-core-utils/node_modules/@cparra/apexdocs/lib/service/file-system.js:7:19)
at /Users/jclark/Documents/dev/axia-core-utils/node_modules/@cparra/apexdocs/lib/service/apex-file-reader.js:17:52
at Array.forEach (<anonymous>)
at Function.processFiles (/Users/jclark/Documents/dev/axia-core-utils/node_modules/@cparra/apexdocs/lib/service/apex-file-reader.js:15:27)
at /Users/jclark/Documents/dev/axia-core-utils/node_modules/@cparra/apexdocs/lib/service/apex-file-reader.js:18:45
at Array.forEach (<anonymous>)
at Function.processFiles (/Users/jclark/Documents/dev/axia-core-utils/node_modules/@cparra/apexdocs/lib/service/apex-file-reader.js:15:27)
at /Users/jclark/Documents/dev/axia-core-utils/node_modules/@cparra/apexdocs/lib/service/apex-file-reader.js:18:45
Node.js v17.2.0
I tried it in an empty project with a single apex class, with a single method (see below), and I get the same error. Should I try with a different version of Node.js?
/**********************************************************
@group core-utils
@description Core apex utilities for use in all projects
@author Jason Clark
@date 11/10/20
***********************************************************/
public class ApexUtil {
/**
* @Description Given a list of sObjects, return a set of IDs of the objects.
* @param objs List of SObjects
* @return Set of Ids for all sObjects
* @example Set<Id> accountIds = ApexUtil.getIds(accounts);
*/
public static Set<Id> getIds(List<SObject> objs) {
Map<Id,SObject> tmpMap = new Map<Id,SObject>(objs);
return tmpMap.keySet().clone();
}
}
Hi,
after install using instructions I can't launch apexdocs-generate and show this error:
zsh: command not found: apexdocs-generate
Thanks in advance
Version: 1.55.2
Commit: 3c4e3df9e89829dce27b7b5c24508306b151f30d
Date: 2021-04-13T09:36:32.643Z (1 day ago)
Electron: 11.3.0
Chrome: 87.0.4280.141
Node.js: 12.18.3
V8: 8.7.220.31-electron.0
OS: Darwin x64 20.3.0
Currently the parser for docs complains about empty @argument
, @return
, and possible other tags where it expects some kind of body. Maybe we can allow for this without the parser complaining and simply not have a description for those that are empty
Hey there. I just updated to the new version and now I'm having issues when generating documentation for test classes. It seems to be choking on the @istest annotation.
Running command: apexdocs-generate -s input -t temp\markdown\
5/17/2022, 2:55:43 PM: Parsing error Exception: Error parsing Apex Body. Line 2:0 - no viable alternative at input '@isTest\n/** \n* @Name StripeIntegrationWrapperTest\n* \n* @Date 2/28/2022\n* @Group Stripe Integration\n* @See StripeIntegrationWrapper\n* @Description Test class for StripeIntegrationWrapper\n**/'
5/17/2022, 2:55:44 PM: Parsing error Exception: Error parsing Apex Body. Line 2:0 - no viable alternative at input '@isTest\n/** \n* @Name StripeRESTServiceTest\n* \n* @Date 3/2/2022\n* @Group Stripe Integration\n* @See StripeRESTService\n* @Description Test class for StripeRESTService. Ensures all methos in the class work as expected.\n**/'
5/17/2022, 2:55:44 PM: Parsed 1 files
StripeRESTService - Doc comment parsing error. Level: Type
Comment:
/**
* @Name StripeRESTService
* @Date 3/2/2022
* @Group Stripe Integration
* @See StripeRESTServiceTest
* @Description Apex class that creates and exposes a REST endpoint by the name of 'Stripe'. [ORG_URL]/services/apexrest/Stripe (case sensitive!)
*
*
Add an option to filter out files, especially useful for managed packages that only have a (hidden) content.
Add option to ignore files without comments or with a certain annotation
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.