@cparra/apexdocs 3.0.0-rc.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +50 -571
  2. package/dist/cli/generate.js +73 -3094
  3. package/dist/defaults-BcE8DTat.js +13 -0
  4. package/dist/defaults-D07y_bq4.js +40 -0
  5. package/dist/defaults-gPzwP66p.js +14 -0
  6. package/dist/index.d.ts +35 -3
  7. package/dist/index.js +90 -2
  8. package/dist/logger-BEbUIfqN.js +3282 -0
  9. package/dist/logger-BGuf1PnL.js +3281 -0
  10. package/dist/logger-CWBRF2za.js +3284 -0
  11. package/dist/logger-CdBmDEN1.js +3283 -0
  12. package/dist/logger-Ce4QqPFR.js +3278 -0
  13. package/dist/logger-CyEVYaAC.js +3284 -0
  14. package/dist/logger-D7a83ycP.js +3277 -0
  15. package/dist/logger-DGaHeBKk.js +3279 -0
  16. package/dist/logger-Dqhl_lO_.js +3278 -0
  17. package/dist/logger-aySSWi0G.js +3280 -0
  18. package/dist/logger-qLCcAtiy.js +3284 -0
  19. package/examples/README.md +5 -0
  20. package/examples/docsify/README.md +17 -0
  21. package/examples/docsify/apexdocs.config.ts +13 -0
  22. package/examples/docsify/classes/ASampleClass.cls +57 -0
  23. package/examples/docsify/classes/CodeControl.cls +19 -0
  24. package/examples/docsify/classes/SampleClass.cls +95 -0
  25. package/examples/docsify/classes/SampleInterface.cls +17 -0
  26. package/examples/docsify/classes/SomeDto.cls +122 -0
  27. package/examples/docsify/docs/.nojekyll +0 -0
  28. package/examples/docsify/docs/README.md +25 -0
  29. package/examples/docsify/docs/_config.yml +1 -0
  30. package/examples/docsify/docs/index.html +22 -0
  31. package/examples/docsify/docs/miscellaneous/ASampleClass.md +88 -0
  32. package/examples/docsify/docs/miscellaneous/CodeControl.md +107 -0
  33. package/examples/docsify/docs/miscellaneous/SomeDto.md +244 -0
  34. package/examples/docsify/docs/sample-classes/SampleClass.md +171 -0
  35. package/examples/docsify/docs/sample-interfaces/SampleInterface.md +36 -0
  36. package/examples/docsify/package-lock.json +2459 -0
  37. package/examples/docsify/package.json +14 -0
  38. package/examples/imported/.forceignore +12 -0
  39. package/examples/imported/README.md +6 -0
  40. package/examples/imported/config/project-scratch-def.json +5 -0
  41. package/examples/imported/docs/index.md +109 -0
  42. package/examples/imported/docs/miscellaneous/BaseClass.md +13 -0
  43. package/examples/imported/docs/miscellaneous/MultiInheritanceClass.md +69 -0
  44. package/examples/imported/docs/miscellaneous/ParentInterface.md +12 -0
  45. package/examples/imported/docs/miscellaneous/ReferencedEnum.md +5 -0
  46. package/examples/imported/docs/miscellaneous/SampleException.md +21 -0
  47. package/examples/imported/docs/miscellaneous/SampleInterface.md +113 -0
  48. package/examples/imported/docs/miscellaneous/Url.md +308 -0
  49. package/examples/imported/docs/sample-enums/SampleEnum.md +33 -0
  50. package/examples/imported/docs/samplegroup/SampleClass.md +167 -0
  51. package/examples/imported/force-app/classes/BaseClass.cls +3 -0
  52. package/examples/imported/force-app/classes/MultiInheritanceClass.cls +1 -0
  53. package/examples/imported/force-app/classes/ParentInterface.cls +3 -0
  54. package/examples/imported/force-app/classes/ReferencedEnum.cls +3 -0
  55. package/examples/imported/force-app/classes/SampleClass.cls +72 -0
  56. package/examples/imported/force-app/classes/SampleInterface.cls +50 -0
  57. package/examples/imported/force-app/classes/Url.cls +196 -0
  58. package/examples/imported/package-lock.json +665 -0
  59. package/examples/imported/package.json +6 -0
  60. package/examples/imported/scripts/process-docs.mjs +16 -0
  61. package/examples/imported/sfdx-project.json +12 -0
  62. package/examples/markdown/README.md +7 -0
  63. package/examples/markdown-jsconfig/README.md +9 -0
  64. package/examples/markdown-jsconfig/apexdocs.config.mjs +1 -0
  65. package/examples/markdown-jsconfig/docs/index.md +1 -1
  66. package/examples/open-api/README.md +5 -0
  67. package/examples/open-api/docs/openapi.json +2 -570
  68. package/examples/vitepress/README.md +25 -0
  69. package/examples/vitepress/apexdocs.config.ts +2 -0
  70. package/examples/vitepress/force-app/main/default/classes/{SampleClass.cls → feature-a/SampleClass.cls} +1 -0
  71. package/examples/vitepress/force-app/main/default/classes/feature-a/SampleEnum.cls +30 -0
  72. package/examples/vitepress/force-app/main/default/classes/feature-a/SampleException.cls +17 -0
  73. package/package.json +2 -2
  74. package/src/application/Apexdocs.ts +16 -19
  75. package/src/application/__tests__/apex-file-reader.spec.ts +108 -67
  76. package/src/application/apex-file-reader.ts +1 -0
  77. package/src/application/generators/openapi.ts +17 -13
  78. package/src/cli/args.ts +12 -3
  79. package/src/cli/commands/markdown.ts +14 -9
  80. package/src/cli/commands/openapi.ts +5 -5
  81. package/src/cli/generate.ts +20 -4
  82. package/src/core/markdown/__test__/generating-class-docs.spec.ts +14 -257
  83. package/src/core/markdown/__test__/generating-docs.spec.ts +271 -4
  84. package/src/core/markdown/__test__/generating-enum-docs.spec.ts +4 -264
  85. package/src/core/markdown/__test__/generating-interface-docs.spec.ts +4 -232
  86. package/src/core/markdown/__test__/generating-reference-guide.spec.ts +17 -1
  87. package/src/core/markdown/__test__/test-helpers.ts +3 -1
  88. package/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts +3 -1
  89. package/src/core/markdown/adapters/renderable-to-page-data.ts +6 -4
  90. package/src/core/markdown/generate-docs.ts +13 -15
  91. package/src/core/markdown/reflection/__test__/filter-scope.spec.ts +2 -18
  92. package/src/core/markdown/reflection/__test__/helpers.ts +18 -0
  93. package/src/core/markdown/reflection/__test__/remove-excluded-tags.spec.ts +200 -0
  94. package/src/core/markdown/reflection/remove-excluded-tags.ts +168 -0
  95. package/src/core/markdown/reflection/{sort-members.ts → sort-types-and-members.ts} +7 -5
  96. package/src/core/markdown/templates/reference-guide.ts +2 -2
  97. package/src/core/openapi/__tests__/open-api-docs-processor.spec.ts +6 -3
  98. package/src/core/openapi/open-api-docs-processor.ts +3 -3
  99. package/src/core/openapi/parser.ts +5 -2
  100. package/src/core/shared/types.d.ts +4 -2
  101. package/src/defaults.ts +15 -3
  102. package/src/index.ts +65 -4
  103. package/src/util/error-logger.ts +36 -36
  104. package/src/util/logger.ts +18 -11
  105. /package/examples/{vitepress/force-app/main/default → imported/force-app}/classes/SampleEnum.cls +0 -0
  106. /package/examples/{vitepress/force-app/main/default → imported/force-app}/classes/SampleException.cls +0 -0
  107. /package/examples/vitepress/force-app/main/default/classes/{SampleInterface.cls → feature-a/SampleInterface.cls} +0 -0
