to-spreadsheet 1.2.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 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
@@ -145,7 +194,7 @@ const data = [
145
194
  - [x] Cell borders
146
195
  - [x] Cell styling (background colors, foreground colors, dates)
147
196
  - [x] Date cells with proper Excel formatting
148
- - [ ] Cell alignment
197
+ - [x] Cell alignment (horizontal and vertical)
149
198
  - [ ] Sheet styling
150
199
 
151
200
  ## Cell Borders
@@ -290,3 +339,121 @@ Colors should be specified in hex format:
290
339
  - `#000000` - Black
291
340
  - `#FFFFFF` - White
292
341
  - `#CCCCCC` - Light gray
342
+
343
+ ## Cell Alignment
344
+
345
+ You can align cell content both horizontally and vertically:
346
+
347
+ ### Basic Alignment Usage
348
+
349
+ ```ts
350
+ import {
351
+ generateExcel,
352
+ createHorizontallyAlignedCell,
353
+ createVerticallyAlignedCell,
354
+ createAlignedCell,
355
+ createCenteredCell,
356
+ HorizontalAlignment,
357
+ VerticalAlignment
358
+ } from 'to-spreadsheet/lib/index';
359
+
360
+ const data = [
361
+ {
362
+ title: 'AlignmentDemo',
363
+ content: [
364
+ [
365
+ 'Feature',
366
+ 'Horizontal',
367
+ 'Vertical',
368
+ 'Both'
369
+ ],
370
+ [
371
+ 'Left Align',
372
+ createHorizontallyAlignedCell('Left Text', HorizontalAlignment.left),
373
+ createVerticallyAlignedCell('Top Text', VerticalAlignment.top),
374
+ createAlignedCell('Top-Left', HorizontalAlignment.left, VerticalAlignment.top)
375
+ ],
376
+ [
377
+ 'Center Align',
378
+ createHorizontallyAlignedCell('Center Text', HorizontalAlignment.center),
379
+ createVerticallyAlignedCell('Center Text', VerticalAlignment.center),
380
+ createCenteredCell('Full Center')
381
+ ],
382
+ [
383
+ 'Right Align',
384
+ createHorizontallyAlignedCell('Right Text', HorizontalAlignment.right),
385
+ createVerticallyAlignedCell('Bottom Text', VerticalAlignment.bottom),
386
+ createAlignedCell('Bottom-Right', HorizontalAlignment.right, VerticalAlignment.bottom)
387
+ ]
388
+ ]
389
+ }
390
+ ];
391
+ ```
392
+
393
+ ### Horizontal Alignment Options
394
+
395
+ - `HorizontalAlignment.general` - General alignment (Excel default)
396
+ - `HorizontalAlignment.left` - Left alignment
397
+ - `HorizontalAlignment.center` - Center alignment
398
+ - `HorizontalAlignment.right` - Right alignment
399
+ - `HorizontalAlignment.fill` - Fill alignment
400
+ - `HorizontalAlignment.justify` - Justify alignment
401
+ - `HorizontalAlignment.centerContinuous` - Center across selection
402
+ - `HorizontalAlignment.distributed` - Distributed alignment
403
+
404
+ ### Vertical Alignment Options
405
+
406
+ - `VerticalAlignment.top` - Top alignment
407
+ - `VerticalAlignment.center` - Center alignment
408
+ - `VerticalAlignment.bottom` - Bottom alignment
409
+ - `VerticalAlignment.justify` - Justify alignment
410
+ - `VerticalAlignment.distributed` - Distributed alignment
411
+
412
+ ### Alignment Helper Functions
413
+
414
+ - `createHorizontallyAlignedCell(value, alignment)` - Creates cell with horizontal alignment
415
+ - `createVerticallyAlignedCell(value, alignment)` - Creates cell with vertical alignment
416
+ - `createAlignedCell(value, horizontal, vertical)` - Creates cell with both alignments
417
+ - `createCenteredCell(value)` - Creates center-aligned cell (convenience function)
418
+
419
+ ### Combined with Other Features
420
+
421
+ Alignment works seamlessly with all other styling features:
422
+
423
+ ```ts
424
+ import {
425
+ createStyledCell,
426
+ HorizontalAlignment,
427
+ VerticalAlignment,
428
+ createAllBorders,
429
+ BorderStyle
430
+ } from 'to-spreadsheet/lib/index';
431
+
432
+ const data = [
433
+ {
434
+ title: 'ComplexStyling',
435
+ content: [
436
+ [
437
+ // Full styling with alignment, colors, and borders
438
+ createStyledCell('Complete Style', {
439
+ horizontalAlignment: HorizontalAlignment.center,
440
+ verticalAlignment: VerticalAlignment.center,
441
+ backgroundColor: '#CCFFCC',
442
+ foregroundColor: '#FF0000',
443
+ border: createAllBorders(BorderStyle.thick, '#000000')
444
+ }),
445
+
446
+ // Aligned date cell
447
+ createDateCell(new Date(), {
448
+ horizontalAlignment: HorizontalAlignment.right,
449
+ verticalAlignment: VerticalAlignment.center,
450
+ backgroundColor: '#FFFFCC'
451
+ }),
452
+
453
+ // Simple centered text
454
+ createCenteredCell('Centered')
455
+ ]
456
+ ]
457
+ }
458
+ ];
459
+ ```
@@ -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 };
@@ -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 index_1 = require("./index");
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 === index_1.ICellType.date) {
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 generateExcel = (dump, environmentType = EnvironmentType.NODE) => {
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: index_1.ICellType.number, value: content });
49
+ cells.push({ type: types_1.ICellType.number, value: content });
49
50
  }
