exceljs
Version:
Excel Workbook Manager - Read and Write xlsx and csv Files.
1,942 lines (1,773 loc) • 1.3 MB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.ExcelJS = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
var PromishLib = require('../utils/promish');
function setValue(key, value, overwrite) {
if (overwrite === undefined) {
// only avoid overwrite if explicitly disabled
overwrite = true;
}
switch (key.toLowerCase()) {
case 'promise':
if (!overwrite && PromishLib.Promish) return;
PromishLib.Promish = value;
break;
default:
break;
}
}
module.exports = setValue;
},{"../utils/promish":15}],2:[function(require,module,exports){
/**
* Copyright (c) 2015-2017 Guyon Roche
* LICENCE: MIT - please refer to LICENCE file included with this module
* or https://github.com/guyonroche/exceljs/blob/master/LICENSE
*/
'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var fs = require('fs');
var csv = require('fast-csv');
var moment = require('moment');
var PromishLib = require('../utils/promish');
var utils = require('../utils/utils');
var CSV = module.exports = function (workbook) {
this.workbook = workbook;
this.worksheet = null;
};
/* eslint-disable quote-props */
var SpecialValues = {
'true': true,
'false': false,
'#N/A': { error: '#N/A' },
'#REF!': { error: '#REF!' },
'#NAME?': { error: '#NAME?' },
'#DIV/0!': { error: '#DIV/0!' },
'#NULL!': { error: '#NULL!' },
'#VALUE!': { error: '#VALUE!' },
'#NUM!': { error: '#NUM!' }
};
/* eslint-ensable quote-props */
CSV.prototype = {
readFile: function readFile(filename, options) {
var self = this;
options = options || {};
var stream;
return utils.fs.exists(filename).then(function (exists) {
if (!exists) {
throw new Error('File not found: ' + filename);
}
stream = fs.createReadStream(filename);
return self.read(stream, options);
}).then(function (worksheet) {
stream.close();
return worksheet;
});
},
read: function read(stream, options) {
var _this = this;
options = options || {};
return new PromishLib.Promish(function (resolve, reject) {
var csvStream = _this.createInputStream(options).on('worksheet', resolve).on('error', reject);
stream.pipe(csvStream);
});
},
createInputStream: function createInputStream(options) {
options = options || {};
var worksheet = this.workbook.addWorksheet(options.sheetName);
var dateFormats = options.dateFormats || [moment.ISO_8601, 'MM-DD-YYYY', 'YYYY-MM-DD'];
var map = options.map || function (datum) {
if (datum === '') {
return null;
}
if (!isNaN(datum)) {
return parseFloat(datum);
}
var dt = moment(datum, dateFormats, true);
if (dt.isValid()) {
return new Date(dt.valueOf());
}
var special = SpecialValues[datum];
if (special !== undefined) {
return special;
}
return datum;
};
var csvStream = csv(options).on('data', function (data) {
worksheet.addRow(data.map(map));
}).on('end', function () {
csvStream.emit('worksheet', worksheet);
});
return csvStream;
},
write: function write(stream, options) {
var _this2 = this;
return new PromishLib.Promish(function (resolve, reject) {
options = options || {};
// var encoding = options.encoding || 'utf8';
// var separator = options.separator || ',';
// var quoteChar = options.quoteChar || '\'';
var worksheet = _this2.workbook.getWorksheet(options.sheetName || options.sheetId);
var csvStream = csv.createWriteStream(options);
stream.on('finish', function () {
resolve();
});
csvStream.on('error', reject);
csvStream.pipe(stream);
var dateFormat = options.dateFormat;
var map = options.map || function (value) {
if (value) {
if (value.text || value.hyperlink) {
return value.hyperlink || value.text || '';
}
if (value.formula || value.result) {
return value.result || '';
}
if (value instanceof Date) {
return dateFormat ? moment(value).format(dateFormat) : moment(value).format();
}
if (value.error) {
return value.error;
}
if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object') {
return JSON.stringify(value);
}
}
return value;
};
var includeEmptyRows = options.includeEmptyRows === undefined || options.includeEmptyRows;
var lastRow = 1;
if (worksheet) {
worksheet.eachRow(function (row, rowNumber) {
if (includeEmptyRows) {
while (lastRow++ < rowNumber - 1) {
csvStream.write([]);
}
}
var values = row.values;
values.shift();
csvStream.write(values.map(map));
lastRow = rowNumber;
});
}
csvStream.end();
});
},
writeFile: function writeFile(filename, options) {
options = options || {};
var streamOptions = {
encoding: options.encoding || 'utf8'
};
var stream = fs.createWriteStream(filename, streamOptions);
return this.write(stream, options);
}
};
},{"../utils/promish":15,"../utils/utils":20,"fast-csv":125,"fs":93,"moment":176}],3:[function(require,module,exports){
/**
* Copyright (c) 2014-2017 Guyon Roche
* LICENCE: MIT - please refer to LICENCE file included with this module
* or https://github.com/guyonroche/exceljs/blob/master/LICENSE
*/
'use strict';
var colCache = require('../utils/col-cache');
var Enums = require('./enums');
var _require = require('../utils/shared-formula'),
slideFormula = _require.slideFormula;
// Cell requirements
// Operate inside a worksheet
// Store and retrieve a value with a range of types: text, number, date, hyperlink, reference, formula, etc.
// Manage/use and manipulate cell format either as local to cell or inherited from column or row.
var Cell = module.exports = function (row, column, address) {
if (!row || !column) {
throw new Error('A Cell needs a Row');
}
this._row = row;
this._column = column;
colCache.validateAddress(address);
this._address = address;
// TODO: lazy evaluation of this._value
this._value = Value.create(Cell.Types.Null, this);
this.style = this._mergeStyle(row.style, column.style, {});
this._mergeCount = 0;
};
Cell.Types = Enums.ValueType;
Cell.prototype = {
get worksheet() {
return this._row.worksheet;
},
get workbook() {
return this._row.worksheet.workbook;
},
// help GC by removing cyclic (and other) references
destroy: function destroy() {
delete this.style;
delete this._value;
delete this._row;
delete this._column;
delete this._address;
},
// =========================================================================
// Styles stuff
get numFmt() {
return this.style.numFmt;
},
set numFmt(value) {
this.style.numFmt = value;
},
get font() {
return this.style.font;
},
set font(value) {
this.style.font = value;
},
get alignment() {
return this.style.alignment;
},
set alignment(value) {
this.style.alignment = value;
},
get border() {
return this.style.border;
},
set border(value) {
this.style.border = value;
},
get fill() {
return this.style.fill;
},
set fill(value) {
this.style.fill = value;
},
_mergeStyle: function _mergeStyle(rowStyle, colStyle, style) {
var numFmt = rowStyle && rowStyle.numFmt || colStyle && colStyle.numFmt;
if (numFmt) style.numFmt = numFmt;
var font = rowStyle && rowStyle.font || colStyle && colStyle.font;
if (font) style.font = font;
var alignment = rowStyle && rowStyle.alignment || colStyle && colStyle.alignment;
if (alignment) style.alignment = alignment;
var border = rowStyle && rowStyle.border || colStyle && colStyle.border;
if (border) style.border = border;
var fill = rowStyle && rowStyle.fill || colStyle && colStyle.fill;
if (fill) style.fill = fill;
return style;
},
// =========================================================================
// return the address for this cell
get address() {
return this._address;
},
get row() {
return this._row.number;
},
get col() {
return this._column.number;
},
get $col$row() {
return '$' + this._column.letter + '$' + this.row;
},
// =========================================================================
// Value stuff
get type() {
return this._value.type;
},
get effectiveType() {
return this._value.effectiveType;
},
toCsvString: function toCsvString() {
return this._value.toCsvString();
},
// =========================================================================
// Merge stuff
addMergeRef: function addMergeRef() {
this._mergeCount++;
},
releaseMergeRef: function releaseMergeRef() {
this._mergeCount--;
},
get isMerged() {
return this._mergeCount > 0 || this.type === Cell.Types.Merge;
},
merge: function merge(master) {
this._value.release();
this._value = Value.create(Cell.Types.Merge, this, master);
this.style = master.style;
},
unmerge: function unmerge() {
if (this.type === Cell.Types.Merge) {
this._value.release();
this._value = Value.create(Cell.Types.Null, this);
this.style = this._mergeStyle(this._row.style, this._column.style, {});
}
},
isMergedTo: function isMergedTo(master) {
if (this._value.type !== Cell.Types.Merge) return false;
return this._value.isMergedTo(master);
},
get master() {
if (this.type === Cell.Types.Merge) {
return this._value.master;
}
return this; // an unmerged cell is its own master
},
get isHyperlink() {
return this._value.type === Cell.Types.Hyperlink;
},
get hyperlink() {
return this._value.hyperlink;
},
// return the value
get value() {
return this._value.value;
},
// set the value - can be number, string or raw
set value(v) {
// special case - merge cells set their master's value
if (this.type === Cell.Types.Merge) {
this._value.master.value = v;
return;
}
this._value.release();
// assign value
this._value = Value.create(Value.getType(v), this, v);
},
get text() {
return this._value.toString();
},
toString: function toString() {
return this.text;
},
_upgradeToHyperlink: function _upgradeToHyperlink(hyperlink) {
// if this cell is a string, turn it into a Hyperlink
if (this.type === Cell.Types.String) {
this._value = Value.create(Cell.Types.Hyperlink, this, {
text: this._value.value,
hyperlink: hyperlink
});
}
},
// =========================================================================
// Formula stuff
get formula() {
return this._value.formula;
},
get result() {
return this._value.result;
},
get formulaType() {
return this._value.formulaType;
},
// =========================================================================
// Name stuff
get fullAddress() {
var worksheet = this._row.worksheet;
return {
sheetName: worksheet.name,
address: this.address,
row: this.row,
col: this.col
};
},
get name() {
return this.names[0];
},
set name(value) {
this.names = [value];
},
get names() {
return this.workbook.definedNames.getNamesEx(this.fullAddress);
},
set names(value) {
var self = this;
var definedNames = this.workbook.definedNames;
this.workbook.definedNames.removeAllNames(self.fullAddress);
value.forEach(function (name) {
definedNames.addEx(self.fullAddress, name);
});
},
addName: function addName(name) {
this.workbook.definedNames.addEx(this.fullAddress, name);
},
removeName: function removeName(name) {
this.workbook.definedNames.removeEx(this.fullAddress, name);
},
removeAllNames: function removeAllNames() {
this.workbook.definedNames.removeAllNames(this.fullAddress);
},
// =========================================================================
// Data Validation stuff
get _dataValidations() {
return this.worksheet.dataValidations;
},
get dataValidation() {
return this._dataValidations.find(this.address);
},
set dataValidation(value) {
this._dataValidations.add(this.address, value);
},
// =========================================================================
// Model stuff
get model() {
var model = this._value.model;
model.style = this.style;
return model;
},
set model(value) {
this._value.release();
this._value = Value.create(value.type, this);
this._value.model = value;
if (value.style) {
this.style = value.style;
} else {
this.style = {};
}
}
};
// =============================================================================
// Internal Value Types
var NullValue = function NullValue(cell) {
this.model = {
address: cell.address,
type: Cell.Types.Null
};
};
NullValue.prototype = {
get value() {
return null;
},
set value(value) {
// nothing to do
},
get type() {
return Cell.Types.Null;
},
get effectiveType() {
return Cell.Types.Null;
},
get address() {
return this.model.address;
},
set address(value) {
this.model.address = value;
},
toCsvString: function toCsvString() {
return '';
},
release: function release() {},
toString: function toString() {
return '';
}
};
var NumberValue = function NumberValue(cell, value) {
this.model = {
address: cell.address,
type: Cell.Types.Number,
value: value
};
};
NumberValue.prototype = {
get value() {
return this.model.value;
},
set value(value) {
this.model.value = value;
},
get type() {
return Cell.Types.Number;
},
get effectiveType() {
return Cell.Types.Number;
},
get address() {
return this.model.address;
},
set address(value) {
this.model.address = value;
},
toCsvString: function toCsvString() {
return '' + this.model.value;
},
release: function release() {},
toString: function toString() {
return this.model.value.toString();
}
};
var StringValue = function StringValue(cell, value) {
this.model = {
address: cell.address,
type: Cell.Types.String,
value: value
};
};
StringValue.prototype = {
get value() {
return this.model.value;
},
set value(value) {
this.model.value = value;
},
get type() {
return Cell.Types.String;
},
get effectiveType() {
return Cell.Types.String;
},
get address() {
return this.model.address;
},
set address(value) {
this.model.address = value;
},
toCsvString: function toCsvString() {
return '"' + this.model.value.replace(/"/g, '""') + '"';
},
release: function release() {},
toString: function toString() {
return this.model.value;
}
};
var RichTextValue = function RichTextValue(cell, value) {
this.model = {
address: cell.address,
type: Cell.Types.String,
value: value
};
};
RichTextValue.prototype = {
get value() {
return this.model.value;
},
set value(value) {
this.model.value = value;
},
toString: function toString() {
return this.model.value.richText.map(function (t) {
return t.text;
}).join('');
},
get type() {
return Cell.Types.RichText;
},
get effectiveType() {
return Cell.Types.RichText;
},
get address() {
return this.model.address;
},
set address(value) {
this.model.address = value;
},
toCsvString: function toCsvString() {
return '"' + this.text.replace(/"/g, '""') + '"';
},
release: function release() {}
};
var DateValue = function DateValue(cell, value) {
this.model = {
address: cell.address,
type: Cell.Types.Date,
value: value
};
};
DateValue.prototype = {
get value() {
return this.model.value;
},
set value(value) {
this.model.value = value;
},
get type() {
return Cell.Types.Date;
},
get effectiveType() {
return Cell.Types.Date;
},
get address() {
return this.model.address;
},
set address(value) {
this.model.address = value;
},
toCsvString: function toCsvString() {
return this.model.value.toISOString();
},
release: function release() {},
toString: function toString() {
return this.model.value.toString();
}
};
var HyperlinkValue = function HyperlinkValue(cell, value) {
this.model = {
address: cell.address,
type: Cell.Types.Hyperlink,
text: value ? value.text : undefined,
hyperlink: value ? value.hyperlink : undefined
};
};
HyperlinkValue.prototype = {
get value() {
return {
text: this.model.text,
hyperlink: this.model.hyperlink
};
},
set value(value) {
this.model.text = value.text;
this.model.hyperlink = value.hyperlink;
},
get text() {
return this.model.text;
},
set text(value) {
this.model.text = value;
},
get hyperlink() {
return this.model.hyperlink;
},
set hyperlink(value) {
this.model.hyperlink = value;
},
get type() {
return Cell.Types.Hyperlink;
},
get effectiveType() {
return Cell.Types.Hyperlink;
},
get address() {
return this.model.address;
},
set address(value) {
this.model.address = value;
},
toCsvString: function toCsvString() {
return this.model.hyperlink;
},
release: function release() {},
toString: function toString() {
return this.model.text;
}
};
var MergeValue = function MergeValue(cell, master) {
this.model = {
address: cell.address,
type: Cell.Types.Merge,
master: master ? master.address : undefined
};
this._master = master;
if (master) {
master.addMergeRef();
}
};
MergeValue.prototype = {
get value() {
return this._master.value;
},
set value(value) {
if (value instanceof Cell) {
if (this._master) {
this._master.releaseMergeRef();
}
value.addMergeRef();
this._master = value;
} else {
this._master.value = value;
}
},
isMergedTo: function isMergedTo(master) {
return master === this._master;
},
get master() {
return this._master;
},
get type() {
return Cell.Types.Merge;
},
get effectiveType() {
return this._master.effectiveType;
},
get address() {
return this.model.address;
},
set address(value) {
this.model.address = value;
},
toCsvString: function toCsvString() {
return '';
},
release: function release() {
this._master.releaseMergeRef();
},
toString: function toString() {
return this.value.toString();
}
};
var FormulaValue = function FormulaValue(cell, value) {
this.cell = cell;
this.model = {
address: cell.address,
type: Cell.Types.Formula,
formula: value ? value.formula : undefined,
sharedFormula: value ? value.sharedFormula : undefined,
result: value ? value.result : undefined
};
};
FormulaValue.prototype = {
get value() {
return this.model.formula ? {
formula: this.model.formula,
result: this.model.result
} : {
sharedFormula: this.model.sharedFormula,
result: this.model.result
};
},
set value(value) {
this.model.formula = value.formula;
this.model.sharedFormula = value.sharedFormula;
this.model.result = value.result;
},
validate: function validate(value) {
switch (Value.getType(value)) {
case Cell.Types.Null:
case Cell.Types.String:
case Cell.Types.Number:
case Cell.Types.Date:
break;
case Cell.Types.Hyperlink:
case Cell.Types.Formula:
default:
throw new Error('Cannot process that type of result value');
}
},
get dependencies() {
// find all the ranges and cells mentioned in the formula
var ranges = this.formula.match(/([a-zA-Z0-9]+!)?[A-Z]{1,3}\d{1,4}:[A-Z]{1,3}\d{1,4}/g);
var cells = this.formula.replace(/([a-zA-Z0-9]+!)?[A-Z]{1,3}\d{1,4}:[A-Z]{1,3}\d{1,4}/g, '').match(/([a-zA-Z0-9]+!)?[A-Z]{1,3}\d{1,4}/g);
return {
ranges: ranges,
cells: cells
};
},
get formula() {
return this.model.formula || this._getTranslatedFormula();
},
set formula(value) {
this.model.formula = value;
},
get formulaType() {
if (this.model.formula) {
return Enums.FormulaType.Master;
}
if (this.model.sharedFormula) {
return Enums.FormulaType.Shared;
}
return Enums.FormulaType.None;
},
get result() {
return this.model.result;
},
set result(value) {
this.model.result = value;
},
get type() {
return Cell.Types.Formula;
},
get effectiveType() {
var v = this.model.result;
if (v === null || v === undefined) {
return Enums.ValueType.Null;
} else if (v instanceof String || typeof v === 'string') {
return Enums.ValueType.String;
} else if (typeof v === 'number') {
return Enums.ValueType.Number;
} else if (v instanceof Date) {
return Enums.ValueType.Date;
} else if (v.text && v.hyperlink) {
return Enums.ValueType.Hyperlink;
} else if (v.formula) {
return Enums.ValueType.Formula;
}
return Enums.ValueType.Null;
},
get address() {
return this.model.address;
},
set address(value) {
this.model.address = value;
},
_getTranslatedFormula: function _getTranslatedFormula() {
if (!this._translatedFormula && this.model.sharedFormula) {
var worksheet = this.cell.worksheet;
var master = worksheet.findCell(this.model.sharedFormula);
this._translatedFormula = master && slideFormula(master.formula, master.address, this.model.address);
}
return this._translatedFormula;
},
toCsvString: function toCsvString() {
return '' + (this.model.result || '');
},
release: function release() {},
toString: function toString() {
return this.model.result ? this.model.result.toString() : '';
}
};
var SharedStringValue = function SharedStringValue(cell, value) {
this.model = {
address: cell.address,
type: Cell.Types.SharedString,
value: value
};
};
SharedStringValue.prototype = {
get value() {
return this.model.value;
},
set value(value) {
this.model.value = value;
},
get type() {
return Cell.Types.SharedString;
},
get effectiveType() {
return Cell.Types.SharedString;
},
get address() {
return this.model.address;
},
set address(value) {
this.model.address = value;
},
toCsvString: function toCsvString() {
return '' + this.model.value;
},
release: function release() {},
toString: function toString() {
return this.model.value.toString();
}
};
var BooleanValue = function BooleanValue(cell, value) {
this.model = {
address: cell.address,
type: Cell.Types.Boolean,
value: value
};
};
BooleanValue.prototype = {
get value() {
return this.model.value;
},
set value(value) {
this.model.value = value;
},
get type() {
return Cell.Types.Boolean;
},
get effectiveType() {
return Cell.Types.Boolean;
},
get address() {
return this.model.address;
},
set address(value) {
this.model.address = value;
},
toCsvString: function toCsvString() {
return this.model.value ? 1 : 0;
},
release: function release() {},
toString: function toString() {
return this.model.value.toString();
}
};
var ErrorValue = function ErrorValue(cell, value) {
this.model = {
address: cell.address,
type: Cell.Types.Error,
value: value
};
};
ErrorValue.prototype = {
get value() {
return this.model.value;
},
set value(value) {
this.model.value = value;
},
get type() {
return Cell.Types.Error;
},
get effectiveType() {
return Cell.Types.Error;
},
get address() {
return this.model.address;
},
set address(value) {
this.model.address = value;
},
toCsvString: function toCsvString() {
return this.toString();
},
release: function release() {},
toString: function toString() {
return this.model.value.error.toString();
}
};
var JSONValue = function JSONValue(cell, value) {
this.model = {
address: cell.address,
type: Cell.Types.String,
value: JSON.stringify(value),
rawValue: value
};
};
JSONValue.prototype = {
get value() {
return this.model.rawValue;
},
set value(value) {
this.model.rawValue = value;
this.model.value = JSON.stringify(value);
},
get type() {
return Cell.Types.String;
},
get effectiveType() {
return Cell.Types.String;
},
get address() {
return this.model.address;
},
set address(value) {
this.model.address = value;
},
toCsvString: function toCsvString() {
return this.model.value;
},
release: function release() {},
toString: function toString() {
return this.model.value;
}
};
// Value is a place to hold common static Value type functions
var Value = {
getType: function getType(value) {
if (value === null || value === undefined) {
return Cell.Types.Null;
} else if (value instanceof String || typeof value === 'string') {
return Cell.Types.String;
} else if (typeof value === 'number') {
return Cell.Types.Number;
} else if (typeof value === 'boolean') {
return Cell.Types.Boolean;
} else if (value instanceof Date) {
return Cell.Types.Date;
} else if (value.text && value.hyperlink) {
return Cell.Types.Hyperlink;
} else if (value.formula || value.sharedFormula) {
return Cell.Types.Formula;
} else if (value.richText) {
return Cell.Types.RichText;
} else if (value.sharedString) {
return Cell.Types.SharedString;
} else if (value.error) {
return Cell.Types.Error;
}
return Cell.Types.JSON;
},
// map valueType to constructor
types: [{ t: Cell.Types.Null, f: NullValue }, { t: Cell.Types.Number, f: NumberValue }, { t: Cell.Types.String, f: StringValue }, { t: Cell.Types.Date, f: DateValue }, { t: Cell.Types.Hyperlink, f: HyperlinkValue }, { t: Cell.Types.Formula, f: FormulaValue }, { t: Cell.Types.Merge, f: MergeValue }, { t: Cell.Types.JSON, f: JSONValue }, { t: Cell.Types.SharedString, f: SharedStringValue }, { t: Cell.Types.RichText, f: RichTextValue }, { t: Cell.Types.Boolean, f: BooleanValue }, { t: Cell.Types.Error, f: ErrorValue }].reduce(function (p, t) {
p[t.t] = t.f;return p;
}, []),
create: function create(type, cell, value) {
var T = this.types[type];
if (!T) {
throw new Error('Could not create Value of type ' + type);
}
return new T(cell, value);
}
};
},{"../utils/col-cache":14,"../utils/shared-formula":16,"./enums":7}],4:[function(require,module,exports){
/**
* Copyright (c) 2014-2017 Guyon Roche
* LICENCE: MIT - please refer to LICENCE file included with this module
* or https://github.com/guyonroche/exceljs/blob/master/LICENSE
*/
'use strict';
var _ = require('../utils/under-dash');
var colCache = require('../utils/col-cache');
// Column defines the column properties for 1 column.
// This includes header rows, widths, key, (style), etc.
// Worksheet will condense the columns as appropriate during serialization
var Column = module.exports = function (worksheet, number, defn) {
this._worksheet = worksheet;
this._number = number;
if (defn !== false) {
// sometimes defn will follow
this.defn = defn;
}
};
Column.prototype = {
get number() {
return this._number;
},
get worksheet() {
return this._worksheet;
},
get letter() {
return colCache.n2l(this._number);
},
get isCustomWidth() {
return this.width !== undefined && this.width !== 8;
},
get defn() {
return {
header: this._header,
key: this.key,
width: this.width,
style: this.style,
hidden: this.hidden,
outlineLevel: this.outlineLevel
};
},
set defn(value) {
if (value) {
this.key = value.key;
this.width = value.width;
this.outlineLevel = value.outlineLevel;
if (value.style) {
this.style = value.style;
} else {
this.style = {};
}
// headers must be set after style
this.header = value.header;
this._hidden = !!value.hidden;
} else {
delete this._header;
delete this.key;
delete this.width;
this.style = {};
this.outlineLevel = 0;
}
},
get headers() {
return this._header && this._header instanceof Array ? this._header : [this._header];
},
get header() {
return this._header;
},
set header(value) {
var _this = this;
if (value !== undefined) {
this._header = value;
this.headers.forEach(function (text, index) {
_this._worksheet.getCell(index + 1, _this.number).value = text;
});
} else {
this._header = [];
}
},
get key() {
return this._key;
},
set key(value) {
var column = this._key && this._worksheet.getColumnKey(this._key);
if (column === this) {
this._worksheet.deleteColumnKey(this._key);
}
this._key = value;
if (value) {
this._worksheet.setColumnKey(this._key, this);
}
},
get hidden() {
return !!this._hidden;
},
set hidden(value) {
this._hidden = value;
},
get outlineLevel() {
return this._outlineLevel || 0;
},
set outlineLevel(value) {
this._outlineLevel = value;
},
get collapsed() {
return !!(this._outlineLevel && this._outlineLevel >= this._worksheet.properties.outlineLevelCol);
},
toString: function toString() {
return JSON.stringify({
key: this.key,
width: this.width,
headers: this.headers.length ? this.headers : undefined
});
},
equivalentTo: function equivalentTo(other) {
return this.width === other.width && this.hidden === other.hidden && this.outlineLevel === other.outlineLevel && _.isEqual(this.style, other.style);
},
get isDefault() {
if (this.isCustomWidth) {
return false;
}
if (this.hidden) {
return false;
}
if (this.outlineLevel) {
return false;
}
var s = this.style;
if (s && (s.font || s.numFmt || s.alignment || s.border || s.fill)) {
return false;
}
return true;
},
get headerCount() {
return this.headers.length;
},
eachCell: function eachCell(options, iteratee) {
var colNumber = this.number;
if (!iteratee) {
iteratee = options;
options = null;
}
if (options && options.includeEmpty) {
this._worksheet.eachRow(options, function (row, rowNumber) {
iteratee(row.getCell(colNumber), rowNumber);
});
} else {
this._worksheet.eachRow(function (row, rowNumber) {
var cell = row.findCell(colNumber);
if (cell) {
iteratee(cell, rowNumber);
}
});
}
},
// =========================================================================
// styles
_applyStyle: function _applyStyle(name, value) {
this.style[name] = value;
this.eachCell(function (cell) {
cell[name] = value;
});
return value;
},
get numFmt() {
return this.style.numFmt;
},
set numFmt(value) {
this._applyStyle('numFmt', value);
},
get font() {
return this.style.font;
},
set font(value) {
this._applyStyle('font', value);
},
get alignment() {
return this.style.alignment;
},
set alignment(value) {
this._applyStyle('alignment', value);
},
get border() {
return this.style.border;
},
set border(value) {
this._applyStyle('border', value);
},
get fill() {
return this.style.fill;
},
set fill(value) {
this._applyStyle('fill', value);
}
};
// =============================================================================
// static functions
Column.toModel = function (columns) {
// Convert array of Column into compressed list cols
var cols = [];
var col = null;
if (columns) {
columns.forEach(function (column, index) {
if (column.isDefault) {
if (col) {
col = null;
}
} else if (!col || !column.equivalentTo(col)) {
col = {
min: index + 1,
max: index + 1,
width: column.width,
style: column.style,
isCustomWidth: column.isCustomWidth,
hidden: column.hidden,
outlineLevel: column.outlineLevel,
collapsed: column.collapsed
};
cols.push(col);
} else {
col.max = index + 1;
}
});
}
return cols.length ? cols : undefined;
};
Column.fromModel = function (worksheet, cols) {
cols = cols || [];
var columns = [];
var count = 1;
var index = 0;
while (index < cols.length) {
var col = cols[index++];
while (count < col.min) {
columns.push(new Column(worksheet, count++));
}
while (count <= col.max) {
columns.push(new Column(worksheet, count++, col));
}
}
return columns.length ? columns : null;
};
},{"../utils/col-cache":14,"../utils/under-dash":19}],5:[function(require,module,exports){
/**
* Copyright (c) 2016-2017 Guyon Roche
* LICENCE: MIT - please refer to LICENCE file included with this module
* or https://github.com/guyonroche/exceljs/blob/master/LICENSE
*/
'use strict';
var DataValidations = module.exports = function (model) {
this.model = model || {};
};
DataValidations.prototype = {
add: function add(address, validation) {
return this.model[address] = validation;
},
find: function find(address) {
return this.model[address];
},
remove: function remove(address) {
this.model[address] = undefined;
}
};
},{}],6:[function(require,module,exports){
/**
* Copyright (c) 2016-2017 Guyon Roche
* LICENCE: MIT - please refer to LICENCE file included with this module
* or https://github.com/guyonroche/exceljs/blob/master/LICENSE
*/
'use strict';
var _ = require('../utils/under-dash');
var colCache = require('../utils/col-cache');
var CellMatrix = require('../utils/cell-matrix');
var Range = require('./range');
var rangeRegexp = /[$](\w+)[$](\d+)(:[$](\w+)[$](\d+))?/;
var DefinedNames = module.exports = function () {
this.matrixMap = {};
};
DefinedNames.prototype = {
getMatrix: function getMatrix(name) {
return this.matrixMap[name] || (this.matrixMap[name] = new CellMatrix());
},
// add a name to a cell. locStr in the form SheetName!$col$row or SheetName!$c1$r1:$c2:$r2
add: function add(locStr, name) {
var location = colCache.decodeEx(locStr);
this.addEx(location, name);
},
addEx: function addEx(location, name) {
var matrix = this.getMatrix(name);
if (location.top) {
for (var col = location.left; col <= location.right; col++) {
for (var row = location.top; row <= location.bottom; row++) {
var address = {
sheetName: location.sheetName,
address: colCache.n2l(col) + row,
row: row,
col: col
};
matrix.addCellEx(address);
}
}
} else {
matrix.addCellEx(location);
}
},
remove: function remove(locStr, name) {
var location = colCache.decodeEx(locStr);
this.removeEx(location, name);
},
removeEx: function removeEx(location, name) {
var matrix = this.getMatrix(name);
matrix.removeCellEx(location);
},
removeAllNames: function removeAllNames(location) {
_.each(this.matrixMap, function (matrix) {
matrix.removeCellEx(location);
});
},
forEach: function forEach(callback) {
_.each(this.matrixMap, function (matrix, name) {
matrix.forEach(function (cell) {
callback(name, cell);
});
});
},
// get all the names of a cell
getNames: function getNames(addressStr) {
return this.getNamesEx(colCache.decodeEx(addressStr));
},
getNamesEx: function getNamesEx(address) {
return _.map(this.matrixMap, function (matrix, name) {
return matrix.findCellEx(address) && name;
}).filter(Boolean);
},
_explore: function _explore(matrix, cell) {
cell.mark = false;
var sheetName = cell.sheetName;
var range = new Range(cell.row, cell.col, cell.row, cell.col, sheetName);
var x, y;
// grow vertical - only one col to worry about
function vGrow(yy, edge) {
var c = matrix.findCellAt(sheetName, yy, cell.col);
if (!c || !c.mark) {
return false;
}
range[edge] = yy;
c.mark = false;
return true;
}
for (y = cell.row - 1; vGrow(y, 'top'); y--) {}
for (y = cell.row + 1; vGrow(y, 'bottom'); y++) {}
// grow horizontal - ensure all rows can grow
function hGrow(xx, edge) {
var c,
cells = [];
for (y = range.top; y <= range.bottom; y++) {
c = matrix.findCellAt(sheetName, y, xx);
if (c && c.mark) {
cells.push(c);
} else {
return false;
}
}
range[edge] = xx;
for (var i = 0; i < cells.length; i++) {
cells[i].mark = false;
}
return true;
}
for (x = cell.col - 1; hGrow(x, 'left'); x--) {}
for (x = cell.col + 1; hGrow(x, 'right'); x++) {}
return range;
},
getRanges: function getRanges(name, matrix) {
var _this = this;
matrix = matrix || this.matrixMap[name];
if (!matrix) {
return { name: name, ranges: [] };
}
// mark and sweep!
matrix.forEach(function (cell) {
cell.mark = true;
});
var ranges = matrix.map(function (cell) {
return cell.mark && _this._explore(matrix, cell);
}).filter(Boolean).map(function (range) {
return range.$shortRange;
});
return {
name: name, ranges: ranges
};
},
get model() {
var self = this;
// To get names per cell - just iterate over all names finding cells if they exist
return _.map(this.matrixMap, function (matrix, name) {
return self.getRanges(name, matrix);
}).filter(function (definedName) {
return definedName.ranges.length;
});
},
set model(value) {
// value is [ { name, ranges }, ... ]
var matrixMap = this.matrixMap = {};
value.forEach(function (definedName) {
var matrix = matrixMap[definedName.name] = new CellMatrix();
definedName.ranges.forEach(function (rangeStr) {
if (rangeRegexp.test(rangeStr.split('!').pop() || '')) {
matrix.addCell(rangeStr);
}
});
});
}
};
},{"../utils/cell-matrix":13,"../utils/col-cache":14,"../utils/under-dash":19,"./range":8}],7:[function(require,module,exports){
/**
* Copyright (c) 2016-2017 Guyon Roche
* LICENCE: MIT - please refer to LICENCE file included with this module
* or https://github.com/guyonroche/exceljs/blob/master/LICENSE
*/
'use strict';
module.exports = {
ValueType: {
Null: 0,
Merge: 1,
Number: 2,
String: 3,
Date: 4,
Hyperlink: 5,
Formula: 6,
SharedString: 7,
RichText: 8,
Boolean: 9,
Error: 10
},
FormulaType: {
None: 0,
Master: 1,
Shared: 2
},
RelationshipType: {
None: 0,
OfficeDocument: 1,
Worksheet: 2,
CalcChain: 3,
SharedStrings: 4,
Styles: 5,
Theme: 6,
Hyperlink: 7
},
DocumentType: {
Xlsx: 1
},
ReadingOrder: {
LeftToRight: 1,
RightToLeft: 2
},
ErrorValue: {
NotApplicable: '#N/A',
Ref: '#REF!',
Name: '#NAME?',
DivZero: '#DIV/0!',
Null: '#NULL!',
Value: '#VALUE!',
Num: '#NUM!'
}
};
},{}],8:[function(require,module,exports){
/**
* Copyright (c) 2014-2017 Guyon Roche
* LICENCE: MIT - please refer to LICENCE file included with this module
* or https://github.com/guyonroche/exceljs/blob/master/LICENSE
*/
'use strict';
var colCache = require('./../utils/col-cache');
// used by worksheet to calculate sheet dimensions
var Range = module.exports = function () {
this.decode(arguments);
};
Range.prototype = {
_set_tlbr: function _set_tlbr(t, l, b, r, s) {
this.model = {
top: Math.min(t, b),
left: Math.min(l, r),
bottom: Math.max(t, b),
right: Math.max(l, r),
sheetName: s
};
},
_set_tl_br: function _set_tl_br(tl, br, s) {
tl = colCache.decodeAddress(tl);
br = colCache.decodeAddress(br);
this._set_tlbr(tl.row, tl.col, br.row, br.col, s);
},
decode: function decode(argv) {
switch (argv.length) {
case 5:
// [t,l,b,r,s]
this._set_tlbr(argv[0], argv[1], argv[2], argv[3], argv[4]);
break;
case 4:
// [t,l,b,r]
this._set_tlbr(argv[0], argv[1], argv[2], argv[3]);
break;
case 3:
// [tl,br,s]
this._set_tl_br(argv[0], argv[1], argv[2]);
break;
case 2:
// [tl,br]
this._set_tl_br(argv[0], argv[1]);
break;
case 1:
var value = argv[0];
if (value instanceof Range) {
// copy constructor
this.model = {
top: value.model.top,
left: value.model.left,
bottom: value.model.bottom,
right: value.model.right,
sheetName: value.sheetName
};
} else if (value instanceof Array) {
// an arguments array
this.decode(value);
} else if (value.top && value.left && value.bottom && value.right) {
// a model
this.model = {
top: value.top,
left: value.left,
bottom: value.bottom,
right: value.right,
sheetName: value.sheetName
};
} else {
// [sheetName!]tl:br
var tlbr = colCache.decodeEx(value);
if (tlbr.top) {
this.model = {
top: tlbr.top,
left: tlbr.left,
bottom: tlbr.bottom,
right: tlbr.right,
sheetName: tlbr.sheetName
};
} else {
this.model = {
top: tlbr.row,
left: tlbr.col,
bottom: tlbr.row,
right: tlbr.col,
sheetName: tlbr.sheetName
};
}
}
break;
case 0:
this.model = {
top: 0,
left: 0,
bottom: 0,
right: 0
};
break;
default:
throw new Error('Invalid number of arguments to _getDimensions() - ' + argv.length);
}
},
get top() {
return this.model.top || 1;
},
set top(value) {
this.model.top = value;
},
get left() {
return this.model.left || 1;
},
set left(value) {
this.model.left = value;
},
get bottom() {
return this.model.bottom || 1;
},
set bottom(value) {
this.model.bottom = value;
},
get right() {
return this.model.right || 1;
},
set right(value) {
this.model.right = value;
},
get sheetName() {
return this.model.sheetName;
},
set sheetName(value) {
this.model.sheetName = value;
},
get _serialisedSheetName() {
var sheetName = this.model.sheetName;
if (sheetName) {
if (/^[a-zA-Z0-9]*$/.test(sheetName)) {
return sheetName + '!';
}
return '\'' + sheetName + '\'!';
}
return '';
},
expand: function expand(top, left, bottom, right) {
if (!this.model.top || top < this.top) this.top = top;
if (!this.model.left || left < this.left) this.left = left;
if (!this.model.bottom || bottom > this.bottom) this.bottom = bottom;
if (!this.model.right || right > this.right) this.right = right;
},
expandRow: function expandRow(row) {
if (row) {
var dimensions = row.dimensions;
if (dimensions) {
this.expand(row.number, dimensions.min, row.number, dimensions.max);
}
}
},
expandToAddress: function expandToAddress(addressStr) {
var address = colCache.decodeEx(addressStr);
this.expand(address.row, address.col, address.row, address.col);
},
get tl() {
return colCache.n2l(this.left) + this.top;
},
get $t$l() {
return '$' + colCache.n2l(this.left) + '$' + this.top;
},
get br() {
return colCache.n2l(this.right) + this.bottom;
},
get $b$r() {
return '$' + colCache.n2l(this.right) + '$' + this.bottom;
},
get range() {
return this._serialisedSheetName + this.tl + ':' + this.br;
},
get $range() {
return this._serialisedSheetName + this.$t$l + ':' + this.$b$r;
},
get shortRange() {
return this.count > 1 ? this.range : this._serialisedSheetName + this.tl;
},
get $shortRange() {
return this.count > 1 ? this.$range : this._serialisedSheetName + this.$t$l;
},
get count() {
return (1 + this.bottom - this.top) * (1 + this.right - this.left);
},
toString: function toString() {
return this.range;
},
intersects: function intersects(other) {
if (other.sheetName && this.sheetName && other.sheetName !== this.sheetName) return false;
if (other.bottom < this.top) return false;
if (other.top > this.bottom) return false;
if (other.right < this.left) return false;
if (other.left > this.right) return false;
return true;
},
contains: function contains(addressStr) {
var address = colCache.decodeEx(addressStr);
return this.containsEx(address);
},
containsEx: function containsEx(address) {
if (address.sheetName && this.sheetName && address.sheetName !== this.sheetName) return false;
return address.row >= this.top && address.row <= this.bottom && address.col >= this.left && address.col <= this.right;
}
};
},{"./../utils/col-cache":14}],9:[function(require,module,exports){
/**
* Copyright (c) 2014-2017 Guyon Roche
* LICENCE: MIT - please refer to LICENCE file included with this module
* or https://github.com/guyonroche/exceljs/blob/master/LICENSE
*/
'use strict';
var _ = require('../utils/under-dash');
var Enums = require('./enums');
var colCache = require('./../utils/col-cache');
var Cell = require('./cell');
var Row = module.exports = function (worksheet, number) {
this._worksheet = worksheet;
this._number = number;
this._cells = [];
this.style = {};
this.outlineLevel = 0;
};
Row.prototype = {
// return the row number
get number() {
return this._number;
},
get worksheet() {
return this._worksheet;
},
// Inform Streaming Writer that this row (and all rows before it) are complete
// and ready to write. Has no effect on Worksheet document
commit: function commit() {
this._worksheet._commitRow(this); // eslint-disable-line no-underscore-dangle
},
// helps GC by breaking cyclic references
destroy: function destroy() {
delete this._worksheet;
delete this._cells;
delete this.style;
},
findCell: function findCell(colNumber) {
return this._cells[colNumber - 1];
},
// given {address, row, col}, find or create new cell
getCellEx: function getCellEx(address) {
var cell = this._cells[address.col - 1];
if (!cell) {
var column = this._worksheet.getColumn(address.col);
cell = new Cell(this, column, address.address);
this._cells[address.col - 1] = cell;
}
return cell;
},
// get cell by key, letter or column number
getCell: function getCell(col) {
if (typeof col === 'string') {
// is it a key?
var column = this._worksheet.getColumnKey(col);
if (column) {
col = column.number;
} else {
col = colCache.l2n(col);
}
}
return this._cells[col - 1] || this.getCellEx({
address: colCache.encodeAddress(this._number, col),
row: this._number,
col: col
});
},
// remove cell(s) and shift all higher cells down by count
splice: function splice(start, count) {
var inserts = Array.prototype.slice.call(arguments, 2);
var nKeep = start + count;
var nExpand = inserts.length - count;
var nEnd = this._cells.length;
var i, cSrc, cDst;
if (nExpand < 0) {
// remove cells
for (i = nKeep; i <= nEnd; i++) {
cSrc = this._cells[i - 1];
if (cSrc) {
this.getCell(i + nExpand).value = cSrc.value;
cSrc.value = null;
} else {
cDst = this._cells[i + nExpand - 1];
if (cDst) {
cDst.value = null;
}
}
}
} else if (nExpand > 0) {
// insert new cells
for (i = nEnd; i >= nKeep; i--) {
cSrc = this._cells[i - 1];
if (cSrc) {
this.getCell(i + nExpand).value = cSrc.value;
} else {
this._cells[i + nExpand - 1] = undefined;
}
}
}
// now add the new values
for (i = 0; i < inserts.length; i++) {
this.getCell(start + i).value = inserts[i];
}
},
// Iterate over all non-null cells in this row
eachCell: function eachCell(options, iteratee) {
if (!iteratee) {
iteratee = options;
options = null;
}
if (opt