@@ -5,6 +5,7 @@
5
5
  * @example
6
6
  * SampleClass sample = new SampleClass();
7
7
  * sample.doSomething();
8
+ * @internal This should not appear in the docs
8
9
  */
9
10
  public with sharing virtual class SampleClass extends BaseClass implements SampleInterface, ParentInterface {
10
11
  // @start-group Group Name
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @description This is a sample enum. This references {@link ReferencedEnum}.
3
+ *
4
+ * This description has several lines
5
+ * @group Sample Enums
6
+ * @author John Doe
7
+ * @date 2022-01-01
8
+ * @some-custom Test. I can also have a {@link ReferencedEnum} here.
9
+ * And it can be multiline.
10
+ * @see ReferencedEnum
11
+ * @mermaid
12
+ * graph TD
13
+ * A[SampleEnum] -->|references| B[ReferencedEnum]
14
+ * B -->|referenced by| A
15
+ */
16
+ @NamespaceAccessible
17
+ public enum SampleEnum {
18
+ /**
19
+ * @description This is value 1
20
+ */
21
+ VALUE1,
22
+ /**
23
+ * @description This is value 2
24
+ */
25
+ VALUE2,
26
+ /**
27
+ * @description This is value 3
28
+ */
29
+ VALUE3
30
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @description This is a sample exception.
3
+ * @usage
4
+ *
5
+ * You can use the exception the following way.
6
+ * You can also take a look at {@link SampleClass} to see how it is used.
7
+ * This is a dangerous HTML tag: <script>alert('Hello');</script>
8
+ *
9
+ * ```
10
+ * try {
11
+ * throw new SampleException();
12
+ * } catch (SampleException e) {
13
+ * System.debug('Caught exception');
14
+ * }
15
+ * ```
16
+ */
17
+ public class SampleException extends Exception {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cparra/apexdocs",
3
- "version": "3.0.0-rc.0",
3
+ "version": "3.0.0",
4
4
  "description": "Library with CLI capabilities to generate documentation for Salesforce Apex classes.",
5
5
  "keywords": [
6
6
  "apex",
@@ -59,7 +59,7 @@
59
59
  ]
60
60
  },
61
61
  "dependencies": {
62
- "@cparra/apex-reflection": "2.12.1",
62
+ "@cparra/apex-reflection": "2.13.1",
63
63
  "@types/js-yaml": "^4.0.9",
64
64
  "@types/yargs": "^17.0.32",
65
65
  "chalk": "^4.1.2",
@@ -7,6 +7,7 @@ import { Logger } from '#utils/logger';
7
7
  import { UnparsedSourceFile, UserDefinedConfig, UserDefinedMarkdownConfig } from '../core/shared/types';
8
8
  import { pipe } from 'fp-ts/function';
9
9
  import * as TE from 'fp-ts/TaskEither';
10
+ import * as E from 'fp-ts/Either';
10
11
  import { ReflectionError } from '../core/markdown/reflection/reflect-source';
11
12
 
12
13
  /**
@@ -16,8 +17,8 @@ export class Apexdocs {
16
17
  /**
17
18
  * Generates documentation out of Apex source files.
18
19
  */
19
- static async generate(config: UserDefinedConfig): Promise<void> {
20
- Logger.logSingle(`Generating ${config.targetGenerator} documentation...`);
20
+ static async generate(config: UserDefinedConfig, logger: Logger): Promise<E.Either<unknown[], string>> {
21
+ logger.logSingle(`Generating ${config.targetGenerator} documentation...`);
21
22
 
22
23
  try {
23
24
  const fileBodies = await ApexFileReader.processFiles(
@@ -28,41 +29,37 @@ export class Apexdocs {
28
29
 
29
30
  switch (config.targetGenerator) {
30
31
  case 'markdown':
31
- await generateMarkdownDocumentation(fileBodies, config)();
32
- break;
32
+ return await generateMarkdownDocumentation(fileBodies, config)();
33
33
  case 'openapi':
34
- await openApi(fileBodies, config);
35
- break;
34
+ await openApi(logger, fileBodies, config);
35
+ return E.right('✔️ Documentation generated successfully!');
36
36
  }
37
37
  } catch (error) {
38
- Logger.logSingle(`❌ An error occurred while generating the documentation: ${error}`, 'red');
38
+ return E.left([error]);
39
39
  }
40
40
  }
41
41
  }
42
42
 
43
- function generateMarkdownDocumentation(fileBodies: UnparsedSourceFile[], config: UserDefinedMarkdownConfig) {
43
+ function generateMarkdownDocumentation(
44
+ fileBodies: UnparsedSourceFile[],
45
+ config: UserDefinedMarkdownConfig,
46
+ ): TE.TaskEither<unknown[], string> {
44
47
  return pipe(
45
48
  markdown(fileBodies, config),
46
- TE.map(() => Logger.logSingle('✔️ Documentation generated successfully!')),
49
+ TE.map(() => '✔️ Documentation generated successfully!'),
47
50
  TE.mapLeft((error) => {
48
51
  if (error._tag === 'HookError') {
49
- Logger.error('Error(s) occurred while processing hooks. Please review the following issues:');
50
- Logger.error(error.error);
51
- return;
52
+ return ['Error(s) occurred while processing hooks. Please review the following issues:', error.error];
52
53
  }
53
54
 
54
55
  if (error._tag === 'FileWritingError') {
55
- Logger.error(error.message);
56
- Logger.error(error.error);
57
- return;
56
+ return ['Error(s) occurred while writing files. Please review the following issues:', error.error];
58
57
  }
59
58
 
60
- const errorMessages = [
59
+ return [
61
60
  'Error(s) occurred while parsing files. Please review the following issues:',
62
61
  ...error.errors.map(formatReflectionError),
63
- ].join('\n');
64
-
65
- Logger.error(errorMessages);
62
+ ];
66
63
  }),
67
64
  );
68
65
  }
@@ -1,87 +1,128 @@
1
1
  import { ApexFileReader } from '../apex-file-reader';
2
+ import { FileSystem } from '../file-system';
3
+
4
+ type File = {
5
+ type: 'file';
6
+ path: string;
7
+ content: string;
8
+ };
9
+
10
+ type Directory = {
11
+ type: 'directory';
12
+ path: string;
13
+ files: (File | Directory)[];
14
+ };
15
+
16
+ type Path = File | Directory;
17
+
18
+ class TestFileSystem implements FileSystem {
19
+ constructor(private readonly paths: Path[]) {}
20
+
21
+ async isDirectory(path: string): Promise<boolean> {
22
+ const directory = this.findPath(path);
23
+ return directory ? directory.type === 'directory' : false;
24
+ }
25
+
26
+ joinPath(...paths: string[]): string {
27
+ return paths.join('/');
28
+ }
29
+
30
+ async readDirectory(sourceDirectory: string): Promise<string[]> {
31
+ const directory = this.findPath(sourceDirectory);
32
+ if (!directory || directory.type !== 'directory') {
33
+ throw new Error('Directory not found');
34
+ }
35
+ return directory.files.map((f) => f.path);
36
+ }
37
+
38
+ async readFile(path: string): Promise<string> {
39
+ const file = this.findPath(path);
40
+ if (!file || file.type !== 'file') {
41
+ throw new Error('File not found');
42
+ }
43
+ return file.content;
44
+ }
45
+
46
+ exists(path: string): boolean {
47
+ return this.paths.some((p) => p.path === path);
48
+ }
49
+
50
+ findPath(path: string): Path | undefined {
51
+ const splitPath = path.split('/');
52
+ let currentPath = this.paths.find((p) => p.path === splitPath[0]);
53
+ for (let i = 1; i < splitPath.length; i++) {
54
+ if (!currentPath || currentPath.type !== 'directory') {
55
+ return undefined;
56
+ }
57
+ currentPath = currentPath.files.find((f) => f.path === splitPath[i]);
58
+ }
59
+ return currentPath;
60
+ }
61
+ }
2
62
 
3
63
  describe('File Reader', () => {
4
64
  it('returns an empty list when there are no files in the directory', async () => {
5
- const result = await ApexFileReader.processFiles(
65
+ const fileSystem = new TestFileSystem([
6
66
  {
7
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
8
- isDirectory(_: string): Promise<boolean> {
9
- return Promise.resolve(false);
10
- },
11
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
12
- joinPath(_: string): string {
13
- return '';
14
- },
15
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
16
- readDirectory(_: string): Promise<string[]> {
17
- return Promise.resolve([]);
18
- },
19
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
20
- readFile(_: string): Promise<string> {
21
- return Promise.resolve('');
22
- },
23
- exists(): boolean {
24
- return true;
25
- },
67
+ type: 'directory',
68
+ path: '',
69
+ files: [],
26
70
  },
27
- '',
28
- false,
29
- );
71
+ ]);
72
+
73
+ const result = await ApexFileReader.processFiles(fileSystem, '', false);
74
+
30
75
  expect(result.length).toBe(0);
31
76
  });
32
77
 
33
78
  it('returns an empty list when there are no Apex files in the directory', async () => {
34
- const result = await ApexFileReader.processFiles(
79
+ const fileSystem = new TestFileSystem([
35
80
  {
36
- isDirectory(): Promise<boolean> {
37
- return Promise.resolve(false);
38
- },
39
- joinPath(): string {
40
- return '';
41
- },
42
- readDirectory(): Promise<string[]> {
43
- return Promise.resolve(['SomeFile.md']);
44
- },
45
- readFile(): Promise<string> {
46
- return Promise.resolve('');
47
- },
48
- exists(): boolean {
49
- return true;
50
- },
81
+ type: 'directory',
82
+ path: '',
83
+ files: [
84
+ {
85
+ type: 'file',
86
+ path: 'SomeFile.md',
87
+ content: '## Some Markdown',
88
+ },
89
+ ],
51
90
  },
52
- '',
53
- false,
54
- );
91
+ ]);
92
+
93
+ const result = await ApexFileReader.processFiles(fileSystem, '', false);
55
94
  expect(result.length).toBe(0);
56
95
  });
57
96
 
58
- it('returns the file contents for an Apex file', async () => {
59
- const result = await ApexFileReader.processFiles(
97
+ it('returns the file contents for all Apex files', async () => {
98
+ const fileSystem = new TestFileSystem([
60
99
  {
61
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
62
- isDirectory(_: string): Promise<boolean> {
63
- return Promise.resolve(false);
64
- },
65
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
66
- joinPath(_: string): string {
67
- return 'SomeApexFile.cls';
68
- },
69
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
70
- readDirectory(_: string): Promise<string[]> {
71
- return Promise.resolve(['SomeApexFile.cls']);
72
- },
73
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
74
- readFile(_: string): Promise<string> {
75
- return Promise.resolve('public class MyClass{}');
76
- },
77
- exists(): boolean {
78
- return true;
79
- },
100
+ type: 'directory',
101
+ path: '',
102
+ files: [
103
+ {
104
+ type: 'file',
105
+ path: 'SomeFile.cls',
106
+ content: 'public class MyClass{}',
107
+ },
108
+ {
109
+ type: 'directory',
110
+ path: 'subdir',
111
+ files: [
112
+ {
113
+ type: 'file',
114
+ path: 'AnotherFile.cls',
115
+ content: 'public class AnotherClass{}',
116
+ },
117
+ ],
118
+ },
119
+ ],
80
120
  },
81
- '',
82
- false,
83
- );
84
- expect(result.length).toBe(1);
121
+ ]);
122
+
123
+ const result = await ApexFileReader.processFiles(fileSystem, '', false);
124
+ expect(result.length).toBe(2);
85
125
  expect(result[0].content).toBe('public class MyClass{}');
126
+ expect(result[1].content).toBe('public class AnotherClass{}');
86
127
  });
87
128
  });
@@ -28,6 +28,7 @@ export class ApexFileReader {
28
28
  const currentPath = fileSystem.joinPath(rootPath, filePath);
29
29
  if (await fileSystem.isDirectory(currentPath)) {
30
30
  paths.push(...(await this.getFilePaths(fileSystem, currentPath)));
31
+ return paths;
31
32
  }
32
33
  paths.push(currentPath);
33
34
  }
@@ -12,8 +12,13 @@ import { writeFiles } from '../file-writer';
12
12
  import { pipe } from 'fp-ts/function';
13
13
  import * as TE from 'fp-ts/TaskEither';
14
14
  import { OpenApiSettings } from '../../core/openApiSettings';
15
+ import { apply } from '#utils/fp';
15
16
 
16
- export default async function openApi(fileBodies: UnparsedSourceFile[], config: UserDefinedOpenApiConfig) {
17
+ export default async function openApi(
18
+ logger: Logger,
19
+ fileBodies: UnparsedSourceFile[],
20
+ config: UserDefinedOpenApiConfig,
21
+ ) {
17
22
  OpenApiSettings.build({
18
23
  sourceDirectory: config.sourceDir,
19
24
  outputDir: config.targetDir,
@@ -23,34 +28,33 @@ export default async function openApi(fileBodies: UnparsedSourceFile[], config:
23
28
  version: config.apiVersion,
24
29
  });
25
30
 
26
- const manifest = createManifest(new RawBodyParser(fileBodies), reflectionWithLogger);
31
+ const manifest = createManifest(new RawBodyParser(logger, fileBodies), apply(reflectionWithLogger, logger));
27
32
  TypesRepository.getInstance().populateAll(manifest.types);
28
- const filteredTypes = filterByScopes(manifest);
29
- const processor = new OpenApiDocsProcessor();
33
+ const filteredTypes = filterByScopes(logger, manifest);
34
+ const processor = new OpenApiDocsProcessor(logger);
30
35
  Transpiler.generate(filteredTypes, processor);
31
36
  const generatedFiles = processor.fileBuilder().files();
32
37
 
33
38
  await pipe(
34
39
  writeFiles(generatedFiles, config.targetDir, (file: PageData) => {
35
- Logger.logSingle(`${file.outputDocPath} processed.`, 'green');
40
+ logger.logSingle(`${file.outputDocPath} processed.`, 'green');
36
41
  }),
37
- TE.map(() => Logger.logSingle('✔️ Documentation generated successfully!')),
38
- TE.mapError((error) => Logger.error(error)),
42
+ TE.mapError((error) => logger.error(error)),
39
43
  )();
40
44
 
41
45
  // Logs any errors that the types might have in their doc comment's error field
42
- ErrorLogger.logErrors(filteredTypes);
46
+ ErrorLogger.logErrors(logger, filteredTypes);
43
47
  }
44
48
 
45
- function reflectionWithLogger(apexBundle: UnparsedSourceFile): ReflectionResult {
49
+ function reflectionWithLogger(logger: Logger, apexBundle: UnparsedSourceFile): ReflectionResult {
46
50
  const result = reflect(apexBundle.content);
47
51
  if (result.error) {
48
- Logger.error(`${apexBundle.filePath} - Parsing error ${result.error?.message}`);
52
+ logger.error(`${apexBundle.filePath} - Parsing error ${result.error?.message}`);
49
53
  }
50
54
  return result;
51
55
  }
52
56
 
53
- function filterByScopes(manifest: Manifest) {
57
+ function filterByScopes(logger: Logger, manifest: Manifest) {
54
58
  // If we are dealing with an OpenApi generator, we ignore the passed in access modifiers, and instead
55
59
  // we only keep classes annotated as @RestResource
56
60
  const filteredTypes = manifest.filteredByAccessModifierAndAnnotations([
@@ -65,7 +69,7 @@ function filterByScopes(manifest: Manifest) {
65
69
  manifest.types.length - filteredTypes.length
66
70
  } file(s), only keeping classes annotated as @RestResource.`;
67
71
 
68
- Logger.logSingle(filteredLogMessage, 'green');
69
- Logger.logSingle(`Creating documentation for ${filteredTypes.length} file(s)`, 'green');
72
+ logger.logSingle(filteredLogMessage, 'green');
73
+ logger.logSingle(`Creating documentation for ${filteredTypes.length} file(s)`, 'green');
70
74
  return filteredTypes;
71
75
  }
package/src/cli/args.ts CHANGED
@@ -1,10 +1,14 @@
1
1
  import { cosmiconfig, CosmiconfigResult } from 'cosmiconfig';
2
2
  import * as yargs from 'yargs';
3
- import { UserDefinedMarkdownConfig } from '../core/shared/types';
3
+ import { UserDefinedConfig, UserDefinedMarkdownConfig } from '../core/shared/types';
4
4
  import { TypeScriptLoader } from 'cosmiconfig-typescript-loader';
5
5
  import { markdownOptions } from './commands/markdown';
6
6
  import { openApiOptions } from './commands/openapi';
7
7
 
8
+ const configOnlyDefaults: Partial<UserDefinedMarkdownConfig> = {
9
+ excludeTags: [],
10
+ };
11
+
8
12
  /**
9
13
  * Extracts configuration from a configuration file or the package.json
10
14
  * through cosmiconfig.
@@ -37,10 +41,15 @@ function _extractYargs(config?: CosmiconfigResult) {
37
41
  /**
38
42
  * Combines the extracted configuration and arguments.
39
43
  */
40
- export async function extractArgs(): Promise<UserDefinedMarkdownConfig> {
44
+ export async function extractArgs(): Promise<UserDefinedConfig> {
41
45
  const config = await _extractConfig();
42
46
  const cliArgs = _extractYargs(config);
43
47
  const commandName = cliArgs._[0];
44
48
 
45
- return { ...config?.config, ...cliArgs, targetGenerator: commandName as 'markdown' | 'openapi' };
49
+ const mergedConfig = { ...config?.config, ...cliArgs, targetGenerator: commandName as 'markdown' | 'openapi' };
50
+ if (mergedConfig.targetGenerator === 'markdown') {
51
+ return { ...configOnlyDefaults, ...mergedConfig };
52
+ } else {
53
+ return mergedConfig;
54
+ }
46
55
  }
@@ -1,5 +1,5 @@
1
1
  import { Options } from 'yargs';
2
- import { defaults } from '../../defaults';
2
+ import { markdownDefaults } from '../../defaults';
3
3
 
4
4
  export const markdownOptions: { [key: string]: Options } = {
5
5
  sourceDir: {
@@ -11,41 +11,46 @@ export const markdownOptions: { [key: string]: Options } = {
11
11
  targetDir: {
12
12
  type: 'string',
13
13
  alias: 't',
14
- default: defaults.targetDir,
14
+ default: markdownDefaults.targetDir,
15
15
  describe: 'The directory location where documentation will be generated to.',
16
16
  },
17
17
  scope: {
18
18
  type: 'string',
19
19
  array: true,
20
20
  alias: 'p',
21
- default: defaults.scope,
21
+ default: markdownDefaults.scope,
22
22
  describe:
23
23
  'A list of scopes to document. Values should be separated by a space, e.g --scope global public namespaceaccessible. ' +
24
24
  'Annotations are supported and should be passed lowercased and without the @ symbol, e.g. namespaceaccessible auraenabled.',
25
25
  },
26
26
  defaultGroupName: {
27
27
  type: 'string',
28
- default: defaults.defaultGroupName,
28
+ default: markdownDefaults.defaultGroupName,
29
29
  describe: 'Defines the @group name to be used when a file does not specify it.',
30
30
  },
31
31
  namespace: {
32
32
  type: 'string',
33
33
  describe: 'The package namespace, if any. If provided, it will be added to the generated files.',
34
34
  },
35
- sortMembersAlphabetically: {
35
+ sortAlphabetically: {
36
36
  type: 'boolean',
37
- describe: 'Whether to sort members alphabetically.',
38
- default: defaults.sortMembersAlphabetically,
37
+ describe: 'Whether to sort files and members alphabetically.',
38
+ default: markdownDefaults.sortAlphabetically,
39
39
  },
40
40
  includeMetadata: {
41
41
  type: 'boolean',
42
42
  describe: "Whether to include the file's meta.xml information: Whether it is active and and the API version",
43
- default: defaults.includeMetadata,
43
+ default: markdownDefaults.includeMetadata,
44
44
  },
45
45
  linkingStrategy: {
46
46
  type: 'string',
47
47
  describe: 'The strategy to use when linking to other documentation pages.',
48
48
  choices: ['relative', 'no-link', 'none'],
49
- default: defaults.linkingStrategy,
49
+ default: markdownDefaults.linkingStrategy,
50
+ },
51
+ referenceGuideTitle: {
52
+ type: 'string',
53
+ describe: 'The title of the reference guide.',
54
+ default: markdownDefaults.referenceGuideTitle,
50
55
  },
51
56
  };
@@ -1,5 +1,5 @@
1
1
  import { Options } from 'yargs';
2
- import { defaults } from '../../defaults';
2
+ import { markdownDefaults, openApiDefaults } from '../../defaults';
3
3
 
4
4
  export const openApiOptions: { [key: string]: Options } = {
5
5
  sourceDir: {
@@ -11,12 +11,12 @@ export const openApiOptions: { [key: string]: Options } = {
11
11
  targetDir: {
12
12
  type: 'string',
13
13
  alias: 't',
14
- default: defaults.targetDir,
14
+ default: markdownDefaults.targetDir,
15
15
  describe: 'The directory location where the OpenApi file will be generated.',
16
16
  },
17
17
  fileName: {
18
18
  type: 'string',
19
- default: 'openapi',
19
+ default: openApiDefaults.fileName,
20
20
  describe: 'The name of the OpenApi file to be generated.',
21
21
  },
22
22
  namespace: {
@@ -25,12 +25,12 @@ export const openApiOptions: { [key: string]: Options } = {
25
25
  },
26
26
  title: {
27
27
  type: 'string',
28
- default: 'Apex REST API',
28
+ default: openApiDefaults.title,
29
29
  describe: 'The title of the OpenApi file.',
30
30
  },
31
31
  apiVersion: {
32
32
  type: 'string',
33
- default: '1.0.0',
33
+ default: openApiDefaults.apiVersion,
34
34
  describe: 'The version of the OpenApi file.',
35
35
  },
36
36
  };
@@ -1,16 +1,32 @@
1
1
  #!/usr/bin/env node
2
2
  import { Apexdocs } from '../application/Apexdocs';
3
3
  import { extractArgs } from './args';
4
+ import { StdOutLogger } from '#utils/logger';
5
+ import * as E from 'fp-ts/Either';
6
+
7
+ const logger = new StdOutLogger();
4
8
 
5
9
  function main() {
6
- function catchError(error: Error) {
7
- console.error(error);
10
+ function parseResult(result: E.Either<unknown, string>) {
11
+ E.match(
12
+ (error) => {
13
+ logger.error(`❌ An error occurred while generating the documentation: ${error}`);
14
+ process.exit(1);
15
+ },
16
+ (successMessage: string) => {
17
+ logger.logSingle(successMessage);
18
+ },
19
+ )(result);
20
+ }
21
+
22
+ function catchUnexpectedError(error: Error) {
23
+ logger.error(`❌ An unexpected error occurred: ${error.message}`);
8
24
  process.exit(1);
9
25
  }
10
26
 
11
27
  extractArgs()
12
- .then((config) => Apexdocs.generate(config).catch(catchError))
13
- .catch(catchError);
28
+ .then((config) => Apexdocs.generate(config, logger).then(parseResult))
29
+ .catch(catchUnexpectedError);
14
30
  }
15
31
 
16
32
  main();