@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.
- package/LICENSE +1 -1
- package/README.md +246 -650
- package/dist/cli/generate.js +74 -3095
- package/dist/defaults-BcE8DTat.js +13 -0
- package/dist/defaults-D07y_bq4.js +40 -0
- package/dist/defaults-gPzwP66p.js +14 -0
- package/dist/index.d.ts +49 -19
- package/dist/index.js +90 -2
- package/dist/logger-BEbUIfqN.js +3282 -0
- package/dist/logger-BGuf1PnL.js +3281 -0
- package/dist/logger-CWBRF2za.js +3284 -0
- package/dist/logger-CdBmDEN1.js +3283 -0
- package/dist/logger-Ce4QqPFR.js +3278 -0
- package/dist/logger-CyEVYaAC.js +3284 -0
- package/dist/logger-D7a83ycP.js +3277 -0
- package/dist/logger-DGaHeBKk.js +3279 -0
- package/dist/logger-Dqhl_lO_.js +3278 -0
- package/dist/logger-aySSWi0G.js +3280 -0
- package/dist/logger-qLCcAtiy.js +3284 -0
- package/examples/README.md +5 -0
- package/examples/docsify/README.md +17 -0
- package/examples/docsify/apexdocs.config.ts +13 -0
- package/examples/docsify/classes/ASampleClass.cls +57 -0
- package/examples/docsify/classes/CodeControl.cls +19 -0
- package/examples/docsify/classes/SampleClass.cls +95 -0
- package/examples/docsify/classes/SampleInterface.cls +17 -0
- package/examples/docsify/classes/SomeDto.cls +122 -0
- package/examples/docsify/docs/.nojekyll +0 -0
- package/examples/docsify/docs/README.md +25 -0
- package/examples/docsify/docs/_config.yml +1 -0
- package/examples/docsify/docs/index.html +22 -0
- package/examples/docsify/docs/miscellaneous/ASampleClass.md +88 -0
- package/examples/docsify/docs/miscellaneous/CodeControl.md +107 -0
- package/examples/docsify/docs/miscellaneous/SomeDto.md +244 -0
- package/examples/docsify/docs/sample-classes/SampleClass.md +171 -0
- package/examples/docsify/docs/sample-interfaces/SampleInterface.md +36 -0
- package/examples/docsify/package-lock.json +2459 -0
- package/examples/docsify/package.json +14 -0
- package/examples/imported/.forceignore +12 -0
- package/examples/imported/README.md +6 -0
- package/examples/imported/config/project-scratch-def.json +5 -0
- package/examples/imported/docs/index.md +109 -0
- package/examples/imported/docs/miscellaneous/BaseClass.md +13 -0
- package/examples/imported/docs/miscellaneous/MultiInheritanceClass.md +69 -0
- package/examples/imported/docs/miscellaneous/ParentInterface.md +12 -0
- package/examples/imported/docs/miscellaneous/ReferencedEnum.md +5 -0
- package/examples/imported/docs/miscellaneous/SampleException.md +21 -0
- package/examples/imported/docs/miscellaneous/SampleInterface.md +113 -0
- package/examples/imported/docs/miscellaneous/Url.md +308 -0
- package/examples/imported/docs/sample-enums/SampleEnum.md +33 -0
- package/examples/imported/docs/samplegroup/SampleClass.md +167 -0
- package/examples/imported/force-app/classes/BaseClass.cls +3 -0
- package/examples/imported/force-app/classes/MultiInheritanceClass.cls +1 -0
- package/examples/imported/force-app/classes/ParentInterface.cls +3 -0
- package/examples/imported/force-app/classes/ReferencedEnum.cls +3 -0
- package/examples/imported/force-app/classes/SampleInterface.cls +50 -0
- package/examples/imported/force-app/classes/Url.cls +196 -0
- package/examples/imported/package-lock.json +665 -0
- package/examples/imported/package.json +6 -0
- package/examples/imported/scripts/process-docs.mjs +16 -0
- package/examples/imported/sfdx-project.json +12 -0
- package/examples/markdown/README.md +7 -0
- package/examples/markdown/docs/miscellaneous/Url.md +10 -8
- package/examples/markdown/force-app/classes/Url.cls +3 -1
- package/examples/markdown-jsconfig/.forceignore +12 -0
- package/examples/markdown-jsconfig/README.md +9 -0
- package/examples/markdown-jsconfig/apexdocs.config.mjs +22 -0
- package/examples/markdown-jsconfig/config/project-scratch-def.json +5 -0
- package/examples/markdown-jsconfig/docs/index.md +12 -0
- package/examples/markdown-jsconfig/docs/miscellaneous/Url.md +315 -0
- package/examples/markdown-jsconfig/force-app/classes/Url.cls +196 -0
- package/examples/markdown-jsconfig/package-lock.json +665 -0
- package/examples/markdown-jsconfig/package.json +15 -0
- package/examples/markdown-jsconfig/sfdx-project.json +12 -0
- package/examples/open-api/README.md +5 -0
- package/examples/open-api/docs/openapi.json +2 -570
- package/examples/vitepress/README.md +25 -0
- package/examples/vitepress/apexdocs.config.ts +9 -2
- package/examples/vitepress/docs/index.md +11 -11
- package/examples/vitepress/docs/miscellaneous/BaseClass.md +1 -1
- package/examples/vitepress/docs/miscellaneous/MultiInheritanceClass.md +2 -2
- package/examples/vitepress/docs/miscellaneous/SampleException.md +1 -1
- package/examples/vitepress/docs/miscellaneous/SampleInterface.md +6 -6
- package/examples/vitepress/docs/miscellaneous/Url.md +3 -3
- package/examples/vitepress/docs/sample-enums/SampleEnum.md +3 -3
- package/examples/vitepress/docs/samplegroup/SampleClass.md +5 -5
- package/examples/vitepress/force-app/main/default/classes/feature-a/SampleClass.cls +73 -0
- package/examples/vitepress/force-app/main/default/classes/feature-a/SampleEnum.cls +30 -0
- package/examples/vitepress/force-app/main/default/classes/feature-a/SampleException.cls +17 -0
- package/package.json +3 -3
- package/src/application/Apexdocs.ts +16 -19
- package/src/application/__tests__/apex-file-reader.spec.ts +108 -67
- package/src/application/apex-file-reader.ts +1 -0
- package/src/application/generators/openapi.ts +17 -13
- package/src/cli/args.ts +12 -3
- package/src/cli/commands/markdown.ts +15 -12
- package/src/cli/commands/openapi.ts +5 -5
- package/src/cli/generate.ts +20 -4
- package/src/core/markdown/__test__/generating-class-docs.spec.ts +15 -386
- package/src/core/markdown/__test__/generating-docs.spec.ts +378 -0
- package/src/core/markdown/__test__/generating-enum-docs.spec.ts +4 -328
- package/src/core/markdown/__test__/generating-interface-docs.spec.ts +4 -296
- package/src/core/markdown/__test__/generating-reference-guide.spec.ts +17 -1
- package/src/core/markdown/__test__/test-helpers.ts +3 -1
- package/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts +3 -1
- package/src/core/markdown/adapters/renderable-to-page-data.ts +6 -4
- package/src/core/markdown/generate-docs.ts +13 -15
- package/src/core/markdown/reflection/__test__/filter-scope.spec.ts +290 -0
- package/src/core/markdown/reflection/__test__/helpers.ts +18 -0
- package/src/core/markdown/reflection/__test__/remove-excluded-tags.spec.ts +200 -0
- package/src/core/markdown/reflection/remove-excluded-tags.ts +168 -0
- package/src/core/markdown/reflection/{sort-members.ts → sort-types-and-members.ts} +7 -5
- package/src/core/markdown/templates/reference-guide.ts +2 -2
- package/src/core/openapi/__tests__/open-api-docs-processor.spec.ts +6 -3
- package/src/core/openapi/open-api-docs-processor.ts +3 -3
- package/src/core/openapi/parser.ts +5 -2
- package/src/core/shared/types.d.ts +18 -18
- package/src/defaults.ts +15 -3
- package/src/index.ts +88 -14
- package/src/util/error-logger.ts +36 -36
- package/src/util/logger.ts +18 -11
- /package/examples/{vitepress/force-app/main/default → imported/force-app}/classes/SampleClass.cls +0 -0
- /package/examples/{vitepress/force-app/main/default → imported/force-app}/classes/SampleEnum.cls +0 -0
- /package/examples/{vitepress/force-app/main/default → imported/force-app}/classes/SampleException.cls +0 -0
- /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
|
|
7
|
-
return parsedFiles
|
|
8
|
-
|
|
9
|
-
|
|
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 {
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
...
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
};
|
package/src/util/error-logger.ts
CHANGED
|
@@ -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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
}
|
package/src/util/logger.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
+
}
|