@cparra/apexdocs 2.9.0 → 2.10.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 (69) hide show
  1. package/README.md +111 -66
  2. package/docs/Main/nspc.GroupedClass.md +10 -0
  3. package/docs/Main/{SampleClass.md → nspc.SampleClass.md} +6 -6
  4. package/docs/Misc-Group/nspc.AnotherInterface.md +1 -0
  5. package/docs/Misc-Group/{ChildClass.md → nspc.ChildClass.md} +4 -4
  6. package/docs/Misc-Group/{GrandparentClass.md → nspc.GrandparentClass.md} +1 -1
  7. package/docs/Misc-Group/{InterfaceWithInheritance.md → nspc.InterfaceWithInheritance.md} +3 -3
  8. package/docs/Misc-Group/{ParentClass.md → nspc.ParentClass.md} +2 -2
  9. package/docs/Misc-Group/{Reference1.md → nspc.Reference1.md} +1 -1
  10. package/docs/Misc-Group/nspc.Reference2.md +12 -0
  11. package/docs/Misc-Group/{Reference3.md → nspc.Reference3.md} +1 -1
  12. package/docs/Misc-Group/{Reference4.md → nspc.Reference4.md} +1 -1
  13. package/docs/Misc-Group/{Reference5.md → nspc.Reference5.md} +1 -1
  14. package/docs/Misc-Group/{Reference6.md → nspc.Reference6.md} +1 -1
  15. package/docs/Misc-Group/{SampleClassWithoutModifier.md → nspc.SampleClassWithoutModifier.md} +1 -1
  16. package/docs/Misc-Group/{SampleRestResource.md → nspc.SampleRestResource.md} +1 -1
  17. package/docs/Misc-Group/{SampleRestResourceWithInnerClass.md → nspc.SampleRestResourceWithInnerClass.md} +1 -1
  18. package/docs/README.md +19 -19
  19. package/docs/Sample-Interfaces/{SampleInterface.md → nspc.SampleInterface.md} +1 -1
  20. package/docs/index.html +22 -22
  21. package/docs/{openapi.json → restapi.json} +12 -13
  22. package/examples/force-app/main/default/restapi/SampleRestResource.cls +0 -4
  23. package/examples/force-app/main/default/restapi/references/Reference2.cls +6 -0
  24. package/lib/cli/generate.js +12 -0
  25. package/lib/cli/generate.js.map +1 -1
  26. package/lib/model/markdown-type-file.d.ts +4 -3
  27. package/lib/model/markdown-type-file.js +13 -4
  28. package/lib/model/markdown-type-file.js.map +1 -1
  29. package/lib/model/openapi/open-api.d.ts +1 -1
  30. package/lib/model/openapi/open-api.js.map +1 -1
  31. package/lib/model/openapi/openapi-type-file.js +3 -2
  32. package/lib/model/openapi/openapi-type-file.js.map +1 -1
  33. package/lib/settings.d.ts +5 -0
  34. package/lib/settings.js +12 -0
  35. package/lib/settings.js.map +1 -1
  36. package/lib/test-helpers/DocCommentAnnotationBuilder.d.ts +2 -0
  37. package/lib/test-helpers/DocCommentAnnotationBuilder.js +6 -1
  38. package/lib/test-helpers/DocCommentAnnotationBuilder.js.map +1 -1
  39. package/lib/test-helpers/FieldMirrorBuilder.d.ts +3 -1
  40. package/lib/test-helpers/FieldMirrorBuilder.js +6 -0
  41. package/lib/test-helpers/FieldMirrorBuilder.js.map +1 -1
  42. package/lib/test-helpers/SettingsBuilder.js +1 -0
  43. package/lib/test-helpers/SettingsBuilder.js.map +1 -1
  44. package/lib/transpiler/markdown/class-file-generatorHelper.js +2 -1
  45. package/lib/transpiler/markdown/class-file-generatorHelper.js.map +1 -1
  46. package/lib/transpiler/openapi/open-api-docs-processor.d.ts +1 -0
  47. package/lib/transpiler/openapi/open-api-docs-processor.js +4 -2
  48. package/lib/transpiler/openapi/open-api-docs-processor.js.map +1 -1
  49. package/lib/transpiler/openapi/parsers/ReferenceBuilder.d.ts +2 -0
  50. package/lib/transpiler/openapi/parsers/ReferenceBuilder.js +35 -5
  51. package/lib/transpiler/openapi/parsers/ReferenceBuilder.js.map +1 -1
  52. package/package.json +5 -5
  53. package/src/cli/generate.ts +13 -0
  54. package/src/model/markdown-type-file.ts +14 -4
  55. package/src/model/openapi/open-api.ts +1 -1
  56. package/src/model/openapi/openapi-type-file.ts +3 -2
  57. package/src/service/__tests__/apex-file-reader.spec.ts +1 -0
  58. package/src/settings.ts +17 -0
  59. package/src/test-helpers/DocCommentAnnotationBuilder.ts +7 -1
  60. package/src/test-helpers/FieldMirrorBuilder.ts +8 -1
  61. package/src/test-helpers/SettingsBuilder.ts +1 -0
  62. package/src/transpiler/markdown/class-file-generatorHelper.ts +2 -1
  63. package/src/transpiler/openapi/open-api-docs-processor.ts +4 -2
  64. package/src/transpiler/openapi/parsers/ReferenceBuilder.ts +41 -5
  65. package/src/transpiler/openapi/parsers/__tests__/ReferenceBuilder.spec.ts +85 -0
  66. package/docs/API/SampleClassWithoutModifier.md +0 -11
  67. package/docs/Main/GroupedClass.md +0 -10
  68. package/docs/Misc-Group/AnotherInterface.md +0 -1
  69. package/docs/Misc-Group/Reference2.md +0 -7
