.github/000077500000000000000000000000001516074032300124175ustar00rootroot00000000000000.github/workflows/000077500000000000000000000000001516074032300144545ustar00rootroot00000000000000.github/workflows/build.yml000066400000000000000000000017051516074032300163010ustar00rootroot00000000000000# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions name: build on: schedule: - cron: '0 0 1 * *' push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest strategy: matrix: node-version: ['lts/*'] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - run: npm i -g grunt-cli - run: npm install - run: npm run test .gitignore000066400000000000000000000003501516074032300130450ustar00rootroot00000000000000/build /node_modules /*.log /*.iws .idea/workspace.xml .idea/tasks.xml .idea/profiles_settings.xml .idea/inspectionProfiles/Project_Default.xml .idea/inspectionProfiles/profiles_settings.xml node_modules/.yarn-integrity test.xls .npmignore000066400000000000000000000002711516074032300130560ustar00rootroot00000000000000/.idea /artifacts /build /Gemfile /_layouts /_site /_includes /test /node_modules /*.iml /*.ipr /*.iws /.travis.yml /.scrutinizer.yml /Gruntfile.js /corifeus-boot.json /.github /.vscodeGruntfile.js000066400000000000000000000005261516074032300133570ustar00rootroot00000000000000const utils = require('corifeus-utils'); module.exports = (grunt) => { const builder = require(`corifeus-builder`); const loader = new builder.loader(grunt); loader.js({ replacer: { type: 'p3x', npmio: true, }, }); grunt.registerTask('default', builder.config.task.build.js); } LICENSE000066400000000000000000000024271516074032300120710ustar00rootroot00000000000000 @license p3x-json2xls-worker-thread v2024.4.104 📈 Convert JSON to Excel XLSX with offloading the constructing the data using a worker thread https://corifeus.com/json2xls-worker-thread Copyright (c) 2024 Patrik Laszlo / P3X / Corifeus and contributors. MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. README.md000066400000000000000000000120011516074032300123300ustar00rootroot00000000000000[//]: #@corifeus-header [![NPM](https://nodei.co/npm-dl/p3x-json2xls-worker-thread.png?downloads=true&downloadRank=true)](https://www.npmjs.com/package/p3x-json2xls-worker-thread/) [![Donate for Corifeus / P3X](https://img.shields.io/badge/Donate-Corifeus-003087.svg)](https://paypal.me/patrikx3) [![Contact Corifeus / P3X](https://img.shields.io/badge/Contact-P3X-ff9900.svg)](https://www.patrikx3.com/en/front/contact) [![Corifeus @ Facebook](https://img.shields.io/badge/Facebook-Corifeus-3b5998.svg)](https://www.facebook.com/corifeus.software) [![Uptime Robot ratio (30 days)](https://img.shields.io/uptimerobot/ratio/m780749701-41bcade28c1ea8154eda7cca.svg)](https://stats.uptimerobot.com/9ggnzcWrw) # 📈 Convert JSON to Excel XLSX with offloading the constructing the data using a worker thread v2024.4.104 **Bugs are evident™ - MATRIX️** ### NodeJS LTS is supported ### Built on NodeJs version ```txt v20.11.0 ``` # Description [//]: #@corifeus-header:end Utility to convert json to an excel file, based on [Node-Excel-Export](https://github.com/functionscope/Node-Excel-Export) using a worker thread by not blocking the NodeJs event loop using `async` functions and options. This is a totally fork of the [json2xls](https://github.com/rikkertkoppes/json2xls), but the XLSX constructing can be CPU intensive so we are offloading the XLSX constructing using a worker thread. Of course, when using a worker thread, the execution is about 20-25ms longer, than when we are in the event loop, so the worker thread is valid when we are generating a big dataset. # Installation ```bash npm install p3x-json2xls-worker-thread ``` # Usage Use to save as file: ```js const json2xls = require('p3x-json2xls-worker-thread') const fs = require('fs').promises const json = { foo: 'bar', qux: 'moo', poo: 123, stux: new Date() } const executAsync = async() => { try { // let nodeExcelOptions = undefined /* The following options are supported: - style: a styles xml file, see - fields: either an array or map containing field configuration: - array: a list of names of fields to be exported, in that order - object: a map of names of fields to be exported and the types of those fields. Supported types are 'number','string','bool' */ if (ifSomeConditionIsTrue) { nodeExcelOptions = { fields: ['poo'] } } const options = { output: 'binary' /* default */ || 'base64', nodeExcel: nodeExcelOptions } const xlsBinary = await json2xls(json, options) await fs.writeFile('data.xlsx', xlsBinary, 'binary'); } catch(e) { // handle error console.error(e) } } executAsync() ``` Or use as express middleware. It adds a convenience `xls` method to the response object to immediately output an excel as download. ```js const json2xls = require('p3x-json2xls-worker-thread') const jsonArr = [{ foo: 'bar', qux: 'moo', poo: 123, stux: new Date() }, { foo: 'bar', qux: 'moo', poo: 345, stux: new Date() }]; app.use(json2xls.middleware); app.get('/',function(req, res) { res.xls('data.xlsx', jsonArr); }); ``` It is possible to block the event loop by using the `sync` function eg.: ```js const json2xls = require('p3x-json2xls-worker-thread') const json = { foo: 'bar', qux: 'moo', poo: 123, stux: new Date() } const xlsBinary = json2xls.sync(json, { output: 'base64' // can be binary as well, just sugar... }) console.log(xlsBinary) ``` [//]: #@corifeus-footer --- 🙏 This is an open-source project. Star this repository, if you like it, or even donate to maintain the servers and the development. Thank you so much! Possible, this server, rarely, is down, please, hang on for 15-30 minutes and the server will be back up. All my domains ([patrikx3.com](https://patrikx3.com) and [corifeus.com](https://corifeus.com)) could have minor errors, since I am developing in my free time. However, it is usually stable. **Note about versioning:** Versions are cut in Major.Minor.Patch schema. Major is always the current year. Minor is either 4 (January - June) or 10 (July - December). Patch is incremental by every build. If there is a breaking change, it should be noted in the readme. --- [**P3X-JSON2XLS-WORKER-THREAD**](https://corifeus.com/json2xls-worker-thread) Build v2024.4.104 [![Donate for Corifeus / P3X](https://img.shields.io/badge/Donate-Corifeus-003087.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QZVM4V6HVZJW6) [![Contact Corifeus / P3X](https://img.shields.io/badge/Contact-P3X-ff9900.svg)](https://www.patrikx3.com/en/front/contact) [![Like Corifeus @ Facebook](https://img.shields.io/badge/LIKE-Corifeus-3b5998.svg)](https://www.facebook.com/corifeus.software) [//]: #@corifeus-footer:end package.json000066400000000000000000000025231516074032300133470ustar00rootroot00000000000000{ "name": "p3x-json2xls-worker-thread", "version": "2024.4.104", "corifeus": { "icon": "far fa-file-excel", "prefix": "p3x-", "publish": true, "type": "p3x", "code": "Legend", "nodejs": "v20.11.0", "opencollective": false, "reponame": "json2xls-worker-thread", "build": true }, "description": "📈 Convert JSON to Excel XLSX with offloading the constructing the data using a worker thread", "main": "src/index.js", "scripts": { "test": "grunt && mocha ./test/mocha/*.js" }, "repository": { "type": "git", "url": "git+https://github.com/patrikx3/json2xls-worker-thread.git" }, "keywords": [ "json2xls", "worker", "thread", "offloading", "async", "xls", "xlsx", "json" ], "author": "Patrik Laszlo ", "license": "MIT", "bugs": { "url": "https://github.com/patrikx3/json2xls-worker-thread/issues" }, "homepage": "https://corifeus.com/json2xls-worker-thread", "devDependencies": { "corifeus-builder": "^2024.4.103", "express": "^4.18.2" }, "dependencies": { "excel-export": "^0.5.1", "object-path": "^0.11.8" }, "engines": { "node": ">=12.13.0" } }src/000077500000000000000000000000001516074032300116465ustar00rootroot00000000000000src/index.js000066400000000000000000000043651516074032300133230ustar00rootroot00000000000000const { Worker } = require('worker_threads'); const ensureOptions = (options) => { options = options || {} if (!options.hasOwnProperty('output')) { options.output = 'binary' } if (!options.hasOwnProperty('nodeExcel')) { options.nodeExcel = undefined } if (typeof options.output !== 'string' || (options.output !== 'binary' && options.output !== 'base64')) { throw new Error(`The p3x-json2xls-worker-thread options.output can be 'binary' or 'base64', you requested '${options.output}', which is wrong.`) } return options } const transform = async (data, options) => { options = ensureOptions(options) const workerResult = await new Promise((resolve, reject) => { const worker = new Worker(`${__dirname}/json2xls.worker.js`, { workerData: { data: data, options: options, } }); worker.on('message', resolve); worker.on('error', reject); worker.on('exit', (code) => { if (code !== 0) { reject(new Error(`Worker stopped with exit code ${code}`)); } worker.terminate() }); }); return workerResult }; transform.middleware = function(req, res, next) { res.xls = async (filename, data, options) => { try { options = options || {} options.output = 'binary'; options = ensureOptions(options) const xls = await transform(data, options); res.setHeader('Content-Type', 'application/vnd.openxmlformats'); res.setHeader("Content-Disposition", "attachment; filename=" + filename); res.end(xls, 'binary'); } catch(e) { res.status(500).send({ status: 'error', ok: false, message: e.message }) } }; next(); }; transform.sync = (data, options) => { const json2xls = require('./util'); options = ensureOptions(options) const xls = json2xls(data, options.nodeExcel); if (options.output === 'base64') { const xlsBase64 = Buffer.from(xls, 'binary').toString('base64'); return xlsBase64 } else { return xls } } module.exports = transform src/json2xls.worker.js000066400000000000000000000005551516074032300153030ustar00rootroot00000000000000const { parentPort, workerData } = require('worker_threads'); const json2xls = require('./util'); const xls = json2xls(workerData.data, workerData.options.nodeExcel); if (workerData.options.output === 'base64') { const xlsBase64 = Buffer.from(xls, 'binary').toString('base64'); parentPort.postMessage(xlsBase64) } else { parentPort.postMessage(xls) } src/util.js000066400000000000000000000055651516074032300131740ustar00rootroot00000000000000const nodeExcel = require('excel-export') const objectPath = require('object-path') const transform = function (json, config) { const conf = transform.prepareJson(json, config) const result = nodeExcel.execute(conf) return result } // get a xls type based on js type function getType (obj, type) { if (type) { return type } const t = typeof obj switch (t) { case 'string': case 'number': return t case 'boolean': return 'bool' default: return 'string' } } // get a nested property from a JSON object given its key, i.e 'a.b.c' function getByString (object, path) { path = path.replace(/\[(\w+)\]/g, '.$1') // convert indexes to properties path = path.replace(/^\./, '') // strip a leading dot const defaultValue = object[path] || null return objectPath.get(object, path, defaultValue) } // prepare json to be in the correct format for excel-export transform.prepareJson = function (json, config) { const res = {} const conf = config || {} const jsonArr = [].concat(json) let fields = conf.fields || Object.keys(jsonArr[0] || {}) let types = [] if (!(fields instanceof Array)) { types = Object.keys(fields).map(function (key) { return fields[key] }) fields = Object.keys(fields) } // cols res.cols = fields.map(function (key, i) { return { caption: key, type: getType(jsonArr[0][key], types[i]), beforeCellWrite: function (row, cellData, eOpt) { eOpt.cellType = getType(cellData, types[i]) return cellData } } }) // rows res.rows = jsonArr.map(function (row) { return fields.map(function (key) { let value = getByString(row, key) // stringify objects if (value && value.constructor === Object) value = JSON.stringify(value) // replace illegal xml characters with a square // see http://www.w3.org/TR/xml/#charsets // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] if (typeof value === 'string') { // eslint-disable-next-line no-control-regex value = value.replace(/[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]/g, '') } return value }) }) // add style xml if given if (conf.style) { res.stylesXmlFile = conf.style } return res } /* transform.middleware = function (req, res, next) { res.xls = function (fn, data, config) { const xls = transform(data, config) res.setHeader('Content-Type', 'application/vnd.openxmlformats') res.setHeader('Content-Disposition', 'attachment filename=' + fn) res.end(xls, 'binary') } next() } */ module.exports = transform test/000077500000000000000000000000001516074032300120365ustar00rootroot00000000000000test/fixtures/000077500000000000000000000000001516074032300137075ustar00rootroot00000000000000test/fixtures/array-data.json000066400000000000000000000257471516074032300166460ustar00rootroot00000000000000[ { "name": "Ivy Dickson", "date": "2013-05-27T11:04:15-07:00", "number": 10 }, { "date": "2014-02-07T22:09:58-08:00", "name": "Walker Lynch", "number": 2 }, { "number": 5, "date": "2013-06-16T05:29:13-07:00", "name": "Maxwell U. Holden" }, { "name": "Courtney Short", "date": "2014-03-14T07:32:34-07:00", "number": 6 }, { "name": "Amy Baird", "date": "2014-03-02T17:43:22-08:00", "number": 4 }, { "name": "Kirby G. Hanson", "date": "2014-03-31T00:42:54-07:00", "number": 8 }, { "name": "Cairo U. Witt", "date": "2014-10-05T07:47:46-07:00", "number": 5 }, { "name": "Elliott J. Sandoval", "date": "2013-05-29T19:01:47-07:00", "number": 8 }, { "name": "Quon Fry", "date": "2014-07-16T12:37:51-07:00", "number": 4 }, { "name": "Lynn E. Solomon", "date": "2014-01-12T13:46:28-08:00", "number": 3 }, { "name": "Mona V. Todd", "date": "2012-11-22T01:04:20-08:00", "number": 9 }, { "name": "Maggy Floyd", "date": "2013-03-01T13:08:09-08:00", "number": 1 }, { "name": "Dahlia Schwartz", "date": "2014-01-01T20:46:08-08:00", "number": 9 }, { "name": "Joel C. Kaufman", "date": "2014-05-31T21:59:50-07:00", "number": 4 }, { "name": "Nathaniel J. Orr", "date": "2013-04-27T19:20:15-07:00", "number": 6 }, { "name": "Lucas F. Serrano", "date": "2013-09-25T06:58:37-07:00", "number": 1 }, { "name": "Sylvester R. Foreman", "date": "2013-09-04T16:03:51-07:00", "number": 4 }, { "name": "Ezekiel Byers", "date": "2013-04-10T05:54:03-07:00", "number": 9 }, { "name": "Audrey U. Travis", "date": "2014-02-03T17:59:16-08:00", "number": 6 }, { "name": "Inga B. Gomez", "date": "2013-11-09T07:56:59-08:00", "number": 2 }, { "name": "Dane Dawson", "date": "2014-10-07T21:49:09-07:00", "number": 7 }, { "name": "Xaviera Tyson", "date": "2013-02-21T20:19:30-08:00", "number": 7 }, { "name": "Farrah K. Holcomb", "date": "2012-12-08T03:55:34-08:00", "number": 4 }, { "name": "Carissa Vinson", "date": "2014-10-22T15:25:18-07:00", "number": 7 }, { "name": "Alexandra Sharp", "date": "2012-12-30T03:11:07-08:00", "number": 6 }, { "name": "Karen Clemons", "date": "2013-12-14T12:56:28-08:00", "number": 8 }, { "name": "Brock L. Moody", "date": "2014-09-11T21:03:40-07:00", "number": 1 }, { "name": "Savannah Haynes", "date": "2013-09-08T08:38:35-07:00", "number": 4 }, { "name": "Ivan F. Duffy", "date": "2013-03-23T00:01:47-07:00", "number": 6 }, { "name": "Ignatius Boyd", "date": "2014-09-04T08:16:36-07:00", "number": 5 }, { "name": "Gloria M. Morgan", "date": "2014-05-06T15:52:30-07:00", "number": 3 }, { "name": "Kyla G. Richards", "date": "2013-07-04T21:07:18-07:00", "number": 8 }, { "name": "Joshua Bennett", "date": "2013-03-17T19:55:44-07:00", "number": 10 }, { "name": "Risa R. Charles", "date": "2013-09-01T22:08:00-07:00", "number": 2 }, { "name": "Shellie F. Odom", "date": "2014-02-13T07:43:59-08:00", "number": 4 }, { "name": "Farrah W. Montoya", "date": "2014-08-06T10:07:27-07:00", "number": 5 }, { "name": "Britanney Chandler", "date": "2014-02-14T02:15:13-08:00", "number": 4 }, { "name": "Daria B. Banks", "date": "2013-09-06T11:42:25-07:00", "number": 3 }, { "name": "Hope G. Mccullough", "date": "2013-05-10T14:01:23-07:00", "number": 3 }, { "name": "Jescie Mcfarland", "date": "2013-06-05T20:34:39-07:00", "number": 9 }, { "name": "Octavius Dalton", "date": "2014-10-29T04:24:13-07:00", "number": 5 }, { "name": "Lilah Schmidt", "date": "2014-09-19T13:15:28-07:00", "number": 10 }, { "name": "Tatum Butler", "date": "2013-04-21T22:26:48-07:00", "number": 2 }, { "name": "Maxwell Jackson", "date": "2014-04-01T13:45:43-07:00", "number": 4 }, { "name": "Malachi Camacho", "date": "2014-09-07T05:43:21-07:00", "number": 3 }, { "name": "Dahlia Norman", "date": "2013-12-04T21:43:09-08:00", "number": 8 }, { "name": "Martha Q. Bradford", "date": "2012-12-29T10:54:34-08:00", "number": 8 }, { "name": "Adena Thompson", "date": "2013-07-31T04:00:42-07:00", "number": 9 }, { "name": "Daquan Burke", "date": "2013-03-10T18:19:30-07:00", "number": 3 }, { "name": "Avram Hodges", "date": "2013-04-19T06:25:26-07:00", "number": 2 }, { "name": "Lila G. Strong", "date": "2014-05-15T22:06:01-07:00", "number": 10 }, { "name": "Duncan M. Stout", "date": "2012-12-02T13:13:18-08:00", "number": 6 }, { "name": "Vera Glover", "date": "2013-05-29T20:39:03-07:00", "number": 1 }, { "name": "Norman I. Callahan", "date": "2014-02-18T04:25:02-08:00", "number": 5 }, { "name": "Mia Mcdaniel", "date": "2013-05-09T04:49:23-07:00", "number": 3 }, { "name": "Wing G. Lancaster", "date": "2013-11-29T21:36:19-08:00", "number": 4 }, { "name": "Norman Walter", "date": "2013-03-11T00:10:07-07:00", "number": 9 }, { "name": "Quinn Stephenson", "date": "2013-09-22T19:18:08-07:00", "number": 10 }, { "name": "Shana Q. Hunter", "date": "2013-06-23T00:02:12-07:00", "number": 9 }, { "name": "Amy Bender", "date": "2014-10-01T11:49:28-07:00", "number": 3 }, { "name": "Carla Q. Graham", "date": "2013-04-14T18:09:23-07:00", "number": 1 }, { "name": "Sasha P. Rosario", "date": "2013-02-19T06:21:57-08:00", "number": 7 }, { "name": "Shellie S. Shepard", "date": "2014-08-20T01:34:49-07:00", "number": 3 }, { "name": "Giacomo Burke", "date": "2013-10-21T18:58:22-07:00", "number": 2 }, { "name": "Jack P. Horton", "date": "2013-06-01T07:48:24-07:00", "number": 9 }, { "name": "Jelani H. Edwards", "date": "2013-11-14T09:46:34-08:00", "number": 1 }, { "name": "Tallulah Norman", "date": "2014-08-07T01:10:09-07:00", "number": 8 }, { "name": "Thor Blackburn", "date": "2013-02-10T08:25:08-08:00", "number": 7 }, { "name": "Lee Richard", "date": "2014-04-04T04:44:19-07:00", "number": 9 }, { "name": "Inga Mooney", "date": "2013-06-16T19:01:29-07:00", "number": 10 }, { "name": "Barrett L. Nicholson", "date": "2013-07-14T16:22:48-07:00", "number": 7 }, { "name": "Marsden Haley", "date": "2014-08-24T17:07:57-07:00", "number": 9 }, { "name": "Eugenia Jensen", "date": "2014-02-10T09:53:42-08:00", "number": 3 }, { "name": "Finn I. England", "date": "2014-05-21T11:29:45-07:00", "number": 10 }, { "name": "Christine H. Mccall", "date": "2013-07-31T22:39:23-07:00", "number": 3 }, { "name": "Olivia Sims", "date": "2014-03-22T21:39:53-07:00", "number": 10 }, { "name": "Leah Potter", "date": "2014-05-24T15:34:39-07:00", "number": 8 }, { "name": "Francesca Becker", "date": "2014-11-14T15:50:19-08:00", "number": 5 }, { "name": "Bell Guy", "date": "2014-09-24T06:11:26-07:00", "number": 5 }, { "name": "Brennan R. Camacho", "date": "2013-04-26T19:37:18-07:00", "number": 6 }, { "name": "Branden Hogan", "date": "2013-09-30T02:32:41-07:00", "number": 6 }, { "name": "Ray Greene", "date": "2014-02-25T09:35:15-08:00", "number": 3 }, { "name": "Lewis Patterson", "date": "2014-04-06T04:14:34-07:00", "number": 6 }, { "name": "Freya L. Barry", "date": "2014-10-24T18:49:14-07:00", "number": 2 }, { "name": "Branden Oneal", "date": "2014-02-06T17:10:09-08:00", "number": 10 }, { "name": "Dylan R. Hayes", "date": "2013-11-26T10:36:10-08:00", "number": 6 }, { "name": "Eliana W. Blair", "date": "2013-06-21T06:05:26-07:00", "number": 8 }, { "name": "Hector Goodwin", "date": "2014-01-01T11:40:54-08:00", "number": 1 }, { "name": "Chloe O. Joyner", "date": "2014-02-23T05:20:58-08:00", "number": 8 }, { "name": "Nasim Moore", "date": "2014-02-17T15:54:01-08:00", "number": 8 }, { "name": "Zena Davenport", "date": "2014-04-15T01:34:18-07:00", "number": 6 }, { "name": "Katelyn C. Mays", "date": "2012-12-18T14:18:15-08:00", "number": 7 }, { "name": "Ava H. Hartman", "date": "2014-01-29T14:51:07-08:00", "number": 9 }, { "name": "Rylee Mcfarland", "date": "2013-09-21T21:30:54-07:00", "number": 9 }, { "name": "Hanae K. Doyle", "date": "2014-06-19T09:57:19-07:00", "number": 8 }, { "name": "Quintessa H. Swanson", "date": "2014-02-26T22:16:01-08:00", "number": 5 }, { "name": "Dawn I. Hobbs", "date": "2014-11-01T20:03:31-07:00", "number": 9 }, { "name": "Louis Park", "date": "2014-03-21T23:24:03-07:00", "number": 10 }, { "name": "Jenna Richardson", "date": "2013-09-26T23:07:32-07:00", "number": 10 }, { "name": "Amy V. Aguirre", "date": "2013-12-04T12:50:21-08:00", "number": 9 } ] test/hand-crafted/000077500000000000000000000000001516074032300143565ustar00rootroot00000000000000test/hand-crafted/express-test.js000066400000000000000000000006601516074032300173640ustar00rootroot00000000000000const json2xls = require('../../src') const express = require('express') const app = express() const jsonArr = [ { foo: 'bar', qux: 'moo', poo: 123, stux: new Date() }, { foo: 'bar', qux: 'moo', poo: 345, stux: new Date() } ]; app.use(json2xls.middleware); app.get('/', function (req, res) { res.xls('data.xlsx', jsonArr); }); app.listen(3000) test/hand-crafted/xlsx.js000066400000000000000000000010021516074032300157030ustar00rootroot00000000000000const json2xls = require('../../src') const fs = require('fs').promises const jsonArr = [ { foo: 'bar', qux: 'moo', poo: 123, stux: new Date() }, { foo: 'bar', qux: 'moo', poo: 345, stux: new Date() } ]; const executeAsync = async() => { try { const data = json2xls.sync(jsonArr); await fs.writeFile(`${process.cwd()}/test.xls`, data, 'binary') } catch(e) { console.error(e) } } executeAsync() test/mocha/000077500000000000000000000000001516074032300131255ustar00rootroot00000000000000test/mocha/generate-xls.js000066400000000000000000000013451516074032300160640ustar00rootroot00000000000000const assert = require('assert'); const data = require('../fixtures/array-data') const json2xls = require('../../src') describe('generate-xls', () => { it('check binary', async () => { const xlsBinary = await json2xls(data) assert.ok(xlsBinary.slice(0, 2) === 'PK') }) it('check base64', async () => { const xlsBase64 = await json2xls(data, { output: 'base64' }) assert.ok(xlsBase64 === Buffer.from(xlsBase64, 'base64').toString('base64')) }) it('check base64 sync', () => { const xlsBase64 = json2xls.sync(data, { output: 'base64' }) assert.ok(xlsBase64 === Buffer.from(xlsBase64, 'base64').toString('base64')) }) })