Skip to content

refactor(processors): dynamic-import mammoth, move to optionalDependencies - #974

Merged
murdore merged 1 commit into
releasefrom
refactor/mammoth-optional
Apr 18, 2026
Merged

murdore merged 1 commit into
releasefrom
refactor/mammoth-optional

Conversation

@murdore

@murdore murdore commented Apr 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Convert static mammoth import to lazy dynamic import in WordProcessor
  • Move mammoth (2.3 MB) from dependencies to optionalDependencies
  • Narrow catch to ERR_MODULE_NOT_FOUND with install hint
  • Zero any types, zero eslint-disable directives

Impact

  • Default installs: no change
  • Word doc processing works when mammoth is installed

Test plan

  • pnpm run build succeeds
  • pnpm run check passes
  • Word document processing works

Summary by CodeRabbit

  • Chores
    • Made Word document processing dependency optional with improved error messaging when the library is not installed.

Copilot AI review requested due to automatic review settings April 18, 2026 20:54
@vercel

vercel Bot commented Apr 18, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
neurolink Ready Ready Preview, Comment Apr 18, 2026 9:20pm

@coderabbitai

coderabbitai Bot commented Apr 18, 2026 •

Copy link
Copy Markdown

Walkthrough

The mammoth library dependency was relocated from required to optional dependencies in package.json. The WordProcessor class was refactored to use dynamic imports with runtime error handling, enabling the application to function without mammoth while providing installation guidance if needed.

Changes

Cohort / File(s) Summary
Dependency Configuration
package.json
Moved mammoth from dependencies to optionalDependencies (^1.11.0).
Lazy Loading Implementation
src/lib/processors/document/WordProcessor.ts
Replaced static import with cached dynamic import via loadMammoth() function. Added error handling to detect missing mammoth installation and throw user-friendly error with install instructions. Updated processFile() to await mammoth loading at runtime.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • juspay/neurolink#971: Applies the same optional dependency + dynamic import pattern to @picovoice/cobra-node in voiceWebSocketHandler.

Poem

🐰 A mammoth once required, now optional it seems,
Dynamic loading brings flexibility to our dreams,
With friendly error messages when libraries are sparse,
The codebase grows more graceful—less weight to traverse!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: converting mammoth from a static import to dynamic/lazy loading and moving it from dependencies to optionalDependencies.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/mammoth-optional

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Apr 18, 2026 •

Copy link
Copy Markdown
Contributor

✅ Single Commit Policy - COMPLIANT

Status: Policy requirements met • 1 commit • Valid format • Ready for merge

📊 View validation details

📝 Commit Details

  • Hash: ce6e043985d0544b0a83416e02fbf0a1052cd2b7
  • Message: refactor(processors): dynamic-import mammoth, move to optionalDependencies
  • Author: Sachin Sharma

✅ Validation Results

  • Single commit requirement met
  • No merge commits in branch
  • Semantic commit message format verified
  • Ready for squash merge to release branch

🤖 Automated validation by NeuroLink Single Commit Enforcement

@github-actions

Copy link
Copy Markdown
Contributor

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Refactors Word document processing to make the heavy mammoth dependency optional and lazily loaded at runtime, reducing required dependency footprint for installs that don’t need Word processing.

Changes:

  • Replaced static mammoth import with a cached dynamic import helper in WordProcessor.
  • Moved mammoth from dependencies to optionalDependencies in package.json.
  • Updated pnpm-lock.yaml to reflect mammoth as an optional dependency.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.

File Description
src/lib/processors/document/WordProcessor.ts Introduces lazy-loading of mammoth and uses it during extraction.
package.json Moves mammoth to optionalDependencies to make Word support opt-in.
pnpm-lock.yaml Aligns lockfile with the dependency classification change.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…ncies

Convert static `import * as mammoth from "mammoth"` to a lazy
dynamic import with ERR_MODULE_NOT_FOUND detection. Move mammoth
(2.3 MB) from dependencies to optionalDependencies.
@github-actions

Copy link
Copy Markdown
Contributor

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/processors/document/WordProcessor.ts (1)

286-321: ⚠️ Potential issue | 🟠 Major

Install-hint error is swallowed by the inner try/catch.

loadMammoth() is invoked inside the inner try block at line 287. When mammoth isn't installed, the helpful Error('Word document processing requires the "mammoth" package...') thrown at line 56 is caught at line 309 and re-wrapped as a generic FileErrorCode.PROCESSING_FAILED with reason: "Failed to extract Word document content". The install instructions never surface to the caller, defeating the main UX goal of this refactor.

Consider calling loadMammoth() before the inner try, or detecting the install-hint error and propagating it with a distinct error code (e.g., FileErrorCode.DEPENDENCY_MISSING or reusing the message as reason):