package/src/settings.ts CHANGED
@@ -10,6 +10,8 @@ export interface SettingsConfig {
10
10
  defaultGroupName: string;
11
11
  sanitizeHtml: boolean;
12
12
  openApiTitle?: string;
13
+ namespace?: string;
14
+ openApiFileName: string;
13
15
  }
14
16
 
15
17
  export class Settings {
@@ -63,4 +65,19 @@ export class Settings {
63
65
  public getOpenApiTitle(): string | undefined {
64
66
  return this.config.openApiTitle;
65
67
  }
68
+
69
+ public getNamespace(): string | undefined {
70
+ return this.config.namespace;
71
+ }
72
+
73
+ public getNamespacePrefix(): string {
74
+ if (!this.config.namespace) {
75
+ return '';
76
+ }
77
+ return `${this.config.namespace}.`;
78
+ }
79
+
80
+ public openApiFileName(): string {
81
+ return this.config.openApiFileName;
82
+ }
66
83
  }
@@ -2,17 +2,23 @@ import { DocCommentAnnotation } from '@cparra/apex-reflection';
2
2
 
3
3
  export class DocCommentAnnotationBuilder {
4
4
  private name = '';
5
+ private bodyLines: string[] = [];
5
6
 
6
7
  withName(name: string): DocCommentAnnotationBuilder {
7
8
  this.name = name;
8
9
  return this;
9
10
  }
10
11
 
12
+ withBodyLines(bodyLines: string[]): DocCommentAnnotationBuilder {
13
+ this.bodyLines = bodyLines;
14
+ return this;
15
+ }
16
+
11
17
  build(): DocCommentAnnotation {
12
18
  return {
13
19
  name: this.name,
14
20
  body: '',
15
- bodyLines: [],
21
+ bodyLines: this.bodyLines,
16
22
  };
17
23
  }
18
24
  }
@@ -1,9 +1,10 @@
1
- import { FieldMirror } from '@cparra/apex-reflection';
1
+ import { DocComment, FieldMirror } from '@cparra/apex-reflection';
2
2
  import { ReferencedType } from '@cparra/apex-reflection/index';
3
3
 
4
4
  type MemberModifier = 'static' | 'webservice' | 'final' | 'override' | 'testmethod' | 'transient';
5
5
 
6
6
  export class FieldMirrorBuilder {
7
+ private docComment: DocComment | undefined = undefined;
7
8
  private accessModifier = 'public';
8
9
  private name = 'fieldName';
9
10
  private memberModifiers: MemberModifier[] = [];
@@ -40,6 +41,11 @@ export class FieldMirrorBuilder {
40
41
  return this;
41
42
  }
42
43
 
44
+ withDocComment(docComment: DocComment): FieldMirrorBuilder {
45
+ this.docComment = docComment;
46
+ return this;
47
+ }
48
+
43
49
  build(): FieldMirror {
44
50
  return {
45
51
  access_modifier: this.accessModifier,
@@ -47,6 +53,7 @@ export class FieldMirrorBuilder {
47
53
  name: this.name,
48
54
  memberModifiers: this.memberModifiers,
49
55
  typeReference: this.type,
56
+ docComment: this.docComment,
50
57
  };
51
58
  }
52
59
  }
@@ -16,6 +16,7 @@ export class SettingsBuilder {
16
16
  defaultGroupName: 'Misc',
17
17
  sanitizeHtml: true,
18
18
  openApiTitle: 'Apex API',
19
+ openApiFileName: 'openapi',
19
20
  };
20
21
  }
21
22
  }
@@ -11,7 +11,8 @@ export default class ClassFileGeneratorHelper {
11
11
 
12
12
  public static getFileLink(classModel: Type) {
13
13
  const directoryRoot = this.getDirectoryRoot(classModel);
14
- return `[${classModel.name}](${directoryRoot}${classModel.name}.md)`;
14
+ const fullClassName = `${Settings.getInstance().getNamespacePrefix()}${classModel.name}`;
15
+ return `[${fullClassName}](${directoryRoot}${fullClassName}.md)`;
15
16
  }
16
17
 
17
18
  public static getFileLinkByTypeName(typeName: string) {
@@ -18,7 +18,7 @@ export class OpenApiDocsProcessor extends ProcessorTypeTranspiler {
18
18
  if (!title) {
19
19
  throw Error('No OpenApi title was provided.');
20
20
  }
21
- this.openApiModel = new OpenApi(title, '1.0.0');
21
+ this.openApiModel = new OpenApi(title, '1.0.0', Settings.getInstance().getNamespace());
22
22
  }
23
23
 
24
24
  fileBuilder(): FileContainer {
@@ -57,9 +57,11 @@ export class OpenApiDocsProcessor extends ProcessorTypeTranspiler {
57
57
 
58
58
  // DELETE
59
59
  parser.parseMethod(typeAsClass, endpointPath, 'delete');
60
+ }
60
61
 
62
+ onAfterProcess: ((types: Type[]) => void) | undefined = () => {
61
63
  this._fileContainer.pushFile(new OpenapiTypeFile(this.openApiModel));
62
- }
64
+ };
63
65
 
64
66
  private getEndpointPath(type: Type): string | null {
65
67
  const restResourceAnnotation = type.annotations.find((element) => element.name.toLowerCase() === 'restresource');
@@ -1,3 +1,4 @@
1
+ import * as yaml from 'js-yaml';
1
2
  import {
2
3
  PropertiesObject,
3
4
  ReferenceObject,
@@ -6,8 +7,9 @@ import {
6
7
  SchemaObjectObject,
7
8
  } from '../../../model/openapi/open-api-types';
8
9
  import { TypeBundle, TypesRepository } from '../../../model/types-repository';
9
- import { ClassMirror, FieldMirror, PropertyMirror, Type } from '@cparra/apex-reflection';
10
+ import { ClassMirror, DocCommentAnnotation, FieldMirror, PropertyMirror } from '@cparra/apex-reflection';
10
11
  import { ListObjectType, ReferencedType } from '@cparra/apex-reflection/index';
12
+ import { ApexDocSchemaObject } from '../../../model/openapi/apex-doc-types';
11
13
 
12
14
  type TypeBundleWithIsCollection = TypeBundle & { isCollection: boolean };
13
15
 
@@ -64,12 +66,20 @@ export class ReferenceBuilder {
64
66
  const properties: PropertiesObject = {};
65
67
  let referencedComponents: ReferenceComponent[] = [];
66
68
  propertiesAndFields.forEach((current) => {
67
- const pair = this.getReferenceType(current.typeReference);
68
- properties[current.name] = pair.schema;
69
+ // Check for "@http-schema" annotations within properties themselves. If these are specified they
70
+ // take precedence over the property type itself.
71
+ const manuallyDefinedHttpSchema = current.docComment?.annotations.find(
72
+ (annotation) => annotation.name.toLowerCase() === 'http-schema',
73
+ );
74
+ if (manuallyDefinedHttpSchema) {
75
+ this.handleOverriddenSchema(manuallyDefinedHttpSchema, properties, current, referencedComponents);
76
+ } else {
77
+ const pair = this.getReferenceType(current.typeReference);
78
+ properties[current.name] = pair.schema;
79
+ pair.referenceComponents.forEach((current) => referencedComponents.push(current));
80
+ }
69
81
  properties[current.name].description = current.docComment?.description;
70
- pair.referenceComponents.forEach((current) => referencedComponents.push(current));
71
82
  });
72
-
73
83
  const mainReferenceComponents = this.buildMainReferenceComponent(typeBundle, properties);
74
84
 
75
85
  // Make sure to add the "main" reference first
@@ -83,6 +93,28 @@ export class ReferenceBuilder {
83
93
  };
84
94
  }
85
95
 
96
+ private handleOverriddenSchema(
97
+ manuallyDefinedHttpSchema: DocCommentAnnotation,
98
+ properties: PropertiesObject,
99
+ current: FieldMirror | PropertyMirror,
100
+ referencedComponents: ReferenceComponent[],
101
+ ) {
102
+ // This can be of type ApexDocSchemaObject
103
+ const inYaml = manuallyDefinedHttpSchema?.bodyLines.reduce((prev, current, _) => prev + '\n' + current);
104
+ const asJson = yaml.load(inYaml) as ApexDocSchemaObject;
105
+ const isReference = this.isReferenceString(asJson);
106
+
107
+ if (isReference) {
108
+ const reference = this.build(asJson);
109
+ properties[current.name] = reference.entrypointReferenceObject;
110
+ reference.referenceComponents.forEach((current) => referencedComponents.push(current));
111
+ } else {
112
+ // If we are dealing with a manually defined schema object, we can add it directly to the "properties" map,
113
+ // because we don't need to add a reference component.
114
+ properties[current.name] = asJson;
115
+ }
116
+ }
117
+
86
118
  private getReferenceName(typeBundle: TypeBundleWithIsCollection): string {
87
119
  let referenceName = typeBundle.type.name;
88
120
  if (typeBundle.isChild) {
@@ -180,6 +212,10 @@ export class ReferenceBuilder {
180
212
  referenceComponents: [...innerReference.referenceComponents],
181
213
  };
182
214
  }
215
+
216
+ private isReferenceString = (targetObject: any): targetObject is string => {
217
+ return typeof targetObject === 'string' || targetObject instanceof String;
218
+ };
183
219
  }
184
220
 
185
221
  type SchemaObjectReferencePair = {
@@ -3,6 +3,8 @@ import { ReferenceBuilder } from '../ReferenceBuilder';
3
3
  import { ClassMirrorBuilder } from '../../../../test-helpers/ClassMirrorBuilder';
4
4
  import { FieldMirrorBuilder } from '../../../../test-helpers/FieldMirrorBuilder';
5
5
  import { SchemaObjectArray, SchemaObjectObject } from '../../../../model/openapi/open-api-types';
6
+ import { DocCommentBuilder } from '../../../../test-helpers/DocCommentBuilder';
7
+ import { DocCommentAnnotationBuilder } from '../../../../test-helpers/DocCommentAnnotationBuilder';
6
8
 
7
9
  describe('ReferenceBuilder', () => {
8
10
  describe('Validation', () => {
@@ -619,4 +621,87 @@ describe('ReferenceBuilder', () => {
619
621
  expect((result.referenceComponents[1].schema as SchemaObjectObject).properties).toHaveProperty('fieldName');
620
622
  });
621
623
  });
624
+
625
+ describe('References can override their type', () => {
626
+ it("should correctly parse a manually defined schema in the reference's ApexDoc", function () {
627
+ const classMirror = new ClassMirrorBuilder()
628
+ .addFiled(
629
+ new FieldMirrorBuilder()
630
+ .withName('fieldName')
631
+ .withType('Object')
632
+ .withDocComment(
633
+ new DocCommentBuilder()
634
+ .addAnnotation(
635
+ new DocCommentAnnotationBuilder().withName('http-schema').withBodyLines(['type: string']).build(),
636
+ )
637
+ .build(),
638
+ )
639
+ .build(),
640
+ )
641
+ .build();
642
+
643
+ TypesRepository.getInstance = jest.fn().mockReturnValue({
644
+ getFromAllByName: jest.fn().mockReturnValue({ type: classMirror, isChild: false }),
645
+ });
646
+
647
+ const result = new ReferenceBuilder().build('className');
648
+
649
+ const schema = result.referenceComponents[0].schema as SchemaObjectObject;
650
+ expect(schema.properties).toHaveProperty('fieldName');
651
+ const fieldSchema = schema.properties!['fieldName'] as SchemaObjectObject;
652
+ expect(fieldSchema.type).toBe('string');
653
+ });
654
+
655
+ it('should correctly parse a manually defined reference while parsing properties', function () {
656
+ const mainClassMirror = new ClassMirrorBuilder()
657
+ .withName('parent')
658
+ .addFiled(
659
+ new FieldMirrorBuilder()
660
+ .withName('childClassMember')
661
+ .withType('Object')
662
+ .withDocComment(
663
+ new DocCommentBuilder()
664
+ .addAnnotation(
665
+ new DocCommentAnnotationBuilder().withName('http-schema').withBodyLines(['ChildClass']).build(),
666
+ )
667
+ .build(),
668
+ )
669
+ .build(),
670
+ )
671
+ .build();
672
+
673
+ const childClass = new ClassMirrorBuilder()
674
+ .withName('child')
675
+ .addFiled(
676
+ new FieldMirrorBuilder()
677
+ .withName('grandChildClassMember')
678
+ .withReferencedType({
679
+ type: 'GrandChildClass',
680
+ rawDeclaration: 'GrandChildClass',
681
+ })
682
+ .build(),
683
+ )
684
+ .build();
685
+
686
+ const grandChildClass = new ClassMirrorBuilder()
687
+ .withName('grandchild')
688
+ .addFiled(new FieldMirrorBuilder().withName('stringMember').withType('String').build())
689
+ .build();
690
+
691
+ TypesRepository.getInstance = jest.fn().mockReturnValue({
692
+ getFromAllByName: jest
693
+ .fn()
694
+ .mockReturnValueOnce({ type: mainClassMirror, isChild: false })
695
+ .mockReturnValueOnce({ type: childClass, isChild: false })
696
+ .mockReturnValueOnce({ type: grandChildClass, isChild: false }),
697
+ });
698
+
699
+ const result = new ReferenceBuilder().build('className');
700
+
701
+ expect(result.referenceComponents).toHaveLength(3);
702
+ expect(result.referenceComponents.some((ref) => ref.referencedClass === 'parent')).toBe(true);
703
+ expect(result.referenceComponents.some((ref) => ref.referencedClass === 'child')).toBe(true);
704
+ expect(result.referenceComponents.some((ref) => ref.referencedClass === 'grandchild')).toBe(true);
705
+ });
706
+ });
622
707
  });
@@ -1,11 +0,0 @@
1
- # SampleClassWithoutModifier
2
-
3
- `ISTEST`
4
- ## Methods
5
- ### `static thisIsAClassWithoutAModifier()`
6
-
7
- `ISTEST`
8
-
9
- This is a test method
10
-
11
- ---
@@ -1,10 +0,0 @@
1
- # GroupedClass
2
-
3
- Uses a block style apex doc
4
-
5
-
6
- **Group** Main
7
-
8
-
9
- **Test Class** [SampleClass](/Main/SampleClass.md)
10
-
@@ -1 +0,0 @@
1
- # AnotherInterface
@@ -1,7 +0,0 @@
1
- # Reference2
2
- ## Fields
3
-
4
- ### `stringMember` → `String`
5
-
6
-
7
- ---