json-as-xlsx 2.6.0 → 2.6.1
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 +54 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ You can see a live demo on any of these sites (there are several, just in case):
|
|
|
19
19
|
## Features
|
|
20
20
|
|
|
21
21
|
- 📊 Turn an array of JSON sheets into a multi-sheet workbook.
|
|
22
|
+
- 🧱 Render several tables in the same sheet (opt-in, vertical or horizontal layout).
|
|
22
23
|
- 🧭 Read deeply nested values (`"more.phone"`) or compute them with a function.
|
|
23
24
|
- 🎨 Per-column number, date, currency and hyperlink formatting.
|
|
24
25
|
- 🖌️ Opt-in cell styling for fonts, fills, borders, alignment and number formats.
|
|
@@ -233,6 +234,57 @@ Supported style groups are `alignment`, `border`, `fill`, `font`, and `numFmt`.
|
|
|
233
234
|
Column `format` values are also preserved as number formats when styles are
|
|
234
235
|
enabled.
|
|
235
236
|
|
|
237
|
+
### Multiple tables per sheet
|
|
238
|
+
|
|
239
|
+
By default a sheet renders a single table from its `columns` and `content`. To
|
|
240
|
+
place **several independent tables in the same sheet**, provide a `tables` array
|
|
241
|
+
instead — each entry has its own `columns` and `content` (with the same
|
|
242
|
+
formatting and styling options). This is fully opt-in: sheets that don't set
|
|
243
|
+
`tables` keep working exactly as before.
|
|
244
|
+
|
|
245
|
+
```js
|
|
246
|
+
let data = [
|
|
247
|
+
{
|
|
248
|
+
sheet: "Quarter summary",
|
|
249
|
+
tablesLayout: "vertical", // "vertical" (default) stacks tables; "horizontal" places them side by side
|
|
250
|
+
tablesGap: 1, // blank rows (vertical) or columns (horizontal) between tables — defaults to 1
|
|
251
|
+
tables: [
|
|
252
|
+
{
|
|
253
|
+
columns: [
|
|
254
|
+
{ label: "Product", value: "product" },
|
|
255
|
+
{ label: "Revenue", value: "revenue", format: "$#,##0.00" },
|
|
256
|
+
],
|
|
257
|
+
content: [
|
|
258
|
+
{ product: "Keyboard", revenue: 35988 },
|
|
259
|
+
{ product: "Monitor", revenue: 67830 },
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
columns: [
|
|
264
|
+
{ label: "Team", value: "team" },
|
|
265
|
+
{ label: "Expenses", value: "expenses", format: "$#,##0.00" },
|
|
266
|
+
],
|
|
267
|
+
content: [
|
|
268
|
+
{ team: "Engineering", expenses: 42000 },
|
|
269
|
+
{ team: "Marketing", expenses: 18500 },
|
|
270
|
+
],
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
},
|
|
274
|
+
]
|
|
275
|
+
|
|
276
|
+
xlsx(data, { fileName: "MultiTableSpreadsheet" })
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
When `tables` is present and non-empty it takes precedence over the sheet's
|
|
280
|
+
top-level `columns`/`content`.
|
|
281
|
+
|
|
282
|
+
| Sheet option | Type | Default | Description |
|
|
283
|
+
| --------------- | ---------------------------- | ------------ | ------------------------------------------------------------------------ |
|
|
284
|
+
| `tables` | `{ columns, content }[]` | — | Render multiple tables in the sheet. Each table keeps its own formatting. |
|
|
285
|
+
| `tablesLayout` | `"vertical"`/`"horizontal"` | `"vertical"` | Stack tables top-to-bottom or place them left-to-right. |
|
|
286
|
+
| `tablesGap` | `number` | `1` | Blank rows (vertical) or columns (horizontal) left between tables. |
|
|
287
|
+
|
|
236
288
|
## TypeScript
|
|
237
289
|
|
|
238
290
|
The package is written in TypeScript and ships its own type definitions. The
|
|
@@ -253,8 +305,8 @@ xlsx(data, settings)
|
|
|
253
305
|
|
|
254
306
|
## Examples
|
|
255
307
|
|
|
256
|
-
These are
|
|
257
|
-
|
|
308
|
+
These examples are part of the Yarn workspace and are intended to be installed
|
|
309
|
+
and run from the repository root.
|
|
258
310
|
|
|
259
311
|
- [Express with TypeScript](https://github.com/LuisEnMarroquin/json-as-xlsx/blob/main/packages/demo-express)
|
|
260
312
|
- [ReactJS with TypeScript](https://github.com/LuisEnMarroquin/json-as-xlsx/blob/main/packages/demo-reactjs)
|
package/dist/index.d.ts
CHANGED
|
@@ -12,11 +12,18 @@ export type IContentValue = string | number | boolean | Date | IContent | IStyle
|
|
|
12
12
|
export interface IContent {
|
|
13
13
|
[key: string]: IContentValue;
|
|
14
14
|
}
|
|
15
|
-
export interface
|
|
16
|
-
sheet?: string;
|
|
15
|
+
export interface IJsonSheetTable {
|
|
17
16
|
columns: IColumn[];
|
|
18
17
|
content: IContent[];
|
|
19
18
|
}
|
|
19
|
+
export interface IJsonSheet {
|
|
20
|
+
sheet?: string;
|
|
21
|
+
columns?: IColumn[];
|
|
22
|
+
content?: IContent[];
|
|
23
|
+
tables?: IJsonSheetTable[];
|
|
24
|
+
tablesLayout?: "vertical" | "horizontal";
|
|
25
|
+
tablesGap?: number;
|
|
26
|
+
}
|
|
20
27
|
export interface ISettings {
|
|
21
28
|
enableStyles?: boolean;
|
|
22
29
|
extraLength?: number;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.libraryName=exports.getWorksheetColumnWidths=exports.getJsonSheetRow=exports.getContentProperty=exports.utils=void 0;exports.xlsx=xlsx;const xlsx_1=require("@e965/xlsx");Object.defineProperty(exports,"utils",{enumerable:true,get:function(){return xlsx_1.utils}});const styles_1=require("./styles");const getContentProperty=(content,property)=>{const accessContentProperties=(content,properties)=>{const value=content[properties[0]];if(properties.length===1){return value!==null&&value!==void 0?value:""}if(value===undefined||value===null||typeof value==="string"||typeof value==="boolean"||typeof value==="number"||value instanceof Date){return""}return accessContentProperties(value,properties.slice(1))};const properties=property.split(".");return accessContentProperties(content,properties)};exports.getContentProperty=getContentProperty;const getJsonSheetRow=(content,columns)=>{const jsonSheetRow={};columns.forEach(column=>{if(typeof column.value==="function"){jsonSheetRow[column.label]=column.value(content)}else{jsonSheetRow[column.label]=(0,exports.getContentProperty)(content,column.value)}});return jsonSheetRow};exports.getJsonSheetRow=getJsonSheetRow;const applyColumnFormat=(worksheet,
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.libraryName=exports.getWorksheetColumnWidths=exports.getJsonSheetRow=exports.getContentProperty=exports.utils=void 0;exports.xlsx=xlsx;const xlsx_1=require("@e965/xlsx");Object.defineProperty(exports,"utils",{enumerable:true,get:function(){return xlsx_1.utils}});const styles_1=require("./styles");const getContentProperty=(content,property)=>{const accessContentProperties=(content,properties)=>{const value=content[properties[0]];if(properties.length===1){return value!==null&&value!==void 0?value:""}if(value===undefined||value===null||typeof value==="string"||typeof value==="boolean"||typeof value==="number"||value instanceof Date){return""}return accessContentProperties(value,properties.slice(1))};const properties=property.split(".");return accessContentProperties(content,properties)};exports.getContentProperty=getContentProperty;const getJsonSheetRow=(content,columns)=>{const jsonSheetRow={};columns.forEach(column=>{if(typeof column.value==="function"){jsonSheetRow[column.label]=column.value(content)}else{jsonSheetRow[column.label]=(0,exports.getContentProperty)(content,column.value)}});return jsonSheetRow};exports.getJsonSheetRow=getJsonSheetRow;const applyColumnFormat=(worksheet,table,columnFormats)=>{for(let i=0;i<columnFormats.length;i+=1){const columnFormat=columnFormats[i];if(!columnFormat){continue}const column=table.startCol+i;for(let row=table.startRow+1;row<=table.startRow+table.dataRowCount;++row){const ref=xlsx_1.utils.encode_cell({r:row,c:column});if(worksheet[ref]){switch(columnFormat){case"hyperlink":worksheet[ref].l={Target:worksheet[ref].v};break;default:worksheet[ref].z=columnFormat}}}}};const applyHeaderStyles=(worksheet,table,headerStyles)=>{for(let i=0;i<headerStyles.length;i+=1){const headerStyle=headerStyles[i];if(!headerStyle){continue}const column=table.startCol+i;const ref=xlsx_1.utils.encode_cell({r:table.startRow,c:column});if(worksheet[ref]){applyCellStyles(worksheet[ref],headerStyle)}}};const applyColumnStyles=(worksheet,table,columnStyles)=>{for(let i=0;i<columnStyles.length;i+=1){const columnStyle=columnStyles[i];if(!columnStyle){continue}const column=table.startCol+i;for(let row=table.startRow+1;row<=table.startRow+table.dataRowCount;++row){const ref=xlsx_1.utils.encode_cell({r:row,c:column});if(worksheet[ref]){applyCellStyles(worksheet[ref],columnStyle)}}}};const getWorksheetColumnIds=worksheet=>{var _a;const columnRange=xlsx_1.utils.decode_range((_a=worksheet["!ref"])!==null&&_a!==void 0?_a:"");const columnIds=[];for(let C=columnRange.s.c;C<=columnRange.e.c;C++){const address=xlsx_1.utils.encode_col(C);columnIds.push(address)}return columnIds};const getObjectLength=object=>{if(isStyledCell(object)){return getObjectLength(object.v)}if(typeof object==="string"){return Math.max(...object.split("\n").map(string=>string.length))}if(typeof object==="number"){return object.toString().length}if(typeof object==="boolean"){return object?"true".length:"false".length}if(object instanceof Date){return object.toString().length}return 0};const getWorksheetColumnWidths=(worksheet,extraLength=1)=>{const columnLetters=getWorksheetColumnIds(worksheet);return columnLetters.map(column=>{const columnCells=Object.keys(worksheet).filter(cell=>{return cell.replace(/[0-9]/g,"")===column});const maxWidthCell=columnCells.reduce((maxWidth,cellId)=>{const cell=worksheet[cellId];const cellContentLength=getObjectLength(cell.v);if(!cell.z){return Math.max(maxWidth,cellContentLength)}const cellFormatLength=cell.z.length;const largestWidth=Math.max(cellContentLength,cellFormatLength);return Math.max(maxWidth,largestWidth)},0);return{width:maxWidthCell+extraLength}})};exports.getWorksheetColumnWidths=getWorksheetColumnWidths;const buildJsonSheetRows=(columns,content)=>{if(content.length>0){return content.map(contentItem=>(0,exports.getJsonSheetRow)(contentItem,columns))}return columns.map(column=>({[column.label]:""}))};const getWorksheet=(jsonSheet,settings)=>{var _a,_b,_c,_d;const tables=jsonSheet.tables&&jsonSheet.tables.length>0?jsonSheet.tables:[{columns:(_a=jsonSheet.columns)!==null&&_a!==void 0?_a:[],content:(_b=jsonSheet.content)!==null&&_b!==void 0?_b:[]}];const layout=(_c=jsonSheet.tablesLayout)!==null&&_c!==void 0?_c:"vertical";const gap=(_d=jsonSheet.tablesGap)!==null&&_d!==void 0?_d:1;let worksheet;let nextRow=0;let nextCol=0;const placedTables=[];tables.forEach(table=>{const jsonSheetRows=buildJsonSheetRows(table.columns,table.content);const startRow=nextRow;const startCol=nextCol;if(!worksheet){worksheet=xlsx_1.utils.json_to_sheet(jsonSheetRows)}else{xlsx_1.utils.sheet_add_json(worksheet,jsonSheetRows,{origin:{r:startRow,c:startCol}})}placedTables.push({columns:table.columns,startRow:startRow,startCol:startCol,dataRowCount:jsonSheetRows.length});if(layout==="horizontal"){nextCol=startCol+table.columns.length+gap}else{nextRow=startRow+1+jsonSheetRows.length+gap}});const builtWorksheet=worksheet;placedTables.forEach(placedTable=>{const tableColumnFormats=placedTable.columns.map(tableColumn=>{var _a;return(_a=tableColumn.format)!==null&&_a!==void 0?_a:null});applyColumnFormat(builtWorksheet,placedTable,tableColumnFormats);if(settings.enableStyles){const tableHeaderStyles=placedTable.columns.map(tableColumn=>{var _a;return(_a=tableColumn.headerStyle)!==null&&_a!==void 0?_a:null});const tableColumnStyles=placedTable.columns.map(tableColumn=>{var _a;return(_a=tableColumn.cellStyle)!==null&&_a!==void 0?_a:null});applyHeaderStyles(builtWorksheet,placedTable,tableHeaderStyles);applyColumnStyles(builtWorksheet,placedTable,tableColumnStyles)}});builtWorksheet["!cols"]=(0,exports.getWorksheetColumnWidths)(builtWorksheet,settings.extraLength);return builtWorksheet};const applyCellStyles=(cell,...styles)=>{const existingStyle=(0,styles_1.isCellStyleObject)(cell.s)?cell.s:undefined;const mergedStyle=(0,styles_1.mergeCellStyles)(...styles,existingStyle);if(Object.keys(mergedStyle).length>0){cell.s=mergedStyle}};const validCellTypes=new Set(["b","n","e","s","d","z","str"]);const styleKeys=new Set(["alignment","border","fill","font","numFmt"]);const hasStyleKeys=style=>{return(0,styles_1.isCellStyleObject)(style)&&Object.keys(style).some(key=>styleKeys.has(key))};const isCellLink=value=>{return Boolean(value)&&typeof value==="object"&&!Array.isArray(value)&&typeof value.Target==="string"};const isStyledCell=value=>{if(!value||typeof value!=="object"||Array.isArray(value)){return false}const cell=value;return"v"in cell&&(validCellTypes.has(String(cell.t))||hasStyleKeys(cell.s)||typeof cell.z==="string"||isCellLink(cell.l))};const writeWorkbook=(workbook,settings={})=>{var _a,_b,_c,_d,_e,_f;var _g;const RTL=Boolean(settings.RTL);(_a=workbook.Workbook)!==null&&_a!==void 0?_a:workbook.Workbook={};(_b=(_g=workbook.Workbook).Views)!==null&&_b!==void 0?_b:_g.Views=[{}];workbook.Workbook.Views.forEach(view=>{view.RTL=RTL});const filename=`${(_c=settings.fileName)!==null&&_c!==void 0?_c:"Spreadsheet"}.xlsx`;const writeOptions=(_d=settings.writeOptions)!==null&&_d!==void 0?_d:{};const writeType=(_e=writeOptions.type)!==null&&_e!==void 0?_e:"buffer";if(settings.enableStyles){const bookType=(_f=writeOptions.bookType)!==null&&_f!==void 0?_f:"xlsx";if(bookType!=="xlsx"){throw new Error("enableStyles only supports the xlsx book type")}const rawWorkbook=(0,xlsx_1.write)(workbook,Object.assign(Object.assign({},writeOptions),{bookType:bookType,type:"array"}));const styledWorkbook=(0,styles_1.patchStyledWorkbook)(workbook,rawWorkbook);if(settings.writeMode==="write"){return(0,styles_1.toStyledOutput)(styledWorkbook,writeType)}else if(settings.writeMode==="writeFile"){(0,styles_1.saveXlsxOutput)(styledWorkbook,filename);return}else if(writeOptions.type==="buffer"){return(0,styles_1.toStyledOutput)(styledWorkbook,writeOptions.type)}else{(0,styles_1.saveXlsxOutput)(styledWorkbook,filename);return}}if(settings.writeMode==="write"){return(0,xlsx_1.write)(workbook,Object.assign(Object.assign({},writeOptions),{type:writeType}))}else if(settings.writeMode==="writeFile"){(0,xlsx_1.writeFile)(workbook,filename,writeOptions);return}else if(writeOptions.type==="buffer"){return(0,xlsx_1.write)(workbook,writeOptions)}else{(0,xlsx_1.writeFile)(workbook,filename,writeOptions);return}};function xlsx(jsonSheets,settings={},workbookCallback=()=>{}){if(jsonSheets.length===0)return;const workbook=xlsx_1.utils.book_new();jsonSheets.forEach((actualSheet,actualIndex)=>{var _a;const worksheet=getWorksheet(actualSheet,settings);const worksheetName=(_a=actualSheet.sheet)!==null&&_a!==void 0?_a:`Sheet ${actualIndex+1}`;xlsx_1.utils.book_append_sheet(workbook,worksheet,worksheetName)});workbookCallback(workbook);return writeWorkbook(workbook,settings)}exports.default=xlsx;exports.libraryName="json-as-xlsx";module.exports=xlsx;module.exports.getContentProperty=exports.getContentProperty;module.exports.getJsonSheetRow=exports.getJsonSheetRow;module.exports.getWorksheetColumnWidths=exports.getWorksheetColumnWidths;module.exports.utils=xlsx_1.utils;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-as-xlsx",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
],
|
|
34
34
|
"repository": {
|
|
35
35
|
"type": "git",
|
|
36
|
-
"url": "https://github.com/LuisEnMarroquin/json-as-xlsx.git"
|
|
36
|
+
"url": "git+https://github.com/LuisEnMarroquin/json-as-xlsx.git"
|
|
37
37
|
},
|
|
38
38
|
"bugs": {
|
|
39
39
|
"url": "https://github.com/LuisEnMarroquin/json-as-xlsx/issues"
|