pdf-lib Code Review Agent
Purpose
This skill provides a step-by-step validation checklist for reviewing pdf-lib code. Follow EVERY check in order. Each check includes what to verify, why it matters, and how to fix violations.
Quick Reference: Severity Legend
| Level | Meaning |
|---|---|
| CRITICAL | Code WILL fail at runtime or produce corrupt output |
| WARNING | Code MAY produce incorrect visual output or unexpected behavior |
| INFO | Code works but violates best practices or may cause issues at scale |
Validation Checklist
CHECK 1: Async/Await Audit [CRITICAL]
What: Verify that ALL async pdf-lib methods use await.
Async methods that ALWAYS require await:
| Method | Returns |
|---|---|
PDFDocument.create() |
Promise<PDFDocument> |
PDFDocument.load() |
Promise<PDFDocument> |
pdfDoc.embedFont() |
Promise<PDFFont> |
pdfDoc.embedPng() |
Promise<PDFImage> |
pdfDoc.embedJpg() |
Promise<PDFImage> |
pdfDoc.copyPages() |
Promise<PDFPage[]> |
pdfDoc.embedPdf() |
Promise<PDFEmbeddedPage[]> |
pdfDoc.embedPage() |
Promise<PDFEmbeddedPage> |
pdfDoc.embedPages() |
Promise<PDFEmbeddedPage[]> |
pdfDoc.save() |
Promise<Uint8Array> |
pdfDoc.saveAsBase64() |
Promise<string> |
pdfDoc.copy() |
Promise<PDFDocument> |
pdfDoc.flush() |
Promise<void> |
pdfDoc.attach() |
Promise<void> |
Sync exception: pdfDoc.embedStandardFont() does NOT need await.
How to fix: Add await before every call. Ensure the containing function is async.
See references/methods.md for the complete async/sync method reference.
CHECK 2: Import Completeness [CRITICAL]
What: Verify ALL used pdf-lib exports are imported.
Required imports by operation type:
| Operation | Required Imports |
|---|---|
| Any pdf-lib usage | PDFDocument from 'pdf-lib' |
| Standard fonts | StandardFonts from 'pdf-lib' |
| Color (RGB) | rgb from 'pdf-lib' |
| Color (CMYK) | cmyk from 'pdf-lib' |
| Color (Grayscale) | grayscale from 'pdf-lib' |
| Rotation | degrees or radians from 'pdf-lib' |
| Page sizes | PageSizes from 'pdf-lib' |
| Text alignment | TextAlignment from 'pdf-lib' |
| Blend modes | BlendMode from 'pdf-lib' |
| Custom fonts | fontkit from '@pdf-lib/fontkit' (separate package) |
How to fix: Add missing imports. NEVER use destructured names without importing them.
CHECK 3: Coordinate System Verification [WARNING]
What: Verify coordinates use bottom-left origin (PDF standard).
Rules:
- y=0 is the BOTTOM of the page, NOT the top
- To position content near the top, use
height - offset - ALWAYS call
page.getSize()orpage.getHeight()to calculate top-relative positions
Pattern to verify:
const { width, height } = page.getSize()
// Top of page: y = height - margin
// Bottom of page: y = margin
Red flags:
- Using small y values (e.g.,
y: 50) and expecting content at the top - Using large y values without referencing page height
- Hardcoded y values without comments explaining positioning intent
How to fix: Replace hardcoded top-relative values with height - offset calculations.
CHECK 4: Font Handling [CRITICAL]
What: Verify font usage matches character requirements.
Sub-checks:
4a. Standard font character support:
- Standard fonts (Helvetica, TimesRoman, Courier, etc.) support ONLY WinAnsi encoding
- WinAnsi covers basic Latin and Western European characters
- NEVER use standard fonts with: Cyrillic, CJK, Arabic, Hebrew, Thai, emoji
- Error produced:
"WinAnsi cannot encode "X" (0xNNNN)"
4b. Custom font registration:
- If code uses
pdfDoc.embedFont(fontBytes)with raw bytes,pdfDoc.registerFontkit(fontkit)MUST be called first @pdf-lib/fontkitMUST be installed as a dependency- Registration MUST happen before ANY
embedFont()call with custom bytes
4c. Form field fonts:
- Default form font is Helvetica (Latin-only)
- For non-Latin text in form fields, ALWAYS call
form.updateFieldAppearances(customFont)after setting values - fontkit registration is REQUIRED for custom form fonts
How to fix: See references/anti-patterns.md sections on font handling.
CHECK 5: Image Format Validation [CRITICAL]
What: Verify only PNG and JPG images are used.
Rules:
- ONLY
pdfDoc.embedPng()andpdfDoc.embedJpg()exist - There is NO
embedGif(),embedBmp(),embedSvg(),embedWebP(), or genericembedImage() - NEVER pass non-PNG/JPG data to these methods
How to fix: Convert unsupported formats to PNG or JPG before embedding.
CHECK 6: Cross-Document Operations [CRITICAL]
What: Verify pages are copied correctly between documents.
Rules:
- ALWAYS use
await targetDoc.copyPages(sourceDoc, indices)to transfer pages - NEVER add a page from one document directly to another via
addPage(sourcePage) - After
copyPages(), ALWAYS calladdPage()orinsertPage()for each copied page copyPages()alone does NOT add pages to the document
How to fix: Replace direct page addition with the copyPages + addPage pattern.
CHECK 7: Form Field Validation [WARNING]
What: Verify form operations follow correct patterns.
Sub-checks:
7a. Field enumeration before access:
- ALWAYS enumerate fields with
form.getFields()before accessing by name - Field names are CASE-SENSITIVE
- Field names use fully qualified dot-notation (e.g.,
"form.section.fieldName")
7b. Duplicate field names:
- NEVER create two fields with the same name — this throws an error
- Use unique suffixed names when creating multiple similar fields
7c. Form flattening:
- ALWAYS flatten forms when generating final output PDFs
- NEVER flatten if the form needs to be filled again later
- Call
form.flatten()AFTER setting all field values
7d. Appearance updates:
- After setting form field values, appearances MUST be updated for correct rendering
- Either rely on
save({ updateFieldAppearances: true })(default) or callform.updateFieldAppearances()explicitly - For custom fonts in forms, ALWAYS pass the font:
form.updateFieldAppearances(customFont)
7e. XFA forms:
- If working with XFA-based PDFs, call
form.deleteXFA()before manipulating AcroForm fields
See references/examples.md for correct form handling patterns.
CHECK 8: Color Value Range [WARNING]
What: Verify all color values are in the 0.0-1.0 range.
Rules:
rgb(r, g, b)— each value MUST be 0.0 to 1.0, NOT 0 to 255cmyk(c, m, y, k)— each value MUST be 0.0 to 1.0grayscale(g)— value MUST be 0.0 to 1.0opacityvalues — MUST be 0.0 to 1.0
Red flags:
- Values greater than 1.0 (e.g.,
rgb(255, 0, 0)) - Integer values where decimals are expected
How to fix: Divide by 255 if converting from 0-255 range: rgb(r/255, g/255, b/255).
CHECK 9: Save Options Review [INFO]
What: Verify save options are appropriate for the use case.
Sub-checks:
9a. updateFieldAppearances option:
- Default:
true— refreshes form field visual rendering on save - Set to
falseONLY if you manually calledform.updateFieldAppearances()or have no form fields - Setting to
falsewhen form fields exist may cause fields to appear empty
9b. addDefaultPage option:
- Default:
true— inserts a blank page if the document has zero pages - Set to
falsewhen intentionally creating empty documents or when page count is managed explicitly
9c. useObjectStreams option:
- Default:
true— enables compression for smaller file size - Set to
falsefor maximum compatibility with older PDF readers
How to fix: Review save options against the intended output requirements.
CHECK 10: Image Aspect Ratio [INFO]
What: Verify images maintain correct proportions.
Rules:
- ALWAYS use
image.scale(factor)orimage.scaleToFit(maxWidth, maxHeight)for proportional sizing - NEVER set arbitrary
widthandheightindependently without calculating aspect ratio - For manual scaling: calculate one dimension from the other using the original ratio
How to fix: Replace independent width/height with scale() or scaleToFit() calls.
Review Execution Order
When reviewing pdf-lib code, execute checks in this exact order (CRITICAL first):
- CHECK 1 — Async/Await Audit [CRITICAL]
- CHECK 2 — Import Completeness [CRITICAL]
- CHECK 4 — Font Handling [CRITICAL]
- CHECK 5 — Image Format Validation [CRITICAL]
- CHECK 6 — Cross-Document Operations [CRITICAL]
- CHECK 3 — Coordinate System Verification [WARNING]
- CHECK 7 — Form Field Validation [WARNING]
- CHECK 8 — Color Value Range [WARNING]
- CHECK 9 — Save Options Review [INFO]
- CHECK 10 — Image Aspect Ratio [INFO]
Review Output Format
For each violation found, report:
[SEVERITY] CHECK N: Brief description
Line(s): <line numbers>
Issue: <what is wrong>
Fix: <how to correct it>
Reference Files
- references/methods.md — Complete async/sync method reference
- references/examples.md — Before/after code review examples
- references/anti-patterns.md — Complete anti-pattern checklist