---
name: extracting-render-metadata
description: >
  Load when extracting article or preview metadata from Xincodo Body data
  with toPlainText, richTextToPlainText, extractHeadings,
  extractHeadingAnchors, slugifyHeading, createExcerpt,
  estimateReadingTime, collectImageSources, or collectLinks.
type: core
library: "@ryhrm-gz/xincodo-lib"
library_version: "0.1.0"
requires:
  - building-and-parsing-body
sources:
  - "ryhrm-gz/xincodo-lib:README.md"
  - "ryhrm-gz/xincodo-lib:src/rendering.ts"
  - "ryhrm-gz/xincodo-lib:src/utils.ts"
  - "ryhrm-gz/xincodo-lib:src/traversal.ts"
  - "ryhrm-gz/xincodo-lib:tests/rendering.test.ts"
---

# Extracting Render Metadata

This skill builds on `building-and-parsing-body`. Use these helpers to prepare
metadata for preview and article pages; do not use them as UI renderers.

## Setup

```ts
import {
  collectImageSources,
  collectLinks,
  createExcerpt,
  estimateReadingTime,
  extractHeadingAnchors,
  toPlainText,
} from "@ryhrm-gz/xincodo-lib";

const metadata = {
  plainText: toPlainText(body),
  headings: extractHeadingAnchors(body),
  excerpt: createExcerpt(body, { maxLength: 120, preserveWords: true }),
  readingTime: estimateReadingTime(body),
  images: collectImageSources(body),
  links: collectLinks(body),
};
```

## Core Patterns

### Build table-of-contents data

```ts
import { extractHeadingAnchors } from "@ryhrm-gz/xincodo-lib";

const tableOfContents = extractHeadingAnchors(body).map((heading) => ({
  id: heading.anchorId,
  href: heading.href,
  level: heading.level,
  text: heading.text,
}));
```

`extractHeadingAnchors` preserves existing heading ids by default, creates
unique slugs, and URI-encodes href values.

### Create listing metadata

```ts
import { createExcerpt, estimateReadingTime, toPlainText } from "@ryhrm-gz/xincodo-lib";

const listing = {
  text: toPlainText(body),
  excerpt: createExcerpt(body, { maxLength: 160, preserveWords: true }),
  readingTime: estimateReadingTime(body),
};
```

`estimateReadingTime` accounts for Latin words and CJK characters.

### Collect linked resources

```ts
import { collectImageSources, collectLinks } from "@ryhrm-gz/xincodo-lib";

const resources = {
  imageUrls: collectImageSources(body).map((item) => item.source.url),
  externalHrefs: collectLinks(body)
    .filter((link) => link.kind === "text_link")
    .map((link) => link.href),
  pageReferences: collectLinks(body).filter((link) => link.kind === "page_link"),
};
```

Image sources include image blocks, gallery images, and callout image icons.

## Common Mistakes

### HIGH Building heading hrefs by hand

Wrong:

```ts
import { extractHeadings } from "@ryhrm-gz/xincodo-lib";

const hrefs = extractHeadings(body).map(
  (heading) => `#${heading.text.toLowerCase().replaceAll(" ", "-")}`,
);
```

Correct:

```ts
import { extractHeadingAnchors } from "@ryhrm-gz/xincodo-lib";

const hrefs = extractHeadingAnchors(body).map((heading) => heading.href);
```

Manual slugging can duplicate anchors, ignore existing ids, or fail to encode
CJK headings correctly.

Source: `src/rendering.ts`; `tests/rendering.test.ts`

### HIGH Collecting only image blocks

Wrong:

```ts
const images = body.content.filter((block) => block.type === "image").map((block) => block.source);
```

Correct:

```ts
import { collectImageSources } from "@ryhrm-gz/xincodo-lib";

const images = collectImageSources(body).map((item) => item.source);
```

Renderable image sources can appear in image blocks, gallery images, and
callout image icons.

Source: `src/rendering.ts`; `tests/rendering.test.ts`

### MEDIUM Assuming excerpts preserve words

Wrong:

```ts
import { createExcerpt } from "@ryhrm-gz/xincodo-lib";

const excerpt = createExcerpt(body, { maxLength: 120 });
```

Correct:

```ts
import { createExcerpt } from "@ryhrm-gz/xincodo-lib";

const excerpt = createExcerpt(body, {
  maxLength: 120,
  preserveWords: true,
});
```

`createExcerpt` truncates by character length unless `preserveWords` is
explicitly enabled.

Source: `README.md`; `src/rendering.ts`; `tests/rendering.test.ts`

## References

- [Metadata helper return shapes](references/metadata-helper-return-shapes.md)

See also: `article-render-preparation/SKILL.md` — article page preparation
composes these extraction APIs into an application workflow.