50
51
  else if (typeof content === 'string') {
51
- const type = index_1.ICellType.string;
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: index_1.ICellType.string, value });
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: index_1.ICellType.skip, value: undefined });
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: index_1.ICellType.equation, value: content });
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 === index_1.ICellType.string && typeof cell.value === 'string') {
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: index_1.ICellType.skip });
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
- const workbook = {
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,21 +1,8 @@
1
1
  import { generateExcel, EnvironmentType } from "./generate-excel";
2
- import { SkipCell, skipCell, Equation, writeEquation, createBorder, createAllBorders, createTopBorder, createBottomBorder, createLeftBorder, createRightBorder, createStyledCell, createBorderedCell, createDateCell, createBorderedDateCell, createBackgroundCell, createForegroundCell, createColoredCell, createBackgroundDateCell } from "./util";
3
- declare enum ICellType {
4
- string = "s",
5
- number = "n",
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
- }
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
+ 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";
19
6
  interface IBorder {
20
7
  top?: BorderStyle;
21
8
  right?: BorderStyle;
@@ -27,6 +14,8 @@ interface ICellStyle {
27
14
  border?: IBorder;
28
15
  backgroundColor?: string;
29
16
  foregroundColor?: string;
17
+ horizontalAlignment?: HorizontalAlignment;
18
+ verticalAlignment?: VerticalAlignment;
30
19
  }
31
20
  interface ICellString {
32
21
  type: ICellType.string;
@@ -51,7 +40,7 @@ interface ICellDate {
51
40
  value: Date;
52
41
  style?: ICellStyle;
53
42
  }
54
- declare type ICell = ICellString | ICellNumber | ICellDate | ICellSkip | ICellEquation;
43
+ type ICell = ICellString | ICellNumber | ICellDate | ICellSkip | ICellEquation;
55
44
  interface IRows {
56
45
  cells: ICell[];
57
46
  }
@@ -68,7 +57,8 @@ interface IPage {
68
57
  title: string;
69
58
  content: (string | number | undefined | SkipCell | Equation | ICell)[][];
70
59
  }
71
- export { ICell, ISheet, IWorkbook, IRows, ICellType, IPage, BorderStyle, IBorder, ICellStyle, ICellDate };
60
+ export { ICell, ISheet, IWorkbook, IRows, ICellType, IPage, BorderStyle, IBorder, ICellStyle, ICellDate, HorizontalAlignment, VerticalAlignment };
61
+ export { ReadCellValue, IReadSheet, IReadWorkbook, IReadOptions, ReadExcelInput, ICsvOptions };
72
62
  declare const sampleData: ({
73
63
  title: string;
74
64
  content: (string[] | (number | Equation)[])[];
@@ -82,4 +72,5 @@ declare const sampleData: ({
82
72
  title: string;
83
73
  content: (string | number | ICell)[][];
84
74
  })[];
85
- export { generateExcel, sampleData, EnvironmentType, skipCell, writeEquation, createBorder, createAllBorders, createTopBorder, createBottomBorder, createLeftBorder, createRightBorder, createStyledCell, createBorderedCell, createDateCell, createBorderedDateCell, createBackgroundCell, createForegroundCell, createColoredCell, createBackgroundDateCell };
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.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.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; } });
@@ -21,26 +21,19 @@ Object.defineProperty(exports, "createBackgroundCell", { enumerable: true, get:
21
21
  Object.defineProperty(exports, "createForegroundCell", { enumerable: true, get: function () { return util_1.createForegroundCell; } });
22
22
  Object.defineProperty(exports, "createColoredCell", { enumerable: true, get: function () { return util_1.createColoredCell; } });
23
23
  Object.defineProperty(exports, "createBackgroundDateCell", { enumerable: true, get: function () { return util_1.createBackgroundDateCell; } });
24
- var ICellType;
25
- (function (ICellType) {
26
- ICellType["string"] = "s";
27
- ICellType["number"] = "n";
28
- ICellType["date"] = "d";
29
- ICellType["skip"] = "skip";
30
- ICellType["equation"] = "equation";
31
- })(ICellType || (ICellType = {}));
32
- exports.ICellType = ICellType;
33
- var BorderStyle;
34
- (function (BorderStyle) {
35
- BorderStyle["none"] = "none";
36
- BorderStyle["thin"] = "thin";
37
- BorderStyle["medium"] = "medium";
38
- BorderStyle["thick"] = "thick";
39
- BorderStyle["double"] = "double";
40
- BorderStyle["dotted"] = "dotted";
41
- BorderStyle["dashed"] = "dashed";
42
- })(BorderStyle || (BorderStyle = {}));
43
- exports.BorderStyle = BorderStyle;
24
+ Object.defineProperty(exports, "createHorizontallyAlignedCell", { enumerable: true, get: function () { return util_1.createHorizontallyAlignedCell; } });
25
+ Object.defineProperty(exports, "createVerticallyAlignedCell", { enumerable: true, get: function () { return util_1.createVerticallyAlignedCell; } });
26
+ Object.defineProperty(exports, "createAlignedCell", { enumerable: true, get: function () { return util_1.createAlignedCell; } });
27
+ Object.defineProperty(exports, "createCenteredCell", { enumerable: true, get: function () { return util_1.createCenteredCell; } });
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; } });
44
37
  const sampleData = [
45
38
  {
46
39
  title: 'Maifee1', content: [
@@ -57,9 +50,9 @@ const sampleData = [
57
50
  title: 'BorderDemo',
58
51
  content: [
59
52
  [
60
- (0, util_1.createBorderedCell)('Product', (0, util_1.createAllBorders)(BorderStyle.thick, '#000000')),
61
- (0, util_1.createBorderedCell)('Price', (0, util_1.createAllBorders)(BorderStyle.thick, '#000000')),
62
- (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'))
63
56
  ],
64
57
  [
65
58
  (0, util_1.createBorderedCell)('Apple', (0, util_1.createLeftBorder)()),
@@ -69,8 +62,8 @@ const sampleData = [
69
62
  [
70
63
  (0, util_1.createStyledCell)('Custom', {
71
64
  border: {
72
- left: BorderStyle.double,
73
- bottom: BorderStyle.thin,
65
+ left: types_1.BorderStyle.double,
66
+ bottom: types_1.BorderStyle.thin,
74
67
  color: '#0000FF'
75
68
  }
76
69
  }),
@@ -90,7 +83,7 @@ const sampleData = [
90
83
  [
91
84
  'Project Start',
92
85
  (0, util_1.createDateCell)(new Date('2024-01-01')),
93
- (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'))
94
87
  ],
95
88
  [
96
89
  'Milestone 1',
@@ -101,8 +94,8 @@ const sampleData = [
101
94
  'Custom Date Style',
102
95
  (0, util_1.createDateCell)(new Date('2024-06-15'), {
103
96
  border: {
104
- top: BorderStyle.thick,
105
- bottom: BorderStyle.double,
97
+ top: types_1.BorderStyle.thick,
98
+ bottom: types_1.BorderStyle.double,
106
99
  color: '#FF0000'
107
100
  }
108
101
  }),
@@ -145,12 +138,53 @@ const sampleData = [
145
138
  (0, util_1.createStyledCell)('Complex', {
146
139
  backgroundColor: '#FFFFCC',
147
140
  foregroundColor: '#0000FF',
148
- border: (0, util_1.createAllBorders)(BorderStyle.thick, '#000000')
141
+ border: (0, util_1.createAllBorders)(types_1.BorderStyle.thick, '#000000')
149
142
  }),
150
143
  'Plain text',
151
144
  42
152
145
  ]
153
146
  ]
147
+ },
148
+ {
149
+ title: 'AlignmentDemo',
150
+ content: [
151
+ [
152
+ 'Feature',
153
+ 'Horizontal Alignment',
154
+ 'Vertical Alignment',
155
+ 'Both Alignments'
156
+ ],
157
+ [
158
+ 'Left Align',
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)
162
+ ],
163
+ [
164
+ 'Center Align',
165
+ (0, util_1.createHorizontallyAlignedCell)('Center Text', types_1.HorizontalAlignment.center),
166
+ (0, util_1.createVerticallyAlignedCell)('Center Text', types_1.VerticalAlignment.center),
167
+ (0, util_1.createCenteredCell)('Full Center')
168
+ ],
169
+ [
170
+ 'Right Align',
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)
174
+ ],
175
+ [
176
+ 'Complex Style',
177
+ (0, util_1.createStyledCell)('All Features', {
178
+ horizontalAlignment: types_1.HorizontalAlignment.center,
179
+ verticalAlignment: types_1.VerticalAlignment.center,
180
+ backgroundColor: '#CCFFCC',
181
+ foregroundColor: '#FF0000',
182
+ border: (0, util_1.createAllBorders)(types_1.BorderStyle.thick, '#000000')
183
+ }),
184
+ (0, util_1.createAlignedCell)(new Date(), types_1.HorizontalAlignment.right, types_1.VerticalAlignment.center),
185
+ (0, util_1.createCenteredCell)(42)
186
+ ]
187
+ ]
154
188
  }
155
189
  ];
156
190
  exports.sampleData = sampleData;
@@ -0,0 +1,6 @@
1
+ interface ICsvOptions {
2
+ delimiter?: string;
3
+ skipEmptyTrailingRow?: boolean;
4
+ }
5
+ declare const parseCsv: (text: string, options?: ICsvOptions) => string[][];
6
+ export { parseCsv, ICsvOptions };
@@ -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(/&lt;/g, "<")
17
+ .replace(/&gt;/g, ">")
18
+ .replace(/&quot;/g, '"')
19
+ .replace(/&apos;/g, "'")
20
+ .replace(/&amp;/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, BorderStyle, ICellStyle, ICell } from ".";
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;
@@ -33,4 +34,8 @@ declare const createBackgroundCell: (value: string | number, backgroundColor: st
33
34
  declare const createForegroundCell: (value: string | number, foregroundColor: string) => ICell;
34
35
  declare const createColoredCell: (value: string | number, backgroundColor: string, foregroundColor: string) => ICell;
35
36
  declare const createBackgroundDateCell: (date: Date, backgroundColor: string) => ICell;
36
- export { indexToVbIndex, indexToVbRelationIndex, indexToRowIndex, rowColumnToVbPosition, calculateExtant, SkipCell, skipCell, Equation, writeEquation, createBorder, createAllBorders, createTopBorder, createBottomBorder, createLeftBorder, createRightBorder, getBorderKey, getStyleKey, createStyledCell, createBorderedCell, dateToExcelSerial, createDateCell, createBorderedDateCell, createBackgroundCell, createForegroundCell, createColoredCell, createBackgroundDateCell };
37
+ declare const createHorizontallyAlignedCell: (value: string | number | Date, alignment: HorizontalAlignment) => ICell;
38
+ declare const createVerticallyAlignedCell: (value: string | number | Date, alignment: VerticalAlignment) => ICell;
39
+ declare const createAlignedCell: (value: string | number | Date, horizontal: HorizontalAlignment, vertical: VerticalAlignment) => ICell;
40
+ declare const createCenteredCell: (value: string | number | Date) => ICell;
41
+ export { indexToVbIndex, indexToVbRelationIndex, indexToRowIndex, rowColumnToVbPosition, calculateExtant, SkipCell, skipCell, Equation, writeEquation, createBorder, createAllBorders, createTopBorder, createBottomBorder, createLeftBorder, createRightBorder, getBorderKey, getStyleKey, createStyledCell, createBorderedCell, dateToExcelSerial, createDateCell, createBorderedDateCell, createBackgroundCell, createForegroundCell, createColoredCell, createBackgroundDateCell, createHorizontallyAlignedCell, createVerticallyAlignedCell, createAlignedCell, createCenteredCell };
package/lib/util.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- 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 _1 = require(".");
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 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 = _1.BorderStyle.thin, color = "#000000") => ({
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 = _1.BorderStyle.thin, color = "#000000") => ({
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 = _1.BorderStyle.thin, color = "#000000") => ({
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 = _1.BorderStyle.thin, color = "#000000") => ({
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 = _1.BorderStyle.thin, color = "#000000") => ({
67
+ const createRightBorder = (style = types_1.BorderStyle.thin, color = "#000000") => ({
68
68
  right: style,
69
69
  color
70
70
  });
@@ -88,7 +88,9 @@ const getStyleKey = (style) => {
88
88
  const parts = [
89
89
  getBorderKey(style.border),
90
90
  style.backgroundColor || "no-bg",
91
- style.foregroundColor || "no-fg"
91
+ style.foregroundColor || "no-fg",
92
+ style.horizontalAlignment || "no-halign",
93
+ style.verticalAlignment || "no-valign"
92
94
  ];
93
95
  return parts.join("|");
94
96
  };
@@ -96,14 +98,14 @@ exports.getStyleKey = getStyleKey;
96
98
  const createStyledCell = (value, style) => {
97
99
  if (typeof value === 'string') {
98
100
  return {
99
- type: _1.ICellType.string,
101
+ type: types_1.ICellType.string,
100
102
  value: value,
101
103
  style
102
104
  };
103
105
  }
104
106
  else {
105
107
  return {
106
- type: _1.ICellType.number,
108
+ type: types_1.ICellType.number,
107
109
  value,
108
110
  style
109
111
  };
@@ -123,7 +125,7 @@ const dateToExcelSerial = (date) => {
123
125
  exports.dateToExcelSerial = dateToExcelSerial;
124
126
  const createDateCell = (date, style) => {
125
127
  return {
126
- type: _1.ICellType.date,
128
+ type: types_1.ICellType.date,
127
129
  value: date,
128
130
  style
129
131
  };
@@ -149,3 +151,34 @@ const createBackgroundDateCell = (date, backgroundColor) => {
149
151
  return createDateCell(date, { backgroundColor });
150
152
  };
151
153
  exports.createBackgroundDateCell = createBackgroundDateCell;
154
+ const createHorizontallyAlignedCell = (value, alignment) => {
155
+ if (value instanceof Date) {
156
+ return createDateCell(value, { horizontalAlignment: alignment });
157
+ }
158
+ return createStyledCell(value, { horizontalAlignment: alignment });
159
+ };
160
+ exports.createHorizontallyAlignedCell = createHorizontallyAlignedCell;
161
+ const createVerticallyAlignedCell = (value, alignment) => {
162
+ if (value instanceof Date) {
163
+ return createDateCell(value, { verticalAlignment: alignment });
164
+ }
165
+ return createStyledCell(value, { verticalAlignment: alignment });
166
+ };
167
+ exports.createVerticallyAlignedCell = createVerticallyAlignedCell;
168
+ const createAlignedCell = (value, horizontal, vertical) => {
169
+ if (value instanceof Date) {
170
+ return createDateCell(value, {
171
+ horizontalAlignment: horizontal,
172
+ verticalAlignment: vertical
173
+ });
174
+ }
175
+ return createStyledCell(value, {
176
+ horizontalAlignment: horizontal,
177
+ verticalAlignment: vertical
178
+ });
179
+ };
180
+ exports.createAlignedCell = createAlignedCell;
181
+ const createCenteredCell = (value) => {
182
+ return createAlignedCell(value, types_1.HorizontalAlignment.center, types_1.VerticalAlignment.center);
183
+ };
184
+ exports.createCenteredCell = createCenteredCell;
@@ -1,25 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateStyleXml = void 0;
4
- const __1 = require("..");
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 === __1.BorderStyle.none) {
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 === __1.BorderStyle.none
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 === __1.BorderStyle.none
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 === __1.BorderStyle.none
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 === __1.BorderStyle.none
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 `
@@ -59,6 +59,20 @@ const generateFillXml = (color) => {
59
59
  </patternFill>
60
60
  </fill>`;
61
61
  };
62
+ const generateAlignmentXml = (style) => {
63
+ const hasAlignment = style.horizontalAlignment || style.verticalAlignment;
64
+ if (!hasAlignment) {
65
+ return '';
66
+ }
67
+ let alignmentAttrs = '';
68
+ if (style.horizontalAlignment) {
69
+ alignmentAttrs += ` horizontal="${style.horizontalAlignment}"`;
70
+ }
71
+ if (style.verticalAlignment) {
72
+ alignmentAttrs += ` vertical="${style.verticalAlignment}"`;
73
+ }
74
+ return `<alignment${alignmentAttrs} />`;
75
+ };
62
76
  const generateStyleXml = (styleMap, hasDateCells = false) => {
63
77
  const styles = Array.from(styleMap.values());
64
78
  const styleCount = styles.length;
@@ -98,14 +112,18 @@ const generateStyleXml = (styleMap, hasDateCells = false) => {
98
112
  const borderIndex = Array.from(uniqueBorders.keys()).indexOf(JSON.stringify(style.border || {}));
99
113
  const fontIndex = Array.from(uniqueFonts.keys()).indexOf(style.foregroundColor || "default");
100
114
  const fillIndex = Array.from(uniqueFills.keys()).indexOf(style.backgroundColor || "none");
101
- return `<xf numFmtId="0" fontId="${fontIndex}" fillId="${fillIndex}" borderId="${borderIndex}" xfId="0" />`;
115
+ const alignmentXml = generateAlignmentXml(style);
116
+ const applyAlignment = style.horizontalAlignment || style.verticalAlignment ? ' applyAlignment="1"' : '';
117
+ return `<xf numFmtId="0" fontId="${fontIndex}" fillId="${fillIndex}" borderId="${borderIndex}" xfId="0"${applyAlignment}>${alignmentXml}</xf>`;
102
118
  }).join('\n ');
103
119
  cellXfsXml += '\n ';
104
120
  cellXfsXml += styles.map((style, index) => {
105
121
  const borderIndex = Array.from(uniqueBorders.keys()).indexOf(JSON.stringify(style.border || {}));
106
122
  const fontIndex = Array.from(uniqueFonts.keys()).indexOf(style.foregroundColor || "default");
107
123
  const fillIndex = Array.from(uniqueFills.keys()).indexOf(style.backgroundColor || "none");
108
- return `<xf numFmtId="164" fontId="${fontIndex}" fillId="${fillIndex}" borderId="${borderIndex}" xfId="0" />`;
124
+ const alignmentXml = generateAlignmentXml(style);
125
+ const applyAlignment = style.horizontalAlignment || style.verticalAlignment ? ' applyAlignment="1"' : '';
126
+ return `<xf numFmtId="164" fontId="${fontIndex}" fillId="${fillIndex}" borderId="${borderIndex}" xfId="0"${applyAlignment}>${alignmentXml}</xf>`;
109
127
  }).join('\n ');
110
128
  cellXfsCount = styleCount * 2;
111
129
  }
@@ -114,7 +132,9 @@ const generateStyleXml = (styleMap, hasDateCells = false) => {
114
132
  const borderIndex = Array.from(uniqueBorders.keys()).indexOf(JSON.stringify(style.border || {}));
115
133
  const fontIndex = Array.from(uniqueFonts.keys()).indexOf(style.foregroundColor || "default");
116
134
  const fillIndex = Array.from(uniqueFills.keys()).indexOf(style.backgroundColor || "none");
117
- return `<xf numFmtId="0" fontId="${fontIndex}" fillId="${fillIndex}" borderId="${borderIndex}" xfId="0" />`;
135
+ const alignmentXml = generateAlignmentXml(style);
136
+ const applyAlignment = style.horizontalAlignment || style.verticalAlignment ? ' applyAlignment="1"' : '';
137
+ return `<xf numFmtId="0" fontId="${fontIndex}" fillId="${fillIndex}" borderId="${borderIndex}" xfId="0"${applyAlignment}>${alignmentXml}</xf>`;
118
138
  }).join('\n ');
119
139
  }
120
140
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateSheetXml = void 0;
4
- const __1 = require("../..");
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 !== __1.ICellType.skip) {
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 === __1.ICellType.date;
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 === __1.ICellType.equation) {
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 === __1.ICellType.date) {
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.2.0",
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": "^6.0.1",
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
- "@types/archiver": "^5.3.3",
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
+ }