@cparra/apexdocs 2.25.0-alpha.1 → 2.25.0-alpha.2

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 (51) hide show
  1. package/examples/plain-markdown/docs/Miscellaneous/ns.MultiInheritanceClass.md +73 -0
  2. package/examples/plain-markdown/docs/Miscellaneous/ns.SampleException.md +1 -1
  3. package/examples/plain-markdown/docs/SampleGroup/ns.SampleClass.md +1 -1
  4. package/examples/plain-markdown/docs/index.md +11 -14
  5. package/examples/plain-markdown/force-app/classes/MultiInheritanceClass.cls +1 -0
  6. package/lib/adapters/apex-types.d.ts +2 -4
  7. package/lib/adapters/apex-types.js +16 -19
  8. package/lib/adapters/apex-types.js.map +1 -1
  9. package/lib/adapters/fields-and-properties.js +1 -2
  10. package/lib/adapters/fields-and-properties.js.map +1 -1
  11. package/lib/adapters/methods-and-constructors.js +9 -10
  12. package/lib/adapters/methods-and-constructors.js.map +1 -1
  13. package/lib/application/Apexdocs.js +21 -15
  14. package/lib/application/Apexdocs.js.map +1 -1
  15. package/lib/application/flows/generate-markdown-files.d.ts +3 -0
  16. package/lib/application/flows/generate-markdown-files.js +57 -0
  17. package/lib/application/flows/generate-markdown-files.js.map +1 -0
  18. package/lib/core/__test__/inheritance-chain.test.d.ts +1 -0
  19. package/lib/core/__test__/inheritance-chain.test.js +42 -0
  20. package/lib/core/__test__/inheritance-chain.test.js.map +1 -0
  21. package/lib/core/generate-docs.d.ts +1 -0
  22. package/lib/core/generate-docs.js +37 -11
  23. package/lib/core/generate-docs.js.map +1 -1
  24. package/lib/core/inheritance-chain.d.ts +2 -0
  25. package/lib/core/inheritance-chain.js +35 -0
  26. package/lib/core/inheritance-chain.js.map +1 -0
  27. package/lib/model/inheritance.d.ts +4 -1
  28. package/lib/model/markdown-file.d.ts +1 -1
  29. package/lib/model/markdown-file.js +1 -1
  30. package/lib/model/markdown-file.js.map +1 -1
  31. package/lib/test-helpers/ClassMirrorBuilder.d.ts +4 -0
  32. package/lib/test-helpers/ClassMirrorBuilder.js +11 -1
  33. package/lib/test-helpers/ClassMirrorBuilder.js.map +1 -1
  34. package/lib/transpiler/markdown/plain-markdown/class-template.js +3 -3
  35. package/lib/util/logger.js +1 -1
  36. package/lib/util/logger.js.map +1 -1
  37. package/package.json +3 -3
  38. package/src/adapters/apex-types.ts +48 -41
  39. package/src/adapters/fields-and-properties.ts +2 -2
  40. package/src/adapters/methods-and-constructors.ts +16 -12
  41. package/src/application/Apexdocs.ts +21 -15
  42. package/src/application/flows/generate-markdown-files.ts +47 -0
  43. package/src/core/__test__/inheritance-chain.test.ts +54 -0
  44. package/src/core/generate-docs.ts +52 -13
  45. package/src/core/inheritance-chain.ts +23 -0
  46. package/src/core/renderable/types.d.ts +1 -1
  47. package/src/model/inheritance.ts +2 -1
  48. package/src/model/markdown-file.ts +1 -1
  49. package/src/test-helpers/ClassMirrorBuilder.ts +14 -1
  50. package/src/transpiler/markdown/plain-markdown/class-template.ts +3 -3
  51. package/src/util/logger.ts +1 -1
@@ -12,6 +12,7 @@ import ApexBundle from '../model/apex-bundle';
12
12
  import Manifest from '../model/manifest';
13
13
  import { TypesRepository } from '../model/types-repository';
