Skip to content

Add markdown-to-pdf extension#26550

Open
shaynelarocque wants to merge 4 commits intoraycast:mainfrom
shaynelarocque:ext/markdown-to-pdf
Open

Add markdown-to-pdf extension#26550
shaynelarocque wants to merge 4 commits intoraycast:mainfrom
shaynelarocque:ext/markdown-to-pdf

Conversation

@shaynelarocque
Copy link

@shaynelarocque shaynelarocque commented Mar 22, 2026

Description

An AI-tool extension that converts markdown into styled PDFs. Mention @markdown to PDF in Ask AI, AI Chat, or AI Commands with your markdown content.

Features:

  • Styled PDF output with headings, lists, tables, code blocks, blockquotes, and clickable hyperlinks
  • 5 built-in color themes (default, minimal, executive, ocean, warm)
  • Custom theme support via extension preferences
  • Layout controls: font (Helvetica/Times/Courier), font size, line spacing, and per-side margins
  • Pure pdf-lib rendering

Screencast

1 2 3 4

Checklist

@raycastbot raycastbot added new extension Label for PRs with new extensions AI Extension labels Mar 22, 2026
@raycastbot
Copy link
Collaborator

Congratulations on your new Raycast extension! 🚀

We're currently experiencing a high volume of incoming requests. As a result, the initial review may take up to 10-15 business days.

Once the PR is approved and merged, the extension will be available on our Store.

@shaynelarocque shaynelarocque marked this pull request as ready for review March 22, 2026 03:38
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 22, 2026

Greptile Summary

This PR adds a new markdown-to-pdf AI tool extension that converts markdown content to styled PDFs via Raycast's Ask AI interface. It features a custom pure pdf-lib renderer with support for headings, lists, tables, code blocks, blockquotes, and clickable hyperlinks, plus five built-in colour themes and full custom theme support through extension preferences.

  • TypeScript compile errorOutputFormat is used as a parameter type in getUniqueOutputPath (normalization.ts:201) but is not included in the import from ./types, which will cause a TypeScript error at build time.
  • Manual getPreferenceValues typeresolveTheme calls getPreferenceValues with a manually authored inline type via require(). The auto-generated Preferences type from raycast-env.d.ts should be used instead (getPreferenceValues<Preferences>()).
  • Hardcoded changelog date – The CHANGELOG.md initial release entry uses a static date (2026-03-21) rather than the required {PR_MERGE_DATE} template placeholder.

Confidence Score: 3/5

  • Not ready to merge — a missing type import will cause a TypeScript compile error, and two convention violations need fixing first.
  • The extension is well-architected and the core rendering logic is solid, but the missing OutputFormat import in normalization.ts is a blocking TypeScript compile error. The other two issues (manual getPreferenceValues type and hardcoded changelog date) are convention violations required by the repo's custom rules. All three are straightforward one-line or small targeted fixes.
  • extensions/markdown-to-pdf/src/lib/normalization.ts (missing import + manual preference type), extensions/markdown-to-pdf/CHANGELOG.md (hardcoded date)

Important Files Changed

Filename Overview
extensions/markdown-to-pdf/src/lib/normalization.ts Contains two issues: OutputFormat type is referenced in getUniqueOutputPath but not imported (TypeScript compile error), and getPreferenceValues is called with a manually typed generic via require() instead of using the auto-generated Preferences type.
extensions/markdown-to-pdf/CHANGELOG.md Uses a hardcoded date 2026-03-21 instead of the required {PR_MERGE_DATE} template placeholder.
extensions/markdown-to-pdf/src/lib/pdf/render.ts Well-structured PDF rendering engine using pdf-lib. Handles paragraphs, headings, lists, tables, code blocks, blockquotes, and clickable hyperlinks. Minor: colorForStyle has a redundant code branch that returns the same value as the default.
extensions/markdown-to-pdf/src/lib/pdf/markdown-model.ts Markdown-to-PDF block model parser using markdown-it tokens. Clean implementation handling all major markdown constructs including task lists, tables, and nested blockquotes.
extensions/markdown-to-pdf/src/lib/conversion.ts Entry-point orchestration layer; validates input, normalises layout options, resolves paths, and delegates to the PDF renderer. Clean and straightforward.
extensions/markdown-to-pdf/src/tools/convert-markdown-to-doc.ts Raycast AI tool exposing the markdown-to-PDF conversion with a well-documented Input type and a confirmation handler that summarises all layout options before writing to disk.
extensions/markdown-to-pdf/package.json Well-formed extension manifest. Categories (Productivity, Developer Tools), platform (macOS), preferences, and AI description are all properly configured.
extensions/markdown-to-pdf/src/lib/types.ts Comprehensive type definitions for layouts, themes, fonts, and I/O shapes. No issues found.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/markdown-to-pdf/src/lib/normalization.ts
Line: 4-14

Comment:
**`OutputFormat` type not imported**

`OutputFormat` is used as a type annotation in the function signature but is never imported from `./types`. This will cause a TypeScript compilation error.

Add `type OutputFormat` to the import block at the top of the file:

