Repository navigation
ExcelReader
Type: Component (Service) Domain: District Volume Import / Spreadsheet Processing Status: Complete (Issue #905) Last updated: 2026-06-17
ExcelReader is a pure file-reading service that forms the file-I/O layer of the spreadsheet import pipeline. It wraps the exceljs library to load .xlsx workbooks from browser File objects, providing typed worksheet access and sheet-name introspection.
Migrated from SheetJS (xlsx) to exceljs for better merged-cell support, streaming, and an actively maintained codebase (see MatrixParser for merged-cell resolution).
Stateless service. No constructor parameters.
Loads the file into an exceljs Workbook object.
| Parameter | Type | Required | Description |
|---|---|---|---|
file |
File |
yes | Browser File from <input type="file" />
|
Throws: ExcelReadError — on corrupt file, arrayBuffer failure, or unsupported format.
Returns a specific worksheet by name, or the first worksheet if no name given.
| Parameter | Type | Required | Description |
|---|---|---|---|
file |
File |
yes | Browser File |
sheetName |
string |
no | Worksheet name (default: first sheet) |
Returns: ExcelJS.Worksheet — provides row/column/cell access including merge info.
Throws: ExcelReadError — on missing sheet, empty workbook, or file load failure.
Returns all worksheet names in the workbook.
| Parameter | Type | Required | Description |
|---|---|---|---|
file |
File |
yes | Browser File |
Returns: string[] — worksheet names in document order.
Typed error for file-level failures.
export class ExcelReadError extends Error {
name = 'ExcelReadError';
constructor(message: string);
}- Does NOT import Zod, React, or Carbon UI libraries
- Only reads and selects worksheets
- Reusable in non-React contexts
- exceljs is actively maintained;
xlsx(SheetJS) is unmaintained - exceljs provides native merged-cell resolution via
worksheet.mergeCellsandworksheet.getCell().type - ExcelFile API:
file.arrayBuffer()→workbook.xlsx.load(buffer)
// arrayBuffer failure → ExcelReadError
// workbook.xlsx.load failure → ExcelReadError
// Missing sheet → ExcelReadError| Dependency | Version | Purpose | License |
|---|---|---|---|
exceljs |
^4.4+ | Read .xlsx into typed workbook/worksheet objects | MIT |
| Constraint | Detail |
|---|---|
| Supported formats |
.xlsx only (CSV not supported by exceljs in browser) |
| File size limit | 2 MB (enforced by UI layer via maxFileSizeBytes) |
| Error type | Always ExcelReadError for file-level failures |
| No Zod/React | Must never import zod, react, or @carbon/*
|
| Artifact | Path |
|---|---|
| Service | frontend/src/services/spreadsheet/excelReader.ts |
| Types | frontend/src/services/spreadsheet/types.ts |
| Tests | frontend/src/services/spreadsheet/excelReader.unit.test.ts |
6 tests covering: read (first sheet, named sheet, missing sheet, corrupt file, arrayBuffer failure) and listSheets.
- Named sheet not found →
ExcelReadError - Corrupt file data →
ExcelReadErrorfromworkbook.xlsx.load() - arrayBuffer rejection →
ExcelReadError - Empty workbook →
ExcelReadError
Layer 1 — ExcelReader file → ExcelJS.Worksheet
Layer 2 — MatrixParser Worksheet → flat Record[] (via MatrixConfig)
Layer 3 — SpreadsheetValidator Worksheet headers → ValidationResult
Layer 4 — DistrictVolumeProcessor orchestrates 1-3 → ProcessorResult<TableData>
| Consumer | Location | Usage |
|---|---|---|
| MatrixParser | src/services/spreadsheet/matrixParser.ts |
Receives Worksheet for row iteration |
| SpreadsheetValidator | src/services/spreadsheet/spreadsheetValidator.ts |
Receives Worksheet for header validation |
| DistrictVolumeProcessor | src/services/districtvolumes/processors/ |
Creates ExcelReader, calls read + listSheets |
| Interior Validator | src/services/districtvolumes/validators/ |
Creates ExcelReader for pre-upload validation |
| Coast Validator | src/services/districtvolumes/validators/ |
Creates ExcelReader for pre-upload validation |
import { ExcelReader } from '@/services/spreadsheet/excelReader';
const reader = new ExcelReader();
const worksheet = await reader.read(file, 'Interior');const sheets = await reader.listSheets(file);
// ['Interior', 'Coast', 'Data', ...]| Reference | Link |
|---|---|
| GitHub Issue | #905 |
| Epic | District Average Waste Volume Tables |
| Related page | MatrixParser |
| Related page | SpreadsheetValidator |
| Related page | DistrictVolumeProcessor |
This wiki documents NR Waste Plus for users and developers. Verify security and deployment guidance against the current application configuration before applying it elsewhere.
- Report an issue or ask a question in the GitHub repository.
- Follow the Contributing Guidelines to propose an update.
- Read the Code of Conduct.
Collection indexes support human browsing and machine retrieval. Keep both current when adding or moving wiki pages.
NR Waste Plus Wiki | GitHub Repository