@cparra/apexdocs 3.0.0-beta.1 → 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 (125) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +246 -650
  3. package/dist/cli/generate.js +74 -3095
  4. package/dist/defaults-BcE8DTat.js +13 -0
  5. package/dist/defaults-D07y_bq4.js +40 -0
  6. package/dist/defaults-gPzwP66p.js +14 -0
  7. package/dist/index.d.ts +49 -19
  8. package/dist/index.js +90 -2
  9. package/dist/logger-BEbUIfqN.js +3282 -0
  10. package/dist/logger-BGuf1PnL.js +3281 -0
  11. package/dist/logger-CWBRF2za.js +3284 -0
  12. package/dist/logger-CdBmDEN1.js +3283 -0
  13. package/dist/logger-Ce4QqPFR.js +3278 -0
  14. package/dist/logger-CyEVYaAC.js +3284 -0
  15. package/dist/logger-D7a83ycP.js +3277 -0
  16. package/dist/logger-DGaHeBKk.js +3279 -0
  17. package/dist/logger-Dqhl_lO_.js +3278 -0
  18. package/dist/logger-aySSWi0G.js +3280 -0
  19. package/dist/logger-qLCcAtiy.js +3284 -0
  20. package/examples/README.md +5 -0
  21. package/examples/docsify/README.md +17 -0
  22. package/examples/docsify/apexdocs.config.ts +13 -0
  23. package/examples/docsify/classes/ASampleClass.cls +57 -0
  24. package/examples/docsify/classes/CodeControl.cls +19 -0
  25. package/examples/docsify/classes/SampleClass.cls +95 -0
  26. package/examples/docsify/classes/SampleInterface.cls +17 -0
  27. package/examples/docsify/classes/SomeDto.cls +122 -0
  28. package/examples/docsify/docs/.nojekyll +0 -0
  29. package/examples/docsify/docs/README.md +25 -0
  30. package/examples/docsify/docs/_config.yml +1 -0
  31. package/examples/docsify/docs/index.html +22 -0
  32. package/examples/docsify/docs/miscellaneous/ASampleClass.md +88 -0
  33. package/examples/docsify/docs/miscellaneous/CodeControl.md +107 -0
  34. package/examples/docsify/docs/miscellaneous/SomeDto.md +244 -0
  35. package/examples/docsify/docs/sample-classes/SampleClass.md +171 -0
  36. package/examples/docsify/docs/sample-interfaces/SampleInterface.md +36 -0
  37. package/examples/docsify/package-lock.json +2459 -0
  38. package/examples/docsify/package.json +14 -0
  39. package/examples/imported/.forceignore +12 -0
  40. package/examples/imported/README.md +6 -0
  41. package/examples/imported/config/project-scratch-def.json +5 -0
  42. package/examples/imported/docs/index.md +109 -0
  43. package/examples/imported/docs/miscellaneous/BaseClass.md +13 -0
  44. package/examples/imported/docs/miscellaneous/MultiInheritanceClass.md +69 -0
  45. package/examples/imported/docs/miscellaneous/ParentInterface.md +12 -0
  46. package/examples/imported/docs/miscellaneous/ReferencedEnum.md +5 -0
  47. package/examples/imported/docs/miscellaneous/SampleException.md +21 -0
  48. package/examples/imported/docs/miscellaneous/SampleInterface.md +113 -0
  49. package/examples/imported/docs/miscellaneous/Url.md +308 -0
  50. package/examples/imported/docs/sample-enums/SampleEnum.md +33 -0
  51. package/examples/imported/docs/samplegroup/SampleClass.md +167 -0
  52. package/examples/imported/force-app/classes/BaseClass.cls +3 -0
  53. package/examples/imported/force-app/classes/MultiInheritanceClass.cls +1 -0
  54. package/examples/imported/force-app/classes/ParentInterface.cls +3 -0
  55. package/examples/imported/force-app/classes/ReferencedEnum.cls +3 -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/docs/miscellaneous/Url.md +10 -8
  64. package/examples/markdown/force-app/classes/Url.cls +3 -1
  65. package/examples/markdown-jsconfig/.forceignore +12 -0
  66. package/examples/markdown-jsconfig/README.md +9 -0
  67. package/examples/markdown-jsconfig/apexdocs.config.mjs +22 -0
  68. package/examples/markdown-jsconfig/config/project-scratch-def.json +5 -0
  69. package/examples/markdown-jsconfig/docs/index.md +12 -0
  70. package/examples/markdown-jsconfig/docs/miscellaneous/Url.md +315 -0
  71. package/examples/markdown-jsconfig/force-app/classes/Url.cls +196 -0
  72. package/examples/markdown-jsconfig/package-lock.json +665 -0
  73. package/examples/markdown-jsconfig/package.json +15 -0
  74. package/examples/markdown-jsconfig/sfdx-project.json +12 -0
  75. package/examples/open-api/README.md +5 -0
  76. package/examples/open-api/docs/openapi.json +2 -570
  77. package/examples/vitepress/README.md +25 -0
  78. package/examples/vitepress/apexdocs.config.ts +9 -2
  79. package/examples/vitepress/docs/index.md +11 -11
  80. package/examples/vitepress/docs/miscellaneous/BaseClass.md +1 -1
  81. package/examples/vitepress/docs/miscellaneous/MultiInheritanceClass.md +2 -2
  82. package/examples/vitepress/docs/miscellaneous/SampleException.md +1 -1
  83. package/examples/vitepress/docs/miscellaneous/SampleInterface.md +6 -6
  84. package/examples/vitepress/docs/miscellaneous/Url.md +3 -3
  85. package/examples/vitepress/docs/sample-enums/SampleEnum.md +3 -3
  86. package/examples/vitepress/docs/samplegroup/SampleClass.md +5 -5
  87. package/examples/vitepress/force-app/main/default/classes/feature-a/SampleClass.cls +73 -0
  88. package/examples/vitepress/force-app/main/default/classes/feature-a/SampleEnum.cls +30 -0
  89. package/examples/vitepress/force-app/main/default/classes/feature-a/SampleException.cls +17 -0
  90. package/package.json +3 -3
  91. package/src/application/Apexdocs.ts +16 -19
  92. package/src/application/__tests__/apex-file-reader.spec.ts +108 -67
  93. package/src/application/apex-file-reader.ts +1 -0
  94. package/src/application/generators/openapi.ts +17 -13
  95. package/src/cli/args.ts +12 -3
  96. package/src/cli/commands/markdown.ts +15 -12
  97. package/src/cli/commands/openapi.ts +5 -5
  98. package/src/cli/generate.ts +20 -4
  99. package/src/core/markdown/__test__/generating-class-docs.spec.ts +15 -386
  100. package/src/core/markdown/__test__/generating-docs.spec.ts +378 -0
  101. package/src/core/markdown/__test__/generating-enum-docs.spec.ts +4 -328
  102. package/src/core/markdown/__test__/generating-interface-docs.spec.ts +4 -296
  103. package/src/core/markdown/__test__/generating-reference-guide.spec.ts +17 -1
  104. package/src/core/markdown/__test__/test-helpers.ts +3 -1
  105. package/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts +3 -1
  106. package/src/core/markdown/adapters/renderable-to-page-data.ts +6 -4
  107. package/src/core/markdown/generate-docs.ts +13 -15
  108. package/src/core/markdown/reflection/__test__/filter-scope.spec.ts +290 -0
  109. package/src/core/markdown/reflection/__test__/helpers.ts +18 -0
  110. package/src/core/markdown/reflection/__test__/remove-excluded-tags.spec.ts +200 -0
  111. package/src/core/markdown/reflection/remove-excluded-tags.ts +168 -0
  112. package/src/core/markdown/reflection/{sort-members.ts → sort-types-and-members.ts} +7 -5
  113. package/src/core/markdown/templates/reference-guide.ts +2 -2
  114. package/src/core/openapi/__tests__/open-api-docs-processor.spec.ts +6 -3
  115. package/src/core/openapi/open-api-docs-processor.ts +3 -3
  116. package/src/core/openapi/parser.ts +5 -2
  117. package/src/core/shared/types.d.ts +18 -18
  118. package/src/defaults.ts +15 -3
  119. package/src/index.ts +88 -14
  120. package/src/util/error-logger.ts +36 -36
  121. package/src/util/logger.ts +18 -11
  122. /package/examples/{vitepress/force-app/main/default → imported/force-app}/classes/SampleClass.cls +0 -0
  123. /package/examples/{vitepress/force-app/main/default → imported/force-app}/classes/SampleEnum.cls +0 -0
  124. /package/examples/{vitepress/force-app/main/default → imported/force-app}/classes/SampleException.cls +0 -0
  125. /package/examples/vitepress/force-app/main/default/classes/{SampleInterface.cls → feature-a/SampleInterface.cls} +0 -0
