From 7c1f4e1b941bf983db080cd6cb48b0cb79d438e8 Mon Sep 17 00:00:00 2001 From: Kaiichiro Date: Sun, 26 Nov 2023 13:46:32 +0900 Subject: [PATCH 1/3] Add test for parse and reconcile --- .../unit/xlsx/xform/sheet/data/sheet.7.3.json | 66 +++++++++++++++++++ .../unit/xlsx/xform/sheet/data/sheet.7.4.json | 66 +++++++++++++++++++ .../xlsx/xform/sheet/worksheet-xform.spec.js | 4 +- 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 spec/unit/xlsx/xform/sheet/data/sheet.7.3.json create mode 100644 spec/unit/xlsx/xform/sheet/data/sheet.7.4.json diff --git a/spec/unit/xlsx/xform/sheet/data/sheet.7.3.json b/spec/unit/xlsx/xform/sheet/data/sheet.7.3.json new file mode 100644 index 000000000..63833ec74 --- /dev/null +++ b/spec/unit/xlsx/xform/sheet/data/sheet.7.3.json @@ -0,0 +1,66 @@ +{ + "dimensions": "A1:C7", + "properties": { + "defaultRowHeight": 14.4, + "dyDescent": 0.55, + "outlineLevelRow": 2, + "outlineLevelCol": 0 + }, + "pageSetup": { + "margins": {"left": 0.7, "right": 0.7, "top": 0.75, "bottom": 0.75, "header": 0.3, "footer": 0.3 }, + "fitToPage": false + }, + "rows": [ + { + "number": 1, "min": 1, "max": 3, + "cells": [ + {"address": "A1", "type": 3, "value": 0}, + {"address": "C1", "type": 3, "value": 1} + ] + }, + { + "number": 2, "min": 1, "max": 3, "outlineLevel": 1, + "cells": [ + {"address": "C2", "type": 3, "value": 2} + ] + }, + { + "number": 3, "min": 1, "max": 3, "outlineLevel": 2, "collapsed": true, + "cells": [ + {"address": "C3", "type": 3, "value": 3} + ] + }, + { + "number": 5, "min": 1, "max": 3, + "cells": [ + {"address": "A5", "type": 3, "value": 4} + ] + }, + { + "number": 7, "min": 1, "max": 3, + "cells": [ + {"address": "A7", "type": 3, "value": 5}, + {"address": "B7", "type": 2, "value": 5} + ] + } + ], + "cols": null, + "background": null, + "mergeCells": null, + "dataValidations": null, + "drawing": null, + "headerFooter": null, + "hyperlinks": null, + "views": [{ + "rightToLeft": false, + "showGridLines": true, + "showRowColHeaders": true, + "showRuler": true, + "state": "normal", + "workbookViewId": 0, + "zoomScale": 100, + "zoomScaleNormal": 100 + }], + "tables": null, + "conditionalFormattings": [] +} diff --git a/spec/unit/xlsx/xform/sheet/data/sheet.7.4.json b/spec/unit/xlsx/xform/sheet/data/sheet.7.4.json new file mode 100644 index 000000000..c40830814 --- /dev/null +++ b/spec/unit/xlsx/xform/sheet/data/sheet.7.4.json @@ -0,0 +1,66 @@ +{ + "dimensions": "A1:C7", + "properties": { + "defaultRowHeight": 14.4, + "dyDescent": 0.55, + "outlineLevelRow": 2, + "outlineLevelCol": 0 + }, + "pageSetup": { + "margins": {"left": 0.7, "right": 0.7, "top": 0.75, "bottom": 0.75, "header": 0.3, "footer": 0.3 }, + "fitToPage": false + }, + "rows": [ + { + "number": 1, "min": 1, "max": 3, "style": {}, + "cells": [ + {"address": "A1", "type": 3, "value": "Name"}, + {"address": "C1", "type": 3, "value": "Tom"} + ] + }, + { + "number": 2, "min": 1, "max": 3, "outlineLevel": 1, "style": {}, + "cells": [ + {"address": "C2", "type": 3, "value": "Dick"} + ] + }, + { + "number": 3, "min": 1, "max": 3, "outlineLevel": 2, "collapsed": true, "style": {}, + "cells": [ + {"address": "C3", "type": 3, "value": "Harry"} + ] + }, + { + "number": 5, "min": 1, "max": 3, "style": {}, + "cells": [ + {"address": "A5", "type": 3, "value": "Inline"} + ] + }, + { + "number": 7, "min": 1, "max": 3, "style": {}, + "cells": [ + {"address": "A7", "type": 3, "value": "Between"}, + {"address": "B7", "type": 2, "value": 5} + ] + } + ], + "cols": null, + "background": null, + "mergeCells": null, + "dataValidations": null, + "drawing": null, + "headerFooter": null, + "media": [], + "views": [{ + "rightToLeft": false, + "showGridLines": true, + "showRowColHeaders": true, + "showRuler": true, + "state": "normal", + "workbookViewId": 0, + "zoomScale": 100, + "zoomScaleNormal": 100 + }], + "tables": [], + "conditionalFormattings": [] +} diff --git a/spec/unit/xlsx/xform/sheet/worksheet-xform.spec.js b/spec/unit/xlsx/xform/sheet/worksheet-xform.spec.js index 8c571a0fc..0fcb93295 100644 --- a/spec/unit/xlsx/xform/sheet/worksheet-xform.spec.js +++ b/spec/unit/xlsx/xform/sheet/worksheet-xform.spec.js @@ -135,7 +135,9 @@ const expectations = [ initialModel: require('./data/sheet.7.0.json'), preparedModel: require('./data/sheet.7.1.json'), xml: fs.readFileSync(`${__dirname}/data/sheet.7.2.xml`).toString(), - tests: ['prepare', 'render'], + parsedModel: require('./data/sheet.7.3.json'), + reconciledModel: require('./data/sheet.7.4.json'), + tests: ['prepare', 'render', 'parse', 'reconcile'], options: { sharedStrings: new SharedStringsXform(), hyperlinks: [], From 4d0c259c8c358bdde693edaf668f033f4e90c78e Mon Sep 17 00:00:00 2001 From: Kaiichiro Date: Sun, 26 Nov 2023 20:01:09 +0900 Subject: [PATCH 2/3] Parse rowBreaks tag --- lib/doc/worksheet.js | 1 + lib/xlsx/xform/sheet/page-breaks-xform.js | 11 ++-- lib/xlsx/xform/sheet/row-breaks-xform.js | 62 ++++++++++++++----- lib/xlsx/xform/sheet/worksheet-xform.js | 2 +- .../unit/xlsx/xform/sheet/data/sheet.1.3.json | 1 + .../unit/xlsx/xform/sheet/data/sheet.5.3.json | 1 + .../unit/xlsx/xform/sheet/data/sheet.6.3.json | 1 + .../unit/xlsx/xform/sheet/data/sheet.7.3.json | 4 ++ .../unit/xlsx/xform/sheet/data/sheet.7.4.json | 4 ++ 9 files changed, 66 insertions(+), 21 deletions(-) diff --git a/lib/doc/worksheet.js b/lib/doc/worksheet.js index 1855b499e..1640100d5 100644 --- a/lib/doc/worksheet.js +++ b/lib/doc/worksheet.js @@ -927,6 +927,7 @@ Please leave feedback at https://github.com/exceljs/exceljs/discussions/2575` this._parseRows(value); this._parseMergeCells(value); + this.rowBreaks = value.rowBreaks; this.dataValidations = new DataValidations(value.dataValidations); this.properties = value.properties; this.pageSetup = value.pageSetup; diff --git a/lib/xlsx/xform/sheet/page-breaks-xform.js b/lib/xlsx/xform/sheet/page-breaks-xform.js index 8d08d6b32..a03867ac3 100644 --- a/lib/xlsx/xform/sheet/page-breaks-xform.js +++ b/lib/xlsx/xform/sheet/page-breaks-xform.js @@ -10,15 +10,18 @@ class PageBreaksXform extends BaseXform { } parseOpen(node) { - if (node.name === 'brk') { - this.model = node.attributes.ref; + if (node.name === this.tag) { + this.model = { + id: node.attributes.id ? parseInt(node.attributes.id, 10) : undefined, + max: node.attributes.max ? parseInt(node.attributes.max, 10) : undefined, + min: node.attributes.min ? parseInt(node.attributes.min, 10) : undefined, + man: node.attributes.man ? parseInt(node.attributes.man, 10) : undefined, + }; return true; } return false; } - parseText() {} - parseClose() { return false; } diff --git a/lib/xlsx/xform/sheet/row-breaks-xform.js b/lib/xlsx/xform/sheet/row-breaks-xform.js index cc01008a8..206dbb426 100644 --- a/lib/xlsx/xform/sheet/row-breaks-xform.js +++ b/lib/xlsx/xform/sheet/row-breaks-xform.js @@ -2,31 +2,29 @@ const PageBreaksXform = require('./page-breaks-xform'); -const ListXform = require('../list-xform'); +const BaseXform = require('../base-xform'); -class RowBreaksXform extends ListXform { +class RowBreaksXform extends BaseXform { constructor() { - const options = { - tag: 'rowBreaks', - count: true, - childXform: new PageBreaksXform(), + super(); + + this.map = { + brk: new PageBreaksXform(), }; - super(options); } - // get tag() { return 'rowBreaks'; } + get tag() { + return 'rowBreaks'; + } render(xmlStream, model) { if (model && model.length) { - xmlStream.openNode(this.tag, this.$); - if (this.count) { - xmlStream.addAttribute(this.$count, model.length); - xmlStream.addAttribute('manualBreakCount', model.length); - } + xmlStream.openNode(this.tag); + xmlStream.addAttribute('count', model.length); + xmlStream.addAttribute('manualBreakCount', model.length); - const {childXform} = this; - model.forEach(childModel => { - childXform.render(xmlStream, childModel); + model.forEach(brk => { + this.map.brk.render(xmlStream, brk); }); xmlStream.closeNode(); @@ -34,6 +32,38 @@ class RowBreaksXform extends ListXform { xmlStream.leafNode(this.tag); } } + + parseOpen(node) { + if (this.parser) { + this.parser.parseOpen(node); + return true; + } + switch (node.name) { + case this.tag: + this.model = []; + return true; + default: + this.parser = this.map[node.name]; + if (this.parser) { + this.parser.parseOpen(node); + } + return true; + } + } + + parseClose(name) { + if (this.parser) { + if (!this.parser.parseClose(name)) { + if (name === 'brk') { + this.model.push(this.parser.model); + } + this.parser = undefined; + } + return true; + } + + return false; + } } module.exports = RowBreaksXform; diff --git a/lib/xlsx/xform/sheet/worksheet-xform.js b/lib/xlsx/xform/sheet/worksheet-xform.js index f1fd59580..b623b8bb1 100644 --- a/lib/xlsx/xform/sheet/worksheet-xform.js +++ b/lib/xlsx/xform/sheet/worksheet-xform.js @@ -377,7 +377,6 @@ class WorkSheetXform extends BaseXform { }); return true; } - if (this.map[node.name] && !this.ignoreNodes.includes(node.name)) { this.parser = this.map[node.name]; this.parser.parseOpen(node); @@ -425,6 +424,7 @@ class WorkSheetXform extends BaseXform { cols: this.map.cols.model, rows: this.map.sheetData.model, mergeCells: this.map.mergeCells.model, + rowBreaks: this.map.rowBreaks.model, hyperlinks: this.map.hyperlinks.model, dataValidations: this.map.dataValidations.model, properties, diff --git a/spec/unit/xlsx/xform/sheet/data/sheet.1.3.json b/spec/unit/xlsx/xform/sheet/data/sheet.1.3.json index cb4981573..94a390d76 100644 --- a/spec/unit/xlsx/xform/sheet/data/sheet.1.3.json +++ b/spec/unit/xlsx/xform/sheet/data/sheet.1.3.json @@ -85,6 +85,7 @@ "evenHeader": "&C&KCCCCCC&\"Aril\"3 exceljs evenHeader", "evenFooter": "&Lexceljs&C&F&RPage &P evenHeader" }, + "rowBreaks": null, "tables": null, "conditionalFormattings": [] } diff --git a/spec/unit/xlsx/xform/sheet/data/sheet.5.3.json b/spec/unit/xlsx/xform/sheet/data/sheet.5.3.json index 08627ab47..e71039d41 100644 --- a/spec/unit/xlsx/xform/sheet/data/sheet.5.3.json +++ b/spec/unit/xlsx/xform/sheet/data/sheet.5.3.json @@ -22,6 +22,7 @@ "cols": null, "hyperlinks": null, "views": null, + "rowBreaks": null, "tables": null, "conditionalFormattings": [] } diff --git a/spec/unit/xlsx/xform/sheet/data/sheet.6.3.json b/spec/unit/xlsx/xform/sheet/data/sheet.6.3.json index 4d7984b52..c24acd9d3 100644 --- a/spec/unit/xlsx/xform/sheet/data/sheet.6.3.json +++ b/spec/unit/xlsx/xform/sheet/data/sheet.6.3.json @@ -23,6 +23,7 @@ "cols": null, "hyperlinks": null, "views": null, + "rowBreaks": null, "tables": null, "conditionalFormattings": [] } diff --git a/spec/unit/xlsx/xform/sheet/data/sheet.7.3.json b/spec/unit/xlsx/xform/sheet/data/sheet.7.3.json index 63833ec74..8f0e2c150 100644 --- a/spec/unit/xlsx/xform/sheet/data/sheet.7.3.json +++ b/spec/unit/xlsx/xform/sheet/data/sheet.7.3.json @@ -61,6 +61,10 @@ "zoomScale": 100, "zoomScaleNormal": 100 }], + "rowBreaks": [ + {"id": 2, "max": 2, "min": 0, "man": 1}, + {"id": 5, "max": 2, "min": 0, "man": 1} + ], "tables": null, "conditionalFormattings": [] } diff --git a/spec/unit/xlsx/xform/sheet/data/sheet.7.4.json b/spec/unit/xlsx/xform/sheet/data/sheet.7.4.json index c40830814..70853b63a 100644 --- a/spec/unit/xlsx/xform/sheet/data/sheet.7.4.json +++ b/spec/unit/xlsx/xform/sheet/data/sheet.7.4.json @@ -61,6 +61,10 @@ "zoomScale": 100, "zoomScaleNormal": 100 }], + "rowBreaks": [ + {"id": 2, "max": 2, "min": 0, "man": 1}, + {"id": 5, "max": 2, "min": 0, "man": 1} + ], "tables": [], "conditionalFormattings": [] } From 336ee5b08238dc41bcc6492d8eefdb4a189a0f8c Mon Sep 17 00:00:00 2001 From: Kaiichiro Date: Sun, 26 Nov 2023 20:25:25 +0900 Subject: [PATCH 3/3] Refactor: rename PageBreaksXform to BrkXform --- lib/xlsx/xform/sheet/{page-breaks-xform.js => brk-xform.js} | 4 ++-- lib/xlsx/xform/sheet/row-breaks-xform.js | 4 ++-- .../sheet/{page-breaks-xform.spec.js => brk-xform.spec.js} | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) rename lib/xlsx/xform/sheet/{page-breaks-xform.js => brk-xform.js} (89%) rename spec/unit/xlsx/xform/sheet/{page-breaks-xform.spec.js => brk-xform.spec.js} (75%) diff --git a/lib/xlsx/xform/sheet/page-breaks-xform.js b/lib/xlsx/xform/sheet/brk-xform.js similarity index 89% rename from lib/xlsx/xform/sheet/page-breaks-xform.js rename to lib/xlsx/xform/sheet/brk-xform.js index a03867ac3..a28f7587b 100644 --- a/lib/xlsx/xform/sheet/page-breaks-xform.js +++ b/lib/xlsx/xform/sheet/brk-xform.js @@ -1,6 +1,6 @@ const BaseXform = require('../base-xform'); -class PageBreaksXform extends BaseXform { +class BrkXform extends BaseXform { get tag() { return 'brk'; } @@ -27,4 +27,4 @@ class PageBreaksXform extends BaseXform { } } -module.exports = PageBreaksXform; +module.exports = BrkXform; diff --git a/lib/xlsx/xform/sheet/row-breaks-xform.js b/lib/xlsx/xform/sheet/row-breaks-xform.js index 206dbb426..dd94c09ea 100644 --- a/lib/xlsx/xform/sheet/row-breaks-xform.js +++ b/lib/xlsx/xform/sheet/row-breaks-xform.js @@ -1,6 +1,6 @@ 'use strict'; -const PageBreaksXform = require('./page-breaks-xform'); +const BrkXform = require('./brk-xform'); const BaseXform = require('../base-xform'); @@ -9,7 +9,7 @@ class RowBreaksXform extends BaseXform { super(); this.map = { - brk: new PageBreaksXform(), + brk: new BrkXform(), }; } diff --git a/spec/unit/xlsx/xform/sheet/page-breaks-xform.spec.js b/spec/unit/xlsx/xform/sheet/brk-xform.spec.js similarity index 75% rename from spec/unit/xlsx/xform/sheet/page-breaks-xform.spec.js rename to spec/unit/xlsx/xform/sheet/brk-xform.spec.js index e85e98c8d..7306bffea 100644 --- a/spec/unit/xlsx/xform/sheet/page-breaks-xform.spec.js +++ b/spec/unit/xlsx/xform/sheet/brk-xform.spec.js @@ -1,12 +1,12 @@ const testXformHelper = require('../test-xform-helper'); -const PageBreaksXform = verquire('xlsx/xform/sheet/page-breaks-xform'); +const BrkXform = verquire('xlsx/xform/sheet/brk-xform'); const expectations = [ { title: 'one page break', create() { - return new PageBreaksXform(); + return new BrkXform(); }, initialModel: {id: 2, max: 3, min: 1, man: 1}, preparedModel: {id: 2, max: 3, min: 1, man: 1}, @@ -16,6 +16,6 @@ const expectations = [ }, ]; -describe('PageBreaksXform', () => { +describe('BrkXform', () => { testXformHelper(expectations); });