```suggestion
import {
  BUILTIN_THEME_NAMES,
  BUILTIN_THEMES,
  type BuiltinThemeName,
  FONT_CHOICES,
  type ConvertContentInput,
  type DocumentLayoutOptions,
  type FontChoice,
  type NumericInput,
  type OutputFormat,
  type ThemePalette,
} from "./types";
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/markdown-to-pdf/src/lib/normalization.ts
Line: 104-113

Comment:
**Manual `getPreferenceValues` type annotation**

`getPreferenceValues` is being called with a manually written inline type. Per Raycast extension conventions, the `Preferences` type is auto-generated in `raycast-env.d.ts` when the extension runs, so the explicit type parameter should be removed in favour of `getPreferenceValues<Preferences>()`. Manual type definitions can drift out of sync with the actual preference schema in `package.json` and cause type mismatches at runtime.

The `require()` workaround for test isolation is also non-standard; a conventional top-level `import` should be used instead, and tests that need to avoid the Raycast runtime can mock the module.

**Rule Used:** What: Don't manually define `Preferences` for `get... ([source](https://app.greptile.com/review/custom-context?memory=d93fc9fb-a45d-4479-a6a4-b1b4af98ebc8))

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/markdown-to-pdf/CHANGELOG.md
Line: 3

Comment:
**Hardcoded date instead of `{PR_MERGE_DATE}` placeholder**

The changelog date should use the `{PR_MERGE_DATE}` template placeholder so the merge date is automatically populated when the PR is merged, rather than a manually set date.

```suggestion
## [Initial Release] - {PR_MERGE_DATE}
```

**Rule Used:** What: Changelog entries must use `{PR_MERGE_DATE}`... ([source](https://app.greptile.com/review/custom-context?memory=c2214c11-df56-490a-b1c0-09a385df481a))

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: "Fix TypeScript stric..."

Comment on lines +4 to +14
import {
BUILTIN_THEME_NAMES,
BUILTIN_THEMES,
type BuiltinThemeName,
FONT_CHOICES,
type ConvertContentInput,
type DocumentLayoutOptions,
type FontChoice,
type NumericInput,
type OutputFormat,
type ThemePalette,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 OutputFormat type not imported

OutputFormat is used as a type annotation in the function signature but is never imported from ./types. This will cause a TypeScript compilation error.

Add type OutputFormat to the import block at the top of the file:

Suggested change
import {
BUILTIN_THEME_NAMES,
BUILTIN_THEMES,
type BuiltinThemeName,
FONT_CHOICES,
type ConvertContentInput,
type DocumentLayoutOptions,
type FontChoice,
type NumericInput,
type OutputFormat,
type ThemePalette,
import {
BUILTIN_THEME_NAMES,
BUILTIN_THEMES,
type BuiltinThemeName,
FONT_CHOICES,
type ConvertContentInput,
type DocumentLayoutOptions,
type FontChoice,
type NumericInput,
type OutputFormat,
type ThemePalette,
} from "./types";
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/markdown-to-pdf/src/lib/normalization.ts
Line: 4-14

Comment:
**`OutputFormat` type not imported**

`OutputFormat` is used as a type annotation in the function signature but is never imported from `./types`. This will cause a TypeScript compilation error.

Add `type OutputFormat` to the import block at the top of the file:

```suggestion
import {
  BUILTIN_THEME_NAMES,
  BUILTIN_THEMES,
  type BuiltinThemeName,
  FONT_CHOICES,
  type ConvertContentInput,
  type DocumentLayoutOptions,
  type FontChoice,
  type NumericInput,
  type OutputFormat,
  type ThemePalette,
} from "./types";
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +104 to +113
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const api = require("@raycast/api") as {
getPreferenceValues: () => {
customThemeName?: string;
customAccentColor?: string;
customTextColor?: string;
customSurfaceColor?: string;
};
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Manual getPreferenceValues type annotation

getPreferenceValues is being called with a manually written inline type. Per Raycast extension conventions, the Preferences type is auto-generated in raycast-env.d.ts when the extension runs, so the explicit type parameter should be removed in favour of getPreferenceValues<Preferences>(). Manual type definitions can drift out of sync with the actual preference schema in package.json and cause type mismatches at runtime.

The require() workaround for test isolation is also non-standard; a conventional top-level import should be used instead, and tests that need to avoid the Raycast runtime can mock the module.

Rule Used: What: Don't manually define Preferences for `get... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/markdown-to-pdf/src/lib/normalization.ts
Line: 104-113

Comment:
**Manual `getPreferenceValues` type annotation**

`getPreferenceValues` is being called with a manually written inline type. Per Raycast extension conventions, the `Preferences` type is auto-generated in `raycast-env.d.ts` when the extension runs, so the explicit type parameter should be removed in favour of `getPreferenceValues<Preferences>()`. Manual type definitions can drift out of sync with the actual preference schema in `package.json` and cause type mismatches at runtime.

The `require()` workaround for test isolation is also non-standard; a conventional top-level `import` should be used instead, and tests that need to avoid the Raycast runtime can mock the module.

**Rule Used:** What: Don't manually define `Preferences` for `get... ([source](https://app.greptile.com/review/custom-context?memory=d93fc9fb-a45d-4479-a6a4-b1b4af98ebc8))

How can I resolve this? If you propose a fix, please make it concise.

@@ -0,0 +1,9 @@
# Changelog

## [Initial Release] - 2026-03-21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Hardcoded date instead of {PR_MERGE_DATE} placeholder

The changelog date should use the {PR_MERGE_DATE} template placeholder so the merge date is automatically populated when the PR is merged, rather than a manually set date.

Suggested change
## [Initial Release] - 2026-03-21
## [Initial Release] - {PR_MERGE_DATE}

Rule Used: What: Changelog entries must use {PR_MERGE_DATE}... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/markdown-to-pdf/CHANGELOG.md
Line: 3

Comment:
**Hardcoded date instead of `{PR_MERGE_DATE}` placeholder**

The changelog date should use the `{PR_MERGE_DATE}` template placeholder so the merge date is automatically populated when the PR is merged, rather than a manually set date.

```suggestion
## [Initial Release] - {PR_MERGE_DATE}
```

**Rule Used:** What: Changelog entries must use `{PR_MERGE_DATE}`... ([source](https://app.greptile.com/review/custom-context?memory=c2214c11-df56-490a-b1c0-09a385df481a))

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Extension new extension Label for PRs with new extensions platform: macOS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants