Skip to content

Commit 0f20c22

Browse files
authored
Merge pull request #214 from cesarParra/changelog-frontmatter-support
Changelog frontmatter support
2 parents aa60bec + cea4495 commit 0f20c22

File tree

9 files changed

+132
-39
lines changed

9 files changed

+132
-39
lines changed

examples/vitepress/apexdocs.config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ export default {
3030
previousVersionDir: 'previous',
3131
currentVersionDir: 'force-app',
3232
scope: ['global', 'public', 'protected', 'private', 'namespaceaccessible'],
33+
transformChangeLogPage: () => {
34+
return {
35+
frontmatter: {
36+
title: 'Changelog',
37+
},
38+
};
39+
},
3340
}),
3441
markdown: defineMarkdownConfig({
3542
sourceDir: 'force-app',

examples/vitepress/docs/changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
---
2+
title: Changelog
3+
---
4+
15
# Changelog
26

37
## New Classes

src/application/generators/changelog.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import { pipe } from 'fp-ts/function';
2-
import { PageData, Skip, UnparsedSourceBundle, UserDefinedChangelogConfig } from '../../core/shared/types';
2+
import {
3+
ChangeLogPageData,
4+
PageData,
5+
Skip,
6+
UnparsedSourceBundle,
7+
UserDefinedChangelogConfig,
8+
} from '../../core/shared/types';
39
import * as TE from 'fp-ts/TaskEither';
410
import { writeFiles } from '../file-writer';
5-
import { ChangeLogPageData, generateChangeLog } from '../../core/changelog/generate-change-log';
11+
import { generateChangeLog } from '../../core/changelog/generate-change-log';
612
import { FileWritingError } from '../errors';
713
import { isSkip } from '../../core/shared/utils';
814

src/core/changelog/__test__/generating-change-log.spec.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
import { UnparsedApexBundle, UnparsedCustomObjectBundle, UnparsedSourceBundle } from '../../shared/types';
2-
import { ChangeLogPageData, generateChangeLog } from '../generate-change-log';
1+
import {
2+
ChangeLogPageData,
3+
UnparsedApexBundle,
4+
UnparsedCustomObjectBundle,
5+
UnparsedSourceBundle,
6+
} from '../../shared/types';
7+
import { generateChangeLog } from '../generate-change-log';
38
import { assertEither } from '../../test-helpers/assert-either';
49
import { isSkip } from '../../shared/utils';
510
import { unparsedFieldBundleFromRawString } from '../../test-helpers/test-data-builders';
@@ -466,4 +471,16 @@ describe('when generating a changelog', () => {
466471
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('PhotoUrl__c'));
467472
});
468473
});
474+
475+
describe('and a custom hook is provided to customize the frontmatter', () => {
476+
it('includes the custom frontmatter', async () => {
477+
const hook = () => ({
478+
frontmatter: '---\ntitle: Custom Title\n---',
479+
});
480+
481+
const result = await generateChangeLog([], [], { ...config, transformChangeLogPage: hook })();
482+
483+
assertEither(result, (data) => expect((data as ChangeLogPageData).frontmatter).toContain('title: Custom Title'));
484+
});
485+
});
469486
});

src/core/changelog/generate-change-log.ts

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import {
2+
ChangeLogPageData,
23
ParsedFile,
34
Skip,
5+
TransformChangelogPage,
46
UnparsedApexBundle,
57
UnparsedSourceBundle,
68
UserDefinedChangelogConfig,
@@ -12,26 +14,24 @@ import { Changelog, hasChanges, processChangelog, VersionManifest } from './proc
1214
import { convertToRenderableChangelog, RenderableChangelog } from './renderable-changelog';
1315
import { CompilationRequest, Template } from '../template';
1416
import { changelogTemplate } from './templates/changelog-template';
15-
import { ReflectionErrors } from '../errors/errors';
17+
import { HookError, ReflectionErrors } from '../errors/errors';
1618
import { apply } from '#utils/fp';
1719
import { filterScope } from '../reflection/apex/filter-scope';
18-
import { isInSource, skip } from '../shared/utils';
20+
import { isInSource, isSkip, passThroughHook, skip, toFrontmatterString } from '../shared/utils';
1921
import { reflectCustomFieldsAndObjects } from '../reflection/sobject/reflectCustomFieldsAndObjects';
2022
import { CustomObjectMetadata } from '../reflection/sobject/reflect-custom-object-sources';
2123
import { Type } from '@cparra/apex-reflection';
2224
import { filterApexSourceFiles, filterCustomObjectsAndFields } from '#utils/source-bundle-utils';
2325
import { CustomFieldMetadata } from '../reflection/sobject/reflect-custom-field-source';
26+
import { hookableTemplate } from '../markdown/templates/hookable';
2427

25-
export type ChangeLogPageData = {
26-
content: string;
27-
outputDocPath: string;
28-
};
28+
type Config = Omit<UserDefinedChangelogConfig, 'targetGenerator'>;
2929

3030
export function generateChangeLog(
3131
oldBundles: UnparsedSourceBundle[],
3232
newBundles: UnparsedSourceBundle[],
33-
config: Omit<UserDefinedChangelogConfig, 'targetGenerator'>,
34-
): TE.TaskEither<ReflectionErrors, ChangeLogPageData | Skip> {
33+
config: Config,
34+
): TE.TaskEither<ReflectionErrors | HookError, ChangeLogPageData | Skip> {
3535
const convertToPageData = apply(toPageData, config.fileName);
3636

3737
function handleConversion({ changelog, newManifest }: { changelog: Changelog; newManifest: VersionManifest }) {
@@ -51,6 +51,8 @@ export function generateChangeLog(
5151
newManifest,
5252
})),
5353
TE.map(handleConversion),
54+
TE.flatMap(transformChangelogPageHook(config)),
55+
TE.map(postHookCompile),
5456
);
5557
}
5658

@@ -106,7 +108,45 @@ function compile(renderable: RenderableChangelog): string {
106108

107109
function toPageData(fileName: string, content: string): ChangeLogPageData {
108110
return {
111+
frontmatter: null,
109112
content,
110113
outputDocPath: `${fileName}.md`,
111114
};
112115
}
116+
117+
function transformChangelogPageHook(config: Config) {
118+
return (page: ChangeLogPageData | Skip) =>
119+
TE.tryCatch(
120+
() => transformChangelogPage(page, config.transformChangeLogPage),
121+
(error) => new HookError(error),
122+
);
123+
}
124+
125+
async function transformChangelogPage(
126+
page: ChangeLogPageData | Skip,
127+
hook: TransformChangelogPage = passThroughHook,
128+
): Promise<ChangeLogPageData | Skip> {
129+
if (isSkip(page)) {
130+
return page;
131+
}
132+
return {
133+
...page,
134+
...(await hook(page)),
135+
};
136+
}
137+
138+
function postHookCompile(page: ChangeLogPageData | Skip): ChangeLogPageData | Skip {
139+
if (isSkip(page)) {
140+
return page;
141+
}
142+
return {
143+
...page,
144+
content: Template.getInstance().compile({
145+
source: {
146+
frontmatter: toFrontmatterString(page.frontmatter),
147+
content: page.content,
148+
},
149+
template: hookableTemplate,
150+
}),
151+
};
152+
}

src/core/markdown/generate-docs.ts

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import { pipe } from 'fp-ts/function';
22
import * as TE from 'fp-ts/TaskEither';
3-
import yaml from 'js-yaml';
43

54
import { apply } from '#utils/fp';
65
import {
76
DocPageData,
87
DocumentationBundle,
9-
Frontmatter,
108
PostHookDocumentationBundle,
119
ReferenceGuidePageData,
1210
UnparsedApexBundle,
@@ -28,7 +26,7 @@ import { filterScope } from '../reflection/apex/filter-scope';
2826
import { Template } from '../template';
2927
import { hookableTemplate } from './templates/hookable';
3028
import { sortTypesAndMembers } from '../reflection/sort-types-and-members';
31-
import { isSkip } from '../shared/utils';
29+
import { isSkip, passThroughHook, toFrontmatterString } from '../shared/utils';
3230
import { parsedFilesToReferenceGuide } from './adapters/reference-guide';
3331
import { removeExcludedTags } from '../reflection/apex/remove-excluded-tags';
3432
import { HookError } from '../errors/errors';
@@ -129,9 +127,6 @@ function transformDocumentationBundleHook(config: MarkdownGeneratorConfig) {
129127
}
130128

131129
// Configurable hooks
132-
function passThroughHook<T>(value: T): T {
133-
return value;
134-
}
135130

136131
const execTransformReferenceHook = async (
137132
references: DocPageReference[],
@@ -219,16 +214,3 @@ function postHookCompile(bundle: PostHookDocumentationBundle) {
219214
})),
220215
};
221216
}
222-
223-
function toFrontmatterString(frontmatter: Frontmatter): string {
224-
if (typeof frontmatter === 'string') {
225-
return frontmatter;
226-
}
227-
228-
if (!frontmatter) {
229-
return '';
230-
}
231-
232-
const yamlString = yaml.dump(frontmatter);
233-
return `---\n${yamlString}---\n`;
234-
}

src/core/shared/types.d.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Type } from '@cparra/apex-reflection';
2-
import { ChangeLogPageData } from '../changelog/generate-change-log';
32
import { CustomObjectMetadata } from '../reflection/sobject/reflect-custom-object-sources';
43
import { CustomFieldMetadata } from '../reflection/sobject/reflect-custom-field-source';
54

@@ -34,7 +33,7 @@ export type UserDefinedMarkdownConfig = {
3433
excludeTags: string[];
3534
exclude: string[];
3635
} & CliConfigurableMarkdownConfig &
37-
Partial<ConfigurableHooks>;
36+
Partial<MarkdownConfigurableHooks>;
3837

3938
export type UserDefinedOpenApiConfig = {
4039
targetGenerator: 'openapi';
@@ -56,7 +55,7 @@ export type UserDefinedChangelogConfig = {
5655
scope: string[];
5756
exclude: string[];
5857
skipIfNoChanges: boolean;
59-
};
58+
} & Partial<ChangelogConfigurableHooks>;
6059

6160
export type UserDefinedConfig = UserDefinedMarkdownConfig | UserDefinedOpenApiConfig | UserDefinedChangelogConfig;
6261

@@ -144,6 +143,12 @@ export type DocPageData = {
144143

145144
export type OpenApiPageData = Omit<DocPageData, 'source' | 'type'>;
146145

146+
export type ChangeLogPageData = {
147+
frontmatter: Frontmatter;
148+
content: string;
149+
outputDocPath: string;
150+
};
151+
147152
export type PageData = DocPageData | OpenApiPageData | ReferenceGuidePageData | ChangeLogPageData;
148153

149154
export type DocumentationBundle = {
@@ -166,9 +171,9 @@ export type PostHookDocumentationBundle = {
166171
// CONFIGURABLE HOOKS
167172

168173
/**
169-
* The configurable hooks that can be used to modify the output of the generator.
174+
* The configurable hooks that can be used to modify the output of the Markdown generator.
170175
*/
171-
export type ConfigurableHooks = {
176+
export type MarkdownConfigurableHooks = {
172177
transformReferenceGuide: TransformReferenceGuide;
173178
transformDocs: TransformDocs;
174179
transformDocPage: TransformDocPage;
@@ -206,3 +211,11 @@ export type TransformDocs = (docs: DocPageData[]) => DocPageData[] | Promise<Doc
206211
export type TransformDocPage = (
207212
doc: DocPageData,
208213
) => Partial<ConfigurableDocPageData> | Promise<Partial<ConfigurableDocPageData>>;
214+
215+
export type ChangelogConfigurableHooks = {
216+
transformChangeLogPage: TransformChangelogPage;
217+
};
218+
219+
export type TransformChangelogPage = (
220+
page: ChangeLogPageData,
221+
) => Partial<ChangeLogPageData> | Promise<Partial<ChangeLogPageData>>;

src/core/shared/utils.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { ExternalMetadata, Skip, SourceFileMetadata } from './types';
1+
import { ExternalMetadata, Frontmatter, Skip, SourceFileMetadata } from './types';
22
import { Type } from '@cparra/apex-reflection';
33
import { CustomObjectMetadata } from '../reflection/sobject/reflect-custom-object-sources';
44
import { MarkdownGeneratorConfig } from '../markdown/generate-docs';
55
import { CustomFieldMetadata } from '../reflection/sobject/reflect-custom-field-source';
6+
import yaml from 'js-yaml';
67

78
/**
89
* Represents a file to be skipped.
@@ -44,3 +45,20 @@ export function getTypeGroup(type: Type | CustomObjectMetadata, config: Markdown
4445
return getGroup(type, config);
4546
}
4647
}
48+
49+
export function passThroughHook<T>(value: T): T {
50+
return value;
51+
}
52+
53+
export function toFrontmatterString(frontmatter: Frontmatter): string {
54+
if (typeof frontmatter === 'string') {
55+
return frontmatter;
56+
}
57+
58+
if (!frontmatter) {
59+
return '';
60+
}
61+
62+
const yamlString = yaml.dump(frontmatter);
63+
return `---\n${yamlString}---\n`;
64+
}

src/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import type {
2-
ConfigurableHooks,
2+
MarkdownConfigurableHooks,
33
Skip,
44
UserDefinedMarkdownConfig,
55
ReferenceGuidePageData,
66
DocPageData,
77
DocPageReference,
8+
ChangeLogPageData,
89
ConfigurableDocPageData,
910
TransformReferenceGuide,
1011
TransformDocs,
@@ -13,6 +14,8 @@ import type {
1314
ConfigurableDocPageReference,
1415
UserDefinedOpenApiConfig,
1516
UserDefinedChangelogConfig,
17+
ChangelogConfigurableHooks,
18+
TransformChangelogPage,
1619
} from './core/shared/types';
1720
import { skip } from './core/shared/utils';
1821
import { changeLogDefaults, markdownDefaults, openApiDefaults } from './defaults';
@@ -72,12 +75,15 @@ export {
7275
TransformDocs,
7376
TransformDocPage,
7477
TransformReference,
75-
ConfigurableHooks,
78+
MarkdownConfigurableHooks,
7679
ReferenceGuidePageData,
7780
DocPageData,
81+
ChangeLogPageData,
7882
DocPageReference,
7983
Skip,
8084
ConfigurableDocPageData,
8185
ConfigurableDocPageReference,
8286
process,
87+
ChangelogConfigurableHooks,
88+
TransformChangelogPage,
8389
};

0 commit comments

Comments
 (0)