Skip to content

Commit fae15c6

Browse files
committed
feat: add protective comment to auto-generated markdown files
1 parent e8fcd41 commit fae15c6

File tree

6 files changed

+90
-15
lines changed

6 files changed

+90
-15
lines changed

examples/per-kind-output/apps.example.com-v2-webapp.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# WebApp
22

3+
<!-- This file is auto-generated by KARG (https://github.com/appthrust/karg). Please don't edit it manually - your changes will be overwritten when the file is regenerated. -->
4+
35
WebApp represents a web application deployment
46

57
- **API version:** `apps.example.com/v2`

examples/per-kind-output/data.example.com-v1beta1-database.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Database
22

3+
<!-- This file is auto-generated by KARG (https://github.com/appthrust/karg). Please don't edit it manually - your changes will be overwritten when the file is regenerated. -->
4+
35
Database represents a **managed database instance** with automated backups and high availability.
46

57
## Supported Engines

examples/per-kind-output/library.example.com-v1-book.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Book
22

3+
<!-- This file is auto-generated by KARG (https://github.com/appthrust/karg). Please don't edit it manually - your changes will be overwritten when the file is regenerated. -->
4+
35
Book represents a book in the library catalog system.
46

57
## Overview

examples/single-file-output.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# API Documentation
22

3+
<!-- This file is auto-generated by KARG (https://github.com/appthrust/karg). Please don't edit it manually - your changes will be overwritten when the file is regenerated. -->
4+
35
- [Book](#book)
46
- [Database](#database)
57
- [WebApp](#webapp)

ts/writer/__tests__/markdown.test.ts

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,29 @@ describe("markdown writer", () => {
6161
expect(result).toContain("Name of the resource");
6262
});
6363

64+
test("inserts protective comment after H1 heading", () => {
65+
const apiDoc = createAPIDoc("TestResource");
66+
67+
const result = renderAPIDocumentation(apiDoc);
68+
69+
// Check that comment appears after the heading
70+
expect(result).toContain(
71+
"# TestResource\n\n<!-- This file is auto-generated by KARG (https://github.com/appthrust/karg). " +
72+
"Please don't edit it manually - your changes will be overwritten when the file is regenerated. -->"
73+
);
74+
});
75+
6476
test("includes description when provided", () => {
6577
const apiDoc = createAPIDoc("TestResource", [], [], {
6678
description: "This is a test resource for unit testing.",
6779
});
6880

6981
const result = renderAPIDocumentation(apiDoc);
7082

71-
// Description appears right after the title, not in a separate section
72-
expect(result).toContain(
73-
"# TestResource\n\nThis is a test resource for unit testing."
74-
);
83+
// Description appears after the title and protective comment
84+
expect(result).toContain("# TestResource");
85+
expect(result).toContain("<!-- This file is auto-generated by KARG");
86+
expect(result).toContain("This is a test resource for unit testing.");
7587
});
7688

7789
test("renders API description with Markdown formatting", () => {
@@ -119,8 +131,10 @@ spec:
119131
expect(result).toContain("kind: Book"); // Content inside code block
120132
expect(result).toContain("*special handling*"); // Italic text (converted from underscores)
121133

122-
// Ensure the description appears right after the main title
123-
expect(result).toContain("# Book\n\nThis resource manages **books**");
134+
// Ensure the description appears after the title and comment
135+
expect(result).toContain("# Book");
136+
expect(result).toContain("<!-- This file is auto-generated by KARG");
137+
expect(result).toContain("This resource manages **books**");
124138
});
125139

126140
test("handles API description with complex nested Markdown", () => {
@@ -178,8 +192,12 @@ spec:
178192
const apiDocNoDesc = createAPIDoc("TestResource");
179193
const resultNoDesc = renderAPIDocumentation(apiDocNoDesc);
180194

181-
// Should not have extra blank lines after title
182-
expect(resultNoDesc).toContain("# TestResource\n\n- **API version:**");
195+
// Should have title, comment, then API version
196+
expect(resultNoDesc).toContain("# TestResource");
197+
expect(resultNoDesc).toContain(
198+
"<!-- This file is auto-generated by KARG"
199+
);
200+
expect(resultNoDesc).toContain("- **API version:**");
183201

184202
// Test with empty string description
185203
const apiDocEmptyDesc = createAPIDoc("TestResource", [], [], {
@@ -188,7 +206,11 @@ spec:
188206
const resultEmptyDesc = renderAPIDocumentation(apiDocEmptyDesc);
189207

190208
// Should handle empty description gracefully
191-
expect(resultEmptyDesc).toContain("# TestResource\n\n- **API version:**");
209+
expect(resultEmptyDesc).toContain("# TestResource");
210+
expect(resultEmptyDesc).toContain(
211+
"<!-- This file is auto-generated by KARG"
212+
);
213+
expect(resultEmptyDesc).toContain("- **API version:**");
192214
});
193215

194216
test("includes metadata details", () => {
@@ -824,6 +846,22 @@ Default configuration uses PostgreSQL.`;
824846
expect(result).toContain("spec.fieldB");
825847
});
826848

849+
test("inserts protective comment after main H1 heading", () => {
850+
const apiDocs = [createAPIDoc("ResourceA"), createAPIDoc("ResourceB")];
851+
852+
const result = renderCombinedDocumentation(apiDocs);
853+
854+
// Check that comment appears after the main heading
855+
expect(result).toContain(
856+
"# API Documentation\n\n<!-- This file is auto-generated by KARG (https://github.com/appthrust/karg). " +
857+
"Please don't edit it manually - your changes will be overwritten when the file is regenerated. -->"
858+
);
859+
860+
// Comment should only appear once at the top, not for each resource
861+
const commentMatches = result.match(/<!-- This file is auto-generated/g);
862+
expect(commentMatches?.length).toBe(1);
863+
});
864+
827865
test("creates table of contents", () => {
828866
const apiDocs = [
829867
createAPIDoc("Book"),
@@ -872,12 +910,18 @@ Default configuration uses PostgreSQL.`;
872910

873911
const result = renderCombinedDocumentation(apiDocs);
874912

913+
// Check that protective comment is at the top
914+
expect(result).toContain("# API Documentation");
915+
expect(result).toContain("<!-- This file is auto-generated by KARG");
916+
875917
// Check that descriptions are rendered with Markdown
876-
expect(result).toContain("## Author\n\nRepresents book authors.");
918+
expect(result).toContain("## Author");
919+
expect(result).toContain("Represents book authors.");
877920
expect(result).toContain("- Supports multiple pen names");
878921
expect(result).toContain("Links to [books](#book)");
879922

880-
expect(result).toContain("## Book\n\nManages **books**");
923+
expect(result).toContain("## Book");
924+
expect(result).toContain("Manages **books**");
881925
expect(result).toContain("*metadata*");
882926
expect(result).toContain("`ISBN`");
883927
});
@@ -924,7 +968,12 @@ Default configuration uses PostgreSQL.`;
924968

925969
const result = renderAPIDocumentation(apiDoc);
926970

927-
// Check that there's a blank line between description and metadata
971+
// Check that there's a protective comment and a blank line between description and metadata
972+
expect(result).toContain("# TestResource");
973+
expect(result).toContain("<!-- This file is auto-generated by KARG");
974+
expect(result).toContain(
975+
"This is a test resource for testing blank lines"
976+
);
928977
expect(result).toContain(
929978
"This is a test resource for testing blank lines\n\n- **API version:**"
930979
);

ts/writer/markdown.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
FootnoteDefinition,
55
FootnoteReference,
66
Heading,
7+
Html,
78
InlineCode,
89
Link,
910
List,
@@ -93,6 +94,9 @@ export function renderCombinedDocumentation(
9394
// Add main title
9495
children.push(heading(1, "API Documentation"));
9596

97+
// Insert protective comment after main title
98+
children.push(protectiveComment() as RootContent);
99+
96100
// Sort API docs alphabetically by Kind name
97101
const sortedApiDocs = [...apiDocs].sort((a, b) =>
98102
a.kind.localeCompare(b.kind)
@@ -109,7 +113,7 @@ export function renderCombinedDocumentation(
109113

110114
// Add each API documentation with base heading level 2
111115
for (const apiDoc of sortedApiDocs) {
112-
const apiAST = buildDocumentASTWithFootnotes(apiDoc, 2, footnotes);
116+
const apiAST = buildDocumentASTWithFootnotes(apiDoc, 2, footnotes, false);
113117
// Add all children except footnote definitions (we'll add them at the end)
114118
children.push(
115119
...apiAST.children.filter((child) => child.type !== "footnoteDefinition")
@@ -187,14 +191,20 @@ export function renderCombinedDocumentation(
187191
function buildDocumentASTWithFootnotes(
188192
apiDoc: APIDocumentation,
189193
baseHeadingLevel: number,
190-
footnotes: Map<string, string>
194+
footnotes: Map<string, string>,
195+
includeProtectiveComment = true
191196
): Root {
192197
const children: Array<RootContent> = [];
193198

194199
// Title
195200
children.push(heading(baseHeadingLevel, apiDoc.title));
196201

197-
// API description (right after title)
202+
// Insert protective comment after title only if requested
203+
if (includeProtectiveComment) {
204+
children.push(protectiveComment() as RootContent);
205+
}
206+
207+
// API description (right after title and comment)
198208
if (apiDoc.description) {
199209
const parsed = fromMarkdown(apiDoc.description, {
200210
extensions: [gfmTable()],
@@ -579,6 +589,14 @@ function addExamplesToList(
579589
}
580590

581591
// AST helper functions (Low-level abstraction)
592+
function protectiveComment(): Html {
593+
return u(
594+
"html",
595+
"<!-- This file is auto-generated by KARG (https://github.com/appthrust/karg). " +
596+
"Please don't edit it manually - your changes will be overwritten when the file is regenerated. -->"
597+
) as Html;
598+
}
599+
582600
function heading(
583601
depth: number,
584602
content: string | Array<PhrasingContent>

0 commit comments

Comments
 (0)