Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions FORK.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ This AI-assisted workflow enables rapid response to community issues while maint

## Fork Release History

### Unreleased

**Bug Fix: `workbook.getWorksheet(name)` is now case-insensitive** ([upstream #3028](https://github.com/exceljs/exceljs/issues/3028))

`Workbook.addWorksheet(name)` already enforces case-insensitive uniqueness (and Excel itself treats sheet names case-insensitively), but `Workbook.getWorksheet(name)` was matching with a case-sensitive `===`. The two APIs disagreed: a workbook would refuse to add `"sheet1"` because `"Sheet1"` exists, yet `getWorksheet("sheet1")` would return `undefined` for that same sheet.

`getWorksheet` now lowercases both sides of the comparison so any casing of an existing sheet name resolves to that sheet. Numeric-id and no-arg branches are unchanged.

Minor behavior change: code that relied on a casing mismatch returning `undefined` will now find the sheet. We consider this a bug fix — the previous behavior contradicted `addWorksheet`'s own constraint.

### 4.4.0-protobi.9 (2026-02-01)

**New Feature: Pivot Table & Chart Round-Trip Preservation** ([#41](https://github.com/cjnoname/excelts/issues/41))
Expand Down
29 changes: 15 additions & 14 deletions lib/doc/workbook.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,20 @@ class Workbook {
// if options is a color, call it tabColor (and signal deprecated message)
if (options) {
if (typeof options === 'string') {
const argbMsg =
'tabColor argument is now deprecated. Please use workbook.addWorksheet(name, {properties: { tabColor: { argb: "rbg value" } }';
// eslint-disable-next-line no-console
console.trace(
'tabColor argument is now deprecated. Please use workbook.addWorksheet(name, {properties: { tabColor: { argb: "rbg value" } }'
);
console.trace(argbMsg);
options = {
properties: {
tabColor: {argb: options},
},
};
} else if (options.argb || options.theme || options.indexed) {
const tabMsg =
'tabColor argument is now deprecated. Please use workbook.addWorksheet(name, {properties: { tabColor: { ... } }';
// eslint-disable-next-line no-console
console.trace(
'tabColor argument is now deprecated. Please use workbook.addWorksheet(name, {properties: { tabColor: { ... } }'
);
console.trace(tabMsg);
options = {
properties: {
tabColor: options,
Expand All @@ -79,13 +79,12 @@ class Workbook {
}
}

const lastOrderNo = this._worksheets.reduce((acc, ws) => ((ws && ws.orderNo) > acc ? ws.orderNo : acc), 0);
const worksheetOptions = Object.assign({}, options, {
id,
name,
orderNo: lastOrderNo + 1,
workbook: this,
});
let lastOrderNo = 0;
for (const w of this._worksheets) {
if (w && w.orderNo > lastOrderNo) lastOrderNo = w.orderNo;
}
const orderNo = lastOrderNo + 1;
const worksheetOptions = Object.assign({}, options, {id, name, orderNo, workbook: this});

const worksheet = new Worksheet(worksheetOptions);

Expand All @@ -112,7 +111,9 @@ class Workbook {
return this._worksheets[id];
}
if (typeof id === 'string') {
return this._worksheets.find(worksheet => worksheet && worksheet.name === id);
// Case-insensitive to match addWorksheet's uniqueness rule (and Excel itself).
const target = id.toLowerCase();
return this._worksheets.find(ws => ws && ws.name.toLowerCase() === target);
}
return undefined;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const ExcelJS = verquire('exceljs');

describe('github issues', () => {
describe('issue 3028 - workbook.getWorksheet should be case-insensitive', () => {
it('returns the same worksheet regardless of name casing', () => {
const wb = new ExcelJS.Workbook();
const ws = wb.addWorksheet('TestSheet');

expect(wb.getWorksheet('TestSheet')).to.equal(ws);
expect(wb.getWorksheet('testsheet')).to.equal(ws);
expect(wb.getWorksheet('TESTSHEET')).to.equal(ws);
expect(wb.getWorksheet('tEsTsHeEt')).to.equal(ws);
});

it('still returns undefined for genuinely unknown names', () => {
const wb = new ExcelJS.Workbook();
wb.addWorksheet('TestSheet');

expect(wb.getWorksheet('OtherSheet')).to.equal(undefined);
});

it('preserves numeric id lookup', () => {
const wb = new ExcelJS.Workbook();
const ws = wb.addWorksheet('TestSheet');

expect(wb.getWorksheet(ws.id)).to.equal(ws);
});

it('preserves the no-arg first-worksheet shortcut', () => {
const wb = new ExcelJS.Workbook();
const ws = wb.addWorksheet('TestSheet');

expect(wb.getWorksheet()).to.equal(ws);
});

it('aligns getWorksheet with addWorksheet case-insensitive uniqueness', () => {
// addWorksheet rejects "testsheet" as a duplicate of "TestSheet";
// therefore getWorksheet("testsheet") must locate the existing sheet.
const wb = new ExcelJS.Workbook();
const ws = wb.addWorksheet('TestSheet');

expect(() => wb.addWorksheet('testsheet')).to.throw(/already exists/);
expect(wb.getWorksheet('testsheet')).to.equal(ws);
});
});
});