-
Notifications
You must be signed in to change notification settings - Fork 84
XLSX support with ExcelJS #248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
a8f7998
XLSX support with ExcelJS
visnup 38fceab
Prettier
visnup 9226446
Change range option to nested arrays
visnup 77159f0
Tests and bug fixes
visnup d8904d0
Respect header row order when resolving conflicts
visnup ee0dfbf
Fil/xlsx (#249)
Fil fd177b0
Column only range test case
visnup f6ddcff
sheetNames is enumerable
visnup 9b9eab6
One more test to check for empty columns
visnup a845086
Add Node 16 to the test matrix
visnup f30b626
Revert reporter to classic for Node 16
visnup e421983
Don't fail matrix quickly in actions
visnup e8b0153
More coverage.
visnup e7c82d4
Example of .xlsx in README
visnup 1440400
Remove Excel from Workbook naming
visnup d444ebe
Fix dates
visnup 410f4c9
Fix for sharedFormula
visnup 57cb0e0
Coerce errors to NaN
visnup e2976b1
Properly escape html
visnup e618095
Merge branch 'main' into visnup/xlsx
visnup b97b9f6
Make sheetNames read-only
visnup e5eb8d6
Require colons in range specifiers
visnup 81433c6
Include row numbers
visnup 2f26284
Use only string form ranges
visnup 66a539c
Coerce range specifiers to strings
visnup fcb6eb7
Update README.md
visnup 162d55e
Apply suggestions from code review
visnup 9c9e91b
Simplify hyperlinks
visnup 1a0345e
Prettier
visnup 5daef26
Pass options through
visnup 92c4af1
Rename helper functions for clarity, range tests
visnup 6f13d59
Simpler
visnup c52b73f
Consistent comment format
visnup 5b21a79
Consistent regexes
visnup 0a59d0c
Fix hyperlinks for certain cases
visnup File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
export class ExcelWorkbook { | ||
constructor(workbook) { | ||
Object.defineProperty(this, "_", {value: workbook}); | ||
} | ||
sheetNames() { | ||
return this._.worksheets.map(sheet => sheet.name); | ||
} | ||
sheet(name, options) { | ||
name = (typeof name === "number") ? name = this.sheetNames()[name] : name + ""; | ||
const sheet = this._.getWorksheet(name); | ||
if (!sheet) throw new Error(`Sheet not found: ${name}`); | ||
return extract(sheet, options); | ||
} | ||
} | ||
|
||
function extract(sheet, options = {}) { | ||
const { range, headers = false } = options; | ||
let [[c0, r0], [c1, r1]] = parseRange(range, sheet); | ||
const empty = {}; | ||
const output = new Array(r1 - r0).fill(empty); | ||
|
||
const headerRow = headers && sheet._rows[r0++]; | ||
const seen = new Set(); | ||
const names = []; | ||
function name(n) { | ||
if (!names[n]) { | ||
visnup marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let name = (headerRow ? valueOf(headerRow._cells[n]) : AA(n)) || AA(n); | ||
while (seen.has(name)) name += "_"; | ||
seen.add((names[n] = name)); | ||
} | ||
return names[n]; | ||
} | ||
|
||
for (let r = r0; r < r1; r++) { | ||
const _row = sheet._rows[r]; | ||
if (!_row || !_row.hasValues) continue; | ||
const row = (output[r - r0] = {}); | ||
for (let c = c0; c < c1; c++) { | ||
const value = valueOf(_row._cells[c]); | ||
if (value) row[name(c)] = value; | ||
} | ||
} | ||
|
||
output.columns = names.filter(() => true); | ||
visnup marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return output; | ||
} | ||
|
||
function valueOf(cell) { | ||
if (!cell) return; | ||
const { value } = cell; | ||
if (value && typeof value === "object") { | ||
if (value.formula) return value.result; | ||
if (value.richText) return value.richText.map((d) => d.text).join(""); | ||
if (value.text && value.hyperlink) | ||
return `<a href="${value.hyperlink}">${value.text}</a>`; | ||
visnup marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
return value; | ||
} | ||
|
||
function parseRange(specifier = {}, { columnCount, rowCount }) { | ||
if (typeof specifier === "string") { | ||
const [ | ||
[c0 = 0, r0 = 0] = [], | ||
[c1 = columnCount, r1 = rowCount] = [] | ||
] = specifier.split(":").map(NN); | ||
return [ | ||
[c0, r0], | ||
[c1, r1] | ||
]; | ||
} else if (typeof specifier === "object") { | ||
const { | ||
start: [c0 = 0, r0 = 0] = [], | ||
end: [c1 = columnCount, r1 = rowCount] = [] | ||
} = specifier; | ||
return [ | ||
[c0, r0], | ||
[c1, r1] | ||
]; | ||
} | ||
} | ||
|
||
function AA(x) { | ||
let s = ""; | ||
x++; | ||
do { | ||
s = String.fromCharCode(64 + (x % 26 || 26)) + s; | ||
} while ((x = Math.floor((x - 1) / 26))); | ||
return s; | ||
} | ||
|
||
function NN(s = "") { | ||
const [, sc, sr] = s.match(/^([a-zA-Z]+)?(\d+)?$/); | ||
visnup marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let c = undefined; | ||
if (sc) { | ||
c = 0; | ||
visnup marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for (let i = 0; i < sc.length; i++) | ||
c += Math.pow(26, sc.length - i - 1) * (sc.charCodeAt(i) - 64); | ||
} | ||
return [c && c - 1, sr && +sr - 1]; | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.