From f219555dab1c8c5af7ff1f8420de7727d1e0bfa5 Mon Sep 17 00:00:00 2001 From: Robert Patch Date: Wed, 18 Mar 2026 02:56:01 -0700 Subject: [PATCH] fix: resolve TypeScript compilation errors for K-1 import feature - Update pdf-parse usage from v1 to v2 API (PDFParse class with getText()) - Fix Prisma relation names: memberships -> members, isActive -> endDate: null - Remove unused imports, variables, and service injections - Fix noUnusedLocals/noUnusedParameters violations across 9 files --- .../cell-mapping/cell-mapping.controller.ts | 7 +---- .../app/cell-mapping/cell-mapping.service.ts | 2 +- .../extractors/pdf-parse-extractor.ts | 12 +++++---- .../extractors/tesseract-extractor.ts | 7 ++--- .../app/k1-import/k1-aggregation.service.ts | 4 +-- .../app/k1-import/k1-confidence.service.ts | 2 +- .../src/app/k1-import/k1-import.service.ts | 26 +++++++++---------- .../k1-verification.component.ts | 3 --- .../app/services/k1-import-data.service.ts | 1 - 9 files changed, 27 insertions(+), 37 deletions(-) diff --git a/apps/api/src/app/cell-mapping/cell-mapping.controller.ts b/apps/api/src/app/cell-mapping/cell-mapping.controller.ts index 6a54ae4bb..b33c44688 100644 --- a/apps/api/src/app/cell-mapping/cell-mapping.controller.ts +++ b/apps/api/src/app/cell-mapping/cell-mapping.controller.ts @@ -1,19 +1,15 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { permissions } from '@ghostfolio/common/permissions'; -import type { RequestWithUser } from '@ghostfolio/common/types'; - import { Body, Controller, Delete, Get, - Inject, Put, Query, UseGuards } from '@nestjs/common'; -import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; import { CellMappingService } from './cell-mapping.service'; @@ -21,8 +17,7 @@ import { CellMappingService } from './cell-mapping.service'; @Controller('api/v1/cell-mapping') export class CellMappingController { public constructor( - private readonly cellMappingService: CellMappingService, - @Inject(REQUEST) private readonly request: RequestWithUser + private readonly cellMappingService: CellMappingService ) {} /** diff --git a/apps/api/src/app/cell-mapping/cell-mapping.service.ts b/apps/api/src/app/cell-mapping/cell-mapping.service.ts index 6b3caf3b6..3a08451e3 100644 --- a/apps/api/src/app/cell-mapping/cell-mapping.service.ts +++ b/apps/api/src/app/cell-mapping/cell-mapping.service.ts @@ -253,7 +253,7 @@ export class CellMappingService implements OnModuleInit { where: { partnershipId } }); - const results = await this.prismaService.cellAggregationRule.createMany({ + await this.prismaService.cellAggregationRule.createMany({ data: rules.map((rule, i) => ({ partnershipId, name: rule.name, diff --git a/apps/api/src/app/k1-import/extractors/pdf-parse-extractor.ts b/apps/api/src/app/k1-import/extractors/pdf-parse-extractor.ts index e9e9ef35f..765d2c083 100644 --- a/apps/api/src/app/k1-import/extractors/pdf-parse-extractor.ts +++ b/apps/api/src/app/k1-import/extractors/pdf-parse-extractor.ts @@ -1,7 +1,7 @@ -import type { K1ExtractionResult, K1ExtractedField, K1UnmappedItem } from '@ghostfolio/common/interfaces'; +import type { K1ExtractionResult, K1ExtractedField } from '@ghostfolio/common/interfaces'; import { Injectable, Logger } from '@nestjs/common'; -import * as pdfParse from 'pdf-parse'; +import { PDFParse } from 'pdf-parse'; import type { K1Extractor } from './k1-extractor.interface'; @@ -245,9 +245,10 @@ export class PdfParseExtractor implements K1Extractor { ): Promise { this.logger.log(`Extracting from digital PDF: ${fileName}`); - const parsed = await pdfParse(buffer); + const parser = new PDFParse({ data: buffer }); + const parsed = await parser.getText(); const text = parsed.text; - const pageCount = parsed.numpages; + const pageCount = parsed.total; // Extract metadata const metadata = this.extractMetadata(text); @@ -394,7 +395,8 @@ export class PdfParseExtractor implements K1Extractor { */ public async isDigitalK1(buffer: Buffer): Promise { try { - const parsed = await pdfParse(buffer); + const parser = new PDFParse({ data: buffer }); + const parsed = await parser.getText(); const text = parsed.text || ''; if (text.length < 100) return false; diff --git a/apps/api/src/app/k1-import/extractors/tesseract-extractor.ts b/apps/api/src/app/k1-import/extractors/tesseract-extractor.ts index 73554f32a..b2f26e637 100644 --- a/apps/api/src/app/k1-import/extractors/tesseract-extractor.ts +++ b/apps/api/src/app/k1-import/extractors/tesseract-extractor.ts @@ -55,10 +55,11 @@ export class TesseractExtractor implements K1Extractor { // Fallback: try pdf-parse to at least get any embedded text try { - const pdfParse = await import('pdf-parse'); - const parsed = await pdfParse.default(buffer); + const { PDFParse } = await import('pdf-parse'); + const parser = new PDFParse({ data: buffer }); + const parsed = await parser.getText(); text = parsed.text; - pageCount = parsed.numpages; + pageCount = parsed.total; } catch (parseError) { this.logger.error( `Both Tesseract and pdf-parse failed: ${parseError}` diff --git a/apps/api/src/app/k1-import/k1-aggregation.service.ts b/apps/api/src/app/k1-import/k1-aggregation.service.ts index 1c6215855..7c8f36ef3 100644 --- a/apps/api/src/app/k1-import/k1-aggregation.service.ts +++ b/apps/api/src/app/k1-import/k1-aggregation.service.ts @@ -1,7 +1,7 @@ import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import type { K1AggregationResult } from '@ghostfolio/common/interfaces'; -import { HttpException, Injectable, Logger } from '@nestjs/common'; +import { HttpException, Injectable } from '@nestjs/common'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { CellMappingService } from '../cell-mapping/cell-mapping.service'; @@ -13,8 +13,6 @@ import { CellMappingService } from '../cell-mapping/cell-mapping.service'; */ @Injectable() export class K1AggregationService { - private readonly logger = new Logger(K1AggregationService.name); - public constructor( private readonly prismaService: PrismaService, private readonly cellMappingService: CellMappingService diff --git a/apps/api/src/app/k1-import/k1-confidence.service.ts b/apps/api/src/app/k1-import/k1-confidence.service.ts index 02af8a35a..db7631b67 100644 --- a/apps/api/src/app/k1-import/k1-confidence.service.ts +++ b/apps/api/src/app/k1-import/k1-confidence.service.ts @@ -16,7 +16,7 @@ export class K1ConfidenceService { */ public scoreFields( fields: K1ExtractedField[], - method: 'pdf-parse' | 'azure' | 'tesseract' + _method: 'pdf-parse' | 'azure' | 'tesseract' ): K1ExtractedField[] { const scored = fields.map((field) => ({ ...field, diff --git a/apps/api/src/app/k1-import/k1-import.service.ts b/apps/api/src/app/k1-import/k1-import.service.ts index f69e43250..69e76c844 100644 --- a/apps/api/src/app/k1-import/k1-import.service.ts +++ b/apps/api/src/app/k1-import/k1-import.service.ts @@ -7,14 +7,11 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; -import { CellMappingService } from '../cell-mapping/cell-mapping.service'; import { UploadService } from '../upload/upload.service'; import { AzureExtractor } from './extractors/azure-extractor'; import { PdfParseExtractor } from './extractors/pdf-parse-extractor'; import { TesseractExtractor } from './extractors/tesseract-extractor'; -import { K1AggregationService } from './k1-aggregation.service'; import { K1AllocationService } from './k1-allocation.service'; -import { K1ConfidenceService } from './k1-confidence.service'; import { K1FieldMapperService } from './k1-field-mapper.service'; const MAX_FILE_SIZE = 25 * 1024 * 1024; // 25 MB @@ -26,11 +23,8 @@ export class K1ImportService { public constructor( private readonly prismaService: PrismaService, private readonly uploadService: UploadService, - private readonly cellMappingService: CellMappingService, private readonly fieldMapperService: K1FieldMapperService, - private readonly confidenceService: K1ConfidenceService, private readonly allocationService: K1AllocationService, - private readonly aggregationService: K1AggregationService, private readonly pdfParseExtractor: PdfParseExtractor, private readonly azureExtractor: AzureExtractor, private readonly tesseractExtractor: TesseractExtractor @@ -74,8 +68,10 @@ export class K1ImportService { userId }, include: { - memberships: { - where: { isActive: true } + members: { + where: { + endDate: null + } } } }); @@ -87,7 +83,7 @@ export class K1ImportService { ); } - if (!partnership.memberships || partnership.memberships.length === 0) { + if (!partnership.members || partnership.members.length === 0) { throw new HttpException( 'Partnership has no active members', StatusCodes.BAD_REQUEST @@ -585,7 +581,7 @@ export class K1ImportService { await this.prismaService.partnershipMembership.findMany({ where: { partnershipId: session.partnershipId, - isActive: true + endDate: null }, include: { entity: true } }); @@ -768,8 +764,9 @@ export class K1ImportService { */ private async checkPasswordProtected(buffer: Buffer): Promise { try { - const pdfParse = await import('pdf-parse'); - await pdfParse.default(buffer); + const { PDFParse } = await import('pdf-parse'); + const parser = new PDFParse({ data: buffer }); + await parser.getText(); } catch (error) { if ( error?.message?.includes('password') || @@ -793,8 +790,9 @@ export class K1ImportService { entityCount: number; }> { try { - const pdfParse = await import('pdf-parse'); - const parsed = await pdfParse.default(buffer); + const { PDFParse } = await import('pdf-parse'); + const parser = new PDFParse({ data: buffer }); + const parsed = await parser.getText(); const text = parsed.text || ''; // Count "Schedule K-1" header occurrences diff --git a/apps/client/src/app/pages/k1-import/k1-verification/k1-verification.component.ts b/apps/client/src/app/pages/k1-import/k1-verification/k1-verification.component.ts index a3545b2c0..66935e2ba 100644 --- a/apps/client/src/app/pages/k1-import/k1-verification/k1-verification.component.ts +++ b/apps/client/src/app/pages/k1-import/k1-verification/k1-verification.component.ts @@ -89,8 +89,6 @@ export class K1VerificationComponent implements OnInit { // Available box numbers for assigning unmapped items public availableBoxNumbers: string[] = []; - private partnershipId: string; - public constructor( private readonly activatedRoute: ActivatedRoute, private readonly changeDetectorRef: ChangeDetectorRef, @@ -294,7 +292,6 @@ export class K1VerificationComponent implements OnInit { } this.taxYear = session.taxYear; - this.partnershipId = session.partnershipId; const extraction = session.rawExtraction || session.verifiedData; if (extraction) { diff --git a/apps/client/src/app/services/k1-import-data.service.ts b/apps/client/src/app/services/k1-import-data.service.ts index 4aa831f1e..4682f282b 100644 --- a/apps/client/src/app/services/k1-import-data.service.ts +++ b/apps/client/src/app/services/k1-import-data.service.ts @@ -1,5 +1,4 @@ import type { - K1ExtractionResult, K1ImportSessionSummary, K1AggregationResult } from '@ghostfolio/common/interfaces';