@cparra/apexdocs 3.0.0-alpha.1 → 3.0.0-alpha.10

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/dist/cli/generate.js +511 -293
  2. package/dist/{defaults-jLXD2y8-.js → defaults-DGKfeZq-.js} +1 -1
  3. package/dist/index.d.ts +23 -7
  4. package/dist/index.js +1 -1
  5. package/examples/markdown/docs/miscellaneous/MultiInheritanceClass.md +1 -1
  6. package/examples/markdown/docs/miscellaneous/SampleInterface.md +12 -8
  7. package/examples/markdown/docs/miscellaneous/Url.md +3 -3
  8. package/examples/markdown/force-app/classes/SampleInterface.cls +4 -0
  9. package/examples/vitepress/apexdocs.config.ts +1 -1
  10. package/examples/vitepress/docs/index.md +10 -10
  11. package/examples/vitepress/docs/miscellaneous/BaseClass.md +1 -1
  12. package/examples/vitepress/docs/miscellaneous/MultiInheritanceClass.md +2 -2
  13. package/examples/vitepress/docs/miscellaneous/SampleException.md +1 -1
  14. package/examples/vitepress/docs/miscellaneous/SampleInterface.md +6 -6
  15. package/examples/vitepress/docs/miscellaneous/Url.md +3 -3
  16. package/examples/vitepress/docs/sample-enums/SampleEnum.md +3 -3
  17. package/examples/vitepress/docs/samplegroup/SampleClass.md +4 -4
  18. package/package.json +2 -3
  19. package/src/application/Apexdocs.ts +53 -10
  20. package/src/application/__tests__/apex-file-reader.spec.ts +25 -25
  21. package/src/application/apex-file-reader.ts +32 -19
  22. package/src/application/file-system.ts +46 -10
  23. package/src/application/file-writer.ts +37 -15
  24. package/src/application/generators/markdown.ts +18 -31
  25. package/src/application/generators/openapi.ts +12 -8
  26. package/src/cli/commands/markdown.ts +4 -3
  27. package/src/core/markdown/__test__/generating-class-docs.spec.ts +3 -5
  28. package/src/core/markdown/__test__/generating-enum-docs.spec.ts +3 -3
  29. package/src/core/markdown/__test__/generating-interface-docs.spec.ts +5 -5
  30. package/src/core/markdown/__test__/generating-reference-guide.spec.ts +3 -3
  31. package/src/core/markdown/__test__/test-helpers.ts +1 -1
  32. package/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts +1 -1
  33. package/src/core/markdown/adapters/__tests__/link-generator.spec.ts +130 -0
  34. package/src/core/markdown/adapters/documentables.ts +0 -1
  35. package/src/core/markdown/adapters/generate-link.ts +82 -0
  36. package/src/core/markdown/adapters/reference-guide.ts +3 -1
  37. package/src/core/markdown/adapters/renderable-bundle.ts +5 -22
  38. package/src/core/markdown/adapters/renderable-to-page-data.ts +2 -2
  39. package/src/core/markdown/generate-docs.ts +9 -13
  40. package/src/core/markdown/reflection/reflect-source.ts +109 -31
  41. package/src/core/openapi/open-api-docs-processor.ts +1 -1
  42. package/src/core/openapi/openapi-type-file.ts +1 -1
  43. package/src/core/openapi/parser.ts +1 -15
  44. package/src/core/parse-apex-metadata.ts +21 -5
  45. package/src/core/shared/types.d.ts +22 -6
  46. package/src/defaults.ts +1 -1
  47. package/src/index.ts +1 -6
  48. package/src/util/logger.ts +8 -21
  49. package/dist/defaults-DUwru49Q.js +0 -12
  50. package/dist/defaults-SH0Rsi5E.js +0 -11
  51. package/src/core/markdown/reflection/error-handling.ts +0 -37
@@ -0,0 +1,82 @@
1
+ import { StringOrLink } from './types';
2
+ import path from 'path';
3
+ import { LinkingStrategy } from '../../shared/types';
4
+
5
+ export type LinkingStrategyFn = (
6
+ references: Record<string, { referencePath: string; displayName: string } | undefined>,
7
+ from: string,
8
+ referenceName: string,
9
+ ) => StringOrLink;
10
+
11
+ export const generateLink = (strategy: LinkingStrategy): LinkingStrategyFn => {
12
+ switch (strategy) {
13
+ case 'relative':
14
+ return generateRelativeLink;
15
+ case 'no-link':
16
+ return generateNoLink;
17
+ case 'none':
18
+ return returnReferenceAsIs;
19
+ }
20
+ };
21
+
22
+ const generateRelativeLink = (
23
+ references: Record<string, { referencePath: string; displayName: string } | undefined>,
24
+ from: string, // The name of the file for which the reference is being generated
25
+ referenceName: string,
26
+ ): StringOrLink => {
27
+ function getRelativePath(fromPath: string, toPath: string) {
28
+ return path.relative(path.parse(path.join('/', fromPath)).dir, path.join('/', toPath));
29
+ }
30
+
31
+ const referenceTo = references[referenceName];
32
+ if (!referenceTo) {
33
+ return referenceName;
34
+ }
35
+ // When linking from the base path (e.g. the reference guide/index page), the reference path is the same as the output
36
+ // path.
37
+ if (referenceTo && from === '__base__') {
38
+ return {
39
+ __type: 'link',
40
+ title: referenceTo.displayName,
41
+ url: getRelativePath('', referenceTo.referencePath),
42
+ };
43
+ }
44
+
45
+ const referenceFrom = references[from];
46
+
47
+ if (!referenceFrom) {
48
+ return referenceTo.displayName;
49
+ }
50
+
51
+ return {
52
+ __type: 'link',
53
+ title: referenceTo.displayName,
54
+ url: getRelativePath(referenceFrom.referencePath, referenceTo.referencePath),
55
+ };
56
+ };
57
+
58
+ const generateNoLink = (
59
+ references: Record<string, { referencePath: string; displayName: string } | undefined>,
60
+ _from: string,
61
+ referenceName: string,
62
+ ): StringOrLink => {
63
+ const referenceTo = references[referenceName];
64
+ return referenceTo ? referenceTo.displayName : referenceName;
65
+ };
66
+
67
+ const returnReferenceAsIs = (
68
+ references: Record<string, { referencePath: string; displayName: string } | undefined>,
69
+ _from: string,
70
+ referenceName: string,
71
+ ): StringOrLink => {
72
+ const referenceTo = references[referenceName];
73
+ if (!referenceTo) {
74
+ return referenceName;
75
+ }
76
+
77
+ return {
78
+ __type: 'link',
79
+ title: referenceTo.displayName,
80
+ url: referenceTo.referencePath,
81
+ };
82
+ };
@@ -13,10 +13,12 @@ export function parsedFilesToReferenceGuide(
13
13
  }
14
14
 
15
15
  function parsedFileToDocPageReference(config: MarkdownGeneratorConfig, parsedFile: ParsedFile): DocPageReference {
16
+ const path = `${slugify(getTypeGroup(parsedFile.type, config))}/${parsedFile.type.name}.md`;
16
17
  return {
17
18
  source: parsedFile.source,
18
19
  displayName: parsedFile.type.name,
19
- pathFromRoot: `${slugify(getTypeGroup(parsedFile.type, config))}/${parsedFile.type.name}.md`,
20
+ outputDocPath: path,
21
+ referencePath: path,
20
22
  };
21
23
  }
22
24
 
@@ -1,29 +1,29 @@
1
1
  import { DocPageReference, ParsedFile } from '../../shared/types';
2
- import { Link, ReferenceGuideReference, Renderable, RenderableBundle, StringOrLink } from './types';
2
+ import { Link, ReferenceGuideReference, Renderable, RenderableBundle } from './types';
3
3
  import { typeToRenderable } from './apex-types';
4
4
  import { adaptDescribable } from './documentables';
5
5
  import { MarkdownGeneratorConfig } from '../generate-docs';
6
6
  import { apply } from '#utils/fp';
7
7
  import { Type } from '@cparra/apex-reflection';
8
- import * as path from 'path';
8
+ import { generateLink } from './generate-link';
9
9
 
10
10
  export function parsedFilesToRenderableBundle(
11
11
  config: MarkdownGeneratorConfig,
12
12
  parsedFiles: ParsedFile[],
13
13
  references: Record<string, DocPageReference>,
14
14
  ): RenderableBundle {
15
- const referenceFinder = apply(linkGenerator, references, config.documentationRootDir);
15
+ const referenceFinder = apply(generateLink(config.linkingStrategy), references);
16
16
 
17
17
  function toReferenceGuide(parsedFiles: ParsedFile[]): Record<string, ReferenceGuideReference[]> {
18
18
  return parsedFiles.reduce<Record<string, ReferenceGuideReference[]>>(
19
- addToReferenceGuide(referenceFinder, config, references),
19
+ addToReferenceGuide(apply(referenceFinder, '__base__'), config, references),
20
20
  {},
21
21
  );
22
22
  }
23
23
 
24
24
  function toRenderables(parsedFiles: ParsedFile[]): Renderable[] {
25
25
  return parsedFiles.reduce<Renderable[]>((acc, parsedFile) => {
26
- const renderable = typeToRenderable(parsedFile, referenceFinder, config);
26
+ const renderable = typeToRenderable(parsedFile, apply(referenceFinder, parsedFile.source.name), config);
27
27
  acc.push(renderable);
28
28
  return acc;
29
29
  }, []);
@@ -55,23 +55,6 @@ function addToReferenceGuide(
55
55
  };
56
56
  }
57
57
 
58
- const linkGenerator = (
59
- references: Record<string, DocPageReference>,
60
- documentationRootDir: string,
61
- referenceName: string,
62
- ): StringOrLink => {
63
- const reference: DocPageReference | undefined = references[referenceName];
64
-
65
- return reference
66
- ? // Starting the path with a "/" will ensure the link will always be relative to the root of the site.
67
- {
68
- __type: 'link',
69
- title: reference.displayName,
70
- url: path.join('/', documentationRootDir, reference.pathFromRoot),
71
- }
72
- : referenceName;
73
- };
74
-
75
58
  function getTypeGroup(type: Type, config: MarkdownGeneratorConfig): string {
76
59
  const groupAnnotation = type.docComment?.annotations.find((annotation) => annotation.name.toLowerCase() === 'group');
77
60
  return groupAnnotation?.body ?? config.defaultGroupName;
@@ -14,7 +14,7 @@ export const convertToDocumentationBundle = (
14
14
  referenceGuide: {
15
15
  frontmatter: null,
16
16
  content: referencesToReferenceGuideContent(referencesByGroup, referenceGuideTemplate),
17
- filePath: 'index.md',
17
+ outputDocPath: 'index.md',
18
18
  },
19
19
  docs: renderables.map((renderable: Renderable) =>
20
20
  renderableToPageData(Object.values(referencesByGroup).flat(), renderable),
@@ -56,7 +56,7 @@ function renderableToPageData(referenceGuideReference: ReferenceGuideReference[]
56
56
  name: renderable.name,
57
57
  type: renderable.type,
58
58
  },
59
- filePath: reference!.reference.pathFromRoot,
59
+ outputDocPath: reference!.reference.outputDocPath,
60
60
  frontmatter: null,
61
61
  content: docContents,
62
62
  group: renderable.doc.group ?? defaults.defaultGroupName,
@@ -1,5 +1,4 @@
1
1
  import { pipe } from 'fp-ts/function';
2
- import * as E from 'fp-ts/Either';
3
2
  import * as TE from 'fp-ts/TaskEither';
4
3
  import yaml from 'js-yaml';
5
4
 
@@ -20,8 +19,7 @@ import {
20
19
  ParsedFile,
21
20
  } from '../shared/types';
22
21
  import { parsedFilesToRenderableBundle } from './adapters/renderable-bundle';
23
- import { reflectSourceCode } from './reflection/reflect-source';
24
- import { checkForReflectionErrors } from './reflection/error-handling';
22
+ import { reflectBundles } from './reflection/reflect-source';
25
23
  import { addInheritanceChainToTypes } from './reflection/inheritance-chain-expanion';
26
24
  import { addInheritedMembersToTypes } from './reflection/inherited-member-expansion';
27
25
  import { convertToDocumentationBundle } from './adapters/renderable-to-page-data';
@@ -42,7 +40,7 @@ export type MarkdownGeneratorConfig = Pick<
42
40
  | 'transformDocs'
43
41
  | 'transformDocPage'
44
42
  | 'transformReference'
45
- | 'documentationRootDir'
43
+ | 'linkingStrategy'
46
44
  > & {
47
45
  referenceGuideTemplate: string;
48
46
  sortMembersAlphabetically: boolean;
@@ -63,15 +61,13 @@ export function generateDocs(apexBundles: UnparsedSourceFile[], config: Markdown
63
61
 
64
62
  return pipe(
65
63
  apexBundles,
66
- reflectSourceCode,
67
- checkForReflectionErrors,
68
- E.map(filterOutOfScope),
69
- E.map(addInheritedMembersToTypes),
70
- E.map(addInheritanceChainToTypes),
71
- E.map(sortTypeMembers),
72
- E.bindTo('parsedFiles'),
73
- E.bind('references', ({ parsedFiles }) => E.right(convertToReferences(parsedFiles))),
74
- TE.fromEither,
64
+ reflectBundles,
65
+ TE.map(filterOutOfScope),
66
+ TE.map(addInheritedMembersToTypes),
67
+ TE.map(addInheritanceChainToTypes),
68
+ TE.map(sortTypeMembers),
69
+ TE.bindTo('parsedFiles'),
70
+ TE.bind('references', ({ parsedFiles }) => TE.right(convertToReferences(parsedFiles))),
75
71
  TE.flatMap(({ parsedFiles, references }) => transformReferenceHook(config)({ references, parsedFiles })),
76
72
  TE.map(({ parsedFiles, references }) => convertToRenderableBundle(parsedFiles, references)),
77
73
  TE.map(convertToDocumentationBundleForTemplate),
@@ -1,45 +1,123 @@
1
1
  import { ParsedFile, UnparsedSourceFile } from '../../shared/types';
2
+ import * as TE from 'fp-ts/TaskEither';
2
3
  import * as E from 'fp-ts/Either';
3
- import { reflect as mirrorReflection, Type } from '@cparra/apex-reflection';
4
+ import * as T from 'fp-ts/Task';
5
+ import * as A from 'fp-ts/lib/Array';
6
+ import { Annotation, reflect as mirrorReflection, Type } from '@cparra/apex-reflection';
4
7
  import { pipe } from 'fp-ts/function';
5
8
  import * as O from 'fp-ts/Option';
6
9
  import { parseApexMetadata } from '../../parse-apex-metadata';
7
- import { ReflectionError } from './error-handling';
10
+ import { ParsingError } from '@cparra/apex-reflection';
11
+ import { apply } from '#utils/fp';
12
+ import { Semigroup } from 'fp-ts/Semigroup';
8
13
 
9
- export function reflectSourceCode(apexBundles: UnparsedSourceFile[]) {
10
- return apexBundles.map(reflectSourceBody);
14
+ export class ReflectionErrors {
15
+ readonly _tag = 'ReflectionErrors';
16
+
17
+ constructor(public errors: ReflectionError[]) {}
18
+ }
19
+
20
+ export class ReflectionError {
21
+ constructor(
22
+ public file: string,
23
+ public message: string,
24
+ ) {}
25
+ }
26
+
27
+ async function reflectAsync(rawSource: string): Promise<Type> {
28
+ return new Promise((resolve, reject) => {
29
+ const result = mirrorReflection(rawSource);
30
+ if (result.typeMirror) {
31
+ return resolve(result.typeMirror);
32
+ } else if (result.error) {
33
+ return reject(result.error);
34
+ } else {
35
+ return reject(new Error('Unknown error'));
36
+ }
37
+ });
38
+ }
39
+
40
+ export function reflectBundles(apexBundles: UnparsedSourceFile[]) {
41
+ const semiGroupReflectionError: Semigroup<ReflectionErrors> = {
42
+ concat: (x, y) => new ReflectionErrors([...x.errors, ...y.errors]),
43
+ };
44
+ const Ap = TE.getApplicativeTaskValidation(T.ApplyPar, semiGroupReflectionError);
45
+
46
+ return pipe(apexBundles, A.traverse(Ap)(reflectBundle));
47
+ }
48
+
49
+ function reflectBundle(apexBundle: UnparsedSourceFile): TE.TaskEither<ReflectionErrors, ParsedFile> {
50
+ const convertToParsedFile: (typeMirror: Type) => ParsedFile = apply(toParsedFile, apexBundle.filePath);
51
+ const withMetadata = apply(addMetadata, apexBundle.metadataContent);
52
+
53
+ return pipe(apexBundle, reflectAsTask, TE.map(convertToParsedFile), TE.flatMap(withMetadata));
54
+ }
55
+
56
+ function reflectAsTask(apexBundle: UnparsedSourceFile): TE.TaskEither<ReflectionErrors, Type> {
57
+ return TE.tryCatch(
58
+ () => reflectAsync(apexBundle.content),
59
+ (error) =>
60
+ new ReflectionErrors([new ReflectionError(apexBundle.filePath, (error as ParsingError | Error).message)]),
61
+ );
62
+ }
63
+
64
+ function toParsedFile(filePath: string, typeMirror: Type): ParsedFile {
65
+ return {
66
+ source: {
67
+ filePath: filePath,
68
+ name: typeMirror.name,
69
+ type: typeMirror.type_name,
70
+ },
71
+ type: typeMirror,
72
+ };
11
73
  }
12
74
 
13
- function reflectSourceBody(apexBundle: UnparsedSourceFile): E.Either<ReflectionError, ParsedFile> {
14
- const { filePath, content: input, metadataContent: metadata } = apexBundle;
15
- const result = mirrorReflection(input);
16
- return result.error
17
- ? E.left(new ReflectionError(filePath, result.error.message))
18
- : E.right({
19
- source: {
20
- filePath,
21
- name: result.typeMirror!.name,
22
- type: result.typeMirror!.type_name,
23
- },
24
- type: addFileMetadataToTypeAnnotation(result.typeMirror!, metadata),
25
- });
75
+ function addMetadata(
76
+ rawMetadataContent: string | null,
77
+ parsedFile: ParsedFile,
78
+ ): TE.TaskEither<ReflectionErrors, ParsedFile> {
79
+ return TE.fromEither(
80
+ pipe(
81
+ parsedFile.type,
82
+ (type) => addFileMetadataToTypeAnnotation(type, rawMetadataContent),
83
+ E.map((type) => ({ ...parsedFile, type })),
84
+ E.mapLeft((error) => errorToReflectionErrors(error, parsedFile.source.filePath)),
85
+ ),
86
+ );
26
87
  }
27
88
 
28
- function addFileMetadataToTypeAnnotation(type: Type, metadata: string | null): Type {
89
+ function errorToReflectionErrors(error: Error, filePath: string): ReflectionErrors {
90
+ return new ReflectionErrors([new ReflectionError(filePath, error.message)]);
91
+ }
92
+
93
+ function addFileMetadataToTypeAnnotation(type: Type, metadata: string | null): E.Either<Error, Type> {
94
+ const concatAnnotationToType = apply(concatAnnotations, type);
95
+
29
96
  return pipe(
30
97
  O.fromNullable(metadata),
31
- O.map((metadata) => {
32
- const metadataParams = parseApexMetadata(metadata);
33
- metadataParams.forEach((value, key) => {
34
- const declaration = `${key}: ${value}`;
35
- type.annotations.push({
36
- rawDeclaration: declaration,
37
- name: declaration,
38
- type: declaration,
39
- });
40
- });
41
- return type;
42
- }),
43
- O.getOrElse(() => type),
98
+ O.map(concatAnnotationToType),
99
+ O.getOrElse(() => E.right(type)),
44
100
  );
45
101
  }
102
+
103
+ function concatAnnotations(type: Type, metadataInput: string): E.Either<Error, Type> {
104
+ return pipe(
105
+ metadataInput,
106
+ parseApexMetadata,
107
+ E.map((metadataMap) => ({
108
+ ...type,
109
+ annotations: [...type.annotations, ...mapToAnnotations(metadataMap)],
110
+ })),
111
+ );
112
+ }
113
+
114
+ function mapToAnnotations(metadata: Map<string, string>): Annotation[] {
115
+ return Array.from(metadata.entries()).map(([key, value]) => {
116
+ const declaration = `${key}: ${value}`;
117
+ return {
118
+ name: declaration,
119
+ type: declaration,
120
+ rawDeclaration: declaration,
121
+ };
122
+ });
123
+ }
@@ -25,7 +25,7 @@ export class OpenApiDocsProcessor {
25
25
  }
26
26
 
27
27
  onProcess(type: Type): void {
28
- Logger.logSingle(`Processing ${type.name}`, false, 'green', false);
28
+ Logger.logSingle(`Processing ${type.name}`, 'green');
29
29
 
30
30
  const endpointPath = this.getEndpointPath(type);
31
31
  if (!endpointPath) {
@@ -4,7 +4,7 @@ import { OpenApiPageData } from '../shared/types';
4
4
  export function createOpenApiFile(fileName: string, openApiModel: OpenApi): OpenApiPageData {
5
5
  const content = JSON.stringify({ ...openApiModel, namespace: undefined }, null, 2);
6
6
  return {
7
- filePath: '',
7
+ outputDocPath: '',
8
8
  content,
9
9
  frontmatter: null,
10
10
  group: null,
@@ -1,5 +1,4 @@
1
1
  import { ClassMirror, InterfaceMirror, ReflectionResult, Type } from '@cparra/apex-reflection';
2
- import { parseApexMetadata } from '../parse-apex-metadata';
3
2
  import { Logger } from '#utils/logger';
4
3
  import { UnparsedSourceFile } from '../shared/types';
5
4
 
@@ -16,20 +15,7 @@ export class RawBodyParser implements TypeParser {
16
15
  const types = this.typeBundles
17
16
  .map((currentBundle) => {
18
17
  Logger.log(`Parsing file: ${currentBundle.filePath}`);
19
- const result = reflect(currentBundle);
20
- if (!!result.typeMirror && !!currentBundle.metadataContent) {
21
- // If successful and there is a metadata file
22
- const metadataParams = parseApexMetadata(currentBundle.metadataContent);
23
- metadataParams.forEach((value, key) => {
24
- const declaration = `${key}: ${value}`;
25
- result.typeMirror?.annotations.push({
26
- rawDeclaration: declaration,
27
- name: declaration,
28
- type: declaration,
29
- });
30
- });
31
- }
32
- return result;
18
+ return reflect(currentBundle);
33
19
  })
34
20
  .filter((reflectionResult) => {
35
21
  return reflectionResult.typeMirror;
@@ -1,13 +1,29 @@
1
1
  import { XMLParser } from 'fast-xml-parser';
2
+ import * as E from 'fp-ts/Either';
3
+ import { pipe } from 'fp-ts/function';
4
+
5
+ type ApexMetadata = {
6
+ ApexClass: ApexClassMetadata;
7
+ };
8
+
9
+ type ApexClassMetadata = {
10
+ apiVersion: string;
11
+ status?: string;
12
+ };
2
13
 
3
14
  export function parseApexMetadata(input: string) {
4
- const map = new Map<string, string>();
5
- const xml = new XMLParser().parse(input);
15
+ return pipe(input, parse, E.map(toMap));
16
+ }
6
17
 
7
- map.set('apiVersion', xml.ApexClass.apiVersion ?? '');
18
+ function parse(input: string): E.Either<Error, ApexMetadata> {
19
+ return E.tryCatch(() => new XMLParser().parse(input), E.toError);
20
+ }
8
21
 
9
- if (xml.ApexClass.status) {
10
- map.set('status', xml.ApexClass.status);
22
+ function toMap(metadata: ApexMetadata): Map<string, string> {
23
+ const map = new Map<string, string>();
24
+ map.set('apiVersion', String(metadata.ApexClass.apiVersion));
25
+ if (metadata.ApexClass.status) {
26
+ map.set('status', String(metadata.ApexClass.status));
11
27
  }
12
28
 
13
29
  return map;
@@ -12,6 +12,17 @@ export type ConfigurableHooks = {
12
12
  transformReference: TransformReference;
13
13
  };
14
14
 
15
+ type LinkingStrategy =
16
+ // Links will be generated using relative paths.
17
+ | 'relative'
18
+ // No links will be generated.
19
+ // If the reference is found, the display name will be used.
20
+ // Otherwise, the name
21
+ // of the reference itself will be used.
22
+ | 'no-link'
23
+ // No logic will be applied, the reference path will be used as is.
24
+ | 'none';
25
+
15
26
  export type UserDefinedMarkdownConfig = {
16
27
  targetGenerator: 'markdown';
17
28
  sourceDir: string;
@@ -21,7 +32,7 @@ export type UserDefinedMarkdownConfig = {
21
32
  namespace?: string;
22
33
  sortMembersAlphabetically: boolean;
23
34
  includeMetadata: boolean;
24
- documentationRootDir: string;
35
+ linkingStrategy: LinkingStrategy;
25
36
  } & Partial<ConfigurableHooks>;
26
37
 
27
38
  export type UserDefinedOpenApiConfig = {
@@ -55,8 +66,13 @@ export type DocPageReference = {
55
66
  // The name under which the type should be displayed in the documentation.
56
67
  // By default, this will match the source.name, but it can be configured by the user.
57
68
  displayName: string;
58
- // The location of the file relative to the root of the documentation.
59
- pathFromRoot: string;
69
+ // The location where the file will be written.
70
+ outputDocPath: string;
71
+ // The path to the file relative to the documentation root directory. This is used when linking to the file.
72
+ // Usually the value will be the same as outputDocPath. However, some site generators may have a different way of
73
+ // organizing the files, so this allows for the flexibility of having a path from linking that is different from
74
+ // the path where the file is written.
75
+ referencePath: string;
60
76
  };
61
77
 
62
78
  type Frontmatter = string | Record<string, unknown> | null;
@@ -64,13 +80,13 @@ type Frontmatter = string | Record<string, unknown> | null;
64
80
  export type ReferenceGuidePageData = {
65
81
  frontmatter: Frontmatter;
66
82
  content: string;
67
- filePath: string;
83
+ outputDocPath: string;
68
84
  };
69
85
 
70
86
  export type DocPageData = {
71
87
  source: SourceFileMetadata;
72
88
  group: string | null;
73
- filePath: string;
89
+ outputDocPath: string;
74
90
  frontmatter: Frontmatter;
75
91
  content: string;
76
92
  };
@@ -100,7 +116,7 @@ export type PostHookDocumentationBundle = {
100
116
 
101
117
  type ConfigurableDocPageReference = Omit<DocPageReference, 'source'>;
102
118
 
103
- type ConfigurableDocPageData = Omit<DocPageData, 'source' | 'filePath'>;
119
+ type ConfigurableDocPageData = Omit<DocPageData, 'source' | 'outputDocPath'>;
104
120
 
105
121
  /**
106
122
  * Allows changing where the files are written to.
package/src/defaults.ts CHANGED
@@ -5,5 +5,5 @@ export const defaults = {
5
5
  defaultGroupName: 'Miscellaneous',
6
6
  includeMetadata: false,
7
7
  sortMembersAlphabetically: false,
8
- documentationRootDir: '',
8
+ linkingStrategy: 'relative' as const,
9
9
  };
package/src/index.ts CHANGED
@@ -12,12 +12,7 @@ import { defaults } from './defaults';
12
12
  type ConfigurableMarkdownConfig = Omit<
13
13
  SetOptional<
14
14
  UserDefinedMarkdownConfig,
15
- | 'targetDir'
16
- | 'scope'
17
- | 'defaultGroupName'
18
- | 'includeMetadata'
19
- | 'sortMembersAlphabetically'
20
- | 'documentationRootDir'
15
+ 'targetDir' | 'scope' | 'defaultGroupName' | 'includeMetadata' | 'sortMembersAlphabetically' | 'linkingStrategy'
21
16
  >,
22
17
  'targetGenerator'
23
18
  >;
@@ -1,14 +1,10 @@
1
1
  import chalk from 'chalk';
2
- import logUpdate from 'log-update';
3
-
4
2
  /**
5
3
  * Logs messages to the console.
6
4
  */
7
5
  export class Logger {
8
6
  static currentFrame = 0;
9
7
 
10
- static frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
11
-
12
8
  /**
13
9
  * Logs a message with optional arguments.
14
10
  * @param message The message to log.
@@ -27,31 +23,22 @@ export class Logger {
27
23
  * @param args Optional arguments.
28
24
  */
29
25
  public static error(message: unknown, ...args: string[]) {
30
- this.logSingle(message, false, 'red', false);
26
+ this.logSingle(message, 'red');
31
27
  args.forEach(() => {
32
- this.logSingle(message, false, 'red', false);
28
+ this.logSingle(message, 'red');
33
29
  });
34
30
  }
35
31
 
36
- public static logSingle(text: unknown, showSpinner = true, color: 'green' | 'red' = 'green', overrideConsole = true) {
32
+ public static logSingle(text: unknown, color: 'green' | 'red' = 'green') {
37
33
  if (this.currentFrame > 9) {
38
34
  this.currentFrame = 0;
39
35
  }
40
- const spinner = showSpinner ? `${this.frames[this.currentFrame++]}` : '';
41
- let logMessage;
42
- if (color === 'green') {
43
- logMessage = `${chalk.green(new Date().toLocaleString() + ': ')}${text}\n`;
44
- } else {
45
- logMessage = `${chalk.red(new Date().toLocaleString() + ': ')}${text}\n`;
46
- }
47
- if (overrideConsole) {
48
- logUpdate(`${spinner} ${logMessage}`);
49
- } else {
50
- process.stdout.write(`${spinner} ${logMessage}`);
51
- }
36
+
37
+ const logMessage = `${this.getChalkFn(color)(new Date().toLocaleString() + ': ')}${text}\n`;
38
+ process.stdout.write(logMessage);
52
39
  }
53
40
 
54
- public static clear() {
55
- logUpdate.clear();
41
+ private static getChalkFn(color: 'green' | 'red') {
42
+ return color === 'green' ? chalk.green : chalk.red;
56
43
  }
57
44
  }
@@ -1,12 +0,0 @@
1
- 'use strict';
2
-
3
- const defaults = {
4
- targetGenerator: "markdown",
5
- targetDir: "./docs/",
6
- scope: ["global"],
7
- defaultGroupName: "Miscellaneous",
8
- includeMetadata: false,
9
- sortMembersAlphabetically: false
10
- };
11
-
12
- exports.defaults = defaults;
@@ -1,11 +0,0 @@
1
- 'use strict';
2
-
3
- const defaults = {
4
- targetGenerator: "markdown",
5
- targetDir: "./docs/",
6
- scope: ["global"],
7
- defaultGroupName: "Miscellaneous",
8
- includeMetadata: false
9
- };
10
-
11
- exports.defaults = defaults;
@@ -1,37 +0,0 @@
1
- import * as E from 'fp-ts/Either';
2
- import { ParsedFile } from '../../shared/types';
3
- import { pipe } from 'fp-ts/function';
4
-
5
- export class ReflectionErrors {
6
- readonly _tag = 'ReflectionErrors';
7
- constructor(public errors: ReflectionError[]) {}
8
- }
9
-
10
- export class ReflectionError {
11
- constructor(
12
- public file: string,
13
- public message: string,
14
- ) {}
15
- }
16
-
17
- export function checkForReflectionErrors(reflectionResult: E.Either<ReflectionError, ParsedFile>[]) {
18
- function reduceReflectionResultIntoSingleEither(results: E.Either<ReflectionError, ParsedFile>[]): {
19
- errors: ReflectionError[];
20
- parsedFiles: ParsedFile[];
21
- } {
22
- return results.reduce<{ errors: ReflectionError[]; parsedFiles: ParsedFile[] }>(
23
- (acc, result) => {
24
- E.isLeft(result) ? acc.errors.push(result.left) : acc.parsedFiles.push(result.right);
25
- return acc;
26
- },
27
- {
28
- errors: [],
29
- parsedFiles: [],
30
- },
31
- );
32
- }
33
-
34
- return pipe(reflectionResult, reduceReflectionResultIntoSingleEither, ({ errors, parsedFiles }) =>
35
- errors.length ? E.left(new ReflectionErrors(errors)) : E.right(parsedFiles),
36
- );
37
- }