to-spreadsheet 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -0
- package/lib/generate-excel.d.ts +14 -2
- package/lib/generate-excel.js +17 -12
- package/lib/index.d.ts +6 -34
- package/lib/index.js +31 -63
- package/lib/read-csv.d.ts +6 -0
- package/lib/read-csv.js +80 -0
- package/lib/read-excel.d.ts +23 -0
- package/lib/read-excel.js +265 -0
- package/lib/types.d.ts +34 -0
- package/lib/types.js +44 -0
- package/lib/util.d.ts +2 -1
- package/lib/util.js +10 -10
- package/lib/xl/styles.xml.js +6 -6
- package/lib/xl/worksheets/sheet.xml.js +5 -5
- package/package.json +13 -10
package/README.md
CHANGED
|
@@ -40,6 +40,55 @@ generateExcel(sampleData); // <-- by default generate XLSX for node
|
|
|
40
40
|
generateExcel(sampleData, EnvironmentType.BROWSER); // <-- for browser
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
# Reading / Importing
|
|
44
|
+
|
|
45
|
+
`to-spreadsheet` can also read spreadsheets back into plain JavaScript values. The
|
|
46
|
+
reader works in **both Node.js and the browser** and covers `.xlsx` (OOXML) files —
|
|
47
|
+
those produced by this library as well as ordinary files from Excel and other tools —
|
|
48
|
+
plus CSV text.
|
|
49
|
+
|
|
50
|
+
## Reading an `.xlsx` file
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { readExcel } from 'to-spreadsheet/lib/index';
|
|
54
|
+
|
|
55
|
+
// Node.js: pass a file path, a Buffer, or a Uint8Array/ArrayBuffer
|
|
56
|
+
const workbook = await readExcel('./report.xlsx');
|
|
57
|
+
|
|
58
|
+
// Browser: pass a File/Blob (e.g. from <input type="file">) or an ArrayBuffer
|
|
59
|
+
// const workbook = await readExcel(file);
|
|
60
|
+
|
|
61
|
+
workbook.sheets.forEach((sheet) => {
|
|
62
|
+
console.log(sheet.title); // sheet (tab) name
|
|
63
|
+
console.log(sheet.rows); // ReadCellValue[][] — a dense grid, gaps are null
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Each cell comes back as a `string`, `number`, `boolean`, `Date` (for date-formatted
|
|
68
|
+
cells) or `null` (empty). Date conversion can be disabled to get the raw Excel serial:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const workbook = await readExcel('./report.xlsx', { cellDates: false });
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Formula cells are surfaced on an optional parallel `sheet.formulas` grid (the formula
|
|
75
|
+
text without the leading `=`), present only when a sheet contains at least one formula.
|
|
76
|
+
|
|
77
|
+
## Parsing CSV
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { parseCsv } from 'to-spreadsheet/lib/index';
|
|
81
|
+
|
|
82
|
+
const rows = parseCsv('name,age\nalice,30\n"bob, jr.",25');
|
|
83
|
+
// [["name","age"], ["alice","30"], ["bob, jr.","25"]]
|
|
84
|
+
|
|
85
|
+
// custom delimiter
|
|
86
|
+
const tsv = parseCsv(tabText, { delimiter: '\t' });
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`parseCsv` follows RFC 4180: quoted fields, escaped quotes (`""`), embedded commas and
|
|
90
|
+
newlines, `\r\n`/`\n` line endings, and a leading UTF-8 BOM are all handled.
|
|
91
|
+
|
|
43
92
|
# Cell Features
|
|
44
93
|
|
|
45
94
|
## Dates
|
package/lib/generate-excel.d.ts
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
import { IPage } from "./index";
|
|
1
|
+
import { IPage, IWorkbook } from "./index";
|
|
2
|
+
declare const generateTree: (workbook: IWorkbook) => {
|
|
3
|
+
"[Content_Types].xml": string;
|
|
4
|
+
"_rels/.rels": string;
|
|
5
|
+
"docProps/app.xml": string;
|
|
6
|
+
"docProps/core.xml": string;
|
|
7
|
+
"xl/_rels/workbook.xml.rels": string;
|
|
8
|
+
"xl/sharedStrings.xml": string;
|
|
9
|
+
"xl/styles.xml": string;
|
|
10
|
+
"xl/theme/theme1.xml": string;
|
|
11
|
+
"xl/workbook.xml": string;
|
|
12
|
+
};
|
|
2
13
|
declare enum EnvironmentType {
|
|
3
14
|
NODE = 0,
|
|
4
15
|
BROWSER = 1
|
|
5
16
|
}
|
|
17
|
+
declare const buildWorkbook: (dump: IPage[]) => IWorkbook;
|
|
6
18
|
declare const generateExcel: (dump: IPage[], environmentType?: EnvironmentType) => Promise<void>;
|
|
7
|
-
export { generateExcel, EnvironmentType };
|
|
19
|
+
export { generateExcel, EnvironmentType, buildWorkbook, generateTree };
|
package/lib/generate-excel.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EnvironmentType = exports.generateExcel = void 0;
|
|
3
|
+
exports.generateTree = exports.buildWorkbook = exports.EnvironmentType = exports.generateExcel = void 0;
|
|
4
4
|
const content_types_xml_1 = require("./content-types.xml");
|
|
5
5
|
const _rels_1 = require("./_rels/.rels");
|
|
6
6
|
const app_xml_1 = require("./docProps/app.xml");
|
|
@@ -11,7 +11,7 @@ const styles_xml_1 = require("./xl/styles.xml");
|
|
|
11
11
|
const theme1_xml_1 = require("./xl/theme/theme1.xml");
|
|
12
12
|
const workbook_xml_1 = require("./xl/workbook.xml");
|
|
13
13
|
const sheet_xml_1 = require("./xl/worksheets/sheet.xml");
|
|
14
|
-
const
|
|
14
|
+
const types_1 = require("./types");
|
|
15
15
|
const util_1 = require("./util");
|
|
16
16
|
const generateTree = (workbook) => {
|
|
17
17
|
const styleMap = new Map();
|
|
@@ -20,7 +20,7 @@ const generateTree = (workbook) => {
|
|
|
20
20
|
workbook.sheets.forEach(sheet => {
|
|
21
21
|
sheet.rows.forEach(row => {
|
|
22
22
|
row.cells.forEach(cell => {
|
|
23
|
-
if (cell.type ===
|
|
23
|
+
if (cell.type === types_1.ICellType.date) {
|
|
24
24
|
hasDateCells = true;
|
|
25
25
|
}
|
|
26
26
|
if ('style' in cell && cell.style) {
|
|
@@ -32,41 +32,42 @@ const generateTree = (workbook) => {
|
|
|
32
32
|
});
|
|
33
33
|
return Object.assign({ "[Content_Types].xml": (0, content_types_xml_1.generateContentTypesXml)(workbook), "_rels/.rels": (0, _rels_1.generateRels)(), "docProps/app.xml": (0, app_xml_1.generateAppXml)(workbook), "docProps/core.xml": (0, core_xml_1.generateCoreXml)({}), "xl/_rels/workbook.xml.rels": (0, workbook_xml_rels_1.generateWorkBookXmlRels)(workbook), "xl/sharedStrings.xml": (0, sharedStrings_xml_1.generateSharedStrings)(workbook), "xl/styles.xml": (0, styles_xml_1.generateStyleXml)(styleMap, hasDateCells), "xl/theme/theme1.xml": (0, theme1_xml_1.generateTheme1)(), "xl/workbook.xml": (0, workbook_xml_1.generateWorkBookXml)(workbook) }, workbook.sheets.reduce((acc, sheet, idx) => (Object.assign(Object.assign({}, acc), { [`xl/worksheets/sheet${idx + 1}.xml`]: (0, sheet_xml_1.generateSheetXml)(sheet, styleMap, hasDateCells) })), {}));
|
|
34
34
|
};
|
|
35
|
+
exports.generateTree = generateTree;
|
|
35
36
|
var EnvironmentType;
|
|
36
37
|
(function (EnvironmentType) {
|
|
37
38
|
EnvironmentType[EnvironmentType["NODE"] = 0] = "NODE";
|
|
38
39
|
EnvironmentType[EnvironmentType["BROWSER"] = 1] = "BROWSER";
|
|
39
40
|
})(EnvironmentType || (EnvironmentType = {}));
|
|
40
41
|
exports.EnvironmentType = EnvironmentType;
|
|
41
|
-
const
|
|
42
|
+
const buildWorkbook = (dump) => {
|
|
42
43
|
const strings = [];
|
|
43
44
|
const sheets = dump.map(({ title, content }) => {
|
|
44
45
|
const rows = content.map(row => {
|
|
45
46
|
const cells = [];
|
|
46
47
|
row.forEach(content => {
|
|
47
48
|
if (typeof content === 'number') {
|
|
48
|
-
cells.push({ type:
|
|
49
|
+
cells.push({ type: types_1.ICellType.number, value: content });
|
|
49
50
|
}
|
|
50
51
|
else if (typeof content === 'string') {
|
|
51
|
-
const type =
|
|
52
|
+
const type = types_1.ICellType.string;
|
|
52
53
|
let value = strings.indexOf(content);
|
|
53
54
|
if (value === -1) {
|
|
54
55
|
strings.push(content);
|
|
55
56
|
value = strings.length - 1;
|
|
56
57
|
}
|
|
57
|
-
cells.push({ type:
|
|
58
|
+
cells.push({ type: types_1.ICellType.string, value });
|
|
58
59
|
}
|
|
59
60
|
else if (content instanceof util_1.SkipCell) {
|
|
60
61
|
for (let i = 0; i < content.getSkipCell(); i++) {
|
|
61
|
-
cells.push({ type:
|
|
62
|
+
cells.push({ type: types_1.ICellType.skip, value: undefined });
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
else if (content instanceof util_1.Equation) {
|
|
65
|
-
cells.push({ type:
|
|
66
|
+
cells.push({ type: types_1.ICellType.equation, value: content });
|
|
66
67
|
}
|
|
67
68
|
else if (content && typeof content === 'object' && 'type' in content) {
|
|
68
69
|
const cell = content;
|
|
69
|
-
if (cell.type ===
|
|
70
|
+
if (cell.type === types_1.ICellType.string && typeof cell.value === 'string') {
|
|
70
71
|
let stringIndex = strings.indexOf(cell.value);
|
|
71
72
|
if (stringIndex === -1) {
|
|
72
73
|
strings.push(cell.value);
|
|
@@ -79,18 +80,22 @@ const generateExcel = (dump, environmentType = EnvironmentType.NODE) => {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
else {
|
|
82
|
-
cells.push({ type:
|
|
83
|
+
cells.push({ type: types_1.ICellType.skip });
|
|
83
84
|
}
|
|
84
85
|
});
|
|
85
86
|
return { cells };
|
|
86
87
|
});
|
|
87
88
|
return { title, rows };
|
|
88
89
|
});
|
|
89
|
-
|
|
90
|
+
return {
|
|
90
91
|
sheets,
|
|
91
92
|
strings,
|
|
92
93
|
filename: "tem.xlsx"
|
|
93
94
|
};
|
|
95
|
+
};
|
|
96
|
+
exports.buildWorkbook = buildWorkbook;
|
|
97
|
+
const generateExcel = (dump, environmentType = EnvironmentType.NODE) => {
|
|
98
|
+
const workbook = buildWorkbook(dump);
|
|
94
99
|
if (environmentType === EnvironmentType.BROWSER) {
|
|
95
100
|
return generateExcelWorkbookBrowser(workbook);
|
|
96
101
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,38 +1,8 @@
|
|
|
1
1
|
import { generateExcel, EnvironmentType } from "./generate-excel";
|
|
2
2
|
import { SkipCell, skipCell, Equation, writeEquation, createBorder, createAllBorders, createTopBorder, createBottomBorder, createLeftBorder, createRightBorder, createStyledCell, createBorderedCell, createDateCell, createBorderedDateCell, createBackgroundCell, createForegroundCell, createColoredCell, createBackgroundDateCell, createHorizontallyAlignedCell, createVerticallyAlignedCell, createAlignedCell, createCenteredCell } from "./util";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
date = "d",
|
|
7
|
-
skip = "skip",
|
|
8
|
-
equation = "equation"
|
|
9
|
-
}
|
|
10
|
-
declare enum BorderStyle {
|
|
11
|
-
none = "none",
|
|
12
|
-
thin = "thin",
|
|
13
|
-
medium = "medium",
|
|
14
|
-
thick = "thick",
|
|
15
|
-
double = "double",
|
|
16
|
-
dotted = "dotted",
|
|
17
|
-
dashed = "dashed"
|
|
18
|
-
}
|
|
19
|
-
declare enum HorizontalAlignment {
|
|
20
|
-
general = "general",
|
|
21
|
-
left = "left",
|
|
22
|
-
center = "center",
|
|
23
|
-
right = "right",
|
|
24
|
-
fill = "fill",
|
|
25
|
-
justify = "justify",
|
|
26
|
-
centerContinuous = "centerContinuous",
|
|
27
|
-
distributed = "distributed"
|
|
28
|
-
}
|
|
29
|
-
declare enum VerticalAlignment {
|
|
30
|
-
top = "top",
|
|
31
|
-
center = "center",
|
|
32
|
-
bottom = "bottom",
|
|
33
|
-
justify = "justify",
|
|
34
|
-
distributed = "distributed"
|
|
35
|
-
}
|
|
3
|
+
import { readExcel, ReadCellValue, IReadSheet, IReadWorkbook, IReadOptions, ReadExcelInput } from "./read-excel";
|
|
4
|
+
import { parseCsv, ICsvOptions } from "./read-csv";
|
|
5
|
+
import { ICellType, BorderStyle, HorizontalAlignment, VerticalAlignment } from "./types";
|
|
36
6
|
interface IBorder {
|
|
37
7
|
top?: BorderStyle;
|
|
38
8
|
right?: BorderStyle;
|
|
@@ -70,7 +40,7 @@ interface ICellDate {
|
|
|
70
40
|
value: Date;
|
|
71
41
|
style?: ICellStyle;
|
|
72
42
|
}
|
|
73
|
-
|
|
43
|
+
type ICell = ICellString | ICellNumber | ICellDate | ICellSkip | ICellEquation;
|
|
74
44
|
interface IRows {
|
|
75
45
|
cells: ICell[];
|
|
76
46
|
}
|
|
@@ -88,6 +58,7 @@ interface IPage {
|
|
|
88
58
|
content: (string | number | undefined | SkipCell | Equation | ICell)[][];
|
|
89
59
|
}
|
|
90
60
|
export { ICell, ISheet, IWorkbook, IRows, ICellType, IPage, BorderStyle, IBorder, ICellStyle, ICellDate, HorizontalAlignment, VerticalAlignment };
|
|
61
|
+
export { ReadCellValue, IReadSheet, IReadWorkbook, IReadOptions, ReadExcelInput, ICsvOptions };
|
|
91
62
|
declare const sampleData: ({
|
|
92
63
|
title: string;
|
|
93
64
|
content: (string[] | (number | Equation)[])[];
|
|
@@ -102,3 +73,4 @@ declare const sampleData: ({
|
|
|
102
73
|
content: (string | number | ICell)[][];
|
|
103
74
|
})[];
|
|
104
75
|
export { generateExcel, sampleData, EnvironmentType, skipCell, writeEquation, createBorder, createAllBorders, createTopBorder, createBottomBorder, createLeftBorder, createRightBorder, createStyledCell, createBorderedCell, createDateCell, createBorderedDateCell, createBackgroundCell, createForegroundCell, createColoredCell, createBackgroundDateCell, createHorizontallyAlignedCell, createVerticallyAlignedCell, createAlignedCell, createCenteredCell };
|
|
76
|
+
export { readExcel, parseCsv };
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createCenteredCell = exports.createAlignedCell = exports.createVerticallyAlignedCell = exports.createHorizontallyAlignedCell = exports.createBackgroundDateCell = exports.createColoredCell = exports.createForegroundCell = exports.createBackgroundCell = exports.createBorderedDateCell = exports.createDateCell = exports.createBorderedCell = exports.createStyledCell = exports.createRightBorder = exports.createLeftBorder = exports.createBottomBorder = exports.createTopBorder = exports.createAllBorders = exports.createBorder = exports.writeEquation = exports.skipCell = exports.EnvironmentType = exports.sampleData = exports.generateExcel = exports.VerticalAlignment = exports.HorizontalAlignment = exports.BorderStyle = exports.ICellType = void 0;
|
|
3
|
+
exports.parseCsv = exports.readExcel = exports.createCenteredCell = exports.createAlignedCell = exports.createVerticallyAlignedCell = exports.createHorizontallyAlignedCell = exports.createBackgroundDateCell = exports.createColoredCell = exports.createForegroundCell = exports.createBackgroundCell = exports.createBorderedDateCell = exports.createDateCell = exports.createBorderedCell = exports.createStyledCell = exports.createRightBorder = exports.createLeftBorder = exports.createBottomBorder = exports.createTopBorder = exports.createAllBorders = exports.createBorder = exports.writeEquation = exports.skipCell = exports.EnvironmentType = exports.sampleData = exports.generateExcel = exports.VerticalAlignment = exports.HorizontalAlignment = exports.BorderStyle = exports.ICellType = void 0;
|
|
4
4
|
const generate_excel_1 = require("./generate-excel");
|
|
5
5
|
Object.defineProperty(exports, "generateExcel", { enumerable: true, get: function () { return generate_excel_1.generateExcel; } });
|
|
6
6
|
Object.defineProperty(exports, "EnvironmentType", { enumerable: true, get: function () { return generate_excel_1.EnvironmentType; } });
|
|
@@ -25,47 +25,15 @@ Object.defineProperty(exports, "createHorizontallyAlignedCell", { enumerable: tr
|
|
|
25
25
|
Object.defineProperty(exports, "createVerticallyAlignedCell", { enumerable: true, get: function () { return util_1.createVerticallyAlignedCell; } });
|
|
26
26
|
Object.defineProperty(exports, "createAlignedCell", { enumerable: true, get: function () { return util_1.createAlignedCell; } });
|
|
27
27
|
Object.defineProperty(exports, "createCenteredCell", { enumerable: true, get: function () { return util_1.createCenteredCell; } });
|
|
28
|
-
|
|
29
|
-
(function (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
exports.
|
|
37
|
-
var BorderStyle;
|
|
38
|
-
(function (BorderStyle) {
|
|
39
|
-
BorderStyle["none"] = "none";
|
|
40
|
-
BorderStyle["thin"] = "thin";
|
|
41
|
-
BorderStyle["medium"] = "medium";
|
|
42
|
-
BorderStyle["thick"] = "thick";
|
|
43
|
-
BorderStyle["double"] = "double";
|
|
44
|
-
BorderStyle["dotted"] = "dotted";
|
|
45
|
-
BorderStyle["dashed"] = "dashed";
|
|
46
|
-
})(BorderStyle || (BorderStyle = {}));
|
|
47
|
-
exports.BorderStyle = BorderStyle;
|
|
48
|
-
var HorizontalAlignment;
|
|
49
|
-
(function (HorizontalAlignment) {
|
|
50
|
-
HorizontalAlignment["general"] = "general";
|
|
51
|
-
HorizontalAlignment["left"] = "left";
|
|
52
|
-
HorizontalAlignment["center"] = "center";
|
|
53
|
-
HorizontalAlignment["right"] = "right";
|
|
54
|
-
HorizontalAlignment["fill"] = "fill";
|
|
55
|
-
HorizontalAlignment["justify"] = "justify";
|
|
56
|
-
HorizontalAlignment["centerContinuous"] = "centerContinuous";
|
|
57
|
-
HorizontalAlignment["distributed"] = "distributed";
|
|
58
|
-
})(HorizontalAlignment || (HorizontalAlignment = {}));
|
|
59
|
-
exports.HorizontalAlignment = HorizontalAlignment;
|
|
60
|
-
var VerticalAlignment;
|
|
61
|
-
(function (VerticalAlignment) {
|
|
62
|
-
VerticalAlignment["top"] = "top";
|
|
63
|
-
VerticalAlignment["center"] = "center";
|
|
64
|
-
VerticalAlignment["bottom"] = "bottom";
|
|
65
|
-
VerticalAlignment["justify"] = "justify";
|
|
66
|
-
VerticalAlignment["distributed"] = "distributed";
|
|
67
|
-
})(VerticalAlignment || (VerticalAlignment = {}));
|
|
68
|
-
exports.VerticalAlignment = VerticalAlignment;
|
|
28
|
+
const read_excel_1 = require("./read-excel");
|
|
29
|
+
Object.defineProperty(exports, "readExcel", { enumerable: true, get: function () { return read_excel_1.readExcel; } });
|
|
30
|
+
const read_csv_1 = require("./read-csv");
|
|
31
|
+
Object.defineProperty(exports, "parseCsv", { enumerable: true, get: function () { return read_csv_1.parseCsv; } });
|
|
32
|
+
const types_1 = require("./types");
|
|
33
|
+
Object.defineProperty(exports, "ICellType", { enumerable: true, get: function () { return types_1.ICellType; } });
|
|
34
|
+
Object.defineProperty(exports, "BorderStyle", { enumerable: true, get: function () { return types_1.BorderStyle; } });
|
|
35
|
+
Object.defineProperty(exports, "HorizontalAlignment", { enumerable: true, get: function () { return types_1.HorizontalAlignment; } });
|
|
36
|
+
Object.defineProperty(exports, "VerticalAlignment", { enumerable: true, get: function () { return types_1.VerticalAlignment; } });
|
|
69
37
|
const sampleData = [
|
|
70
38
|
{
|
|
71
39
|
title: 'Maifee1', content: [
|
|
@@ -82,9 +50,9 @@ const sampleData = [
|
|
|
82
50
|
title: 'BorderDemo',
|
|
83
51
|
content: [
|
|
84
52
|
[
|
|
85
|
-
(0, util_1.createBorderedCell)('Product', (0, util_1.createAllBorders)(BorderStyle.thick, '#000000')),
|
|
86
|
-
(0, util_1.createBorderedCell)('Price', (0, util_1.createAllBorders)(BorderStyle.thick, '#000000')),
|
|
87
|
-
(0, util_1.createBorderedCell)('Total', (0, util_1.createAllBorders)(BorderStyle.thick, '#000000'))
|
|
53
|
+
(0, util_1.createBorderedCell)('Product', (0, util_1.createAllBorders)(types_1.BorderStyle.thick, '#000000')),
|
|
54
|
+
(0, util_1.createBorderedCell)('Price', (0, util_1.createAllBorders)(types_1.BorderStyle.thick, '#000000')),
|
|
55
|
+
(0, util_1.createBorderedCell)('Total', (0, util_1.createAllBorders)(types_1.BorderStyle.thick, '#000000'))
|
|
88
56
|
],
|
|
89
57
|
[
|
|
90
58
|
(0, util_1.createBorderedCell)('Apple', (0, util_1.createLeftBorder)()),
|
|
@@ -94,8 +62,8 @@ const sampleData = [
|
|
|
94
62
|
[
|
|
95
63
|
(0, util_1.createStyledCell)('Custom', {
|
|
96
64
|
border: {
|
|
97
|
-
left: BorderStyle.double,
|
|
98
|
-
bottom: BorderStyle.thin,
|
|
65
|
+
left: types_1.BorderStyle.double,
|
|
66
|
+
bottom: types_1.BorderStyle.thin,
|
|
99
67
|
color: '#0000FF'
|
|
100
68
|
}
|
|
101
69
|
}),
|
|
@@ -115,7 +83,7 @@ const sampleData = [
|
|
|
115
83
|
[
|
|
116
84
|
'Project Start',
|
|
117
85
|
(0, util_1.createDateCell)(new Date('2024-01-01')),
|
|
118
|
-
(0, util_1.createBorderedDateCell)(new Date('2024-01-15'), (0, util_1.createAllBorders)(BorderStyle.thin, '#000000'))
|
|
86
|
+
(0, util_1.createBorderedDateCell)(new Date('2024-01-15'), (0, util_1.createAllBorders)(types_1.BorderStyle.thin, '#000000'))
|
|
119
87
|
],
|
|
120
88
|
[
|
|
121
89
|
'Milestone 1',
|
|
@@ -126,8 +94,8 @@ const sampleData = [
|
|
|
126
94
|
'Custom Date Style',
|
|
127
95
|
(0, util_1.createDateCell)(new Date('2024-06-15'), {
|
|
128
96
|
border: {
|
|
129
|
-
top: BorderStyle.thick,
|
|
130
|
-
bottom: BorderStyle.double,
|
|
97
|
+
top: types_1.BorderStyle.thick,
|
|
98
|
+
bottom: types_1.BorderStyle.double,
|
|
131
99
|
color: '#FF0000'
|
|
132
100
|
}
|
|
133
101
|
}),
|
|
@@ -170,7 +138,7 @@ const sampleData = [
|
|
|
170
138
|
(0, util_1.createStyledCell)('Complex', {
|
|
171
139
|
backgroundColor: '#FFFFCC',
|
|
172
140
|
foregroundColor: '#0000FF',
|
|
173
|
-
border: (0, util_1.createAllBorders)(BorderStyle.thick, '#000000')
|
|
141
|
+
border: (0, util_1.createAllBorders)(types_1.BorderStyle.thick, '#000000')
|
|
174
142
|
}),
|
|
175
143
|
'Plain text',
|
|
176
144
|
42
|
|
@@ -188,32 +156,32 @@ const sampleData = [
|
|
|
188
156
|
],
|
|
189
157
|
[
|
|
190
158
|
'Left Align',
|
|
191
|
-
(0, util_1.createHorizontallyAlignedCell)('Left Text', HorizontalAlignment.left),
|
|
192
|
-
(0, util_1.createVerticallyAlignedCell)('Top Text', VerticalAlignment.top),
|
|
193
|
-
(0, util_1.createAlignedCell)('Top-Left', HorizontalAlignment.left, VerticalAlignment.top)
|
|
159
|
+
(0, util_1.createHorizontallyAlignedCell)('Left Text', types_1.HorizontalAlignment.left),
|
|
160
|
+
(0, util_1.createVerticallyAlignedCell)('Top Text', types_1.VerticalAlignment.top),
|
|
161
|
+
(0, util_1.createAlignedCell)('Top-Left', types_1.HorizontalAlignment.left, types_1.VerticalAlignment.top)
|
|
194
162
|
],
|
|
195
163
|
[
|
|
196
164
|
'Center Align',
|
|
197
|
-
(0, util_1.createHorizontallyAlignedCell)('Center Text', HorizontalAlignment.center),
|
|
198
|
-
(0, util_1.createVerticallyAlignedCell)('Center Text', VerticalAlignment.center),
|
|
165
|
+
(0, util_1.createHorizontallyAlignedCell)('Center Text', types_1.HorizontalAlignment.center),
|
|
166
|
+
(0, util_1.createVerticallyAlignedCell)('Center Text', types_1.VerticalAlignment.center),
|
|
199
167
|
(0, util_1.createCenteredCell)('Full Center')
|
|
200
168
|
],
|
|
201
169
|
[
|
|
202
170
|
'Right Align',
|
|
203
|
-
(0, util_1.createHorizontallyAlignedCell)('Right Text', HorizontalAlignment.right),
|
|
204
|
-
(0, util_1.createVerticallyAlignedCell)('Bottom Text', VerticalAlignment.bottom),
|
|
205
|
-
(0, util_1.createAlignedCell)('Bottom-Right', HorizontalAlignment.right, VerticalAlignment.bottom)
|
|
171
|
+
(0, util_1.createHorizontallyAlignedCell)('Right Text', types_1.HorizontalAlignment.right),
|
|
172
|
+
(0, util_1.createVerticallyAlignedCell)('Bottom Text', types_1.VerticalAlignment.bottom),
|
|
173
|
+
(0, util_1.createAlignedCell)('Bottom-Right', types_1.HorizontalAlignment.right, types_1.VerticalAlignment.bottom)
|
|
206
174
|
],
|
|
207
175
|
[
|
|
208
176
|
'Complex Style',
|
|
209
177
|
(0, util_1.createStyledCell)('All Features', {
|
|
210
|
-
horizontalAlignment: HorizontalAlignment.center,
|
|
211
|
-
verticalAlignment: VerticalAlignment.center,
|
|
178
|
+
horizontalAlignment: types_1.HorizontalAlignment.center,
|
|
179
|
+
verticalAlignment: types_1.VerticalAlignment.center,
|
|
212
180
|
backgroundColor: '#CCFFCC',
|
|
213
181
|
foregroundColor: '#FF0000',
|
|
214
|
-
border: (0, util_1.createAllBorders)(BorderStyle.thick, '#000000')
|
|
182
|
+
border: (0, util_1.createAllBorders)(types_1.BorderStyle.thick, '#000000')
|
|
215
183
|
}),
|
|
216
|
-
(0, util_1.createAlignedCell)(new Date(), HorizontalAlignment.right, VerticalAlignment.center),
|
|
184
|
+
(0, util_1.createAlignedCell)(new Date(), types_1.HorizontalAlignment.right, types_1.VerticalAlignment.center),
|
|
217
185
|
(0, util_1.createCenteredCell)(42)
|
|
218
186
|
]
|
|
219
187
|
]
|
package/lib/read-csv.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseCsv = void 0;
|
|
4
|
+
const parseCsv = (text, options = {}) => {
|
|
5
|
+
var _a;
|
|
6
|
+
const delimiter = (_a = options.delimiter) !== null && _a !== void 0 ? _a : ",";
|
|
7
|
+
const skipEmptyTrailingRow = options.skipEmptyTrailingRow !== false;
|
|
8
|
+
const delim = delimiter.charAt(0);
|
|
9
|
+
if (text.charCodeAt(0) === 0xfeff)
|
|
10
|
+
text = text.slice(1);
|
|
11
|
+
const rows = [];
|
|
12
|
+
let row = [];
|
|
13
|
+
let field = "";
|
|
14
|
+
let inQuotes = false;
|
|
15
|
+
let i = 0;
|
|
16
|
+
const length = text.length;
|
|
17
|
+
const endField = () => {
|
|
18
|
+
row.push(field);
|
|
19
|
+
field = "";
|
|
20
|
+
};
|
|
21
|
+
const endRow = () => {
|
|
22
|
+
endField();
|
|
23
|
+
rows.push(row);
|
|
24
|
+
row = [];
|
|
25
|
+
};
|
|
26
|
+
while (i < length) {
|
|
27
|
+
const char = text[i];
|
|
28
|
+
if (inQuotes) {
|
|
29
|
+
if (char === '"') {
|
|
30
|
+
if (text[i + 1] === '"') {
|
|
31
|
+
field += '"';
|
|
32
|
+
i += 2;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
inQuotes = false;
|
|
36
|
+
i++;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
field += char;
|
|
40
|
+
i++;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (char === '"') {
|
|
44
|
+
inQuotes = true;
|
|
45
|
+
i++;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (char === delim) {
|
|
49
|
+
endField();
|
|
50
|
+
i++;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (char === "\n") {
|
|
54
|
+
endRow();
|
|
55
|
+
i++;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (char === "\r") {
|
|
59
|
+
endRow();
|
|
60
|
+
if (text[i + 1] === "\n")
|
|
61
|
+
i += 2;
|
|
62
|
+
else
|
|
63
|
+
i++;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
field += char;
|
|
67
|
+
i++;
|
|
68
|
+
}
|
|
69
|
+
if (field.length > 0 || row.length > 0) {
|
|
70
|
+
endRow();
|
|
71
|
+
}
|
|
72
|
+
if (skipEmptyTrailingRow &&
|
|
73
|
+
rows.length > 0 &&
|
|
74
|
+
rows[rows.length - 1].length === 1 &&
|
|
75
|
+
rows[rows.length - 1][0] === "") {
|
|
76
|
+
rows.pop();
|
|
77
|
+
}
|
|
78
|
+
return rows;
|
|
79
|
+
};
|
|
80
|
+
exports.parseCsv = parseCsv;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
type ReadCellValue = string | number | boolean | Date | null;
|
|
3
|
+
interface IReadSheet {
|
|
4
|
+
title: string;
|
|
5
|
+
rows: ReadCellValue[][];
|
|
6
|
+
formulas?: (string | null)[][];
|
|
7
|
+
}
|
|
8
|
+
interface IReadWorkbook {
|
|
9
|
+
sheets: IReadSheet[];
|
|
10
|
+
}
|
|
11
|
+
interface IReadOptions {
|
|
12
|
+
cellDates?: boolean;
|
|
13
|
+
}
|
|
14
|
+
type ReadExcelInput = string | Uint8Array | ArrayBuffer | Blob;
|
|
15
|
+
declare const columnLettersToIndex: (letters: string) => number;
|
|
16
|
+
declare const excelSerialToDate: (serial: number) => Date;
|
|
17
|
+
declare const parseSharedStrings: (sharedStringsXml: string | undefined) => string[];
|
|
18
|
+
declare const parseWorksheet: (sheetXml: string, sharedStrings: string[], dateStyleFlags: boolean[], cellDates: boolean) => {
|
|
19
|
+
rows: ReadCellValue[][];
|
|
20
|
+
formulas?: (string | null)[][] | undefined;
|
|
21
|
+
};
|
|
22
|
+
declare const readExcel: (input: ReadExcelInput, options?: IReadOptions) => Promise<IReadWorkbook>;
|
|
23
|
+
export { readExcel, ReadCellValue, IReadSheet, IReadWorkbook, IReadOptions, ReadExcelInput, columnLettersToIndex, excelSerialToDate, parseSharedStrings, parseWorksheet, };
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.parseWorksheet = exports.parseSharedStrings = exports.excelSerialToDate = exports.columnLettersToIndex = exports.readExcel = void 0;
|
|
13
|
+
const decodeXml = (text) => text
|
|
14
|
+
.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16)))
|
|
15
|
+
.replace(/&#(\d+);/g, (_, dec) => String.fromCodePoint(parseInt(dec, 10)))
|
|
16
|
+
.replace(/</g, "<")
|
|
17
|
+
.replace(/>/g, ">")
|
|
18
|
+
.replace(/"/g, '"')
|
|
19
|
+
.replace(/'/g, "'")
|
|
20
|
+
.replace(/&/g, "&");
|
|
21
|
+
const getAttr = (attrs, name) => {
|
|
22
|
+
const match = attrs.match(new RegExp(`\\b${name}\\s*=\\s*"([^"]*)"|\\b${name}\\s*=\\s*'([^']*)'`));
|
|
23
|
+
if (!match)
|
|
24
|
+
return undefined;
|
|
25
|
+
return decodeXml(match[1] !== undefined ? match[1] : match[2]);
|
|
26
|
+
};
|
|
27
|
+
const columnLettersToIndex = (letters) => {
|
|
28
|
+
let index = 0;
|
|
29
|
+
for (let i = 0; i < letters.length; i++) {
|
|
30
|
+
index = index * 26 + (letters.charCodeAt(i) - 64);
|
|
31
|
+
}
|
|
32
|
+
return index - 1;
|
|
33
|
+
};
|
|
34
|
+
exports.columnLettersToIndex = columnLettersToIndex;
|
|
35
|
+
const excelSerialToDate = (serial) => {
|
|
36
|
+
const excelEpoch = new Date(1900, 0, 1);
|
|
37
|
+
const offset = serial >= 60 ? 2 : 1;
|
|
38
|
+
const millis = excelEpoch.getTime() + (serial - offset) * 24 * 60 * 60 * 1000;
|
|
39
|
+
return new Date(millis);
|
|
40
|
+
};
|
|
41
|
+
exports.excelSerialToDate = excelSerialToDate;
|
|
42
|
+
const BUILTIN_DATE_FORMAT_IDS = new Set([
|
|
43
|
+
14, 15, 16, 17, 18, 19, 20, 21, 22, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
|
44
|
+
45, 46, 47, 50, 51, 52, 53, 54, 55, 56, 57, 58,
|
|
45
|
+
]);
|
|
46
|
+
const isDateFormatCode = (code) => {
|
|
47
|
+
const stripped = code
|
|
48
|
+
.replace(/\[[^\]]*\]/g, "")
|
|
49
|
+
.replace(/"[^"]*"/g, "")
|
|
50
|
+
.replace(/\\./g, "");
|
|
51
|
+
return /[yYdDhHsS]/.test(stripped) || /\bmm?m?m?\b/.test(stripped) && /[yYdDhH]/.test(code);
|
|
52
|
+
};
|
|
53
|
+
const parseDateStyleFlags = (stylesXml) => {
|
|
54
|
+
if (!stylesXml)
|
|
55
|
+
return [];
|
|
56
|
+
const dateNumFmtIds = new Set(BUILTIN_DATE_FORMAT_IDS);
|
|
57
|
+
const numFmtRe = /<numFmt\b([^>]*)\/?>/g;
|
|
58
|
+
let numFmtMatch;
|
|
59
|
+
while ((numFmtMatch = numFmtRe.exec(stylesXml)) !== null) {
|
|
60
|
+
const id = Number(getAttr(numFmtMatch[1], "numFmtId"));
|
|
61
|
+
const code = getAttr(numFmtMatch[1], "formatCode");
|
|
62
|
+
if (!Number.isNaN(id) && code && isDateFormatCode(code)) {
|
|
63
|
+
dateNumFmtIds.add(id);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const cellXfsBlock = stylesXml.match(/<cellXfs\b[^>]*>([\s\S]*?)<\/cellXfs>/);
|
|
67
|
+
if (!cellXfsBlock)
|
|
68
|
+
return [];
|
|
69
|
+
const flags = [];
|
|
70
|
+
const xfRe = /<xf\b([^>]*?)(?:\/>|>[\s\S]*?<\/xf>)/g;
|
|
71
|
+
let xfMatch;
|
|
72
|
+
while ((xfMatch = xfRe.exec(cellXfsBlock[1])) !== null) {
|
|
73
|
+
const numFmtId = Number(getAttr(xfMatch[1], "numFmtId"));
|
|
74
|
+
flags.push(!Number.isNaN(numFmtId) && dateNumFmtIds.has(numFmtId));
|
|
75
|
+
}
|
|
76
|
+
return flags;
|
|
77
|
+
};
|
|
78
|
+
const parseSharedStrings = (sharedStringsXml) => {
|
|
79
|
+
if (!sharedStringsXml)
|
|
80
|
+
return [];
|
|
81
|
+
const strings = [];
|
|
82
|
+
const siRe = /<si\b[^>]*>([\s\S]*?)<\/si>|<si\b[^>]*\/>/g;
|
|
83
|
+
let siMatch;
|
|
84
|
+
while ((siMatch = siRe.exec(sharedStringsXml)) !== null) {
|
|
85
|
+
const inner = siMatch[1] || "";
|
|
86
|
+
let text = "";
|
|
87
|
+
const tRe = /<t\b[^>]*>([\s\S]*?)<\/t>|<t\b[^>]*\/>/g;
|
|
88
|
+
let tMatch;
|
|
89
|
+
while ((tMatch = tRe.exec(inner)) !== null) {
|
|
90
|
+
text += decodeXml(tMatch[1] || "");
|
|
91
|
+
}
|
|
92
|
+
strings.push(text);
|
|
93
|
+
}
|
|
94
|
+
return strings;
|
|
95
|
+
};
|
|
96
|
+
exports.parseSharedStrings = parseSharedStrings;
|
|
97
|
+
const parseWorkbookRels = (relsXml) => {
|
|
98
|
+
const map = new Map();
|
|
99
|
+
if (!relsXml)
|
|
100
|
+
return map;
|
|
101
|
+
const relRe = /<Relationship\b([^>]*)\/?>/g;
|
|
102
|
+
let match;
|
|
103
|
+
while ((match = relRe.exec(relsXml)) !== null) {
|
|
104
|
+
const id = getAttr(match[1], "Id");
|
|
105
|
+
let target = getAttr(match[1], "Target");
|
|
106
|
+
if (!id || !target)
|
|
107
|
+
continue;
|
|
108
|
+
target = target.replace(/^\//, "").replace(/^xl\//, "");
|
|
109
|
+
map.set(id, `xl/${target}`);
|
|
110
|
+
}
|
|
111
|
+
return map;
|
|
112
|
+
};
|
|
113
|
+
const parseWorkbookSheets = (workbookXml) => {
|
|
114
|
+
var _a, _b;
|
|
115
|
+
if (!workbookXml)
|
|
116
|
+
return [];
|
|
117
|
+
const sheets = [];
|
|
118
|
+
const sheetRe = /<sheet\b([^>]*)\/?>/g;
|
|
119
|
+
let match;
|
|
120
|
+
while ((match = sheetRe.exec(workbookXml)) !== null) {
|
|
121
|
+
const name = (_a = getAttr(match[1], "name")) !== null && _a !== void 0 ? _a : `Sheet${sheets.length + 1}`;
|
|
122
|
+
const rId = (_b = getAttr(match[1], "r:id")) !== null && _b !== void 0 ? _b : getAttr(match[1], "id");
|
|
123
|
+
sheets.push({ name, rId });
|
|
124
|
+
}
|
|
125
|
+
return sheets;
|
|
126
|
+
};
|
|
127
|
+
const parseWorksheet = (sheetXml, sharedStrings, dateStyleFlags, cellDates) => {
|
|
128
|
+
var _a;
|
|
129
|
+
const rows = [];
|
|
130
|
+
const formulas = [];
|
|
131
|
+
let sawFormula = false;
|
|
132
|
+
const rowRe = /<row\b([^>]*)>([\s\S]*?)<\/row>/g;
|
|
133
|
+
let rowMatch;
|
|
134
|
+
let sequentialRowIndex = -1;
|
|
135
|
+
while ((rowMatch = rowRe.exec(sheetXml)) !== null) {
|
|
136
|
+
sequentialRowIndex++;
|
|
137
|
+
const rAttr = getAttr(rowMatch[1], "r");
|
|
138
|
+
const rowIndex = rAttr ? Number(rAttr) - 1 : sequentialRowIndex;
|
|
139
|
+
const rowInner = rowMatch[2];
|
|
140
|
+
const rowValues = [];
|
|
141
|
+
const rowFormulas = [];
|
|
142
|
+
let sequentialColIndex = -1;
|
|
143
|
+
const cellRe = /<c\b([^>]*?)(?:\/>|>([\s\S]*?)<\/c>)/g;
|
|
144
|
+
let cellMatch;
|
|
145
|
+
while ((cellMatch = cellRe.exec(rowInner)) !== null) {
|
|
146
|
+
sequentialColIndex++;
|
|
147
|
+
const attrs = cellMatch[1];
|
|
148
|
+
const inner = cellMatch[2] || "";
|
|
149
|
+
const ref = getAttr(attrs, "r");
|
|
150
|
+
const colLetters = ref ? ref.replace(/[0-9]/g, "") : "";
|
|
151
|
+
const colIndex = colLetters ? columnLettersToIndex(colLetters) : sequentialColIndex;
|
|
152
|
+
const type = getAttr(attrs, "t") || "n";
|
|
153
|
+
const styleIndex = Number(getAttr(attrs, "s") || "0");
|
|
154
|
+
const fMatch = inner.match(/<f\b[^>]*>([\s\S]*?)<\/f>|<f\b[^>]*\/>/);
|
|
155
|
+
const formula = fMatch ? decodeXml(fMatch[1] || "") : null;
|
|
156
|
+
if (formula)
|
|
157
|
+
sawFormula = true;
|
|
158
|
+
const vMatch = inner.match(/<v\b[^>]*>([\s\S]*?)<\/v>/);
|
|
159
|
+
const rawValue = vMatch ? decodeXml(vMatch[1]) : undefined;
|
|
160
|
+
let value = null;
|
|
161
|
+
if (type === "s") {
|
|
162
|
+
const idx = Number(rawValue);
|
|
163
|
+
value = Number.isNaN(idx) ? "" : (_a = sharedStrings[idx]) !== null && _a !== void 0 ? _a : "";
|
|
164
|
+
}
|
|
165
|
+
else if (type === "inlineStr") {
|
|
166
|
+
const isMatch = inner.match(/<is\b[^>]*>([\s\S]*?)<\/is>/);
|
|
167
|
+
let text = "";
|
|
168
|
+
if (isMatch) {
|
|
169
|
+
const tRe = /<t\b[^>]*>([\s\S]*?)<\/t>/g;
|
|
170
|
+
let tMatch;
|
|
171
|
+
while ((tMatch = tRe.exec(isMatch[1])) !== null)
|
|
172
|
+
text += decodeXml(tMatch[1]);
|
|
173
|
+
}
|
|
174
|
+
value = text;
|
|
175
|
+
}
|
|
176
|
+
else if (type === "str") {
|
|
177
|
+
value = rawValue !== null && rawValue !== void 0 ? rawValue : (formula !== null && formula !== void 0 ? formula : "");
|
|
178
|
+
}
|
|
179
|
+
else if (type === "b") {
|
|
180
|
+
value = rawValue === "1" || rawValue === "true";
|
|
181
|
+
}
|
|
182
|
+
else if (type === "e") {
|
|
183
|
+
value = rawValue !== null && rawValue !== void 0 ? rawValue : null;
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
if (rawValue === undefined || rawValue === "") {
|
|
187
|
+
value = formula !== null ? formula : null;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
const num = Number(rawValue);
|
|
191
|
+
if (Number.isNaN(num)) {
|
|
192
|
+
value = rawValue;
|
|
193
|
+
}
|
|
194
|
+
else if (cellDates && dateStyleFlags[styleIndex]) {
|
|
195
|
+
value = excelSerialToDate(num);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
value = num;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
rowValues[colIndex] = value;
|
|
203
|
+
rowFormulas[colIndex] = formula;
|
|
204
|
+
}
|
|
205
|
+
rows[rowIndex] = rowValues;
|
|
206
|
+
formulas[rowIndex] = rowFormulas;
|
|
207
|
+
}
|
|
208
|
+
const width = rows.reduce((max, row) => Math.max(max, row ? row.length : 0), 0);
|
|
209
|
+
for (let r = 0; r < rows.length; r++) {
|
|
210
|
+
if (!rows[r])
|
|
211
|
+
rows[r] = [];
|
|
212
|
+
for (let c = 0; c < width; c++) {
|
|
213
|
+
if (rows[r][c] === undefined)
|
|
214
|
+
rows[r][c] = null;
|
|
215
|
+
if (!formulas[r])
|
|
216
|
+
formulas[r] = [];
|
|
217
|
+
if (formulas[r][c] === undefined)
|
|
218
|
+
formulas[r][c] = null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return sawFormula ? { rows, formulas } : { rows };
|
|
222
|
+
};
|
|
223
|
+
exports.parseWorksheet = parseWorksheet;
|
|
224
|
+
const toZipInput = (input) => __awaiter(void 0, void 0, void 0, function* () {
|
|
225
|
+
if (typeof input === "string") {
|
|
226
|
+
const fs = require("fs");
|
|
227
|
+
return fs.readFileSync(input);
|
|
228
|
+
}
|
|
229
|
+
return input;
|
|
230
|
+
});
|
|
231
|
+
const readExcel = (input, options = {}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
232
|
+
const cellDates = options.cellDates !== false;
|
|
233
|
+
const JSZip = require("jszip");
|
|
234
|
+
const zip = yield JSZip.loadAsync(yield toZipInput(input));
|
|
235
|
+
const readPart = (path) => __awaiter(void 0, void 0, void 0, function* () {
|
|
236
|
+
const file = zip.file(path);
|
|
237
|
+
return file ? yield file.async("string") : undefined;
|
|
238
|
+
});
|
|
239
|
+
const [workbookXml, relsXml, sharedStringsXml, stylesXml] = yield Promise.all([
|
|
240
|
+
readPart("xl/workbook.xml"),
|
|
241
|
+
readPart("xl/_rels/workbook.xml.rels"),
|
|
242
|
+
readPart("xl/sharedStrings.xml"),
|
|
243
|
+
readPart("xl/styles.xml"),
|
|
244
|
+
]);
|
|
245
|
+
const sharedStrings = parseSharedStrings(sharedStringsXml);
|
|
246
|
+
const dateStyleFlags = parseDateStyleFlags(stylesXml);
|
|
247
|
+
const rels = parseWorkbookRels(relsXml);
|
|
248
|
+
const sheetRefs = parseWorkbookSheets(workbookXml);
|
|
249
|
+
const sheets = [];
|
|
250
|
+
for (let i = 0; i < sheetRefs.length; i++) {
|
|
251
|
+
const ref = sheetRefs[i];
|
|
252
|
+
let path = ref.rId ? rels.get(ref.rId) : undefined;
|
|
253
|
+
if (!path || !zip.file(path))
|
|
254
|
+
path = `xl/worksheets/sheet${i + 1}.xml`;
|
|
255
|
+
const sheetXml = yield readPart(path);
|
|
256
|
+
if (sheetXml === undefined) {
|
|
257
|
+
sheets.push({ title: ref.name, rows: [] });
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
const parsed = parseWorksheet(sheetXml, sharedStrings, dateStyleFlags, cellDates);
|
|
261
|
+
sheets.push(Object.assign({ title: ref.name }, parsed));
|
|
262
|
+
}
|
|
263
|
+
return { sheets };
|
|
264
|
+
});
|
|
265
|
+
exports.readExcel = readExcel;
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
declare enum ICellType {
|
|
2
|
+
string = "s",
|
|
3
|
+
number = "n",
|
|
4
|
+
date = "d",
|
|
5
|
+
skip = "skip",
|
|
6
|
+
equation = "equation"
|
|
7
|
+
}
|
|
8
|
+
declare enum BorderStyle {
|
|
9
|
+
none = "none",
|
|
10
|
+
thin = "thin",
|
|
11
|
+
medium = "medium",
|
|
12
|
+
thick = "thick",
|
|
13
|
+
double = "double",
|
|
14
|
+
dotted = "dotted",
|
|
15
|
+
dashed = "dashed"
|
|
16
|
+
}
|
|
17
|
+
declare enum HorizontalAlignment {
|
|
18
|
+
general = "general",
|
|
19
|
+
left = "left",
|
|
20
|
+
center = "center",
|
|
21
|
+
right = "right",
|
|
22
|
+
fill = "fill",
|
|
23
|
+
justify = "justify",
|
|
24
|
+
centerContinuous = "centerContinuous",
|
|
25
|
+
distributed = "distributed"
|
|
26
|
+
}
|
|
27
|
+
declare enum VerticalAlignment {
|
|
28
|
+
top = "top",
|
|
29
|
+
center = "center",
|
|
30
|
+
bottom = "bottom",
|
|
31
|
+
justify = "justify",
|
|
32
|
+
distributed = "distributed"
|
|
33
|
+
}
|
|
34
|
+
export { ICellType, BorderStyle, HorizontalAlignment, VerticalAlignment };
|
package/lib/types.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VerticalAlignment = exports.HorizontalAlignment = exports.BorderStyle = exports.ICellType = void 0;
|
|
4
|
+
var ICellType;
|
|
5
|
+
(function (ICellType) {
|
|
6
|
+
ICellType["string"] = "s";
|
|
7
|
+
ICellType["number"] = "n";
|
|
8
|
+
ICellType["date"] = "d";
|
|
9
|
+
ICellType["skip"] = "skip";
|
|
10
|
+
ICellType["equation"] = "equation";
|
|
11
|
+
})(ICellType || (ICellType = {}));
|
|
12
|
+
exports.ICellType = ICellType;
|
|
13
|
+
var BorderStyle;
|
|
14
|
+
(function (BorderStyle) {
|
|
15
|
+
BorderStyle["none"] = "none";
|
|
16
|
+
BorderStyle["thin"] = "thin";
|
|
17
|
+
BorderStyle["medium"] = "medium";
|
|
18
|
+
BorderStyle["thick"] = "thick";
|
|
19
|
+
BorderStyle["double"] = "double";
|
|
20
|
+
BorderStyle["dotted"] = "dotted";
|
|
21
|
+
BorderStyle["dashed"] = "dashed";
|
|
22
|
+
})(BorderStyle || (BorderStyle = {}));
|
|
23
|
+
exports.BorderStyle = BorderStyle;
|
|
24
|
+
var HorizontalAlignment;
|
|
25
|
+
(function (HorizontalAlignment) {
|
|
26
|
+
HorizontalAlignment["general"] = "general";
|
|
27
|
+
HorizontalAlignment["left"] = "left";
|
|
28
|
+
HorizontalAlignment["center"] = "center";
|
|
29
|
+
HorizontalAlignment["right"] = "right";
|
|
30
|
+
HorizontalAlignment["fill"] = "fill";
|
|
31
|
+
HorizontalAlignment["justify"] = "justify";
|
|
32
|
+
HorizontalAlignment["centerContinuous"] = "centerContinuous";
|
|
33
|
+
HorizontalAlignment["distributed"] = "distributed";
|
|
34
|
+
})(HorizontalAlignment || (HorizontalAlignment = {}));
|
|
35
|
+
exports.HorizontalAlignment = HorizontalAlignment;
|
|
36
|
+
var VerticalAlignment;
|
|
37
|
+
(function (VerticalAlignment) {
|
|
38
|
+
VerticalAlignment["top"] = "top";
|
|
39
|
+
VerticalAlignment["center"] = "center";
|
|
40
|
+
VerticalAlignment["bottom"] = "bottom";
|
|
41
|
+
VerticalAlignment["justify"] = "justify";
|
|
42
|
+
VerticalAlignment["distributed"] = "distributed";
|
|
43
|
+
})(VerticalAlignment || (VerticalAlignment = {}));
|
|
44
|
+
exports.VerticalAlignment = VerticalAlignment;
|
package/lib/util.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { IRows, IBorder,
|
|
1
|
+
import { IRows, IBorder, ICellStyle, ICell } from ".";
|
|
2
|
+
import { BorderStyle, HorizontalAlignment, VerticalAlignment } from "./types";
|
|
2
3
|
declare const indexToVbIndex: (index: number) => number;
|
|
3
4
|
declare const indexToVbRelationIndex: (index: number) => number;
|
|
4
5
|
declare const indexToRowIndex: (index: number) => string;
|
package/lib/util.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createCenteredCell = exports.createAlignedCell = exports.createVerticallyAlignedCell = exports.createHorizontallyAlignedCell = exports.createBackgroundDateCell = exports.createColoredCell = exports.createForegroundCell = exports.createBackgroundCell = exports.createBorderedDateCell = exports.createDateCell = exports.dateToExcelSerial = exports.createBorderedCell = exports.createStyledCell = exports.getStyleKey = exports.getBorderKey = exports.createRightBorder = exports.createLeftBorder = exports.createBottomBorder = exports.createTopBorder = exports.createAllBorders = exports.createBorder = exports.writeEquation = exports.Equation = exports.skipCell = exports.SkipCell = exports.calculateExtant = exports.rowColumnToVbPosition = exports.indexToRowIndex = exports.indexToVbRelationIndex = exports.indexToVbIndex = void 0;
|
|
4
|
-
const
|
|
4
|
+
const types_1 = require("./types");
|
|
5
5
|
const indexToVbIndex = (index) => index + 1;
|
|
6
6
|
exports.indexToVbIndex = indexToVbIndex;
|
|
7
7
|
const indexToVbRelationIndex = (index) => indexToVbIndex(index) + 2;
|
|
@@ -41,7 +41,7 @@ const writeEquation = (equation) => new Equation(equation);
|
|
|
41
41
|
exports.writeEquation = writeEquation;
|
|
42
42
|
const createBorder = (border) => border;
|
|
43
43
|
exports.createBorder = createBorder;
|
|
44
|
-
const createAllBorders = (style =
|
|
44
|
+
const createAllBorders = (style = types_1.BorderStyle.thin, color = "#000000") => ({
|
|
45
45
|
top: style,
|
|
46
46
|
right: style,
|
|
47
47
|
bottom: style,
|
|
@@ -49,22 +49,22 @@ const createAllBorders = (style = _1.BorderStyle.thin, color = "#000000") => ({
|
|
|
49
49
|
color
|
|
50
50
|
});
|
|
51
51
|
exports.createAllBorders = createAllBorders;
|
|
52
|
-
const createTopBorder = (style =
|
|
52
|
+
const createTopBorder = (style = types_1.BorderStyle.thin, color = "#000000") => ({
|
|
53
53
|
top: style,
|
|
54
54
|
color
|
|
55
55
|
});
|
|
56
56
|
exports.createTopBorder = createTopBorder;
|
|
57
|
-
const createBottomBorder = (style =
|
|
57
|
+
const createBottomBorder = (style = types_1.BorderStyle.thin, color = "#000000") => ({
|
|
58
58
|
bottom: style,
|
|
59
59
|
color
|
|
60
60
|
});
|
|
61
61
|
exports.createBottomBorder = createBottomBorder;
|
|
62
|
-
const createLeftBorder = (style =
|
|
62
|
+
const createLeftBorder = (style = types_1.BorderStyle.thin, color = "#000000") => ({
|
|
63
63
|
left: style,
|
|
64
64
|
color
|
|
65
65
|
});
|
|
66
66
|
exports.createLeftBorder = createLeftBorder;
|
|
67
|
-
const createRightBorder = (style =
|
|
67
|
+
const createRightBorder = (style = types_1.BorderStyle.thin, color = "#000000") => ({
|
|
68
68
|
right: style,
|
|
69
69
|
color
|
|
70
70
|
});
|
|
@@ -98,14 +98,14 @@ exports.getStyleKey = getStyleKey;
|
|
|
98
98
|
const createStyledCell = (value, style) => {
|
|
99
99
|
if (typeof value === 'string') {
|
|
100
100
|
return {
|
|
101
|
-
type:
|
|
101
|
+
type: types_1.ICellType.string,
|
|
102
102
|
value: value,
|
|
103
103
|
style
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
106
|
else {
|
|
107
107
|
return {
|
|
108
|
-
type:
|
|
108
|
+
type: types_1.ICellType.number,
|
|
109
109
|
value,
|
|
110
110
|
style
|
|
111
111
|
};
|
|
@@ -125,7 +125,7 @@ const dateToExcelSerial = (date) => {
|
|
|
125
125
|
exports.dateToExcelSerial = dateToExcelSerial;
|
|
126
126
|
const createDateCell = (date, style) => {
|
|
127
127
|
return {
|
|
128
|
-
type:
|
|
128
|
+
type: types_1.ICellType.date,
|
|
129
129
|
value: date,
|
|
130
130
|
style
|
|
131
131
|
};
|
|
@@ -179,6 +179,6 @@ const createAlignedCell = (value, horizontal, vertical) => {
|
|
|
179
179
|
};
|
|
180
180
|
exports.createAlignedCell = createAlignedCell;
|
|
181
181
|
const createCenteredCell = (value) => {
|
|
182
|
-
return createAlignedCell(value,
|
|
182
|
+
return createAlignedCell(value, types_1.HorizontalAlignment.center, types_1.VerticalAlignment.center);
|
|
183
183
|
};
|
|
184
184
|
exports.createCenteredCell = createCenteredCell;
|
package/lib/xl/styles.xml.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateStyleXml = void 0;
|
|
4
|
-
const
|
|
4
|
+
const types_1 = require("../types");
|
|
5
5
|
const generateBorderXml = (border) => {
|
|
6
6
|
const getColorXml = (color) => color ? `<color rgb="${color.replace('#', 'FF')}" />` : '';
|
|
7
7
|
const getBorderSideXml = (side, color) => {
|
|
8
|
-
if (!side || side ===
|
|
8
|
+
if (!side || side === types_1.BorderStyle.none) {
|
|
9
9
|
return '<left />';
|
|
10
10
|
}
|
|
11
11
|
return `<left style="${side}">${getColorXml(color)}</left>`;
|
|
12
12
|
};
|
|
13
|
-
const leftXml = !border.left || border.left ===
|
|
13
|
+
const leftXml = !border.left || border.left === types_1.BorderStyle.none
|
|
14
14
|
? '<left />'
|
|
15
15
|
: `<left style="${border.left}">${getColorXml(border.color)}</left>`;
|
|
16
|
-
const rightXml = !border.right || border.right ===
|
|
16
|
+
const rightXml = !border.right || border.right === types_1.BorderStyle.none
|
|
17
17
|
? '<right />'
|
|
18
18
|
: `<right style="${border.right}">${getColorXml(border.color)}</right>`;
|
|
19
|
-
const topXml = !border.top || border.top ===
|
|
19
|
+
const topXml = !border.top || border.top === types_1.BorderStyle.none
|
|
20
20
|
? '<top />'
|
|
21
21
|
: `<top style="${border.top}">${getColorXml(border.color)}</top>`;
|
|
22
|
-
const bottomXml = !border.bottom || border.bottom ===
|
|
22
|
+
const bottomXml = !border.bottom || border.bottom === types_1.BorderStyle.none
|
|
23
23
|
? '<bottom />'
|
|
24
24
|
: `<bottom style="${border.bottom}">${getColorXml(border.color)}</bottom>`;
|
|
25
25
|
return `
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateSheetXml = void 0;
|
|
4
|
-
const
|
|
4
|
+
const types_1 = require("../../types");
|
|
5
5
|
const util_1 = require("../../util");
|
|
6
6
|
const generateSheetXml = (sheet, styleMap, hasDateCells = false) => {
|
|
7
7
|
const styleToIndex = new Map();
|
|
@@ -29,11 +29,11 @@ const generateSheetXml = (sheet, styleMap, hasDateCells = false) => {
|
|
|
29
29
|
rowContent += `<row r="${(0, util_1.indexToVbIndex)(rowIndex)}">\n`;
|
|
30
30
|
row.cells.forEach((cell, cellIndex) => {
|
|
31
31
|
const cellType = cell.type;
|
|
32
|
-
if (cellType !==
|
|
32
|
+
if (cellType !== types_1.ICellType.skip) {
|
|
33
33
|
const cellPosition = (0, util_1.rowColumnToVbPosition)(cellIndex, rowIndex);
|
|
34
34
|
const cellValue = cell.value || '';
|
|
35
35
|
let styleIndex = 0;
|
|
36
|
-
let isDateCell = cell.type ===
|
|
36
|
+
let isDateCell = cell.type === types_1.ICellType.date;
|
|
37
37
|
if ('style' in cell && cell.style) {
|
|
38
38
|
const styleKey = (0, util_1.getStyleKey)(cell.style);
|
|
39
39
|
const baseStyleIndex = styleToIndex.get(styleKey) || 0;
|
|
@@ -47,13 +47,13 @@ const generateSheetXml = (sheet, styleMap, hasDateCells = false) => {
|
|
|
47
47
|
else if (isDateCell && hasDateCells) {
|
|
48
48
|
styleIndex = styleMap.size;
|
|
49
49
|
}
|
|
50
|
-
if (cell.type ===
|
|
50
|
+
if (cell.type === types_1.ICellType.equation) {
|
|
51
51
|
rowContent += `
|
|
52
52
|
<c r="${cellPosition}" t="n" s="${styleIndex}">
|
|
53
53
|
<f aca="false">${cell.value.getEquation()}</f>
|
|
54
54
|
</c>\n`;
|
|
55
55
|
}
|
|
56
|
-
else if (cell.type ===
|
|
56
|
+
else if (cell.type === types_1.ICellType.date) {
|
|
57
57
|
const excelDateValue = (0, util_1.dateToExcelSerial)(cell.value);
|
|
58
58
|
rowContent += `
|
|
59
59
|
<c r="${cellPosition}" t="n" s="${styleIndex}">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "to-spreadsheet",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "npm package to create spreadsheet in node environment and in browser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"excel",
|
|
@@ -30,11 +30,6 @@
|
|
|
30
30
|
],
|
|
31
31
|
"main": "lib/index.js",
|
|
32
32
|
"types": "lib/index.d.ts",
|
|
33
|
-
"scripts": {
|
|
34
|
-
"prepare": "npm run build",
|
|
35
|
-
"build": "tsc",
|
|
36
|
-
"test:compile": "npx ts-node src/index.ts"
|
|
37
|
-
},
|
|
38
33
|
"repository": {
|
|
39
34
|
"type": "git",
|
|
40
35
|
"url": "git+https://github.com/maifeeulasad/to-spreadsheet.git"
|
|
@@ -49,7 +44,7 @@
|
|
|
49
44
|
},
|
|
50
45
|
"homepage": "https://github.com/maifeeulasad/to-spreadsheet#readme",
|
|
51
46
|
"dependencies": {
|
|
52
|
-
"archiver": "^
|
|
47
|
+
"archiver": "^7.0.1",
|
|
53
48
|
"file-saver": "^2.0.5",
|
|
54
49
|
"jszip": "^3.10.1"
|
|
55
50
|
},
|
|
@@ -59,10 +54,18 @@
|
|
|
59
54
|
"LICENSE"
|
|
60
55
|
],
|
|
61
56
|
"devDependencies": {
|
|
62
|
-
"@
|
|
57
|
+
"@tsconfig/node16": "1.0.4",
|
|
58
|
+
"@types/archiver": "^6.0.4",
|
|
63
59
|
"@types/file-saver": "^2.0.5",
|
|
64
60
|
"@types/node": "^17.0.35",
|
|
65
61
|
"ts-node": "^10.8.0",
|
|
66
|
-
"typescript": "^4.7.2"
|
|
62
|
+
"typescript": "^4.7.2",
|
|
63
|
+
"vitest": "^2.1.9"
|
|
64
|
+
},
|
|
65
|
+
"scripts": {
|
|
66
|
+
"build": "tsc",
|
|
67
|
+
"test:compile": "npx ts-node src/index.ts",
|
|
68
|
+
"test": "vitest run",
|
|
69
|
+
"test:watch": "vitest"
|
|
67
70
|
}
|
|
68
|
-
}
|
|
71
|
+
}
|