From c1f5f041a4d4525fabfb7dbdb5f22c4f426147a1 Mon Sep 17 00:00:00 2001 From: Garrett Luu Date: Sat, 6 Nov 2021 20:34:06 -0400 Subject: [PATCH] xlsx-cli separate package [ci skip] --- bin/xlsx.njs | 15 +- package.json | 8 +- packages/xlsx-cli/.npmignore | 1 + packages/xlsx-cli/README.md | 20 +++ packages/xlsx-cli/bin/xlsx.njs | 7 + packages/xlsx-cli/index.js | 295 +++++++++++++++++++++++++++++++++ packages/xlsx-cli/package.json | 43 +++++ 7 files changed, 384 insertions(+), 5 deletions(-) create mode 100644 packages/xlsx-cli/.npmignore create mode 100644 packages/xlsx-cli/README.md create mode 100644 packages/xlsx-cli/bin/xlsx.njs create mode 100644 packages/xlsx-cli/index.js create mode 100644 packages/xlsx-cli/package.json diff --git a/bin/xlsx.njs b/bin/xlsx.njs index 7e4a676..8896705 100755 --- a/bin/xlsx.njs +++ b/bin/xlsx.njs @@ -6,7 +6,20 @@ var n = "xlsx"; var X = require('../'); try { X = require('../xlsx.flow'); } catch(e) {} require('exit-on-epipe'); -var fs = require('fs'), program = require('commander'); +var fs = require('fs'), program; +try { program = require('commander'); } catch(e) { + [ + "The `xlsx` command line tool is deprecated in favor of `xlsx-cli`.", + "", + "For new versions of node, we recommend using `npx`:", + " $ npx xlsx-cli --help", + "", + "For older versions of node, explicitly install `xlsx-cli` globally:", + " $ npm i -g xlsx-cli", + " $ xlsx-cli --help" + ].forEach(function(m) { console.error(m); }); + process.exit(1); +} program .version(X.version) .usage('[options] [sheetname]') diff --git a/package.json b/package.json index 80683e6..f738c57 100644 --- a/package.json +++ b/package.json @@ -35,10 +35,7 @@ "adler-32": "~1.2.0", "cfb": "^1.1.4", "codepage": "~1.15.0", - "commander": "~2.17.1", "crc-32": "~1.2.0", - "exit-on-epipe": "~1.0.1", - "fflate": "^0.7.1", "ssf": "~0.11.2", "wmf": "~1.0.1", "word": "~0.3.0" @@ -49,10 +46,13 @@ "acorn": "7.4.1", "alex": "^9.1.0", "blanket": "~1.2.3", + "commander": "~2.17.1", "dtslint": "^0.1.2", "eslint": "7.23.0", "eslint-plugin-html": "^6.1.2", "eslint-plugin-json": "^2.1.2", + "exit-on-epipe": "~1.0.1", + "fflate": "^0.7.1", "jsdom": "~11.1.0", "markdown-spellcheck": "^1.3.1", "mocha": "~2.5.3", @@ -90,7 +90,7 @@ }, "homepage": "https://sheetjs.com/", "bugs": { - "url": "https://github.com/SheetJS/js-xlsx/issues" + "url": "https://github.com/SheetJS/sheetjs/issues" }, "license": "Apache-2.0", "engines": { diff --git a/packages/xlsx-cli/.npmignore b/packages/xlsx-cli/.npmignore new file mode 100644 index 0000000..aa1ec1e --- /dev/null +++ b/packages/xlsx-cli/.npmignore @@ -0,0 +1 @@ +*.tgz diff --git a/packages/xlsx-cli/README.md b/packages/xlsx-cli/README.md new file mode 100644 index 0000000..81e6a7d --- /dev/null +++ b/packages/xlsx-cli/README.md @@ -0,0 +1,20 @@ +# xlsx-cli + +This is a standalone version of the CLI tool for [SheetJS](https://sheetjs.com). + +For newer versions of node, the tool should be invoked with `npx`: + +```bash +$ npx xlsx-cli --help # help and usage info +$ npx xlsx-cli --xlsx test.csv # generates test.csv.xlsx from test.csv +``` + +For older versions of node, the tool should be installed globally: + +```bash +$ sudo npm install -g xlsx-cli # install globally (once) + +$ xlsx-cli --help # help and usage info +$ npx xlsx-cli --xlsx test.csv # generates test.csv.xlsx from test.csv +``` + diff --git a/packages/xlsx-cli/bin/xlsx.njs b/packages/xlsx-cli/bin/xlsx.njs new file mode 100644 index 0000000..ae0d8e8 --- /dev/null +++ b/packages/xlsx-cli/bin/xlsx.njs @@ -0,0 +1,7 @@ +#!/usr/bin/env node +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* eslint-env node */ +/* vim: set ts=2 ft=javascript: */ +var cli = require('../'); + +cli(); diff --git a/packages/xlsx-cli/index.js b/packages/xlsx-cli/index.js new file mode 100644 index 0000000..fe8f058 --- /dev/null +++ b/packages/xlsx-cli/index.js @@ -0,0 +1,295 @@ +#!/usr/bin/env node +/* index.js (C) 2020-present SheetJS -- http://sheetjs.com */ +/* eslint-env node */ +/* vim: set ts=2 ft=javascript: */ + +var n = "xlsx-cli"; +var X = require('xlsx'); +require('exit-on-epipe'); +var fs = require('fs'), program = require('commander'); +function run() { + program + .version(X.version) + .usage('[options] [sheetname]') + .option('-f, --file ', 'use specified workbook') + .option('-s, --sheet ', 'print specified sheet (default first sheet)') + .option('-N, --sheet-index ', 'use specified sheet index (0-based)') + .option('-p, --password ', 'if file is encrypted, try with specified pw') + .option('-l, --list-sheets', 'list sheet names and exit') + .option('-o, --output ', 'output to specified file') + + .option('-B, --xlsb', 'emit XLSB to or .xlsb') + .option('-M, --xlsm', 'emit XLSM to or .xlsm') + .option('-X, --xlsx', 'emit XLSX to or .xlsx') + .option('-I, --xlam', 'emit XLAM to or .xlam') + .option('-Y, --ods', 'emit ODS to or .ods') + .option('-8, --xls', 'emit XLS to or .xls (BIFF8)') + .option('-5, --biff5', 'emit XLS to or .xls (BIFF5)') + //.option('-4, --biff4','emit XLS to or .xls (BIFF4)') + //.option('-3, --biff3','emit XLS to or .xls (BIFF3)') + .option('-2, --biff2', 'emit XLS to or .xls (BIFF2)') + .option('-i, --xla', 'emit XLA to or .xla') + .option('-6, --xlml', 'emit SSML to or .xls (2003 XML)') + .option('-T, --fods', 'emit FODS to or .fods (Flat ODS)') + + .option('-S, --formulae', 'emit list of values and formulae') + .option('-j, --json', 'emit formatted JSON (all fields text)') + .option('-J, --raw-js', 'emit raw JS object (raw numbers)') + .option('-A, --arrays', 'emit rows as JS objects (raw numbers)') + .option('-H, --html', 'emit HTML to or .html') + .option('-D, --dif', 'emit DIF to or .dif (Lotus DIF)') + .option('-U, --dbf', 'emit DBF to or .dbf (MSVFP DBF)') + .option('-K, --sylk', 'emit SYLK to or .slk (Excel SYLK)') + .option('-P, --prn', 'emit PRN to or .prn (Lotus PRN)') + .option('-E, --eth', 'emit ETH to or .eth (Ethercalc)') + .option('-t, --txt', 'emit TXT to or .txt (UTF-8 TSV)') + .option('-r, --rtf', 'emit RTF to or .txt (Table RTF)') + .option('-z, --dump', 'dump internal representation as JSON') + .option('--props', 'dump workbook properties as CSV') + + .option('-F, --field-sep ', 'CSV field separator', ",") + .option('-R, --row-sep ', 'CSV row separator', "\n") + .option('-n, --sheet-rows ', 'Number of rows to process (0=all rows)') + .option('--codepage ', 'default to specified codepage when ambiguous') + .option('--req ', 'require module before processing') + .option('--sst', 'generate shared string table for XLS* formats') + .option('--compress', 'use compression when writing XLSX/M/B and ODS') + .option('--read', 'read but do not generate output') + .option('--book', 'for single-sheet formats, emit a file per worksheet') + .option('--all', 'parse everything; write as much as possible') + .option('--dev', 'development mode') + .option('--sparse', 'sparse mode') + .option('-q, --quiet', 'quiet mode'); + + program.on('--help', function () { + console.log(' Default output format is CSV'); + console.log(' Support email: dev@sheetjs.com'); + console.log(' Web Demo: http://oss.sheetjs.com/js-' + n + '/'); + }); + + /* flag, bookType, default ext */ + var workbook_formats = [ + ['xlsx', 'xlsx', 'xlsx'], + ['xlsm', 'xlsm', 'xlsm'], + ['xlam', 'xlam', 'xlam'], + ['xlsb', 'xlsb', 'xlsb'], + ['xls', 'xls', 'xls'], + ['xla', 'xla', 'xla'], + ['biff5', 'biff5', 'xls'], + ['ods', 'ods', 'ods'], + ['fods', 'fods', 'fods'] + ]; + var wb_formats_2 = [ + ['xlml', 'xlml', 'xls'] + ]; + program.parse(process.argv); + + var filename = '', sheetname = ''; + if (program.args[0]) { + filename = program.args[0]; + if (program.args[1]) sheetname = program.args[1]; + } + if (program.sheet) sheetname = program.sheet; + if (program.file) filename = program.file; + + if (!filename) { + console.error(n + ": must specify a filename"); + process.exit(1); + } + if (!fs.existsSync(filename)) { + console.error(n + ": " + filename + ": No such file or directory"); + process.exit(2); + } + + if (program.req) program.req.split(",").forEach(function (r) { + require((fs.existsSync(r) || fs.existsSync(r + '.js')) ? require('path').resolve(r) : r); + }); + + var opts = {}, wb/*:?Workbook*/; + if (program.listSheets) opts.bookSheets = true; + if (program.sheetRows) opts.sheetRows = program.sheetRows; + if (program.password) opts.password = program.password; + var seen = false; + function wb_fmt() { + seen = true; + opts.cellFormula = true; + opts.cellNF = true; + if (program.output) sheetname = program.output; + } + function isfmt(m/*:string*/)/*:boolean*/ { + if (!program.output) return false; + var t = m.charAt(0) === "." ? m : "." + m; + return program.output.slice(-t.length) === t; + } + workbook_formats.forEach(function (m) { if (program[m[0]] || isfmt(m[0])) { wb_fmt(); } }); + wb_formats_2.forEach(function (m) { if (program[m[0]] || isfmt(m[0])) { wb_fmt(); } }); + if (seen) { + } else if (program.formulae) opts.cellFormula = true; + else opts.cellFormula = false; + + var wopts = ({ WTF: opts.WTF, bookSST: program.sst }/*:any*/); + if (program.compress) wopts.compression = true; + + if (program.all) { + opts.cellFormula = true; + opts.bookVBA = true; + opts.cellNF = true; + opts.cellHTML = true; + opts.cellStyles = true; + opts.sheetStubs = true; + opts.cellDates = true; + wopts.cellStyles = true; + wopts.sheetStubs = true; + wopts.bookVBA = true; + } + if (program.sparse) opts.dense = false; else opts.dense = true; + if (program.codepage) opts.codepage = +program.codepage; + + if (program.dev) { + opts.WTF = true; + wb = X.readFile(filename, opts); + } else try { + wb = X.readFile(filename, opts); + } catch (e) { + var msg = (program.quiet) ? "" : n + ": error parsing "; + msg += filename + ": " + e; + console.error(msg); + process.exit(3); + } + if (program.read) process.exit(0); + if (!wb) { console.error(n + ": error parsing " + filename + ": empty workbook"); process.exit(0); } + /*:: if(!wb) throw new Error("unreachable"); */ + if (program.listSheets) { + console.log((wb.SheetNames || []).join("\n")); + process.exit(0); + } + if (program.dump) { + console.log(JSON.stringify(wb)); + process.exit(0); + } + if (program.props) { + if (wb) dump_props(wb); + process.exit(0); + } + + /* full workbook formats */ + workbook_formats.forEach(function (m) { + if (program[m[0]] || isfmt(m[0])) { + wopts.bookType = m[1]; + if (wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts); + process.exit(0); + } + }); + + wb_formats_2.forEach(function (m) { + if (program[m[0]] || isfmt(m[0])) { + wopts.bookType = m[1]; + if (wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts); + process.exit(0); + } + }); + + var target_sheet = sheetname || ''; + if (target_sheet === '') { + if (+program.sheetIndex < (wb.SheetNames || []).length) target_sheet = wb.SheetNames[+program.sheetIndex]; + else target_sheet = (wb.SheetNames || [""])[0]; + } + + var ws; + try { + ws = wb.Sheets[target_sheet]; + if (!ws) { + console.error("Sheet " + target_sheet + " cannot be found"); + process.exit(3); + } + } catch (e) { + console.error(n + ": error parsing " + filename + " " + target_sheet + ": " + e); + process.exit(4); + } + + if (!program.quiet && !program.book) console.error(target_sheet); + + /* single worksheet file formats */ + [ + ['biff2', '.xls'], + ['biff3', '.xls'], + ['biff4', '.xls'], + ['sylk', '.slk'], + ['html', '.html'], + ['prn', '.prn'], + ['eth', '.eth'], + ['rtf', '.rtf'], + ['txt', '.txt'], + ['dbf', '.dbf'], + ['dif', '.dif'] + ].forEach(function (m) { + if (program[m[0]] || isfmt(m[1])) { + wopts.bookType = m[0]; + if (program.book) { + /*:: if(wb == null) throw new Error("Unreachable"); */ + wb.SheetNames.forEach(function (n, i) { + wopts.sheet = n; + X.writeFile(wb, (program.output || sheetname || filename || "") + m[1] + "." + i, wopts); + }); + } else X.writeFile(wb, program.output || sheetname || ((filename || "") + m[1]), wopts); + process.exit(0); + } + }); + + function outit(o, fn) { if (fn) fs.writeFileSync(fn, o); else console.log(o); } + + function doit(cb) { + /*:: if(!wb) throw new Error("unreachable"); */ + if (program.book) wb.SheetNames.forEach(function (n, i) { + /*:: if(!wb) throw new Error("unreachable"); */ + outit(cb(wb.Sheets[n]), (program.output || sheetname || filename) + "." + i); + }); + else outit(cb(ws), program.output); + } + + var jso = {}; + switch (true) { + case program.formulae: + doit(function (ws) { return X.utils.sheet_to_formulae(ws).join("\n"); }); + break; + + case program.arrays: jso.header = 1; + /* falls through */ + case program.rawJs: jso.raw = true; + /* falls through */ + case program.json: + doit(function (ws) { return JSON.stringify(X.utils.sheet_to_json(ws, jso)); }); + break; + + default: + if (!program.book) { + var stream = X.stream.to_csv(ws, { FS: program.fieldSep, RS: program.rowSep }); + if (program.output) stream.pipe(fs.createWriteStream(program.output)); + else stream.pipe(process.stdout); + } else doit(function (ws) { return X.utils.sheet_to_csv(ws, { FS: program.fieldSep, RS: program.rowSep }); }); + break; + } + + function dump_props(wb/*:Workbook*/) { + var propaoa = []; + if (Object.assign && Object.entries) propaoa = Object.entries(Object.assign({}, wb.Props, wb.Custprops)); + else { + var Keys/*:: :Array = []*/, pi; + if (wb.Props) { + Keys = Object.keys(wb.Props); + for (pi = 0; pi < Keys.length; ++pi) { + if (Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]); + } + } + if (wb.Custprops) { + Keys = Object.keys(wb.Custprops); + for (pi = 0; pi < Keys.length; ++pi) { + if (Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]); + } + } + } + console.log(X.utils.sheet_to_csv(X.utils.aoa_to_sheet(propaoa))); + } +} + +module.exports = run; diff --git a/packages/xlsx-cli/package.json b/packages/xlsx-cli/package.json new file mode 100644 index 0000000..cba3e61 --- /dev/null +++ b/packages/xlsx-cli/package.json @@ -0,0 +1,43 @@ +{ + "name": "xlsx-cli", + "version": "1.1.1", + "author": "sheetjs", + "description": "Command-line interface for SheetJS", + "keywords": [ + "excel", + "xls", + "xlsx", + "xlsb", + "xlsm", + "ods", + "csv", + "dbf", + "dif", + "sylk", + "office", + "spreadsheet" + ], + "bin": { + "xlsx-cli": "./bin/xlsx.njs" + }, + "main": "index.js", + "dependencies": { + "commander": "~2.17.1", + "exit-on-epipe": "~1.0.1", + "xlsx": "latest" + }, + "devDependencies": { + }, + "repository": { + "type": "git", + "url": "git://github.com/SheetJS/sheetjs.git" + }, + "homepage": "https://sheetjs.com/", + "bugs": { + "url": "https://github.com/SheetJS/sheetjs/issues" + }, + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } +}