@cparra/apexdocs 2.25.0-alpha.6 → 2.25.0-alpha.9
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/dist/cli/generate.js +192 -225
- package/dist/index.d.ts +51 -13
- package/examples/plain-markdown/docs/index.md +25 -33
- package/examples/plain-markdown/docs/{Miscellaneous/ns.BaseClass.md → miscellaneous/BaseClass.md} +1 -1
- package/examples/plain-markdown/docs/{Miscellaneous/ns.MultiInheritanceClass.md → miscellaneous/MultiInheritanceClass.md} +5 -6
- package/examples/plain-markdown/docs/{Miscellaneous/ns.SampleException.md → miscellaneous/SampleException.md} +3 -4
- package/examples/plain-markdown/docs/{Miscellaneous/ns.SampleInterface.md → miscellaneous/SampleInterface.md} +22 -29
- package/examples/plain-markdown/docs/{Miscellaneous/ns.Url.md → miscellaneous/Url.md} +32 -43
- package/examples/plain-markdown/docs/sample-enums/SampleEnum.md +36 -0
- package/examples/plain-markdown/docs/{SampleGroup/ns.SampleClass.md → samplegroup/SampleClass.md} +8 -11
- package/examples/vitepress/apexdocs.config.ts +1 -3
- package/examples/vitepress/docs/.vitepress/sidebar.json +18 -18
- package/examples/vitepress/docs/index.md +11 -82
- package/examples/vitepress/docs/{Miscellaneous/apexdocs.BaseClass.md → miscellaneous/BaseClass.md} +1 -1
- package/examples/vitepress/docs/{Miscellaneous/apexdocs.MultiInheritanceClass.md → miscellaneous/MultiInheritanceClass.md} +4 -6
- package/examples/vitepress/docs/{Miscellaneous/apexdocs.SampleException.md → miscellaneous/SampleException.md} +1 -1
- package/examples/vitepress/docs/{Miscellaneous/apexdocs.SampleInterface.md → miscellaneous/SampleInterface.md} +22 -28
- package/examples/vitepress/docs/{Miscellaneous/apexdocs.Url.md → miscellaneous/Url.md} +31 -32
- package/examples/vitepress/docs/sample-enums/SampleEnum.md +40 -0
- package/examples/vitepress/docs/{SampleGroup/apexdocs.SampleClass.md → samplegroup/SampleClass.md} +6 -10
- package/examples/vitepress/force-app/main/default/classes/Url.cls +7 -4
- package/package.json +1 -1
- package/src/application/apex-file-reader.ts +3 -3
- package/src/application/file-writer.ts +5 -9
- package/src/application/generators/markdown.ts +9 -4
- package/src/application/generators/openapi.ts +4 -4
- package/src/core/markdown/__test__/generating-class-docs.spec.ts +11 -3
- package/src/core/markdown/__test__/generating-enum-docs.spec.ts +7 -3
- package/src/core/markdown/__test__/generating-interface-docs.spec.ts +11 -3
- package/src/core/markdown/__test__/generating-reference-guide.spec.ts +3 -7
- package/src/core/markdown/__test__/test-helpers.ts +3 -3
- package/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts +40 -5
- package/src/core/markdown/adapters/apex-types.ts +3 -2
- package/src/core/markdown/adapters/documentables.ts +49 -68
- package/src/core/markdown/adapters/reference-guide.ts +35 -0
- package/src/core/markdown/adapters/renderable-bundle.ts +43 -119
- package/src/core/markdown/adapters/renderable-to-page-data.ts +12 -15
- package/src/core/markdown/adapters/types.d.ts +5 -8
- package/src/core/markdown/generate-docs.ts +99 -42
- package/src/core/markdown/reflection/inheritance-chain-expanion.ts +1 -1
- package/src/core/markdown/reflection/reflect-source.ts +8 -4
- package/src/core/markdown/templates/documentable-partial-template.ts +1 -1
- package/src/core/openapi/manifest-factory.ts +2 -2
- package/src/core/openapi/openapi-type-file.ts +1 -3
- package/src/core/openapi/parser.ts +4 -4
- package/src/core/shared/types.d.ts +52 -14
- package/src/index.ts +2 -1
- package/examples/plain-markdown/docs/Sample-Enums/ns.SampleEnum.md +0 -38
- package/examples/vitepress/docs/Sample-Enums/apexdocs.SampleEnum.md +0 -41
- /package/examples/plain-markdown/docs/{Miscellaneous/ns.ParentInterface.md → miscellaneous/ParentInterface.md} +0 -0
- /package/examples/plain-markdown/docs/{Miscellaneous/ns.ReferencedEnum.md → miscellaneous/ReferencedEnum.md} +0 -0
- /package/examples/vitepress/docs/{Miscellaneous/apexdocs.ParentInterface.md → miscellaneous/ParentInterface.md} +0 -0
- /package/examples/vitepress/docs/{Miscellaneous/apexdocs.ReferencedEnum.md → miscellaneous/ReferencedEnum.md} +0 -0
|
@@ -5,21 +5,17 @@ import { PageData } from '../core/shared/types';
|
|
|
5
5
|
export class FileWriter {
|
|
6
6
|
static write(files: PageData[], outputDir: string, onWriteCallback: (file: PageData) => void) {
|
|
7
7
|
files.forEach((file) => {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const filePath = path.join(resolvedFile.directory, `${resolvedFile.fileName}.${resolvedFile.fileExtension}`);
|
|
14
|
-
fs.writeFileSync(filePath, resolvedFile.content, 'utf8');
|
|
15
|
-
onWriteCallback(resolvedFile);
|
|
8
|
+
const { filePath, content } = this.getTargetLocation(file, outputDir);
|
|
9
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
10
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
11
|
+
onWriteCallback(file);
|
|
16
12
|
});
|
|
17
13
|
}
|
|
18
14
|
|
|
19
15
|
private static getTargetLocation(file: PageData, outputDir: string): PageData {
|
|
20
16
|
return {
|
|
21
17
|
...file,
|
|
22
|
-
|
|
18
|
+
filePath: path.join(outputDir, file.filePath),
|
|
23
19
|
};
|
|
24
20
|
}
|
|
25
21
|
}
|
|
@@ -2,13 +2,18 @@ import { generateDocs } from '../../core/markdown/generate-docs';
|
|
|
2
2
|
import { FileWriter } from '../file-writer';
|
|
3
3
|
import { Logger } from '#utils/logger';
|
|
4
4
|
import { pipe } from 'fp-ts/function';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
PageData,
|
|
7
|
+
PostHookDocumentationBundle,
|
|
8
|
+
UnparsedSourceFile,
|
|
9
|
+
UserDefinedMarkdownConfig,
|
|
10
|
+
} from '../../core/shared/types';
|
|
6
11
|
import { ReflectionError } from '../../core/markdown/reflection/error-handling';
|
|
7
12
|
import { referenceGuideTemplate } from '../../core/markdown/templates/reference-guide';
|
|
8
13
|
import * as TE from 'fp-ts/TaskEither';
|
|
9
14
|
import { isSkip } from '../../core/shared/utils';
|
|
10
15
|
|
|
11
|
-
export default function generate(bundles:
|
|
16
|
+
export default function generate(bundles: UnparsedSourceFile[], config: UserDefinedMarkdownConfig) {
|
|
12
17
|
return pipe(
|
|
13
18
|
generateDocumentationBundle(bundles, config),
|
|
14
19
|
TE.map((files) => writeFilesToSystem(files, config.targetDir)),
|
|
@@ -29,7 +34,7 @@ export default function generate(bundles: SourceFile[], config: UserDefinedMarkd
|
|
|
29
34
|
)();
|
|
30
35
|
}
|
|
31
36
|
|
|
32
|
-
function generateDocumentationBundle(bundles:
|
|
37
|
+
function generateDocumentationBundle(bundles: UnparsedSourceFile[], config: UserDefinedMarkdownConfig) {
|
|
33
38
|
return generateDocs(bundles, {
|
|
34
39
|
...config,
|
|
35
40
|
referenceGuideTemplate: referenceGuideTemplate,
|
|
@@ -43,7 +48,7 @@ function writeFilesToSystem(files: PostHookDocumentationBundle, outputDir: strin
|
|
|
43
48
|
.filter((file) => !isSkip(file)) as PageData[],
|
|
44
49
|
outputDir,
|
|
45
50
|
(file: PageData) => {
|
|
46
|
-
Logger.logSingle(`${file.
|
|
51
|
+
Logger.logSingle(`${file.filePath} processed.`, false, 'green', false);
|
|
47
52
|
},
|
|
48
53
|
);
|
|
49
54
|
}
|
|
@@ -7,10 +7,10 @@ import { Logger } from '#utils/logger';
|
|
|
7
7
|
import ErrorLogger from '#utils/error-logger';
|
|
8
8
|
import { reflect, ReflectionResult } from '@cparra/apex-reflection';
|
|
9
9
|
import Manifest from '../../core/manifest';
|
|
10
|
-
import { PageData,
|
|
10
|
+
import { PageData, UnparsedSourceFile, UserDefinedOpenApiConfig } from '../../core/shared/types';
|
|
11
11
|
import { OpenApiDocsProcessor } from '../../core/openapi/open-api-docs-processor';
|
|
12
12
|
|
|
13
|
-
export default function openApi(fileBodies:
|
|
13
|
+
export default function openApi(fileBodies: UnparsedSourceFile[], config: UserDefinedOpenApiConfig) {
|
|
14
14
|
const manifest = createManifest(new RawBodyParser(fileBodies), reflectionWithLogger);
|
|
15
15
|
TypesRepository.getInstance().populateAll(manifest.types);
|
|
16
16
|
const filteredTypes = filterByScopes(manifest);
|
|
@@ -19,14 +19,14 @@ export default function openApi(fileBodies: SourceFile[], config: UserDefinedOpe
|
|
|
19
19
|
const generatedFiles = processor.fileBuilder().files();
|
|
20
20
|
|
|
21
21
|
FileWriter.write(generatedFiles, config.targetDir, (file: PageData) => {
|
|
22
|
-
Logger.logSingle(`${file.
|
|
22
|
+
Logger.logSingle(`${file.filePath} processed.`, false, 'green', false);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
// Error logging
|
|
26
26
|
ErrorLogger.logErrors(filteredTypes);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
function reflectionWithLogger(apexBundle:
|
|
29
|
+
function reflectionWithLogger(apexBundle: UnparsedSourceFile): ReflectionResult {
|
|
30
30
|
const result = reflect(apexBundle.content);
|
|
31
31
|
if (result.error) {
|
|
32
32
|
Logger.error(`${apexBundle.filePath} - Parsing error ${result.error?.message}`);
|
|
@@ -12,7 +12,7 @@ describe('Generates interface documentation', () => {
|
|
|
12
12
|
|
|
13
13
|
const result = await generateDocs([apexBundleFromRawString(input)])();
|
|
14
14
|
expect(result).documentationBundleHasLength(1);
|
|
15
|
-
assertEither(result, (data) => expect(data.docs[0].
|
|
15
|
+
assertEither(result, (data) => expect(data.docs[0].filePath).toContain('MyClass'));
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
it('returns the type as class', async () => {
|
|
@@ -268,7 +268,9 @@ describe('Generates interface documentation', () => {
|
|
|
268
268
|
const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
|
|
269
269
|
expect(result).documentationBundleHasLength(2);
|
|
270
270
|
assertEither(result, (data) =>
|
|
271
|
-
expect(data).firstDocContains(
|
|
271
|
+
expect(data).firstDocContains(
|
|
272
|
+
'This is a description with a [ClassRef](/miscellaneous/ClassRef.md) reference',
|
|
273
|
+
),
|
|
272
274
|
);
|
|
273
275
|
});
|
|
274
276
|
|
|
@@ -302,7 +304,7 @@ describe('Generates interface documentation', () => {
|
|
|
302
304
|
const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
|
|
303
305
|
expect(result).documentationBundleHasLength(2);
|
|
304
306
|
assertEither(result, (data) => expect(data).firstDocContains('See'));
|
|
305
|
-
assertEither(result, (data) => expect(data).firstDocContains('[ClassRef](
|
|
307
|
+
assertEither(result, (data) => expect(data).firstDocContains('[ClassRef](/miscellaneous/ClassRef.md)'));
|
|
306
308
|
});
|
|
307
309
|
|
|
308
310
|
it('displays sees without links when the reference is not found', async () => {
|
|
@@ -340,11 +342,13 @@ describe('Generates interface documentation', () => {
|
|
|
340
342
|
const input = `
|
|
341
343
|
/**
|
|
342
344
|
* @mermaid
|
|
345
|
+
* \`\`\`mermaid
|
|
343
346
|
* graph TD
|
|
344
347
|
* A[Square Rect] -- Link text --> B((Circle))
|
|
345
348
|
* A --> C(Round Rect)
|
|
346
349
|
* B --> D{Rhombus}
|
|
347
350
|
* C --> D
|
|
351
|
+
* \`\`\`
|
|
348
352
|
*/
|
|
349
353
|
public class MyClass {}
|
|
350
354
|
`;
|
|
@@ -359,11 +363,13 @@ describe('Generates interface documentation', () => {
|
|
|
359
363
|
const input = `
|
|
360
364
|
/**
|
|
361
365
|
* @example
|
|
366
|
+
* \`\`\`apex
|
|
362
367
|
* public class MyClass {
|
|
363
368
|
* public void myMethod() {
|
|
364
369
|
* System.debug('Hello, World!');
|
|
365
370
|
* }
|
|
366
371
|
* }
|
|
372
|
+
* \`\`\`
|
|
367
373
|
*/
|
|
368
374
|
public class MyClass {}`;
|
|
369
375
|
|
|
@@ -669,11 +675,13 @@ describe('Generates interface documentation', () => {
|
|
|
669
675
|
public class MyClass {
|
|
670
676
|
/**
|
|
671
677
|
* @mermaid
|
|
678
|
+
* \`\`\`mermaid
|
|
672
679
|
* graph TD
|
|
673
680
|
* A[Square Rect] -- Link text --> B((Circle))
|
|
674
681
|
* A --> C(Round Rect)
|
|
675
682
|
* B --> D{Rhombus}
|
|
676
683
|
* C --> D
|
|
684
|
+
* \`\`\`
|
|
677
685
|
*/
|
|
678
686
|
public void myMethod() {}
|
|
679
687
|
}
|
|
@@ -17,7 +17,7 @@ describe('Generates enum documentation', () => {
|
|
|
17
17
|
|
|
18
18
|
const result = await generateDocs([apexBundleFromRawString(input)])();
|
|
19
19
|
expect(result).documentationBundleHasLength(1);
|
|
20
|
-
assertEither(result, (data) => expect(data.docs[0].
|
|
20
|
+
assertEither(result, (data) => expect(data.docs[0].filePath).toContain('MyEnum'));
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
it('returns the type as enum', async () => {
|
|
@@ -211,7 +211,7 @@ describe('Generates enum documentation', () => {
|
|
|
211
211
|
expect(result).documentationBundleHasLength(2);
|
|
212
212
|
assertEither(result, (data) => expect(data).firstDocContains('Description'));
|
|
213
213
|
assertEither(result, (data) =>
|
|
214
|
-
expect(data).firstDocContains('This is a description with a [EnumRef](
|
|
214
|
+
expect(data).firstDocContains('This is a description with a [EnumRef](/miscellaneous/EnumRef.md) reference'),
|
|
215
215
|
);
|
|
216
216
|
});
|
|
217
217
|
|
|
@@ -245,7 +245,7 @@ describe('Generates enum documentation', () => {
|
|
|
245
245
|
const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
|
|
246
246
|
expect(result).documentationBundleHasLength(2);
|
|
247
247
|
assertEither(result, (data) => expect(data).firstDocContains('See'));
|
|
248
|
-
assertEither(result, (data) => expect(data).firstDocContains('[EnumRef](
|
|
248
|
+
assertEither(result, (data) => expect(data).firstDocContains('[EnumRef](/miscellaneous/EnumRef.md)'));
|
|
249
249
|
});
|
|
250
250
|
|
|
251
251
|
it('displays sees without links when the reference is not found', async () => {
|
|
@@ -287,11 +287,13 @@ describe('Generates enum documentation', () => {
|
|
|
287
287
|
const input = `
|
|
288
288
|
/**
|
|
289
289
|
* @mermaid
|
|
290
|
+
* \`\`\`mermaid
|
|
290
291
|
* graph TD
|
|
291
292
|
* A[Square Rect] -- Link text --> B((Circle))
|
|
292
293
|
* A --> C(Round Rect)
|
|
293
294
|
* B --> D{Rhombus}
|
|
294
295
|
* C --> D
|
|
296
|
+
* \`\`\`
|
|
295
297
|
*/
|
|
296
298
|
public enum MyEnum {
|
|
297
299
|
VALUE1,
|
|
@@ -309,11 +311,13 @@ describe('Generates enum documentation', () => {
|
|
|
309
311
|
const input = `
|
|
310
312
|
/**
|
|
311
313
|
* @example
|
|
314
|
+
* \`\`\`apex
|
|
312
315
|
* public class MyClass {
|
|
313
316
|
* public void myMethod() {
|
|
314
317
|
* System.debug('Hello, World!');
|
|
315
318
|
* }
|
|
316
319
|
* }
|
|
320
|
+
* \`\`\`
|
|
317
321
|
*/
|
|
318
322
|
public enum MyEnum {
|
|
319
323
|
VALUE1,
|
|
@@ -189,7 +189,9 @@ describe('Generates interface documentation', () => {
|
|
|
189
189
|
const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
|
|
190
190
|
expect(result).documentationBundleHasLength(2);
|
|
191
191
|
assertEither(result, (data) =>
|
|
192
|
-
expect(data).firstDocContains(
|
|
192
|
+
expect(data).firstDocContains(
|
|
193
|
+
'This is a description with a [InterfaceRef](/miscellaneous/InterfaceRef.md) reference',
|
|
194
|
+
),
|
|
193
195
|
);
|
|
194
196
|
});
|
|
195
197
|
|
|
@@ -223,7 +225,7 @@ describe('Generates interface documentation', () => {
|
|
|
223
225
|
const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
|
|
224
226
|
expect(result).documentationBundleHasLength(2);
|
|
225
227
|
assertEither(result, (data) => expect(data).firstDocContains('See'));
|
|
226
|
-
assertEither(result, (data) => expect(data).firstDocContains('[InterfaceRef](
|
|
228
|
+
assertEither(result, (data) => expect(data).firstDocContains('[InterfaceRef](/miscellaneous/InterfaceRef.md)'));
|
|
227
229
|
});
|
|
228
230
|
|
|
229
231
|
it('displays sees without links when the reference is not found', async () => {
|
|
@@ -261,11 +263,13 @@ describe('Generates interface documentation', () => {
|
|
|
261
263
|
const input = `
|
|
262
264
|
/**
|
|
263
265
|
* @mermaid
|
|
266
|
+
* \`\`\`mermaid
|
|
264
267
|
* graph TD
|
|
265
268
|
* A[Square Rect] -- Link text --> B((Circle))
|
|
266
269
|
* A --> C(Round Rect)
|
|
267
270
|
* B --> D{Rhombus}
|
|
268
271
|
* C --> D
|
|
272
|
+
* \`\`\`
|
|
269
273
|
*/
|
|
270
274
|
public interface MyInterface {}
|
|
271
275
|
`;
|
|
@@ -280,11 +284,13 @@ describe('Generates interface documentation', () => {
|
|
|
280
284
|
const input = `
|
|
281
285
|
/**
|
|
282
286
|
* @example
|
|
287
|
+
* \`\`\`apex
|
|
283
288
|
* public class MyClass {
|
|
284
289
|
* public void myMethod() {
|
|
285
290
|
* System.debug('Hello, World!');
|
|
286
291
|
* }
|
|
287
292
|
* }
|
|
293
|
+
* \`\`\`
|
|
288
294
|
*/
|
|
289
295
|
public interface MyInterface {}`;
|
|
290
296
|
|
|
@@ -343,11 +349,13 @@ describe('Generates interface documentation', () => {
|
|
|
343
349
|
public interface MyInterface {
|
|
344
350
|
/**
|
|
345
351
|
* @mermaid
|
|
352
|
+
* \`\`\`mermaid
|
|
346
353
|
* graph TD
|
|
347
354
|
* A[Square Rect] -- Link text --> B((Circle))
|
|
348
355
|
* A --> C(Round Rect)
|
|
349
356
|
* B --> D{Rhombus}
|
|
350
357
|
* C --> D
|
|
358
|
+
* \`\`\`
|
|
351
359
|
*/
|
|
352
360
|
void myMethod();
|
|
353
361
|
}
|
|
@@ -445,7 +453,7 @@ describe('Generates interface documentation', () => {
|
|
|
445
453
|
const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
|
|
446
454
|
expect(result).documentationBundleHasLength(2);
|
|
447
455
|
assertEither(result, (data) =>
|
|
448
|
-
expect(data.docs.find((doc) => doc.
|
|
456
|
+
expect(data.docs.find((doc) => doc.filePath.includes('AnotherInterface'))?.content).toContain('Inherited'),
|
|
449
457
|
);
|
|
450
458
|
});
|
|
451
459
|
});
|
|
@@ -25,12 +25,10 @@ describe('Generates a Reference Guide', () => {
|
|
|
25
25
|
expect(result).documentationBundleHasLength(2);
|
|
26
26
|
|
|
27
27
|
assertEither(result, (data) =>
|
|
28
|
-
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('[MyEnum](
|
|
28
|
+
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('[MyEnum](/miscellaneous/MyEnum.md)'),
|
|
29
29
|
);
|
|
30
30
|
assertEither(result, (data) =>
|
|
31
|
-
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain(
|
|
32
|
-
'[MyClass](./Miscellaneous/MyClass.md)',
|
|
33
|
-
),
|
|
31
|
+
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('[MyClass](/miscellaneous/MyClass.md)'),
|
|
34
32
|
);
|
|
35
33
|
});
|
|
36
34
|
|
|
@@ -176,9 +174,7 @@ describe('Generates a Reference Guide', () => {
|
|
|
176
174
|
const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
|
|
177
175
|
expect(result).documentationBundleHasLength(2);
|
|
178
176
|
assertEither(result, (data) =>
|
|
179
|
-
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain(
|
|
180
|
-
'with a [MyClass](./Group2/MyClass.md)',
|
|
181
|
-
),
|
|
177
|
+
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('with a [MyClass](/group2/MyClass.md)'),
|
|
182
178
|
);
|
|
183
179
|
});
|
|
184
180
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UnparsedSourceFile } from '../../shared/types';
|
|
2
2
|
import { generateDocs as gen, MarkdownGeneratorConfig } from '../generate-docs';
|
|
3
3
|
import { referenceGuideTemplate } from '../templates/reference-guide';
|
|
4
4
|
|
|
5
|
-
export function apexBundleFromRawString(raw: string, rawMetadata?: string):
|
|
5
|
+
export function apexBundleFromRawString(raw: string, rawMetadata?: string): UnparsedSourceFile {
|
|
6
6
|
return {
|
|
7
7
|
filePath: 'test.cls',
|
|
8
8
|
content: raw,
|
|
@@ -10,7 +10,7 @@ export function apexBundleFromRawString(raw: string, rawMetadata?: string): Sour
|
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export function generateDocs(apexBundles:
|
|
13
|
+
export function generateDocs(apexBundles: UnparsedSourceFile[], config?: Partial<MarkdownGeneratorConfig>) {
|
|
14
14
|
return gen(apexBundles, {
|
|
15
15
|
targetDir: 'target',
|
|
16
16
|
scope: ['global', 'public'],
|
|
@@ -21,7 +21,14 @@ describe('Conversion from InterfaceMirror to InterfaceSource understandable by t
|
|
|
21
21
|
it('converts the name', () => {
|
|
22
22
|
const interfaceMirror = new InterfaceMirrorBuilder().withName('SampleInterface').build();
|
|
23
23
|
const interfaceSource = typeToRenderable(
|
|
24
|
-
{
|
|
24
|
+
{
|
|
25
|
+
source: {
|
|
26
|
+
filePath: '',
|
|
27
|
+
type: 'interface',
|
|
28
|
+
name: 'SampleInterface',
|
|
29
|
+
},
|
|
30
|
+
type: interfaceMirror,
|
|
31
|
+
},
|
|
25
32
|
linkGenerator,
|
|
26
33
|
defaultMarkdownGeneratorConfig,
|
|
27
34
|
);
|
|
@@ -32,7 +39,14 @@ describe('Conversion from InterfaceMirror to InterfaceSource understandable by t
|
|
|
32
39
|
it('converts the access modifier', () => {
|
|
33
40
|
const interfaceMirror = new InterfaceMirrorBuilder().build();
|
|
34
41
|
const interfaceSource = typeToRenderable(
|
|
35
|
-
{
|
|
42
|
+
{
|
|
43
|
+
source: {
|
|
44
|
+
filePath: '',
|
|
45
|
+
type: 'interface',
|
|
46
|
+
name: 'SampleInterface',
|
|
47
|
+
},
|
|
48
|
+
type: interfaceMirror,
|
|
49
|
+
},
|
|
36
50
|
linkGenerator,
|
|
37
51
|
defaultMarkdownGeneratorConfig,
|
|
38
52
|
);
|
|
@@ -45,7 +59,14 @@ describe('Conversion from InterfaceMirror to InterfaceSource understandable by t
|
|
|
45
59
|
.addAnnotation(new AnnotationBuilder().withName('MyAnnotation').build())
|
|
46
60
|
.build();
|
|
47
61
|
const interfaceSource = typeToRenderable(
|
|
48
|
-
{
|
|
62
|
+
{
|
|
63
|
+
source: {
|
|
64
|
+
filePath: '',
|
|
65
|
+
type: 'interface',
|
|
66
|
+
name: 'SampleInterface',
|
|
67
|
+
},
|
|
68
|
+
type: interfaceMirror,
|
|
69
|
+
},
|
|
49
70
|
linkGenerator,
|
|
50
71
|
defaultMarkdownGeneratorConfig,
|
|
51
72
|
);
|
|
@@ -67,7 +88,14 @@ describe('Conversion from InterfaceMirror to InterfaceSource understandable by t
|
|
|
67
88
|
.build();
|
|
68
89
|
|
|
69
90
|
const interfaceSource = typeToRenderable(
|
|
70
|
-
{
|
|
91
|
+
{
|
|
92
|
+
source: {
|
|
93
|
+
filePath: '',
|
|
94
|
+
type: 'interface',
|
|
95
|
+
name: 'SampleInterface',
|
|
96
|
+
},
|
|
97
|
+
type: interfaceMirror,
|
|
98
|
+
},
|
|
71
99
|
linkGenerator,
|
|
72
100
|
defaultMarkdownGeneratorConfig,
|
|
73
101
|
);
|
|
@@ -99,7 +127,14 @@ describe('Conversion from InterfaceMirror to InterfaceSource understandable by t
|
|
|
99
127
|
.build();
|
|
100
128
|
|
|
101
129
|
const interfaceSource = typeToRenderable(
|
|
102
|
-
{
|
|
130
|
+
{
|
|
131
|
+
source: {
|
|
132
|
+
filePath: '',
|
|
133
|
+
type: 'interface',
|
|
134
|
+
name: 'SampleInterface',
|
|
135
|
+
},
|
|
136
|
+
type: interfaceMirror,
|
|
137
|
+
},
|
|
103
138
|
linkGenerator,
|
|
104
139
|
defaultMarkdownGeneratorConfig,
|
|
105
140
|
);
|
|
@@ -15,6 +15,7 @@ import { adaptDescribable, adaptDocumentable } from './documentables';
|
|
|
15
15
|
import { adaptConstructor, adaptMethod } from './methods-and-constructors';
|
|
16
16
|
import { adaptFieldOrProperty } from './fields-and-properties';
|
|
17
17
|
import { MarkdownGeneratorConfig } from '../generate-docs';
|
|
18
|
+
import { SourceFileMetadata } from '../../shared/types';
|
|
18
19
|
|
|
19
20
|
type GetReturnRenderable<T extends Type> = T extends InterfaceMirror
|
|
20
21
|
? RenderableInterface
|
|
@@ -23,7 +24,7 @@ type GetReturnRenderable<T extends Type> = T extends InterfaceMirror
|
|
|
23
24
|
: RenderableEnum;
|
|
24
25
|
|
|
25
26
|
export function typeToRenderable<T extends Type>(
|
|
26
|
-
parsedFile: {
|
|
27
|
+
parsedFile: { source: SourceFileMetadata; type: T },
|
|
27
28
|
linkGenerator: GetRenderableContentByTypeName,
|
|
28
29
|
config: MarkdownGeneratorConfig,
|
|
29
30
|
): GetReturnRenderable<T> & { filePath: string; namespace?: string } {
|
|
@@ -41,7 +42,7 @@ export function typeToRenderable<T extends Type>(
|
|
|
41
42
|
|
|
42
43
|
return {
|
|
43
44
|
...(getRenderable() as GetReturnRenderable<T>),
|
|
44
|
-
filePath: parsedFile.filePath,
|
|
45
|
+
filePath: parsedFile.source.filePath,
|
|
45
46
|
namespace: config.namespace,
|
|
46
47
|
};
|
|
47
48
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CustomTag, RenderableDocumentation, RenderableContent
|
|
1
|
+
import { CustomTag, RenderableDocumentation, RenderableContent } from './types';
|
|
2
2
|
import { Describable, Documentable, GetRenderableContentByTypeName } from './types';
|
|
3
3
|
import { replaceInlineReferences } from './inline';
|
|
4
4
|
import { isEmptyLine } from './type-utils';
|
|
@@ -9,59 +9,62 @@ export function adaptDescribable(
|
|
|
9
9
|
): {
|
|
10
10
|
description?: RenderableContent[];
|
|
11
11
|
} {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
return {
|
|
13
|
+
description: describableToRenderableContent(describable, linkGenerator),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
17
|
+
export function describableToRenderableContent(
|
|
18
|
+
describable: Describable,
|
|
19
|
+
linkGenerator: GetRenderableContentByTypeName,
|
|
20
|
+
): RenderableContent[] | undefined {
|
|
21
|
+
if (!describable) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let content: RenderableContent[] = [];
|
|
26
|
+
for (let i = 0; i < describable.length; i++) {
|
|
27
|
+
const line = describable[i];
|
|
28
|
+
// The language might or might not be present after ```
|
|
29
|
+
const codeBlockMatch = line.match(/^```([a-zA-Z]*)$/);
|
|
30
|
+
if (codeBlockMatch) {
|
|
31
|
+
// Check if the language is present, if not, fallback to "apex"
|
|
32
|
+
const language = codeBlockMatch[1] || 'apex';
|
|
33
|
+
const codeBlockLines: string[] = [];
|
|
34
|
+
i++;
|
|
35
|
+
while (i < describable.length) {
|
|
36
|
+
const currentLine = describable[i];
|
|
37
|
+
if (currentLine.trim() === '```') {
|
|
38
|
+
break;
|
|
34
39
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{
|
|
38
|
-
__type: 'code-block',
|
|
39
|
-
language,
|
|
40
|
-
content: codeBlockLines,
|
|
41
|
-
},
|
|
42
|
-
{ __type: 'empty-line' },
|
|
43
|
-
];
|
|
44
|
-
continue;
|
|
40
|
+
codeBlockLines.push(currentLine);
|
|
41
|
+
i++;
|
|
45
42
|
}
|
|
46
|
-
|
|
47
43
|
content = [
|
|
48
44
|
...content,
|
|
49
|
-
...replaceInlineReferences(line, linkGenerator),
|
|
50
45
|
{
|
|
51
|
-
__type: '
|
|
46
|
+
__type: 'code-block',
|
|
47
|
+
language,
|
|
48
|
+
content: codeBlockLines,
|
|
52
49
|
},
|
|
50
|
+
{ __type: 'empty-line' },
|
|
53
51
|
];
|
|
52
|
+
continue;
|
|
54
53
|
}
|
|
55
|
-
return (
|
|
56
|
-
content
|
|
57
|
-
// If the last element is an empty line, remove it
|
|
58
|
-
.filter((line, index, lines) => !(isEmptyLine(line) && index === lines.length - 1))
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
55
|
+
content = [
|
|
56
|
+
...content,
|
|
57
|
+
...replaceInlineReferences(line, linkGenerator),
|
|
58
|
+
{
|
|
59
|
+
__type: 'empty-line',
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
return (
|
|
64
|
+
content
|
|
65
|
+
// If the last element is an empty line, remove it
|
|
66
|
+
.filter((line, index, lines) => !(isEmptyLine(line) && index === lines.length - 1))
|
|
67
|
+
);
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
export function adaptDocumentable(
|
|
@@ -70,7 +73,7 @@ export function adaptDocumentable(
|
|
|
70
73
|
subHeadingLevel: number,
|
|
71
74
|
): RenderableDocumentation {
|
|
72
75
|
function extractCustomTags(type: Documentable): CustomTag[] {
|
|
73
|
-
const baseTags = ['description', 'group', 'author', 'date', 'see', 'example', '
|
|
76
|
+
const baseTags = ['description', 'group', 'author', 'date', 'see', 'example', 'throws', 'exception'];
|
|
74
77
|
|
|
75
78
|
return (
|
|
76
79
|
type.docComment?.annotations
|
|
@@ -82,12 +85,6 @@ export function adaptDocumentable(
|
|
|
82
85
|
);
|
|
83
86
|
}
|
|
84
87
|
|
|
85
|
-
function extractAnnotationBodyLines(type: Documentable, annotationName: string): string[] | undefined {
|
|
86
|
-
return type.docComment?.annotations.find(
|
|
87
|
-
(currentAnnotation) => currentAnnotation.name.toLowerCase() === annotationName,
|
|
88
|
-
)?.bodyLines;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
88
|
function extractAnnotationBody(type: Documentable, annotationName: string): string | undefined {
|
|
92
89
|
return type.docComment?.annotations.find(
|
|
93
90
|
(currentAnnotation) => currentAnnotation.name.toLowerCase() === annotationName,
|
|
@@ -102,30 +99,14 @@ export function adaptDocumentable(
|
|
|
102
99
|
);
|
|
103
100
|
}
|
|
104
101
|
|
|
105
|
-
function bodyLinesToCodeBlock(language: string, bodyLines: string[] | undefined): CodeBlock | undefined {
|
|
106
|
-
if (!bodyLines) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
return {
|
|
110
|
-
__type: 'code-block',
|
|
111
|
-
language,
|
|
112
|
-
content: bodyLines,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
102
|
return {
|
|
117
103
|
...adaptDescribable(documentable.docComment?.descriptionLines, linkGenerator),
|
|
118
104
|
annotations: documentable.annotations.map((annotation) => annotation.type.toUpperCase()),
|
|
119
105
|
customTags: extractCustomTags(documentable),
|
|
120
|
-
mermaid: {
|
|
121
|
-
headingLevel: subHeadingLevel,
|
|
122
|
-
heading: 'Diagram',
|
|
123
|
-
value: bodyLinesToCodeBlock('mermaid', extractAnnotationBodyLines(documentable, 'mermaid')),
|
|
124
|
-
},
|
|
125
106
|
example: {
|
|
126
107
|
headingLevel: subHeadingLevel,
|
|
127
108
|
heading: 'Example',
|
|
128
|
-
value:
|
|
109
|
+
value: describableToRenderableContent(documentable.docComment?.exampleAnnotation?.bodyLines, linkGenerator),
|
|
129
110
|
},
|
|
130
111
|
group: extractAnnotationBody(documentable, 'group'),
|
|
131
112
|
author: extractAnnotationBody(documentable, 'author'),
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { MarkdownGeneratorConfig } from '../generate-docs';
|
|
2
|
+
import { DocPageReference, ParsedFile } from '../../shared/types';
|
|
3
|
+
import { Type } from '@cparra/apex-reflection';
|
|
4
|
+
|
|
5
|
+
export function parsedFilesToReferenceGuide(
|
|
6
|
+
config: MarkdownGeneratorConfig,
|
|
7
|
+
parsedFiles: ParsedFile[],
|
|
8
|
+
): Record<string, DocPageReference> {
|
|
9
|
+
return parsedFiles.reduce<Record<string, DocPageReference>>((acc, parsedFile) => {
|
|
10
|
+
acc[parsedFile.type.name] = parsedFileToDocPageReference(config, parsedFile);
|
|
11
|
+
return acc;
|
|
12
|
+
}, {});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function parsedFileToDocPageReference(config: MarkdownGeneratorConfig, parsedFile: ParsedFile): DocPageReference {
|
|
16
|
+
return {
|
|
17
|
+
source: parsedFile.source,
|
|
18
|
+
displayName: parsedFile.type.name,
|
|
19
|
+
pathFromRoot: `${slugify(getTypeGroup(parsedFile.type, config))}/${parsedFile.type.name}.md`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getTypeGroup(type: Type, config: MarkdownGeneratorConfig): string {
|
|
24
|
+
const groupAnnotation = type.docComment?.annotations.find((annotation) => annotation.name.toLowerCase() === 'group');
|
|
25
|
+
return groupAnnotation?.body ?? config.defaultGroupName;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function slugify(text: string): string {
|
|
29
|
+
return text
|
|
30
|
+
.toLowerCase()
|
|
31
|
+
.replace(/[^a-z0-9\s-]/g, '') // Remove non-alphanumeric characters except spaces and hyphens
|
|
32
|
+
.trim()
|
|
33
|
+
.replace(/\s+/g, '-') // Replace spaces with hyphens
|
|
34
|
+
.replace(/-+/g, '-'); // Replace multiple hyphens with a single hyphen
|
|
35
|
+
}
|