@@ -0,0 +1,168 @@
1
+ import * as O from 'fp-ts/Option';
2
+ import { match } from 'fp-ts/boolean';
3
+ import { ParsedFile } from '../../shared/types';
4
+ import { ClassMirror, DocComment, InterfaceMirror, Type } from '@cparra/apex-reflection';
5
+ import { pipe } from 'fp-ts/function';
6
+ import { apply } from '#utils/fp';
7
+
8
+ type AppliedRemoveTagFn = (tagName: string, removeFn: RemoveTagFn) => DocComment;
9
+ type RemoveTagFn = (docComment: DocComment) => DocComment;
10
+ type Documentable = { docComment?: DocComment };
11
+
12
+ export const removeExcludedTags = (excludedTags: string[], parsedFiles: ParsedFile[]): ParsedFile[] => {
13
+ return parsedFiles.map((parsedFile) => {
14
+ return {
15
+ ...parsedFile,
16
+ type: removeExcludedTagsFromType(excludedTags, parsedFile.type),
17
+ };
18
+ });
19
+ };
20
+
21
+ const removeExcludedTagsFromType = <T extends Type>(excludedTags: string[], type: T): T => {
22
+ return {
23
+ ...handleType(excludedTags, type),
24
+ docComment: removeExcludedTagsFromDocComment(excludedTags, type.docComment),
25
+ } as T;
26
+ };
27
+
28
+ const handleType = (excludedTags: string[], type: Type): Type => {
29
+ switch (type.type_name) {
30
+ case 'class':
31
+ return handleClass(excludedTags, type as ClassMirror);
32
+ case 'interface':
33
+ return handleInterface(excludedTags, type as InterfaceMirror);
34
+ case 'enum':
35
+ return type;
36
+ }
37
+ };
38
+
39
+ const handleClass = (excludedTags: string[], classMirror: ClassMirror): ClassMirror => {
40
+ return {
41
+ ...classMirror,
42
+ methods: classMirror.methods.map((method) => removeExcludedTagsFromDocumentable(excludedTags, method)),
43
+ properties: classMirror.properties.map((property) => removeExcludedTagsFromDocumentable(excludedTags, property)),
44
+ fields: classMirror.fields.map((field) => removeExcludedTagsFromDocumentable(excludedTags, field)),
45
+ constructors: classMirror.constructors.map((constructor) =>
46
+ removeExcludedTagsFromDocumentable(excludedTags, constructor),
47
+ ),
48
+ enums: classMirror.enums.map((enumType) => removeExcludedTagsFromType(excludedTags, enumType)),
49
+ interfaces: classMirror.interfaces.map((interfaceType) => removeExcludedTagsFromType(excludedTags, interfaceType)),
50
+ classes: classMirror.classes.map((innerClass) => removeExcludedTagsFromType(excludedTags, innerClass)),
51
+ };
52
+ };
53
+
54
+ const handleInterface = (excludedTags: string[], interfaceMirror: InterfaceMirror): InterfaceMirror => {
55
+ return {
56
+ ...interfaceMirror,
57
+ methods: interfaceMirror.methods.map((method) => removeExcludedTagsFromDocumentable(excludedTags, method)),
58
+ };
59
+ };
60
+
61
+ const removeExcludedTagsFromDocumentable = <T extends Documentable>(excludedTags: string[], documentable: T): T => {
62
+ return {
63
+ ...documentable,
64
+ docComment: removeExcludedTagsFromDocComment(excludedTags, documentable.docComment),
65
+ };
66
+ };
67
+
68
+ const removeExcludedTagsFromDocComment = (
69
+ excludedTags: string[],
70
+ docComment: DocComment | undefined,
71
+ ): DocComment | undefined => {
72
+ const removerFn = apply(remove, excludedTags);
73
+
74
+ return pipe(
75
+ O.fromNullable(docComment),
76
+ O.map((docComment) => removeExcludedTagsFromAnnotations(excludedTags, docComment)),
77
+ O.map((docComment) => removeExampleTag(apply(removerFn, docComment))),
78
+ O.map((docComment) => removeParamTags(apply(removerFn, docComment))),
79
+ O.map((docComment) => removeReturnTag(apply(removerFn, docComment))),
80
+ O.map((docComment) => removeThrowsTag(apply(removerFn, docComment))),
81
+ O.map((docComment) => removeExceptionTag(apply(removerFn, docComment))),
82
+ O.map((docComment) => removeDescription(apply(removerFn, docComment))),
83
+ O.fold(
84
+ () => undefined,
85
+ (updatedDocComment) => updatedDocComment,
86
+ ),
87
+ );
88
+ };
89
+
90
+ const removeExcludedTagsFromAnnotations = (excludedTags: string[], docComment: DocComment): DocComment => {
91
+ return pipe(
92
+ O.some(docComment.annotations),
93
+ O.map((annotations) => annotations.filter((annotation) => !includesIgnoreCase(excludedTags, annotation.name))),
94
+ O.fold(
95
+ () => docComment,
96
+ (filteredAnnotations) => ({
97
+ ...docComment,
98
+ annotations: filteredAnnotations,
99
+ }),
100
+ ),
101
+ );
102
+ };
103
+
104
+ const removeExampleTag = (remover: AppliedRemoveTagFn): DocComment => {
105
+ return remover('example', (docComment) => {
106
+ return {
107
+ ...docComment,
108
+ exampleAnnotation: null,
109
+ };
110
+ });
111
+ };
112
+
113
+ const removeParamTags = (remover: AppliedRemoveTagFn): DocComment => {
114
+ return remover('param', (docComment) => {
115
+ return {
116
+ ...docComment,
117
+ paramAnnotations: [],
118
+ };
119
+ });
120
+ };
121
+
122
+ const removeReturnTag = (remover: AppliedRemoveTagFn): DocComment => {
123
+ return remover('return', (docComment) => {
124
+ return {
125
+ ...docComment,
126
+ returnAnnotation: null,
127
+ };
128
+ });
129
+ };
130
+
131
+ const removeThrowsTag = (remover: AppliedRemoveTagFn): DocComment => {
132
+ return remover('throws', (docComment) => {
133
+ return {
134
+ ...docComment,
135
+ throwsAnnotations: [],
136
+ };
137
+ });
138
+ };
139
+
140
+ const removeExceptionTag = (remover: AppliedRemoveTagFn): DocComment => {
141
+ return remover('exception', (docComment) => {
142
+ return {
143
+ ...docComment,
144
+ throwsAnnotations: [],
145
+ };
146
+ });
147
+ };
148
+
149
+ const removeDescription = (remover: AppliedRemoveTagFn): DocComment => {
150
+ return remover('description', (docComment) => {
151
+ return {
152
+ ...docComment,
153
+ description: '',
154
+ descriptionLines: [],
155
+ };
156
+ });
157
+ };
158
+
159
+ const remove = (excludedTags: string[], docComment: DocComment, tagName: string, removeFn: RemoveTagFn): DocComment => {
160
+ return match(
161
+ () => docComment,
162
+ () => removeFn(docComment!),
163
+ )(includesIgnoreCase(excludedTags, tagName) && !!docComment);
164
+ };
165
+
166
+ const includesIgnoreCase = (excluded: string[], value: string): boolean => {
167
+ return excluded.some((element) => element.toLowerCase() === value.toLowerCase());
168
+ };
@@ -3,11 +3,13 @@ import { ParsedFile } from '../../shared/types';
3
3
 