🔧 Proposed fix
-      // Step 4 & 5: Extract text and HTML content using mammoth
-      let textContent = "";
-      let htmlContent = "";
-      const warnings: string[] = [];
-
-      try {
-        const mammoth = await loadMammoth();
+      // Load mammoth before the extraction try/catch so the missing-dependency
+      // error surfaces with its install instructions instead of being masked.
+      const mammoth = await loadMammoth();
+
+      // Step 4 & 5: Extract text and HTML content using mammoth
+      let textContent = "";
+      let htmlContent = "";
+      const warnings: string[] = [];
+
+      try {
         // Extract plain text
         const textResult = await mammoth.extractRawText({ buffer });

The outer try/catch at line 338 will then return the install-hint message via error.message in UNKNOWN_ERROR, or you can add a dedicated branch that detects the dependency-missing case and maps it to a more specific error code.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/processors/document/WordProcessor.ts` around lines 286 - 321, The
inner try/catch in WordProcessor (around the block calling loadMammoth,
mammoth.extractRawText, and mammoth.convertToHtml) is swallowing the
install-hint error from loadMammoth; move the call to loadMammoth() outside that
inner try so its specific error propagates, or detect the install-hint error
after catching (inspect extractError.message or error type) and rethrow or
return a distinct createError(FileErrorCode.DEPENDENCY_MISSING, { reason:
extractError.message }, extractError) so the original install instructions from
loadMammoth() are preserved instead of being wrapped as PROCESSING_FAILED.
🧹 Nitpick comments (2)
src/lib/processors/document/WordProcessor.ts (2)

45-63: Matching on error message substring is fragile.

e.message.includes("mammoth") works today because Node's ERR_MODULE_NOT_FOUND message embeds the specifier, but message wording isn't part of Node's stable contract and bundlers (esbuild/ncc/vite) may rewrite it. Consider also checking err shape more defensively, e.g., accept ERR_MODULE_NOT_FOUND unconditionally here (this loader only ever imports "mammoth"), or additionally match MODULE_NOT_FOUND for the CJS fallback path:

🔧 Suggested tweak
-    const e = err instanceof Error ? (err as NodeJS.ErrnoException) : null;
-    if (e?.code === "ERR_MODULE_NOT_FOUND" && e.message.includes("mammoth")) {
+    const e = err instanceof Error ? (err as NodeJS.ErrnoException) : null;
+    if (
+      e?.code === "ERR_MODULE_NOT_FOUND" ||
+      e?.code === "MODULE_NOT_FOUND"
+    ) {
       throw new Error(

Since this loader exclusively imports "mammoth", any MODULE_NOT_FOUND here is unambiguously about mammoth.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/processors/document/WordProcessor.ts` around lines 45 - 63, The
current loadMammoth function relies on err.message.includes("mammoth") which is
fragile; update loadMammoth to treat any module-not-found error as a missing
mammoth install by checking err.code for "ERR_MODULE_NOT_FOUND" or
"MODULE_NOT_FOUND" (or by accepting "ERR_MODULE_NOT_FOUND" unconditionally since
this loader only imports "mammoth"), remove the substring check, and rethrow a
user-friendly Error that mentions installing mammoth (preserving the original
err as the cause); reference symbols: loadMammoth, _mammoth, and error codes
ERR_MODULE_NOT_FOUND / MODULE_NOT_FOUND.

65-67: Stale orphan comments.

These two one-line comments (// Re-export for consumers who import from this module and // Import for local use) appear to be leftovers from the removed static import * as mammoth block and no longer reference anything. Safe to delete for clarity.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/processors/document/WordProcessor.ts` around lines 65 - 67, Remove
the two stale one-line comments left over from the removed static import of
`mammoth` in the WordProcessor module—specifically delete the lines "//
Re-export for consumers who import from this module" and "// Import for local
use" in src/lib/processors/document/WordProcessor.ts so the top-of-file comments
no longer reference nonexistent code; no functional changes required aside from
deleting those orphan comments.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/lib/processors/document/WordProcessor.ts`:
- Around line 286-321: The inner try/catch in WordProcessor (around the block
calling loadMammoth, mammoth.extractRawText, and mammoth.convertToHtml) is
swallowing the install-hint error from loadMammoth; move the call to
loadMammoth() outside that inner try so its specific error propagates, or detect
the install-hint error after catching (inspect extractError.message or error
type) and rethrow or return a distinct
createError(FileErrorCode.DEPENDENCY_MISSING, { reason: extractError.message },
extractError) so the original install instructions from loadMammoth() are
preserved instead of being wrapped as PROCESSING_FAILED.

---

Nitpick comments:
In `@src/lib/processors/document/WordProcessor.ts`:
- Around line 45-63: The current loadMammoth function relies on
err.message.includes("mammoth") which is fragile; update loadMammoth to treat
any module-not-found error as a missing mammoth install by checking err.code for
"ERR_MODULE_NOT_FOUND" or "MODULE_NOT_FOUND" (or by accepting
"ERR_MODULE_NOT_FOUND" unconditionally since this loader only imports
"mammoth"), remove the substring check, and rethrow a user-friendly Error that
mentions installing mammoth (preserving the original err as the cause);
reference symbols: loadMammoth, _mammoth, and error codes ERR_MODULE_NOT_FOUND /
MODULE_NOT_FOUND.
- Around line 65-67: Remove the two stale one-line comments left over from the
removed static import of `mammoth` in the WordProcessor module—specifically
delete the lines "// Re-export for consumers who import from this module" and
"// Import for local use" in src/lib/processors/document/WordProcessor.ts so the
top-of-file comments no longer reference nonexistent code; no functional changes
required aside from deleting those orphan comments.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c23047d5-e0ae-4b4c-8de9-d047649afa38

📥 Commits

Reviewing files that changed from the base of the PR and between 2b513f8 and ce6e043.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • package.json
  • src/lib/processors/document/WordProcessor.ts

@murdore
murdore merged commit d669eff into release Apr 18, 2026
16 checks passed
@murdore
murdore deleted the refactor/mammoth-optional branch April 18, 2026 21:31
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 9.55.6 🎉

The release is available on:

Your semantic-release bot 📦🚀

This branch was successfully deployed

1 active deployment
Preview — ce6e0439 Deployed Apr 18, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants