Compare commits
7 Commits
fix-cells-
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| e6e09a0361 | |||
| 3d98e41d2b | |||
| 7c87d3220d | |||
| 8b60ceb39c | |||
|
|
c677c7267b | ||
|
|
415a26e3f1 | ||
|
|
90b97e23e9 |
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@odfjs/odfjs",
|
"name": "@odfjs/odfjs",
|
||||||
"version": "0.29.0",
|
"version": "0.30.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@odfjs/odfjs",
|
"name": "@odfjs/odfjs",
|
||||||
"version": "0.29.0",
|
"version": "0.30.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@xmldom/xmldom": "^0.9.8",
|
"@xmldom/xmldom": "^0.9.8",
|
||||||
"@zip.js/zip.js": "^2.7.57",
|
"@zip.js/zip.js": "^2.7.57",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@odfjs/odfjs",
|
"name": "@odfjs/odfjs",
|
||||||
"version": "0.29.0",
|
"version": "0.30.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": "./exports.js",
|
"exports": "./exports.js",
|
||||||
"files": [
|
"files": [
|
||||||
@ -21,7 +21,7 @@
|
|||||||
"test": "ava"
|
"test": "ava"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"url": "https://github.com/odfjs/odfjs.git"
|
"url": "https://source.netsyms.com/PostalPortal/odfjs.git"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-commonjs": "^25.0.7",
|
"@rollup/plugin-commonjs": "^25.0.7",
|
||||||
|
|||||||
13
readme.md
13
readme.md
@ -18,7 +18,7 @@ Small lib to parse/understand .odf files (.odt, .ods) in the browser and node.js
|
|||||||
### Install
|
### Install
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm i https://github.com/odfjs/odfjs.git#v0.29.0
|
npm i https://github.com/odfjs/odfjs.git#v0.30.0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ import {tableRawContentToObjects, tableWithoutEmptyRows, getODSTableRawContent}
|
|||||||
/**
|
/**
|
||||||
* @param {ArrayBuffer} odsFile - content of an .ods file
|
* @param {ArrayBuffer} odsFile - content of an .ods file
|
||||||
* @return {Promise<any[]>}
|
* @return {Promise<any[]>}
|
||||||
*/
|
*/
|
||||||
async function getFileData(odsFile){
|
async function getFileData(odsFile){
|
||||||
return getODSTableRawContent(odsFile)
|
return getODSTableRawContent(odsFile)
|
||||||
.then(tableWithoutEmptyRows)
|
.then(tableWithoutEmptyRows)
|
||||||
@ -38,9 +38,9 @@ async function getFileData(odsFile){
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The return value is an array of objects where
|
The return value is an array of objects where
|
||||||
the **keys** are the column names in the first row and
|
the **keys** are the column names in the first row and
|
||||||
the **values** are automatically converted from the .ods files (which type numbers, strings, booleans and dates)
|
the **values** are automatically converted from the .ods files (which type numbers, strings, booleans and dates)
|
||||||
to the appropriate JavaScript value
|
to the appropriate JavaScript value
|
||||||
|
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ odf.js proposes a template syntax
|
|||||||
In an .odt file, write the following:
|
In an .odt file, write the following:
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
Hey {nom}!
|
Hey {nom}!
|
||||||
|
|
||||||
Your birthdate is {dateNaissance}
|
Your birthdate is {dateNaissance}
|
||||||
```
|
```
|
||||||
@ -158,4 +158,3 @@ npm run dev
|
|||||||
I hope to be credited for the work on this repo
|
I hope to be credited for the work on this repo
|
||||||
|
|
||||||
Everything written by me and contributors to this repo is licenced under **CC0 1.0 (Public Domain)**
|
Everything written by me and contributors to this repo is licenced under **CC0 1.0 (Public Domain)**
|
||||||
|
|
||||||
|
|||||||
@ -6,11 +6,15 @@ import {serializeToString, createDocument} from './DOMUtils.js'
|
|||||||
/** @import {SheetCellRawContent, SheetName, SheetRawContent} from './types.js' */
|
/** @import {SheetCellRawContent, SheetName, SheetRawContent} from './types.js' */
|
||||||
|
|
||||||
const stylesXml = `<?xml version="1.0" encoding="UTF-8"?>
|
const stylesXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<office:document-styles
|
<office:document-styles
|
||||||
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
||||||
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
|
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
|
||||||
office:version="1.2">
|
office:version="1.2">
|
||||||
<office:styles/>
|
<office:styles>
|
||||||
|
<style:style style:name="boldcell" style:family="table-cell">
|
||||||
|
<style:text-properties fo:font-weight="bold"/>
|
||||||
|
</style:style>
|
||||||
|
</office:styles>
|
||||||
<office:automatic-styles/>
|
<office:automatic-styles/>
|
||||||
<office:master-styles/>
|
<office:master-styles/>
|
||||||
</office:document-styles>`;
|
</office:document-styles>`;
|
||||||
@ -27,11 +31,11 @@ const manifestXml = `<?xml version="1.0" encoding="UTF-8"?>
|
|||||||
* @param {Map<SheetName, SheetRawContent>} sheetsData
|
* @param {Map<SheetName, SheetRawContent>} sheetsData
|
||||||
* @returns {Promise<ArrayBuffer>}
|
* @returns {Promise<ArrayBuffer>}
|
||||||
*/
|
*/
|
||||||
export async function createOdsFile(sheetsData) {
|
export async function createOdsFile(sheetsData, currencyData = null) {
|
||||||
// Create a new zip writer
|
// Create a new zip writer
|
||||||
const zipWriter = new ZipWriter(new BlobWriter('application/vnd.oasis.opendocument.spreadsheet'));
|
const zipWriter = new ZipWriter(new BlobWriter('application/vnd.oasis.opendocument.spreadsheet'));
|
||||||
|
|
||||||
// The “mimetype” file shall be the first file of the zip file.
|
// The “mimetype” file shall be the first file of the zip file.
|
||||||
// It shall not be compressed, and it shall not use an 'extra field' in its header.
|
// It shall not be compressed, and it shall not use an 'extra field' in its header.
|
||||||
// https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part2-packages/OpenDocument-v1.3-os-part2-packages.html#__RefHeading__752809_826425813
|
// https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part2-packages/OpenDocument-v1.3-os-part2-packages.html#__RefHeading__752809_826425813
|
||||||
zipWriter.add(
|
zipWriter.add(
|
||||||
@ -45,7 +49,7 @@ export async function createOdsFile(sheetsData) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const contentXml = generateContentFileXMLString(sheetsData);
|
const contentXml = generateContentFileXMLString(sheetsData, currencyData);
|
||||||
zipWriter.add("content.xml", new TextReader(contentXml), {level: 9});
|
zipWriter.add("content.xml", new TextReader(contentXml), {level: 9});
|
||||||
|
|
||||||
zipWriter.add("styles.xml", new TextReader(stylesXml));
|
zipWriter.add("styles.xml", new TextReader(stylesXml));
|
||||||
@ -60,10 +64,10 @@ export async function createOdsFile(sheetsData) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the content.xml file with spreadsheet data
|
* Generate the content.xml file with spreadsheet data
|
||||||
* @param {Map<SheetName, SheetRawContent>} sheetsData
|
* @param {Map<SheetName, SheetRawContent>} sheetsData
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function generateContentFileXMLString(sheetsData) {
|
function generateContentFileXMLString(sheetsData, currencyData) {
|
||||||
const doc = createDocument('urn:oasis:names:tc:opendocument:xmlns:office:1.0', 'office:document-content');
|
const doc = createDocument('urn:oasis:names:tc:opendocument:xmlns:office:1.0', 'office:document-content');
|
||||||
const root = doc.documentElement;
|
const root = doc.documentElement;
|
||||||
|
|
||||||
@ -75,6 +79,52 @@ function generateContentFileXMLString(sheetsData) {
|
|||||||
root.setAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0');
|
root.setAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0');
|
||||||
root.setAttribute('office:version', '1.2');
|
root.setAttribute('office:version', '1.2');
|
||||||
|
|
||||||
|
const styleNode = doc.createElement("office:automatic-styles");
|
||||||
|
|
||||||
|
var currencyStyleName = "currencyStyle";
|
||||||
|
if (currencyData != null) {
|
||||||
|
currencyStyleName = `currency${currencyData.currencyCode.toUpperCase()}`;
|
||||||
|
const numberStyle = doc.createElement("number:currency-style");
|
||||||
|
numberStyle.setAttribute("style:name", currencyStyleName);
|
||||||
|
|
||||||
|
const numberCurrencySymbolStyle = doc.createElement("number:currency-symbol");
|
||||||
|
numberCurrencySymbolStyle.setAttribute("number:language", "en");
|
||||||
|
numberCurrencySymbolStyle.setAttribute("number:country", currencyData.countryCode.toUpperCase());
|
||||||
|
numberCurrencySymbolStyle.textContent = currencyData.currencySymbol;
|
||||||
|
numberStyle.appendChild(numberCurrencySymbolStyle);
|
||||||
|
|
||||||
|
const numberCurrencyStyle = doc.createElement("number:number");
|
||||||
|
numberCurrencyStyle.setAttribute("number:min-integer-digits", "1");
|
||||||
|
numberCurrencyStyle.setAttribute("number:decimal-places", `${currencyData.decimalPlaces}`);
|
||||||
|
numberCurrencyStyle.setAttribute("number:min-decimal-places", `${currencyData.decimalPlaces}`);
|
||||||
|
numberCurrencyStyle.setAttribute("number:grouping", "true");
|
||||||
|
numberStyle.appendChild(numberCurrencyStyle);
|
||||||
|
|
||||||
|
styleNode.appendChild(numberStyle);
|
||||||
|
|
||||||
|
const currencyCellStyleNode = doc.createElement("style:style");
|
||||||
|
currencyCellStyleNode.setAttribute("style:name", "currencycell");
|
||||||
|
currencyCellStyleNode.setAttribute("style:family", "table-cell");
|
||||||
|
currencyCellStyleNode.setAttribute("style:data-style-name", currencyStyleName);
|
||||||
|
|
||||||
|
const currencyCellTableCellProperties = doc.createElement("style:table-cell-properties");
|
||||||
|
|
||||||
|
currencyCellStyleNode.appendChild(currencyCellTableCellProperties);
|
||||||
|
|
||||||
|
styleNode.appendChild(currencyCellStyleNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
const boldCellStyleNode = doc.createElement("style:style");
|
||||||
|
boldCellStyleNode.setAttribute("style:name", "boldcell");
|
||||||
|
boldCellStyleNode.setAttribute("style:family", "table-cell");
|
||||||
|
const boldCellTextPropsNode = doc.createElement("style:text-properties");
|
||||||
|
boldCellTextPropsNode.setAttribute("fo:font-weight", "bold");
|
||||||
|
boldCellStyleNode.appendChild(boldCellTextPropsNode);
|
||||||
|
styleNode.appendChild(boldCellStyleNode);
|
||||||
|
|
||||||
|
|
||||||
|
root.appendChild(styleNode);
|
||||||
|
|
||||||
const bodyNode = doc.createElement('office:body');
|
const bodyNode = doc.createElement('office:body');
|
||||||
root.appendChild(bodyNode);
|
root.appendChild(bodyNode);
|
||||||
|
|
||||||
@ -87,8 +137,30 @@ function generateContentFileXMLString(sheetsData) {
|
|||||||
tableNode.setAttribute('table:name', sheetName);
|
tableNode.setAttribute('table:name', sheetName);
|
||||||
spreadsheetNode.appendChild(tableNode);
|
spreadsheetNode.appendChild(tableNode);
|
||||||
|
|
||||||
const columnNode = doc.createElement('table:table-column');
|
var columnsWidthChars = {};
|
||||||
tableNode.appendChild(columnNode);
|
for (let r = 0; r < sheetData.length; r++) {
|
||||||
|
for (let c = 0; c < sheetData[r].length; c++) {
|
||||||
|
var len = ((sheetData[r][c].display ?? sheetData[r][c].value) + "").length;
|
||||||
|
if (typeof columnsWidthChars[c] == "undefined") {
|
||||||
|
columnsWidthChars[c] = len;
|
||||||
|
}
|
||||||
|
columnsWidthChars[c] = Math.max(columnsWidthChars[c], len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var prop in columnsWidthChars) {
|
||||||
|
var columnNode = doc.createElement('table:table-column');
|
||||||
|
columnNode.setAttribute("table:style-name", "colwidth" + columnsWidthChars[prop]);
|
||||||
|
tableNode.appendChild(columnNode);
|
||||||
|
|
||||||
|
var columnWidthNode = doc.createElement("style:style");
|
||||||
|
columnWidthNode.setAttribute("style:name", "colwidth" + columnsWidthChars[prop]);
|
||||||
|
columnWidthNode.setAttribute("style:family", "table-column");
|
||||||
|
const columnWidthPropsNode = doc.createElement("style:table-column-properties");
|
||||||
|
columnWidthPropsNode.setAttribute("style:column-width", `${columnsWidthChars[prop] * 0.26}cm`);
|
||||||
|
columnWidthNode.appendChild(columnWidthPropsNode);
|
||||||
|
styleNode.appendChild(columnWidthNode);
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate through rows
|
// Iterate through rows
|
||||||
sheetData.forEach((row) => {
|
sheetData.forEach((row) => {
|
||||||
@ -101,6 +173,10 @@ function generateContentFileXMLString(sheetsData) {
|
|||||||
const cellType = convertCellType(cell.type);
|
const cellType = convertCellType(cell.type);
|
||||||
cellNode.setAttribute('office:value-type', cellType);
|
cellNode.setAttribute('office:value-type', cellType);
|
||||||
|
|
||||||
|
if (cell.style && cell.style == "bold") {
|
||||||
|
cellNode.setAttribute('table:style-name', "boldcell");
|
||||||
|
}
|
||||||
|
|
||||||
// Add value attribute based on type
|
// Add value attribute based on type
|
||||||
if (cell.value !== null && cell.value !== undefined) {
|
if (cell.value !== null && cell.value !== undefined) {
|
||||||
switch (cellType) {
|
switch (cellType) {
|
||||||
@ -111,6 +187,14 @@ function generateContentFileXMLString(sheetsData) {
|
|||||||
cellNode.setAttribute('office:value', cell.value.toString());
|
cellNode.setAttribute('office:value', cell.value.toString());
|
||||||
cellNode.setAttribute('office:value-type', 'percentage');
|
cellNode.setAttribute('office:value-type', 'percentage');
|
||||||
break;
|
break;
|
||||||
|
case 'currency':
|
||||||
|
cellNode.setAttribute('office:value', cell.value.toString());
|
||||||
|
cellNode.setAttribute('office:value-type', 'currency');
|
||||||
|
if (currencyData != null) {
|
||||||
|
cellNode.setAttribute("table:style-name", "currencycell");
|
||||||
|
cellNode.setAttribute('office:currency', currencyData.currencyCode.toUpperCase());
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'date':
|
case 'date':
|
||||||
cellNode.setAttribute('office:date-value', cell.value.toString());
|
cellNode.setAttribute('office:date-value', cell.value.toString());
|
||||||
break;
|
break;
|
||||||
@ -126,7 +210,11 @@ function generateContentFileXMLString(sheetsData) {
|
|||||||
|
|
||||||
if (cellType !== 'string') {
|
if (cellType !== 'string') {
|
||||||
const textNode = doc.createElement('text:p');
|
const textNode = doc.createElement('text:p');
|
||||||
textNode.textContent = cell.value.toString();
|
if (typeof cell.display != "undefined") {
|
||||||
|
textNode.textContent = cell.display.toString();
|
||||||
|
} else {
|
||||||
|
textNode.textContent = cell.value.toString();
|
||||||
|
}
|
||||||
cellNode.appendChild(textNode);
|
cellNode.appendChild(textNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,7 +229,7 @@ function generateContentFileXMLString(sheetsData) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert cell type to OpenDocument format type
|
* Convert cell type to OpenDocument format type
|
||||||
* @param {SheetCellRawContent['type']} type
|
* @param {SheetCellRawContent['type']} type
|
||||||
* @returns {SheetCellRawContent['type']}
|
* @returns {SheetCellRawContent['type']}
|
||||||
*/
|
*/
|
||||||
function convertCellType(type) {
|
function convertCellType(type) {
|
||||||
|
|||||||
@ -11,8 +11,8 @@ import {parseXML} from './DOMUtils.js'
|
|||||||
const TEXT_NODE = 3
|
const TEXT_NODE = 3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {Element} cell
|
* @param {Element} cell
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function extraxtODSCellText(cell) {
|
function extraxtODSCellText(cell) {
|
||||||
@ -33,7 +33,7 @@ function extraxtODSCellText(cell) {
|
|||||||
text += pChild.nodeValue; // Append text inside <text:p>
|
text += pChild.nodeValue; // Append text inside <text:p>
|
||||||
} else if (pChild.nodeName === 'text:line-break') {
|
} else if (pChild.nodeName === 'text:line-break') {
|
||||||
text += '\n'; // Append newline for <text:line-break />
|
text += '\n'; // Append newline for <text:line-break />
|
||||||
} else if (pChild.nodeName === 'text:a') {
|
} else if (pChild.nodeName === 'text:a' || pChild.nodeName === 'text:span') {
|
||||||
text += pChild.textContent
|
text += pChild.textContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ function extraxtODSCellText(cell) {
|
|||||||
text += '\n'; // Append newline for <text:line-break /> directly under <table:table-cell>
|
text += '\n'; // Append newline for <text:line-break /> directly under <table:table-cell>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return text.trim();
|
return text.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ export async function getODSTableRawContent(arrayBuffer) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a cell value to the appropriate JavaScript type based on its cell type.
|
* Converts a cell value to the appropriate JavaScript type based on its cell type.
|
||||||
* @param {SheetCellRawContent} _
|
* @param {SheetCellRawContent} _
|
||||||
* @returns {number | boolean | string | Date} The converted value.
|
* @returns {number | boolean | string | Date} The converted value.
|
||||||
*/
|
*/
|
||||||
export function convertCellValue({value, type}) {
|
export function convertCellValue({value, type}) {
|
||||||
@ -163,10 +163,10 @@ export function convertCellValue({value, type}) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {unknown} value
|
* @param {unknown} value
|
||||||
* @returns {value is OdfjsImage}
|
* @returns {value is OdfjsImage}
|
||||||
*/
|
*/
|
||||||
export function isOdfjsImage(value) {
|
export function isOdfjsImage(value) {
|
||||||
if (typeof value === 'object' && value!==null
|
if (typeof value === 'object' && value!==null
|
||||||
&& "content" in value && value.content instanceof ArrayBuffer
|
&& "content" in value && value.content instanceof ArrayBuffer
|
||||||
&& "fileName" in value && typeof value.fileName === 'string'
|
&& "fileName" in value && typeof value.fileName === 'string'
|
||||||
&& "mediaType" in value && typeof value.mediaType === 'string'
|
&& "mediaType" in value && typeof value.mediaType === 'string'
|
||||||
@ -183,15 +183,15 @@ export function isOdfjsImage(value) {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {Map<SheetName, SheetRawContent>} rawContentSheets
|
* @param {Map<SheetName, SheetRawContent>} rawContentSheets
|
||||||
* @returns {Map<SheetName, ReturnType<convertCellValue>[][]>}
|
* @returns {Map<SheetName, ReturnType<convertCellValue>[][]>}
|
||||||
*/
|
*/
|
||||||
export function tableRawContentToValues(rawContentSheets){
|
export function tableRawContentToValues(rawContentSheets){
|
||||||
return new Map(
|
return new Map(
|
||||||
[...rawContentSheets].map(([sheetName, rawContent]) => {
|
[...rawContentSheets].map(([sheetName, rawContent]) => {
|
||||||
return [
|
return [
|
||||||
sheetName,
|
sheetName,
|
||||||
rawContent
|
rawContent
|
||||||
.map(row => row.map(c => convertCellValue(c)))
|
.map(row => row.map(c => convertCellValue(c)))
|
||||||
]
|
]
|
||||||
@ -204,7 +204,7 @@ export function tableRawContentToValues(rawContentSheets){
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {SheetCellRawContent} rawContentCell
|
* @param {SheetCellRawContent} rawContentCell
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
@ -213,8 +213,8 @@ export function cellRawContentToStrings(rawContentCell){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {SheetRowRawContent} rawContentRow
|
* @param {SheetRowRawContent} rawContentRow
|
||||||
* @returns {string[]}
|
* @returns {string[]}
|
||||||
*/
|
*/
|
||||||
export function rowRawContentToStrings(rawContentRow){
|
export function rowRawContentToStrings(rawContentRow){
|
||||||
@ -222,8 +222,8 @@ export function rowRawContentToStrings(rawContentRow){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {SheetRawContent} rawContentSheet
|
* @param {SheetRawContent} rawContentSheet
|
||||||
* @returns {string[][]}
|
* @returns {string[][]}
|
||||||
*/
|
*/
|
||||||
export function sheetRawContentToStrings(rawContentSheet){
|
export function sheetRawContentToStrings(rawContentSheet){
|
||||||
@ -231,8 +231,8 @@ export function sheetRawContentToStrings(rawContentSheet){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {Map<SheetName, SheetRawContent>} rawContentSheets
|
* @param {Map<SheetName, SheetRawContent>} rawContentSheets
|
||||||
* @returns {Map<SheetName, string[][]>}
|
* @returns {Map<SheetName, string[][]>}
|
||||||
*/
|
*/
|
||||||
export function tableRawContentToStrings(rawContentSheets){
|
export function tableRawContentToStrings(rawContentSheets){
|
||||||
@ -253,16 +253,16 @@ export function tableRawContentToStrings(rawContentSheets){
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This function expects the first row to contain string values which are used as column names
|
* This function expects the first row to contain string values which are used as column names
|
||||||
* It outputs an array of objects which keys are
|
* It outputs an array of objects which keys are
|
||||||
*
|
*
|
||||||
* @param {SheetRawContent} rawContent
|
* @param {SheetRawContent} rawContent
|
||||||
* @returns {any[]}
|
* @returns {any[]}
|
||||||
*/
|
*/
|
||||||
export function sheetRawContentToObjects(rawContent){
|
export function sheetRawContentToObjects(rawContent){
|
||||||
let [firstRow, ...dataRows] = rawContent
|
let [firstRow, ...dataRows] = rawContent
|
||||||
|
|
||||||
/** @type {string[]} */
|
/** @type {string[]} */
|
||||||
|
|
||||||
const columns = firstRow.map((r, i) => {
|
const columns = firstRow.map((r, i) => {
|
||||||
if (r.value === undefined || r.value === null || r.value === "") {
|
if (r.value === undefined || r.value === null || r.value === "") {
|
||||||
return `Column ${i+1}`
|
return `Column ${i+1}`
|
||||||
@ -284,8 +284,8 @@ export function sheetRawContentToObjects(rawContent){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {Map<SheetName, SheetRawContent>} rawContentSheets
|
* @param {Map<SheetName, SheetRawContent>} rawContentSheets
|
||||||
* @returns {Map<SheetName, any[]>}
|
* @returns {Map<SheetName, any[]>}
|
||||||
*/
|
*/
|
||||||
export function tableRawContentToObjects(rawContentSheets){
|
export function tableRawContentToObjects(rawContentSheets){
|
||||||
@ -312,7 +312,7 @@ export function isCellFilled({value}){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {SheetRowRawContent} rawContentRow
|
* @param {SheetRowRawContent} rawContentRow
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isRowNotEmpty(rawContentRow){
|
export function isRowNotEmpty(rawContentRow){
|
||||||
@ -320,7 +320,7 @@ export function isRowNotEmpty(rawContentRow){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {SheetRawContent} sheet
|
* @param {SheetRawContent} sheet
|
||||||
* @returns {SheetRawContent}
|
* @returns {SheetRawContent}
|
||||||
*/
|
*/
|
||||||
export function removeEmptyRowsFromSheet(sheet){
|
export function removeEmptyRowsFromSheet(sheet){
|
||||||
@ -329,8 +329,8 @@ export function removeEmptyRowsFromSheet(sheet){
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {Map<SheetName, SheetRawContent>} rawContentTable
|
* @param {Map<SheetName, SheetRawContent>} rawContentTable
|
||||||
* @returns {Map<SheetName, SheetRawContent>}
|
* @returns {Map<SheetName, SheetRawContent>}
|
||||||
*/
|
*/
|
||||||
export function tableWithoutEmptyRows(rawContentTable){
|
export function tableWithoutEmptyRows(rawContentTable){
|
||||||
@ -339,4 +339,4 @@ export function tableWithoutEmptyRows(rawContentTable){
|
|||||||
return [sheetName, removeEmptyRowsFromSheet(rawContent)]
|
return [sheetName, removeEmptyRowsFromSheet(rawContent)]
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
tests/fixtures/cellule avec style.ods
vendored
Normal file
BIN
tests/fixtures/cellule avec style.ods
vendored
Normal file
Binary file not shown.
@ -75,4 +75,14 @@ test('.ods cells with mails should be recognized', async t => {
|
|||||||
const row3 = feuille1[2]
|
const row3 = feuille1[2]
|
||||||
t.deepEqual(row3[0].value, 'Fanny')
|
t.deepEqual(row3[0].value, 'Fanny')
|
||||||
t.deepEqual(row3[1].value, 'lemaildeFanny@example.com')
|
t.deepEqual(row3[1].value, 'lemaildeFanny@example.com')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('.ods cells with partially styled content should be recognized', async t => {
|
||||||
|
const odsFileWithStyle = (await readFile('./tests/fixtures/cellule avec style.ods')).buffer;
|
||||||
|
const table = await getODSTableRawContent(odsFileWithStyle);
|
||||||
|
|
||||||
|
const feuille1 = table.get('Feuille1');
|
||||||
|
|
||||||
|
const row1 = feuille1[0];
|
||||||
|
t.deepEqual(row1[0].value, 'Toto titi');
|
||||||
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user