Skip to content

Commit a8f8e86

Browse files
fix(docs): expose heading IDs in enumerator JSON
1 parent 02c893f commit a8f8e86

2 files changed

Lines changed: 69 additions & 4 deletions

File tree

internal/cmd/docs_enumerators.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ type docsParagraphListItem struct {
7474
StartIndex int64 `json:"startIndex"`
7575
EndIndex int64 `json:"endIndex"`
7676
Style string `json:"style"`
77+
HeadingID string `json:"headingId,omitempty"`
7778
Text string `json:"text"`
7879
}
7980

@@ -82,6 +83,7 @@ type docsParagraphInspectItem struct {
8283
StartIndex int64 `json:"startIndex"`
8384
EndIndex int64 `json:"endIndex"`
8485
Style string `json:"style"`
86+
HeadingID string `json:"headingId,omitempty"`
8587
Text string `json:"text"`
8688
IsEmpty bool `json:"isEmpty"`
8789
Runs []docsParagraphRun `json:"runs"`
@@ -212,6 +214,7 @@ func (c *DocsHeadingsListCmd) Run(ctx context.Context, flags *RootFlags) error {
212214
StartIndex: paragraph.StartIndex,
213215
EndIndex: paragraph.EndIndex,
214216
Style: paragraph.Style,
217+
HeadingID: paragraph.HeadingID,
215218
Text: paragraph.Text,
216219
})
217220
}
@@ -236,6 +239,7 @@ func (c *DocsParagraphsListCmd) Run(ctx context.Context, flags *RootFlags) error
236239
StartIndex: paragraph.StartIndex,
237240
EndIndex: paragraph.EndIndex,
238241
Style: paragraph.Style,
242+
HeadingID: paragraph.HeadingID,
239243
Text: paragraph.Text,
240244
}
241245
items = append(items, item)
@@ -244,6 +248,7 @@ func (c *DocsParagraphsListCmd) Run(ctx context.Context, flags *RootFlags) error
244248
StartIndex: item.StartIndex,
245249
EndIndex: item.EndIndex,
246250
Style: item.Style,
251+
HeadingID: item.HeadingID,
247252
Text: item.Text,
248253
IsEmpty: paragraph.IsEmpty,
249254
Runs: paragraph.Runs,
@@ -488,6 +493,7 @@ type docsEnumeratedParagraph struct {
488493
StartIndex int64
489494
EndIndex int64
490495
Style string
496+
HeadingID string
491497
Text string
492498
IsEmpty bool
493499
Runs []docsParagraphRun
@@ -506,15 +512,19 @@ func enumerateDocsParagraphs(doc *docs.Document) []docsEnumeratedParagraph {
506512
}
507513
if element.Paragraph != nil {
508514
style := docsNamedStyleNormalText
509-
if element.Paragraph.ParagraphStyle != nil &&
510-
element.Paragraph.ParagraphStyle.NamedStyleType != "" {
511-
style = element.Paragraph.ParagraphStyle.NamedStyleType
515+
headingID := ""
516+
if paragraphStyle := element.Paragraph.ParagraphStyle; paragraphStyle != nil {
517+
if paragraphStyle.NamedStyleType != "" {
518+
style = paragraphStyle.NamedStyleType
519+
}
520+
headingID = paragraphStyle.HeadingId
512521
}
513522
isEmpty, runs := inspectDocsParagraph(element.Paragraph)
514523
paragraphs = append(paragraphs, docsEnumeratedParagraph{
515524
StartIndex: element.StartIndex,
516525
EndIndex: element.EndIndex,
517526
Style: style,
527+
HeadingID: headingID,
518528
Text: paragraphText(element.Paragraph),
519529
IsEmpty: isEmpty,
520530
Runs: runs,

internal/cmd/docs_enumerators_test.go

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,53 @@ func TestDocsHeadingsAndParagraphsFilters(t *testing.T) {
203203
}
204204
}
205205

206+
func TestDocsHeadingsAndParagraphsJSONIncludeHeadingID(t *testing.T) {
207+
t.Parallel()
208+
209+
response := map[string]any{
210+
"documentId": "doc1",
211+
"body": map[string]any{"content": []any{
212+
rawStyledParagraphWithHeadingID(1, 12, "HEADING_1", "h.section", "Section\n"),
213+
rawStyledParagraph(12, 20, "NORMAL_TEXT", "Body\n"),
214+
}},
215+
}
216+
srv := newDocsRawTestServer(t, 0, response)
217+
defer srv.Close()
218+
svc := newMockDocsService(t, srv)
219+
220+
var output bytes.Buffer
221+
ctx := withDocsTestService(newCmdRuntimeJSONOutputContext(t, &output, io.Discard), svc)
222+
if err := runKong(t, &DocsHeadingsListCmd{}, []string{"doc1"}, ctx, &RootFlags{Account: "[email protected]"}); err != nil {
223+
t.Fatalf("headings run: %v", err)
224+
}
225+
var headings struct {
226+
Headings []docsParagraphListItem `json:"headings"`
227+
}
228+
if err := json.Unmarshal(output.Bytes(), &headings); err != nil {
229+
t.Fatalf("unmarshal headings: %v\n%s", err, output.String())
230+
}
231+
if len(headings.Headings) != 1 || headings.Headings[0].HeadingID != "h.section" {
232+
t.Fatalf("headings = %#v", headings.Headings)
233+
}
234+
235+
output.Reset()
236+
if err := runKong(t, &DocsParagraphsListCmd{}, []string{"doc1"}, ctx, &RootFlags{Account: "[email protected]"}); err != nil {
237+
t.Fatalf("paragraphs run: %v", err)
238+
}
239+
var paragraphs struct {
240+
Paragraphs []docsParagraphInspectItem `json:"paragraphs"`
241+
}
242+
if err := json.Unmarshal(output.Bytes(), &paragraphs); err != nil {
243+
t.Fatalf("unmarshal paragraphs: %v\n%s", err, output.String())
244+
}
245+
if len(paragraphs.Paragraphs) != 2 || paragraphs.Paragraphs[0].HeadingID != "h.section" {
246+
t.Fatalf("paragraphs = %#v", paragraphs.Paragraphs)
247+
}
248+
if paragraphs.Paragraphs[1].HeadingID != "" {
249+
t.Fatalf("normal paragraph headingId = %q, want empty", paragraphs.Paragraphs[1].HeadingID)
250+
}
251+
}
252+
206253
func TestDocsParagraphsJSONIncludesRunsAndEmptiness(t *testing.T) {
207254
t.Parallel()
208255

@@ -436,11 +483,19 @@ func rawTableCell(text string) map[string]any {
436483
}
437484

438485
func rawStyledParagraph(start, end int64, style, text string) map[string]any {
486+
return rawStyledParagraphWithHeadingID(start, end, style, "", text)
487+
}
488+
489+
func rawStyledParagraphWithHeadingID(start, end int64, style, headingID, text string) map[string]any {
490+
paragraphStyle := map[string]any{"namedStyleType": style}
491+
if headingID != "" {
492+
paragraphStyle["headingId"] = headingID
493+
}
439494
return map[string]any{
440495
"startIndex": start,
441496
"endIndex": end,
442497
"paragraph": map[string]any{
443-
"paragraphStyle": map[string]any{"namedStyleType": style},
498+
"paragraphStyle": paragraphStyle,
444499
"elements": []any{
445500
map[string]any{
446501
"startIndex": start,

0 commit comments

Comments
 (0)