4
4
  type Named = { name: string };
5
5
 
6
- export function sortMembers(shouldSortMembers: boolean, parsedFiles: ParsedFile[]): ParsedFile[] {
7
- return parsedFiles.map((parsedFile) => ({
8
- ...parsedFile,
9
- type: sortTypeMember(parsedFile.type, shouldSortMembers),
10
- }));
6
+ export function sortTypesAndMembers(shouldSort: boolean, parsedFiles: ParsedFile[]): ParsedFile[] {
7
+ return parsedFiles
8
+ .map((parsedFile) => ({
9
+ ...parsedFile,
10
+ type: sortTypeMember(parsedFile.type, shouldSort),
11
+ }))
12
+ .sort((a, b) => sortByNames(shouldSort, a.type, b.type));
11
13
  }
12
14
 
13
15
  function sortByNames<T extends Named>(shouldSort: boolean, a: T, b: T): number {
@@ -1,7 +1,7 @@
1
1
  export const referenceGuideTemplate = `
2
- # Apex Reference Guide
2
+ # {{referenceGuideTitle}}
3
3
 
4
- {{#each this}}
4
+ {{#each references}}
5
5
  ## {{@key}}
6
6
 
7
7
  {{#each this}}
@@ -4,6 +4,9 @@ import { SettingsBuilder } from '../../../test-helpers/SettingsBuilder';
4
4
  import { DocCommentBuilder } from '../../../test-helpers/DocCommentBuilder';
5
5
  import { AnnotationBuilder } from '../../../test-helpers/AnnotationBuilder';
6
6
  import { ClassMirrorBuilder } from '../../../test-helpers/ClassMirrorBuilder';
7
+ import { NoLogger } from '../../../util/logger';
8
+
9
+ const noLogger = new NoLogger();
7
10
 
8
11
  beforeEach(() => {
9
12
  OpenApiSettings.build(new SettingsBuilder().build());
@@ -18,7 +21,7 @@ it('should add a path based on the @UrlResource annotation on the class', functi
18
21
  .addAnnotation(new AnnotationBuilder().addElementValue(annotationElementValue).build())
19
22
  .build();
20
23
 
21
- const processor = new OpenApiDocsProcessor();
24
+ const processor = new OpenApiDocsProcessor(noLogger);
22
25
  processor.onProcess(classMirror);
23
26
 
24
27
  expect(processor.openApiModel.paths).toHaveProperty('Account/');
@@ -33,7 +36,7 @@ it('should respect slashes', function () {
33
36
  .addAnnotation(new AnnotationBuilder().addElementValue(annotationElementValue).build())
34
37
  .build();
35
38
 
36
- const processor = new OpenApiDocsProcessor();
39
+ const processor = new OpenApiDocsProcessor(noLogger);
37
40
  processor.onProcess(classMirror);
38
41
 
39
42
  expect(processor.openApiModel.paths).toHaveProperty('v1/Account/');
@@ -49,7 +52,7 @@ it('should contain a path with a description when the class has an ApexDoc comme
49
52
  .withDocComment(new DocCommentBuilder().withDescription('My Description').build())
50
53
  .build();
51
54
 
52
- const processor = new OpenApiDocsProcessor();
55
+ const processor = new OpenApiDocsProcessor(noLogger);
53
56
  processor.onProcess(classMirror);
54
57
 
55
58
  expect(processor.openApiModel.paths['Account/'].description).toBe('My Description');
@@ -11,7 +11,7 @@ export class OpenApiDocsProcessor {
11
11
  protected readonly _fileContainer: FileContainer;
12
12
  openApiModel: OpenApi;
13
13
 
14
- constructor() {
14
+ constructor(private logger: Logger) {
15
15
  this._fileContainer = new FileContainer();
16
16
  const title = OpenApiSettings.getInstance().getOpenApiTitle();
17
17
  if (!title) {
@@ -29,7 +29,7 @@ export class OpenApiDocsProcessor {
29
29
  }
30
30
 
31
31
  onProcess(type: Type): void {
32
- Logger.logSingle(`Processing ${type.name}`, 'green');
32
+ this.logger.logSingle(`Processing ${type.name}`, 'green');
33
33
 
34
34
  const endpointPath = this.getEndpointPath(type);
35
35
  if (!endpointPath) {
@@ -80,7 +80,7 @@ export class OpenApiDocsProcessor {
80
80
  (element) => element.key.toLowerCase() === 'urlmapping',
81
81
  );
82
82
  if (!urlMapping) {
83
- Logger.error(`Type does not contain urlMapping annotation ${type.name}`);
83
+ this.logger.error(`Type does not contain urlMapping annotation ${type.name}`);
84
84
  return null;
85
85
  }
86
86
 
@@ -9,12 +9,15 @@ export interface TypeParser {
9
9
  type NameAware = { name: string };
10
10
 
11
11
  export class RawBodyParser implements TypeParser {
12
- constructor(public typeBundles: UnparsedSourceFile[]) {}
12
+ constructor(
13
+ private logger: Logger,
14
+ public typeBundles: UnparsedSourceFile[],
15
+ ) {}
13
16
 
14
17
  parse(reflect: (apexBundle: UnparsedSourceFile) => ReflectionResult): Type[] {
15
18
  const types = this.typeBundles
16
19
  .map((currentBundle) => {
17
- Logger.log(`Parsing file: ${currentBundle.filePath}`);
20
+ this.logger.log(`Parsing file: ${currentBundle.filePath}`);
18
21
  return reflect(currentBundle);
19
22
  })
20
23
  .filter((reflectionResult) => {
@@ -1,17 +1,5 @@
1
1
  import { Type } from '@cparra/apex-reflection';
2
2
 
3
- export type Generator = 'markdown' | 'openapi';
4
-
5
- /**
6
- * The configurable hooks that can be used to modify the output of the generator.
7
- */
8
- export type ConfigurableHooks = {
9
- transformReferenceGuide: TransformReferenceGuide;
10
- transformDocs: TransformDocs;
11
- transformDocPage: TransformDocPage;
12
- transformReference: TransformReference;
13
- };
14
-
15
3
  type LinkingStrategy =
16
4
  // Links will be generated using relative paths.
17
5
  | 'relative'
@@ -24,15 +12,17 @@ type LinkingStrategy =
24
12
  | 'none';
25
13
 
26
14
  export type UserDefinedMarkdownConfig = {
27
- targetGenerator: 'markdown';
28
15
  sourceDir: string;
16
+ targetGenerator: 'markdown';
29
17
  targetDir: string;
30
18
  scope: string[];
31
- defaultGroupName: string;
32
19
  namespace?: string;
33
- sortMembersAlphabetically: boolean;
20
+ defaultGroupName: string;
21
+ sortAlphabetically: boolean;
34
22
  includeMetadata: boolean;
35
23
  linkingStrategy: LinkingStrategy;
24
+ excludeTags: string[];
25
+ referenceGuideTitle: string;
36
26
  } & Partial<ConfigurableHooks>;
37
27
 
38
28
  export type UserDefinedOpenApiConfig = {
@@ -115,11 +105,21 @@ export type PostHookDocumentationBundle = {
115
105
  docs: DocPageData[];
116
106
  };
117
107
 
118
- // Configurable Hooks
108
+ // CONFIGURABLE HOOKS
109
+
110
+ /**
111
+ * The configurable hooks that can be used to modify the output of the generator.
112
+ */
113
+ export type ConfigurableHooks = {
114
+ transformReferenceGuide: TransformReferenceGuide;
115
+ transformDocs: TransformDocs;
116
+ transformDocPage: TransformDocPage;
117
+ transformReference: TransformReference;
118
+ };
119
119
 
120
- type ConfigurableDocPageReference = Omit<DocPageReference, 'source'>;
120
+ export type ConfigurableDocPageReference = Omit<DocPageReference, 'source'>;
121
121
 
122
- type ConfigurableDocPageData = Omit<DocPageData, 'source' | 'outputDocPath'>;
122
+ export type ConfigurableDocPageData = Omit<DocPageData, 'source' | 'outputDocPath'>;
123
123
 
124
124
  /**
125
125
  * Allows changing where the files are written to.
package/src/defaults.ts CHANGED
@@ -1,9 +1,21 @@
1
- export const defaults = {
2
- targetGenerator: 'markdown' as const,
1
+ const commonDefaults = {
3
2
  targetDir: './docs/',
3
+ };
4
+
5
+ export const markdownDefaults = {
6
+ ...commonDefaults,
4
7
  scope: ['global'],
5
8
  defaultGroupName: 'Miscellaneous',
6
9
  includeMetadata: false,
7
- sortMembersAlphabetically: false,
10
+ sortAlphabetically: false,
8
11
  linkingStrategy: 'relative' as const,
12
+ referenceGuideTitle: 'Apex Reference Guide',
13
+ excludeTags: [],
14
+ };
15
+
16
+ export const openApiDefaults = {
17
+ ...commonDefaults,
18
+ fileName: 'openapi',
19
+ title: 'Apex REST API',
20
+ apiVersion: '1.0.0',
9
21
  };
package/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { SetOptional } from 'type-fest';
2
1
  import type {
3
2
  ConfigurableHooks,
4
3
  Skip,
@@ -6,31 +5,106 @@ import type {
6
5
  ReferenceGuidePageData,
7
6
  DocPageData,
8
7
  DocPageReference,
8
+ ConfigurableDocPageData,
9
+ TransformReferenceGuide,
10
+ TransformDocs,
11
+ TransformDocPage,
12
+ TransformReference,
13
+ ConfigurableDocPageReference,
14
+ UserDefinedOpenApiConfig,
15
+ UserDefinedConfig,
9
16
  } from './core/shared/types';
10
- import { defaults } from './defaults';
17
+ import { markdownDefaults, openApiDefaults } from './defaults';
18
+ import { NoLogger } from '#utils/logger';
19
+ import { Apexdocs } from './application/Apexdocs';
20
+ import * as E from 'fp-ts/Either';
11
21
 
12
- type ConfigurableMarkdownConfig = Omit<
13
- SetOptional<
14
- UserDefinedMarkdownConfig,
15
- 'targetDir' | 'scope' | 'defaultGroupName' | 'includeMetadata' | 'sortMembersAlphabetically' | 'linkingStrategy'
16
- >,
17
- 'targetGenerator'
18
- >;
22
+ type ConfigurableMarkdownConfig = Omit<Partial<UserDefinedMarkdownConfig>, 'targetGenerator'>;
19
23
 
20
- function defineMarkdownConfig(config: ConfigurableMarkdownConfig): UserDefinedMarkdownConfig {
24
+ /**
25
+ * Helper function to define a configuration to generate Markdown documentation.
26
+ * @param config The configuration to use.
27
+ */
28
+ function defineMarkdownConfig(config: ConfigurableMarkdownConfig): Partial<UserDefinedMarkdownConfig> {
21
29
  return {
22
- ...defaults,
30
+ ...markdownDefaults,
23
31
  ...config,
24
- targetGenerator: 'markdown',
32
+ targetGenerator: 'markdown' as const,
25
33
  };
26
34
  }
27
35
 
36
+ type ConfigurableOpenApiConfig = Omit<Partial<UserDefinedOpenApiConfig>, 'targetGenerator'>;
37
+
38
+ /**
39
+ * Helper function to define a configuration to generate OpenAPI documentation.
40
+ * @param config The configuration to use.
41
+ */
42
+ function defineOpenApiConfig(config: ConfigurableOpenApiConfig): Partial<UserDefinedOpenApiConfig> {
43
+ return {
44
+ ...openApiDefaults,
45
+ ...config,
46
+ targetGenerator: 'openapi' as const,
47
+ };
48
+ }
49
+
50
+ /**
51
+ * Represents a file to be skipped.
52
+ */
28
53
  function skip(): Skip {
29
54
  return {
30
55
  _tag: 'Skip',
31
56
  };
32
57
  }
33
58
 
34
- // Exports
59
+ type CallableConfig = Partial<UserDefinedConfig> & { sourceDir: string; targetGenerator: 'markdown' | 'openapi' };
60
+
61
+ async function process(config: CallableConfig): Promise<void> {
62
+ const logger = new NoLogger();
63
+ const configWithDefaults = {
64
+ ...getDefault(config),
65
+ ...config,
66
+ };
67
+
68
+ if (!configWithDefaults.sourceDir) {
69
+ throw new Error('sourceDir is required');
70
+ }
35
71
 
36
- export { defineMarkdownConfig, skip, ConfigurableHooks, ReferenceGuidePageData, DocPageData, DocPageReference };
72
+ const result = await Apexdocs.generate(configWithDefaults as UserDefinedConfig, logger);
73
+ E.match(
74
+ (errors) => {
75
+ throw errors;
76
+ },
77
+ () => {},
78
+ )(result);
79
+ }
80
+
81
+ function getDefault(config: CallableConfig) {
82
+ switch (config.targetGenerator) {
83
+ case 'markdown':
84
+ return markdownDefaults;
85
+ case 'openapi':
86
+ return openApiDefaults;
87
+ default:
88
+ throw new Error('Unknown target generator');
89
+ }
90
+ }
91
+
92
+ export {
93
+ defineMarkdownConfig,
94
+ ConfigurableMarkdownConfig,
95
+ defineOpenApiConfig,
96
+ ConfigurableOpenApiConfig,
97
+ skip,
98
+ TransformReferenceGuide,
99
+ TransformDocs,
100
+ TransformDocPage,
101
+ TransformReference,
102
+ ConfigurableHooks,
103
+ ReferenceGuidePageData,
104
+ DocPageData,
105
+ DocPageReference,
106
+ Skip,
107
+ ConfigurableDocPageData,
108
+ ConfigurableDocPageReference,
109
+ process,
110
+ };
@@ -2,90 +2,90 @@ import { ClassMirror, InterfaceMirror, Type } from '@cparra/apex-reflection';
2
2
  import { Logger } from './logger';
3
3
 
4
4
  export default class ErrorLogger {
5
- public static logErrors(types: Type[]): void {
5
+ public static logErrors(logger: Logger, types: Type[]): void {
6
6
  types.forEach((currentType) => {
7
- this.logErrorsForSingleType(currentType);
7
+ this.logErrorsForSingleType(logger, currentType);
8
8
  });
9
9
  }
10
10
 
11
- private static logErrorsForSingleType(currentType: Type): void {
12
- this.logTypeErrors(currentType);
11
+ private static logErrorsForSingleType(logger: Logger, currentType: Type): void {
12
+ this.logTypeErrors(logger, currentType);
13
13
 
14
14
  if (currentType.type_name === 'class') {
15
- this.logErrorsForClass(currentType as ClassMirror);
15
+ this.logErrorsForClass(logger, currentType as ClassMirror);
16
16
  } else if (currentType.type_name === 'interface') {
17
- this.logErrorsForInterface(currentType as InterfaceMirror);
17
+ this.logErrorsForInterface(logger, currentType as InterfaceMirror);
18
18
  }
19
19
  }
20
20
 
21
- private static logTypeErrors(currentType: Type, parentType?: Type) {
21
+ private static logTypeErrors(logger: Logger, currentType: Type, parentType?: Type) {
22
22
  if (currentType.docComment?.error) {
23
23
  const typeName = parentType ? `${parentType!.name}.${currentType.name}` : currentType.name;
24
- Logger.error(`${typeName} - Doc comment parsing error. Level: Type`);
25
- Logger.error(`Comment:\n ${currentType.docComment.rawDeclaration}`);
26
- Logger.error(currentType.docComment.error);
27
- Logger.error('=================================');
24
+ logger.error(`${typeName} - Doc comment parsing error. Level: Type`);
25
+ logger.error(`Comment:\n ${currentType.docComment.rawDeclaration}`);
26
+ logger.error(currentType.docComment.error);
27
+ logger.error('=================================');
28
28
  }
29
29
  }
30
30
 
31
- private static logErrorsForClass(classMirror: ClassMirror, parentType?: Type): void {
31
+ private static logErrorsForClass(logger: Logger, classMirror: ClassMirror, parentType?: Type): void {
32
32
  const typeName = parentType ? `${parentType!.name}.${classMirror.name}` : classMirror.name;
33
33
  classMirror.constructors.forEach((currentConstructor) => {
34
34
  if (currentConstructor.docComment?.error) {
35
- Logger.error(`${typeName} - Doc comment parsing error. Level: Constructor`);
36
- Logger.error(`Comment:\n ${currentConstructor.docComment.rawDeclaration}`);
37
- Logger.error(currentConstructor.docComment.error);
38
- Logger.error('=================================');
35
+ logger.error(`${typeName} - Doc comment parsing error. Level: Constructor`);
36
+ logger.error(`Comment:\n ${currentConstructor.docComment.rawDeclaration}`);
37
+ logger.error(currentConstructor.docComment.error);
38
+ logger.error('=================================');
39
39
  }
40
40
  });
41
41
 
42
42
  classMirror.fields.forEach((currentField) => {
43
43
  if (currentField.docComment?.error) {
44
- Logger.error(`${typeName} - Doc comment parsing error. Level: Field`);
45
- Logger.error(`Comment:\n ${currentField.docComment.rawDeclaration}`);
46
- Logger.error(currentField.docComment.error);
47
- Logger.error('=================================');
44
+ logger.error(`${typeName} - Doc comment parsing error. Level: Field`);
45
+ logger.error(`Comment:\n ${currentField.docComment.rawDeclaration}`);
46
+ logger.error(currentField.docComment.error);
47
+ logger.error('=================================');
48
48
  }
49
49
  });
50
50
 
51
51
  classMirror.properties.forEach((currentProperty) => {
52
52
  if (currentProperty.docComment?.error) {
53
- Logger.error(`${typeName} - Doc comment parsing error. Level: Property`);
54
- Logger.error(`Comment:\n ${currentProperty.docComment.rawDeclaration}`);
55
- Logger.error(currentProperty.docComment.error);
56
- Logger.error('=================================');
53
+ logger.error(`${typeName} - Doc comment parsing error. Level: Property`);
54
+ logger.error(`Comment:\n ${currentProperty.docComment.rawDeclaration}`);
55
+ logger.error(currentProperty.docComment.error);
56
+ logger.error('=================================');
57
57
  }
58
58
  });
59
59
 
60
60
  classMirror.methods.forEach((currentMethod) => {
61
61
  if (currentMethod.docComment?.error) {
62
- Logger.error(`${typeName} - Doc comment parsing error. Level: Method`);
63
- Logger.error(`Comment:\n ${currentMethod.docComment.rawDeclaration}`);
64
- Logger.error(currentMethod.docComment.error);
65
- Logger.error('=================================');
62
+ logger.error(`${typeName} - Doc comment parsing error. Level: Method`);
63
+ logger.error(`Comment:\n ${currentMethod.docComment.rawDeclaration}`);
64
+ logger.error(currentMethod.docComment.error);
65
+ logger.error('=================================');
66
66
  }
67
67
  });
68
68
 
69
69
  classMirror.enums.forEach((currentEnum) => {
70
- this.logErrorsForSingleType(currentEnum);
70
+ this.logErrorsForSingleType(logger, currentEnum);
71
71
  });
72
72
 
73
73
  classMirror.interfaces.forEach((currentInterface) => {
74
- this.logErrorsForSingleType(currentInterface);
74
+ this.logErrorsForSingleType(logger, currentInterface);
75
75
  });
76
76
 
77
77
  classMirror.classes.forEach((currentClass) => {
78
- this.logErrorsForSingleType(currentClass);
78
+ this.logErrorsForSingleType(logger, currentClass);
79
79
  });
80
80
  }
81
81
 
82
- private static logErrorsForInterface(interfaceMirror: InterfaceMirror): void {
82
+ private static logErrorsForInterface(logger: Logger, interfaceMirror: InterfaceMirror): void {
83
83
  interfaceMirror.methods.forEach((currentMethod) => {
84
84
  if (currentMethod.docComment?.error) {
85
- Logger.error(`${interfaceMirror.name} - Doc comment parsing error. Level: Method`);
86
- Logger.error(`Comment: ${currentMethod.docComment.rawDeclaration}`);
87
- Logger.error(currentMethod.docComment.error);
88
- Logger.error('=================================');
85
+ logger.error(`${interfaceMirror.name} - Doc comment parsing error. Level: Method`);
86
+ logger.error(`Comment: ${currentMethod.docComment.rawDeclaration}`);
87
+ logger.error(currentMethod.docComment.error);
88
+ logger.error('=================================');
89
89
  }
90
90
  });
91
91
  }
@@ -1,16 +1,21 @@
1
1
  import chalk from 'chalk';
2
+
3
+ export interface Logger {
4
+ log(message: string, ...args: string[]): void;
5
+ error(message: unknown, ...args: string[]): void;
6
+ logSingle(text: unknown, color?: 'green' | 'red'): void;
7
+ }
8
+
2
9
  /**
3
10
  * Logs messages to the console.
4
11
  */
5
- export class Logger {
6
- static currentFrame = 0;
7
-
12
+ export class StdOutLogger {
8
13
  /**
9
14
  * Logs a message with optional arguments.
10
15
  * @param message The message to log.
11
16
  * @param args Optional arguments.
12
17
  */
13
- public static log(message: string, ...args: string[]) {
18
+ public log(message: string, ...args: string[]) {
14
19
  this.logSingle(message);
15
20
  args.forEach((arg) => {
16
21
  this.logSingle(arg);
@@ -22,23 +27,25 @@ export class Logger {
22
27
  * @param message The error message to log.
23
28
  * @param args Optional arguments.
24
29
  */
25
- public static error(message: unknown, ...args: string[]) {
30
+ public error(message: unknown, ...args: string[]) {
26
31
  this.logSingle(message, 'red');
27
32
  args.forEach(() => {
28
33
  this.logSingle(message, 'red');
29
34
  });
30
35
  }
31
36
 
32
- public static logSingle(text: unknown, color: 'green' | 'red' = 'green') {
33
- if (this.currentFrame > 9) {
34
- this.currentFrame = 0;
35
- }
36
-
37
+ public logSingle(text: unknown, color: 'green' | 'red' = 'green') {
37
38
  const logMessage = `${this.getChalkFn(color)(new Date().toLocaleString() + ': ')}${text}\n`;
38
39
  process.stdout.write(logMessage);
39
40
  }
40
41
 
41
- private static getChalkFn(color: 'green' | 'red') {
42
+ private getChalkFn(color: 'green' | 'red') {
42
43
  return color === 'green' ? chalk.green : chalk.red;
43
44
  }
44
45
  }
46
+
47
+ export class NoLogger implements Logger {
48
+ public log() {}
49
+ public error() {}
50
+ public logSingle() {}
51
+ }