14
14
  import { TypeTranspilerFactory } from '../transpiler/factory';
15
+ import { generateMarkdownFiles } from './flows/generate-markdown-files';
15
16
 
16
17
  /**
17
18
  * Application entry-point to generate documentation out of Apex source files.
@@ -23,24 +24,29 @@ export class Apexdocs {
23
24
  static generate(): void {
24
25
  Logger.log('Initializing...');
25
26
  const fileBodies = ApexFileReader.processFiles(new DefaultFileSystem());
26
- const manifest = createManifest(new RawBodyParser(fileBodies), this._reflectionWithLogger);
27
- TypesRepository.getInstance().populateAll(manifest.types);
28
- const filteredTypes = this.filterByScopes(manifest);
29
- TypesRepository.getInstance().populateScoped(filteredTypes);
30
- const processor = TypeTranspilerFactory.get(Settings.getInstance().targetGenerator);
31
- Transpiler.generate(filteredTypes, processor);
32
- const generatedFiles = processor.fileBuilder().files();
33
27
 
34
- const files: TargetFile[] = [];
35
- FileWriter.write(generatedFiles, (file: TargetFile) => {
36
- Logger.logSingle(`${file.name} processed.`, false, 'green', false);
37
- files.push(file);
38
- });
28
+ if (Settings.getInstance().targetGenerator === 'plain-markdown') {
29
+ generateMarkdownFiles(fileBodies);
30
+ } else {
31
+ const manifest = createManifest(new RawBodyParser(fileBodies), this._reflectionWithLogger);
32
+ TypesRepository.getInstance().populateAll(manifest.types);
33
+ const filteredTypes = this.filterByScopes(manifest);
34
+ TypesRepository.getInstance().populateScoped(filteredTypes);
35
+ const processor = TypeTranspilerFactory.get(Settings.getInstance().targetGenerator);
36
+ Transpiler.generate(filteredTypes, processor);
37
+ const generatedFiles = processor.fileBuilder().files();
38
+
39
+ const files: TargetFile[] = [];
40
+ FileWriter.write(generatedFiles, (file: TargetFile) => {
41
+ Logger.logSingle(`${file.name} processed.`, false, 'green', false);
42
+ files.push(file);
43
+ });
39
44
 
40
- Settings.getInstance().onAfterProcess(files);
45
+ Settings.getInstance().onAfterProcess(files);
41
46
 
42
- // Error logging
43
- ErrorLogger.logErrors(filteredTypes);
47
+ // Error logging
48
+ ErrorLogger.logErrors(filteredTypes);
49
+ }
44
50
  }
45
51
 
46
52
  private static filterByScopes(manifest: Manifest) {
@@ -0,0 +1,47 @@
1
+ import ApexBundle from '../../model/apex-bundle';
2
+ import { Settings, TargetFile } from '../../settings';
3
+ import { DocumentationBundle, generateDocs } from '../../core/generate-docs';
4
+ import { MarkdownFile } from '../../model/markdown-file';
5
+ import { FileWriter } from '../../service/file-writer';
6
+ import { Logger } from '../../util/logger';
7
+ import { flow } from 'fp-ts/function';
8
+ import * as E from 'fp-ts/Either';
9
+
10
+ export const generateMarkdownFiles = flow(
11
+ generateDocumentationBundle,
12
+ E.map(convertToMarkdownFiles),
13
+ E.map(writeFilesToSystem),
14
+ E.mapLeft((errors) => {
15
+ Logger.error(errors.join('\n'));
16
+ }),
17
+ );
18
+
19
+ function generateDocumentationBundle(bundles: ApexBundle[]) {
20
+ return generateDocs(
21
+ bundles.map((file) => file.rawTypeContent),
22
+ {
23
+ scope: Settings.getInstance().scope,
24
+ outputDir: Settings.getInstance().outputDir,
25
+ namespace: Settings.getInstance().getNamespace(),
26
+ sortMembersAlphabetically: Settings.getInstance().sortMembersAlphabetically(),
27
+ defaultGroupName: Settings.getInstance().getDefaultGroupName(),
28
+ },
29
+ );
30
+ }
31
+
32
+ function convertToMarkdownFiles(docBundle: DocumentationBundle): MarkdownFile[] {
33
+ return [
34
+ new MarkdownFile('index', '').addText(docBundle.referenceGuide),
35
+ ...docBundle.docs.map((doc) =>
36
+ new MarkdownFile(`${Settings.getInstance().getNamespacePrefix()}${doc.typeName}`, doc.directory).addText(
37
+ doc.docContents,
38
+ ),
39
+ ),
40
+ ];
41
+ }
42
+
43
+ function writeFilesToSystem(files: MarkdownFile[]) {
44
+ FileWriter.write(files, (file: TargetFile) => {
45
+ Logger.logSingle(`${file.name} processed.`, false, 'green', false);
46
+ });
47
+ }
@@ -0,0 +1,54 @@
1
+ import { ClassMirrorBuilder } from '../../test-helpers/ClassMirrorBuilder';
2
+ import { createInheritanceChain } from '../inheritance-chain';
3
+
4
+ describe('inheritance chain for classes', () => {
5
+ test('returns an empty list of the class does not extend any other class', () => {
6
+ const classMirror = new ClassMirrorBuilder().build();
7
+ const repository = [classMirror];
8
+
9
+ const inheritanceChain = createInheritanceChain(repository, classMirror);
10
+
11
+ expect(inheritanceChain).toEqual([]);
12
+ });
13
+
14
+ test('returns the name of the extended class if it is not found in the repository', () => {
15
+ const classMirror = new ClassMirrorBuilder().withExtendedClass('ExtendedClass').build();
16
+ const repository = [classMirror];
17
+
18
+ const inheritanceChain = createInheritanceChain(repository, classMirror);
19
+
20
+ expect(inheritanceChain).toEqual(['ExtendedClass']);
21
+ });
22
+
23
+ test('returns the extended class when it is present in the repository', () => {
24
+ const classMirror = new ClassMirrorBuilder().withExtendedClass('ExtendedClass').build();
25
+ const extendedClass = new ClassMirrorBuilder().withName('ExtendedClass').build();
26
+ const repository = [classMirror, extendedClass];
27
+
28
+ const inheritanceChain = createInheritanceChain(repository, classMirror);
29
+
30
+ expect(inheritanceChain).toEqual(['ExtendedClass']);
31
+ });
32
+
33
+ test('returns the full inheritance chain when the extended class is also extended', () => {
34
+ const classMirror = new ClassMirrorBuilder().withExtendedClass('ExtendedClass').build();
35
+ const extendedClass = new ClassMirrorBuilder().withName('ExtendedClass').withExtendedClass('SuperClass').build();
36
+ const superClass = new ClassMirrorBuilder().withName('SuperClass').build();
37
+ const repository = [classMirror, extendedClass, superClass];
38
+
39
+ const inheritanceChain = createInheritanceChain(repository, classMirror);
40
+
41
+ expect(inheritanceChain).toEqual(['ExtendedClass', 'SuperClass']);
42
+ });
43
+
44
+ test('returns the inheritance for a class that extends an inner class', () => {
45
+ const classMirror = new ClassMirrorBuilder().withExtendedClass('OuterClass.InnerClass').build();
46
+ const innerClass = new ClassMirrorBuilder().withName('InnerClass').build();
47
+ const outerClass = new ClassMirrorBuilder().withName('OuterClass').addInnerClass(innerClass).build();
48
+ const repository = [classMirror, outerClass];
49
+
50
+ const inheritanceChain = createInheritanceChain(repository, classMirror);
51
+
52
+ expect(inheritanceChain).toEqual(['OuterClass.InnerClass']);
53
+ });
54
+ });
@@ -1,6 +1,6 @@
1
1
  import { ClassMirror, InterfaceMirror, reflect as mirrorReflection, Type } from '@cparra/apex-reflection';
2
2
  import { typeToRenderableType } from '../adapters/apex-types';
3
- import { Renderable, RenderableContent, RenderableEnum, StringOrLink } from './renderable/types';
3
+ import { Link, Renderable, RenderableContent, RenderableEnum, StringOrLink } from './renderable/types';
4
4
  import { classMarkdownTemplate } from '../transpiler/markdown/plain-markdown/class-template';
5
5
  import { enumMarkdownTemplate } from '../transpiler/markdown/plain-markdown/enum-template';
6
6
  import { interfaceMarkdownTemplate } from '../transpiler/markdown/plain-markdown/interface-template';
@@ -10,6 +10,7 @@ import { CompilationRequest, Template } from './template';
10
10
  import Manifest from '../model/manifest';
11
11
  import { referenceGuideTemplate } from './templates/reference-guide';
12
12
  import { adaptDescribable } from '../adapters/documentables';
13
+ import { createInheritanceChain } from './inheritance-chain';
13
14
 
14
15
  export const documentType = flow(typeToRenderableType, resolveApexTypeTemplate, compile);
15
16
 
@@ -29,6 +30,7 @@ type DocumentationConfig = {
29
30
  };
30
31
 
31
32
  type DocOutput = {
33
+ directory: string;
32
34
  docContents: string;
33
35
  typeName: string;
34
36
  type: 'class' | 'interface' | 'enum';
@@ -50,19 +52,22 @@ export function generateDocs(
50
52
  input,
51
53
  (input) => input.map(reflectSourceBody),
52
54
  checkForReflectionErrors,
53
- E.map((types) => types.map((type) => addInheritedMembers(type, types))),
54
55
  E.map((types) => filterTypesOutOfScope(types, configWithDefaults.scope)),
56
+ E.map((types) => types.map((type) => addInheritedMembers(type, types))),
57
+ E.map((types) => types.map((type) => addInheritanceChain(type, types))),
55
58
  E.map((types) => typesToRenderableBundle(types, configWithDefaults)),
56
59
  E.map(({ references, renderables }) => ({
57
60
  referenceGuide: pipe(referencesToReferenceGuide(references, configWithDefaults.referenceGuideTemplate)),
58
- docs: renderables.map(renderableToOutputDoc),
61
+ docs: renderables.map((renderable) => renderableToOutputDoc(Object.values(references).flat(), renderable)),
59
62
  })),
60
63
  E.map(({ referenceGuide, docs }) => ({ format: 'markdown', referenceGuide: referenceGuide, docs })),
61
64
  );
62
65
  }
63
66
 
64
67
  type ReferenceGuideReference = {
65
- title: StringOrLink;
68
+ typeName: string;
69
+ directory: string;
70
+ title: Link;
66
71
  description: RenderableContent[] | undefined;
67
72
  };
68
73
 
@@ -88,11 +93,12 @@ function typesToRenderableBundle(types: Type[], config: DocumentationConfig) {
88
93
 
89
94
  const descriptionLines = type.docComment?.descriptionLines;
90
95
  const reference = {
96
+ typeName: type.name,
97
+ directory: getDirectoryFromRoot(config, type),
91
98
  title: getLinkFromRoot(config, type),
92
- description: adaptDescribable(descriptionLines, (referenceName) => {
93
- const type = findType(types, referenceName);
94
- return type ? getLinkFromRoot(config, type) : referenceName;
95
- }).description,
99
+ description: adaptDescribable(descriptionLines, (referenceName) =>
100
+ getPossibleLinkFromRoot(config, referenceName, findType(types, referenceName)),
101
+ ).description,
96
102
  };
97
103
 
98
104
  const group = getTypeGroup(type, config);
@@ -110,9 +116,13 @@ function typesToRenderableBundle(types: Type[], config: DocumentationConfig) {
110
116
  );
111
117
  }
112
118
 
113
- function renderableToOutputDoc(renderable: Renderable): DocOutput {
119
+ function renderableToOutputDoc(referenceGuideReference: ReferenceGuideReference[], renderable: Renderable): DocOutput {
114
120
  function buildDocOutput(renderable: Renderable, docContents: string): DocOutput {
121
+ const reference = referenceGuideReference.find(
122
+ (ref) => ref.typeName.toLowerCase() === renderable.name.toLowerCase(),
123
+ );
115
124
  return {
125
+ directory: reference!.directory,
116
126
  docContents,
117
127
  typeName: renderable.name,
118
128
  type: renderable.type,
@@ -213,6 +223,18 @@ function addInheritedMembers<T extends Type>(current: T, repository: Type[]): T
213
223
  }
214
224
  }
215
225
 
226
+ function addInheritanceChain<T extends Type>(current: T, repository: Type[]): T {
227
+ if (current.type_name === 'enum' || current.type_name === 'interface') {
228
+ return current;
229
+ } else {
230
+ const inheritanceChain = createInheritanceChain(repository, current as ClassMirror);
231
+ return {
232
+ ...current,
233
+ inheritanceChain,
234
+ };
235
+ }
236
+ }
237
+
216
238
  function getParents<T extends Type>(
217
239
  extendedNamesExtractor: (current: T) => string[],
218
240
  current: T,
@@ -326,14 +348,31 @@ function getFileLinkTuple(
326
348
  return [fullClassName, `${directoryRoot}${fullClassName}.md`];
327
349
  }
328
350
 
329
- function getLinkFromRoot(config: DocumentationConfig, type?: Type): StringOrLink {
351
+ function getDirectoryFromRoot(config: DocumentationConfig, type?: Type): string {
330
352
  if (!type) {
331
353
  return '';
332
354
  }
333
- const namespacePrefix = config.namespace ? `${config.namespace}./` : '';
355
+ return `./${getSanitizedGroup(type, config)}`;
356
+ }
357
+
358
+ function getPossibleLinkFromRoot(config: DocumentationConfig, fallback: string, type?: Type): StringOrLink {
359
+ if (!type) {
360
+ return fallback;
361
+ }
362
+ const namespacePrefix = config.namespace ? `${config.namespace}.` : '';
363
+ const title = `${namespacePrefix}${type.name}`;
364
+ return {
365
+ title: title,
366
+ url: `${getDirectoryFromRoot(config, type)}/${title}.md`,
367
+ };
368
+ }
369
+
370
+ function getLinkFromRoot(config: DocumentationConfig, type: Type): Link {
371
+ const namespacePrefix = config.namespace ? `${config.namespace}.` : '';
372
+ const title = `${namespacePrefix}${type.name}`;
334
373
  return {
335
- title: `${namespacePrefix}${type.name}`,
336
- url: `./${namespacePrefix}${getSanitizedGroup(type, config)}/${type.name}.md`,
374
+ title: title,
375
+ url: `${getDirectoryFromRoot(config, type)}/${title}.md`,
337
376
  };
338
377
  }
339
378
 
@@ -0,0 +1,23 @@
1
+ import { ClassMirror, Type } from '@cparra/apex-reflection';
2
+ import { pipe } from 'fp-ts/function';
3
+ import * as O from 'fp-ts/Option';
4
+
5
+ export function createInheritanceChain(repository: Type[], classMirror: ClassMirror): string[] {
6
+ return pipe(
7
+ O.fromNullable(classMirror.extended_class),
8
+ O.match(
9
+ () => [],
10
+ (extendedClassName) => inheritanceChainFromParentClassName(repository, extendedClassName),
11
+ ),
12
+ );
13
+ }
14
+
15
+ function inheritanceChainFromParentClassName(repository: Type[], className: string): string[] {
16
+ return pipe(
17
+ O.fromNullable(repository.find((type) => type.name.toLowerCase() === className.toLowerCase())),
18
+ O.match(
19
+ () => [className],
20
+ (extendedClass: Type) => [className, ...createInheritanceChain(repository, extendedClass as ClassMirror)],
21
+ ),
22
+ );
23
+ }
@@ -102,7 +102,7 @@ export type GroupedMember<T> = RenderableSection<T[]> & { groupDescription: stri
102
102
 
103
103
  export type RenderableClass = RenderableType & {
104
104
  type: 'class';
105
- extends?: StringOrLink;
105
+ extends?: StringOrLink[];
106
106
  implements?: StringOrLink[];
107
107
  classModifier?: string;
108
108
  sharingModifier?: string;
@@ -1,6 +1,7 @@
1
- import { FieldMirror, MethodMirror, PropertyMirror } from '@cparra/apex-reflection';
1
+ import { ClassMirror, FieldMirror, MethodMirror, PropertyMirror } from '@cparra/apex-reflection';
2
2
 
3
3
  export type InheritanceSupport = { inherited: boolean };
4
+ export type ClassMirrorWithInheritanceChain = ClassMirror & { inheritanceChain: string[] };
4
5
  export type FieldMirrorWithInheritance = FieldMirror & InheritanceSupport;
5
6
  export type PropertyMirrorWithInheritance = PropertyMirror & InheritanceSupport;
6
7
  export type MethodMirrorWithInheritance = MethodMirror & InheritanceSupport;
@@ -19,8 +19,8 @@ export class MarkdownFile extends OutputFile {
19
19
  }
20
20
 
21
21
  public addText(text: string) {
22
- //super.addText(this._replaceInlineReferences(text), encodeHtml);
23
22
  super.addText(text);
23
+ return this;
24
24
  }
25
25
 
26
26
  public addLink(text: string) {
@@ -10,6 +10,8 @@ export class ClassMirrorBuilder {
10
10
  private docComment?: DocComment;
11
11
  private methods: MethodMirror[] = [];
12
12
  private fields: FieldMirror[] = [];
13
+ private innerClasses: ClassMirror[] = [];
14
+ private extendedClass: string | undefined;
13
15
 
14
16
  withName(name: string): ClassMirrorBuilder {
15
17
  this.name = name;
@@ -36,6 +38,16 @@ export class ClassMirrorBuilder {
36
38
  return this;
37
39
  }
38
40
 
41
+ addInnerClass(innerClass: ClassMirror): ClassMirrorBuilder {
42
+ this.innerClasses.push(innerClass);
43
+ return this;
44
+ }
45
+
46
+ withExtendedClass(extendedClass: string): ClassMirrorBuilder {
47
+ this.extendedClass = extendedClass;
48
+ return this;
49
+ }
50
+
39
51
  build(): ClassMirror {
40
52
  return {
41
53
  annotations: this.annotations,
@@ -48,9 +60,10 @@ export class ClassMirrorBuilder {
48
60
  constructors: [],
49
61
  enums: [],
50
62
  interfaces: [],
51
- classes: [],
63
+ classes: this.innerClasses,
52
64
  access_modifier: 'public',
53
65
  docComment: this.docComment,
66
+ extended_class: this.extendedClass,
54
67
  };
55
68
  }
56
69
  }
@@ -6,9 +6,9 @@ export const classMarkdownTemplate = `
6
6
 
7
7
  {{> typeDocumentation}}
8
8
 
9
- {{#if extends}}
10
- **Extends**
11
- {{link extends}}
9
+ {{#if extends.length}}
10
+ **Inheritance**
11
+ {{#each extends}}{{link this}}{{#unless @last}} < {{/unless}}{{/each}}
12
12
  {{/if}}
13
13
 
14
14
  {{#if implements}}
@@ -5,7 +5,7 @@ import logUpdate from 'log-update';
5
5
  * Logs messages to the console.
6
6
  */
7
7
  export class Logger {
8
- static currentFrame = -1;
8
+ static currentFrame = 0;
9
9
 
10
10
  static frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
11
11