@justybase/spreadsheet-tasks 2.1.0 → 2.1.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/CHANGELOG.md +12 -0
- package/README.md +26 -0
- package/dist/cjs/index.d.ts +11 -1
- package/dist/cjs/index.js +282 -34
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +280 -34
- package/dist/esm/index.js.map +1 -1
- package/docs/API.md +51 -0
- package/package.json +3 -2
package/dist/esm/index.js
CHANGED
|
@@ -402,8 +402,8 @@ var XlsbReader = class extends ExcelReaderAbstract {
|
|
|
402
402
|
this.xfIdToNumFmtId = [];
|
|
403
403
|
this.customDateFormats = null;
|
|
404
404
|
}
|
|
405
|
-
async open(
|
|
406
|
-
this.zip = new AdmZip(
|
|
405
|
+
async open(path3, readSharedStrings = true) {
|
|
406
|
+
this.zip = new AdmZip(path3);
|
|
407
407
|
const wbEntry = this.zip.getEntry("xl/workbook.bin");
|
|
408
408
|
if (wbEntry) {
|
|
409
409
|
const buf = wbEntry.getData();
|
|
@@ -448,8 +448,8 @@ var XlsbReader = class extends ExcelReaderAbstract {
|
|
|
448
448
|
this.resultsCount = this.sheets.length;
|
|
449
449
|
this._currentSheetIndex = -1;
|
|
450
450
|
}
|
|
451
|
-
_readSharedStrings(
|
|
452
|
-
const entry = this.zip.getEntry(
|
|
451
|
+
_readSharedStrings(path3) {
|
|
452
|
+
const entry = this.zip.getEntry(path3);
|
|
453
453
|
if (!entry) return;
|
|
454
454
|
const reader = new BiffReaderWriter(entry.getData());
|
|
455
455
|
while (reader.readSharedStrings()) {
|
|
@@ -458,8 +458,8 @@ var XlsbReader = class extends ExcelReaderAbstract {
|
|
|
458
458
|
}
|
|
459
459
|
}
|
|
460
460
|
}
|
|
461
|
-
_readStyles(
|
|
462
|
-
const entry = this.zip.getEntry(
|
|
461
|
+
_readStyles(path3) {
|
|
462
|
+
const entry = this.zip.getEntry(path3);
|
|
463
463
|
if (!entry) return;
|
|
464
464
|
const reader = new BiffReaderWriter(entry.getData());
|
|
465
465
|
while (reader.readStyles()) {
|
|
@@ -651,9 +651,9 @@ var XlsxReader = class extends ExcelReaderAbstract {
|
|
|
651
651
|
this.xfIdToNumFmtId = [];
|
|
652
652
|
this.customDateFormats = /* @__PURE__ */ new Set();
|
|
653
653
|
}
|
|
654
|
-
async open(
|
|
655
|
-
return new Promise((
|
|
656
|
-
yauzl.open(
|
|
654
|
+
async open(path3, readSharedStrings = true) {
|
|
655
|
+
return new Promise((resolve2, reject) => {
|
|
656
|
+
yauzl.open(path3, { lazyEntries: true, autoClose: false }, async (err, zipfile) => {
|
|
657
657
|
if (err) return reject(err);
|
|
658
658
|
this.zipfile = zipfile;
|
|
659
659
|
this.entries = /* @__PURE__ */ new Map();
|
|
@@ -701,7 +701,7 @@ var XlsxReader = class extends ExcelReaderAbstract {
|
|
|
701
701
|
}
|
|
702
702
|
this.resultsCount = this.sheets.length;
|
|
703
703
|
this._currentSheetIndex = -1;
|
|
704
|
-
|
|
704
|
+
resolve2();
|
|
705
705
|
} catch (e) {
|
|
706
706
|
reject(e);
|
|
707
707
|
}
|
|
@@ -715,16 +715,16 @@ var XlsxReader = class extends ExcelReaderAbstract {
|
|
|
715
715
|
this.zipfile.close();
|
|
716
716
|
}
|
|
717
717
|
}
|
|
718
|
-
async _readZipEntryContent(
|
|
719
|
-
const entry = this.entries.get(
|
|
718
|
+
async _readZipEntryContent(path3) {
|
|
719
|
+
const entry = this.entries.get(path3);
|
|
720
720
|
if (!entry) return null;
|
|
721
|
-
return new Promise((
|
|
721
|
+
return new Promise((resolve2, reject) => {
|
|
722
722
|
this.zipfile.openReadStream(entry, (err, readStream) => {
|
|
723
723
|
if (err) return reject(err);
|
|
724
724
|
const chunks = [];
|
|
725
725
|
readStream.on("data", (chunk) => chunks.push(chunk));
|
|
726
726
|
readStream.on("end", () => {
|
|
727
|
-
|
|
727
|
+
resolve2(Buffer.concat(chunks).toString("utf8"));
|
|
728
728
|
});
|
|
729
729
|
readStream.on("error", reject);
|
|
730
730
|
});
|
|
@@ -3330,7 +3330,7 @@ var XlsbWriter = class _XlsbWriter {
|
|
|
3330
3330
|
* Must be awaited before the file is fully written.
|
|
3331
3331
|
*/
|
|
3332
3332
|
finalize() {
|
|
3333
|
-
return new Promise((
|
|
3333
|
+
return new Promise((resolve2, reject) => {
|
|
3334
3334
|
try {
|
|
3335
3335
|
this.saveSst();
|
|
3336
3336
|
this.archive.append(this._buildStylesBin(), { name: "xl/styles.bin" });
|
|
@@ -3428,7 +3428,7 @@ var XlsbWriter = class _XlsbWriter {
|
|
|
3428
3428
|
</Relationships>`;
|
|
3429
3429
|
this.archive.append(wsRels, { name: `xl/worksheets/_rels/${sheet.nameInArchive}.rels` });
|
|
3430
3430
|
}
|
|
3431
|
-
this.output.on("close", () =>
|
|
3431
|
+
this.output.on("close", () => resolve2());
|
|
3432
3432
|
this.archive.on("error", (err) => reject(err));
|
|
3433
3433
|
this.archive.finalize();
|
|
3434
3434
|
} catch (err) {
|
|
@@ -3776,7 +3776,7 @@ var XlsxWriter = class {
|
|
|
3776
3776
|
}
|
|
3777
3777
|
/** Finalize the ZIP package and close the output stream. */
|
|
3778
3778
|
finalize() {
|
|
3779
|
-
return new Promise((
|
|
3779
|
+
return new Promise((resolve2, reject) => {
|
|
3780
3780
|
try {
|
|
3781
3781
|
this._writeSharedStrings();
|
|
3782
3782
|
this._writeStyles();
|
|
@@ -3784,7 +3784,7 @@ var XlsxWriter = class {
|
|
|
3784
3784
|
this._writeContentTypes();
|
|
3785
3785
|
this._writeRels();
|
|
3786
3786
|
this.output.on("close", () => {
|
|
3787
|
-
|
|
3787
|
+
resolve2();
|
|
3788
3788
|
});
|
|
3789
3789
|
this.archive.on("error", (err) => {
|
|
3790
3790
|
reject(err);
|
|
@@ -3927,7 +3927,7 @@ var XlsxUpdater = class {
|
|
|
3927
3927
|
/**
|
|
3928
3928
|
* @param path Path to an existing `.xlsx` file.
|
|
3929
3929
|
*/
|
|
3930
|
-
constructor(
|
|
3930
|
+
constructor(path3) {
|
|
3931
3931
|
this.sheetNameToPath = /* @__PURE__ */ new Map();
|
|
3932
3932
|
this.pivotCacheDefs = [];
|
|
3933
3933
|
this.pivotTableDefPaths = [];
|
|
@@ -3936,12 +3936,12 @@ var XlsxUpdater = class {
|
|
|
3936
3936
|
this.sharedStringsOriginalLength = 0;
|
|
3937
3937
|
this.sharedStringsCount = 0;
|
|
3938
3938
|
this.stringIndexMap = /* @__PURE__ */ new Map();
|
|
3939
|
-
this.sourcePath =
|
|
3939
|
+
this.sourcePath = path3;
|
|
3940
3940
|
this._oaEpoch = Date.UTC(1899, 11, 30);
|
|
3941
|
-
if (!fs3.existsSync(
|
|
3942
|
-
throw new Error(`XlsxUpdater: file not found: ${
|
|
3941
|
+
if (!fs3.existsSync(path3)) {
|
|
3942
|
+
throw new Error(`XlsxUpdater: file not found: ${path3}`);
|
|
3943
3943
|
}
|
|
3944
|
-
this.zip = new AdmZip2(
|
|
3944
|
+
this.zip = new AdmZip2(path3);
|
|
3945
3945
|
if (this.zip.getEntry("xl/workbook.bin")) {
|
|
3946
3946
|
throw new Error(
|
|
3947
3947
|
"XlsxUpdater: XLSB files are not supported yet. Convert the workbook to XLSX first."
|
|
@@ -4326,8 +4326,8 @@ var XlsxUpdater = class {
|
|
|
4326
4326
|
}
|
|
4327
4327
|
}
|
|
4328
4328
|
_addRefreshOnLoadToPivotTables() {
|
|
4329
|
-
for (const
|
|
4330
|
-
const entry = this.zip.getEntry(
|
|
4329
|
+
for (const path3 of this.pivotTableDefPaths) {
|
|
4330
|
+
const entry = this.zip.getEntry(path3);
|
|
4331
4331
|
if (!entry) continue;
|
|
4332
4332
|
let xml = entry.getData().toString("utf8");
|
|
4333
4333
|
const rootRe = /<pivotTableDefinition\b[^>]*>/;
|
|
@@ -4335,7 +4335,7 @@ var XlsxUpdater = class {
|
|
|
4335
4335
|
if (!rootMatch || rootMatch[0].includes("refreshOnLoad")) continue;
|
|
4336
4336
|
const newTag = rootMatch[0].replace(/(\/?>)$/, ' refreshOnLoad="1"$1');
|
|
4337
4337
|
xml = xml.substring(0, rootMatch.index) + newTag + xml.substring(rootMatch.index + rootMatch[0].length);
|
|
4338
|
-
this.zip.updateFile(
|
|
4338
|
+
this.zip.updateFile(path3, Buffer.from(xml, "utf8"));
|
|
4339
4339
|
}
|
|
4340
4340
|
}
|
|
4341
4341
|
};
|
|
@@ -4420,7 +4420,7 @@ var XlsbUpdater = class {
|
|
|
4420
4420
|
/**
|
|
4421
4421
|
* @param path Path to an existing `.xlsb` file.
|
|
4422
4422
|
*/
|
|
4423
|
-
constructor(
|
|
4423
|
+
constructor(path3) {
|
|
4424
4424
|
this.sheetNameToPath = /* @__PURE__ */ new Map();
|
|
4425
4425
|
this.pivotCacheDefPaths = [];
|
|
4426
4426
|
this.sharedStringsBuf = null;
|
|
@@ -4433,12 +4433,12 @@ var XlsbUpdater = class {
|
|
|
4433
4433
|
// Shared strings
|
|
4434
4434
|
// ------------------------------------------------------------------
|
|
4435
4435
|
this._appendCount = 0;
|
|
4436
|
-
this.sourcePath =
|
|
4436
|
+
this.sourcePath = path3;
|
|
4437
4437
|
this._oaEpoch = Date.UTC(1899, 11, 30);
|
|
4438
|
-
if (!fs4.existsSync(
|
|
4439
|
-
throw new Error(`XlsbUpdater: file not found: ${
|
|
4438
|
+
if (!fs4.existsSync(path3)) {
|
|
4439
|
+
throw new Error(`XlsbUpdater: file not found: ${path3}`);
|
|
4440
4440
|
}
|
|
4441
|
-
this.zip = new AdmZip3(
|
|
4441
|
+
this.zip = new AdmZip3(path3);
|
|
4442
4442
|
if (!this.zip.getEntry("xl/workbook.bin")) {
|
|
4443
4443
|
throw new Error(
|
|
4444
4444
|
"XlsbUpdater: not an XLSB workbook (xl/workbook.bin missing). Convert the file to XLSB first."
|
|
@@ -4850,8 +4850,8 @@ var XlsbUpdater = class {
|
|
|
4850
4850
|
// Pivot cache integration
|
|
4851
4851
|
// ------------------------------------------------------------------
|
|
4852
4852
|
_patchPivotCaches(sheetName, rwLast, colLast) {
|
|
4853
|
-
for (const
|
|
4854
|
-
const entry = this.zip.getEntry(
|
|
4853
|
+
for (const path3 of this.pivotCacheDefPaths) {
|
|
4854
|
+
const entry = this.zip.getEntry(path3);
|
|
4855
4855
|
if (!entry) continue;
|
|
4856
4856
|
const buf = Buffer.from(entry.getData());
|
|
4857
4857
|
const rec = { headerStart: 0, dataStart: 0, dataEnd: 0, id: 0, len: 0 };
|
|
@@ -4883,11 +4883,255 @@ var XlsbUpdater = class {
|
|
|
4883
4883
|
}
|
|
4884
4884
|
}
|
|
4885
4885
|
if (patched) {
|
|
4886
|
-
this.zip.updateFile(
|
|
4886
|
+
this.zip.updateFile(path3, buf);
|
|
4887
4887
|
}
|
|
4888
4888
|
}
|
|
4889
4889
|
}
|
|
4890
4890
|
};
|
|
4891
|
+
|
|
4892
|
+
// src/ExcelConverter.ts
|
|
4893
|
+
import * as fs6 from "fs";
|
|
4894
|
+
import * as path2 from "path";
|
|
4895
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
4896
|
+
import { spawn } from "child_process";
|
|
4897
|
+
|
|
4898
|
+
// src/atomicFile.ts
|
|
4899
|
+
import * as fs5 from "fs";
|
|
4900
|
+
import { randomUUID } from "crypto";
|
|
4901
|
+
var realFileOperations = {
|
|
4902
|
+
exists: (filePath) => fs5.existsSync(filePath),
|
|
4903
|
+
rename: (sourcePath, destinationPath) => fs5.renameSync(sourcePath, destinationPath),
|
|
4904
|
+
remove: (filePath) => fs5.rmSync(filePath)
|
|
4905
|
+
};
|
|
4906
|
+
function errorMessage(error) {
|
|
4907
|
+
return error instanceof Error ? error.message : String(error);
|
|
4908
|
+
}
|
|
4909
|
+
function destinationExistsError(destinationPath) {
|
|
4910
|
+
return new Error(
|
|
4911
|
+
`Excel conversion: destination already exists (pass { overwrite: true } to replace it): ${destinationPath}`
|
|
4912
|
+
);
|
|
4913
|
+
}
|
|
4914
|
+
function installTemporaryOutput(temporaryPath, destinationPath, overwrite, operations = realFileOperations) {
|
|
4915
|
+
const backupPath = `${destinationPath}.${randomUUID()}.replacement-backup`;
|
|
4916
|
+
let backupCreated = false;
|
|
4917
|
+
let installed = false;
|
|
4918
|
+
if (operations.exists(destinationPath)) {
|
|
4919
|
+
if (!overwrite) {
|
|
4920
|
+
throw destinationExistsError(destinationPath);
|
|
4921
|
+
}
|
|
4922
|
+
operations.rename(destinationPath, backupPath);
|
|
4923
|
+
backupCreated = true;
|
|
4924
|
+
}
|
|
4925
|
+
try {
|
|
4926
|
+
try {
|
|
4927
|
+
operations.rename(temporaryPath, destinationPath);
|
|
4928
|
+
installed = true;
|
|
4929
|
+
} catch (error) {
|
|
4930
|
+
if (overwrite && !backupCreated && operations.exists(destinationPath)) {
|
|
4931
|
+
operations.rename(destinationPath, backupPath);
|
|
4932
|
+
backupCreated = true;
|
|
4933
|
+
operations.rename(temporaryPath, destinationPath);
|
|
4934
|
+
installed = true;
|
|
4935
|
+
} else {
|
|
4936
|
+
throw error;
|
|
4937
|
+
}
|
|
4938
|
+
}
|
|
4939
|
+
if (backupCreated) {
|
|
4940
|
+
operations.remove(backupPath);
|
|
4941
|
+
}
|
|
4942
|
+
} catch (error) {
|
|
4943
|
+
if (backupCreated && !installed) {
|
|
4944
|
+
if (!operations.exists(destinationPath)) {
|
|
4945
|
+
try {
|
|
4946
|
+
operations.rename(backupPath, destinationPath);
|
|
4947
|
+
backupCreated = false;
|
|
4948
|
+
} catch (rollbackError) {
|
|
4949
|
+
throw new Error(
|
|
4950
|
+
`Excel conversion: final destination install failed (${errorMessage(error)}), and restoring the original destination also failed (${errorMessage(rollbackError)}). Original file remains at ${backupPath}.`
|
|
4951
|
+
);
|
|
4952
|
+
}
|
|
4953
|
+
} else {
|
|
4954
|
+
throw new Error(
|
|
4955
|
+
`Excel conversion: final destination install failed (${errorMessage(error)}). A concurrent destination was preserved; the original file remains at ${backupPath}.`
|
|
4956
|
+
);
|
|
4957
|
+
}
|
|
4958
|
+
}
|
|
4959
|
+
throw error;
|
|
4960
|
+
}
|
|
4961
|
+
}
|
|
4962
|
+
|
|
4963
|
+
// src/ExcelConverter.ts
|
|
4964
|
+
var POWERSHELL_CONVERSION_SCRIPT = `
|
|
4965
|
+
$ErrorActionPreference = 'Stop'
|
|
4966
|
+
$inputPath = [Environment]::GetEnvironmentVariable('JUSTYBASE_EXCEL_INPUT')
|
|
4967
|
+
$outputPath = [Environment]::GetEnvironmentVariable('JUSTYBASE_EXCEL_OUTPUT')
|
|
4968
|
+
$fileFormat = [int][Environment]::GetEnvironmentVariable('JUSTYBASE_EXCEL_FORMAT')
|
|
4969
|
+
$excel = $null
|
|
4970
|
+
$workbook = $null
|
|
4971
|
+
$exitCode = 0
|
|
4972
|
+
|
|
4973
|
+
try {
|
|
4974
|
+
$excel = New-Object -ComObject Excel.Application
|
|
4975
|
+
$excel.Visible = $false
|
|
4976
|
+
$excel.DisplayAlerts = $false
|
|
4977
|
+
$excel.ScreenUpdating = $false
|
|
4978
|
+
|
|
4979
|
+
# Open read-only so the source workbook is never changed by the conversion.
|
|
4980
|
+
$workbook = $excel.Workbooks.Open($inputPath, 0, $true)
|
|
4981
|
+
if ($null -eq $workbook) {
|
|
4982
|
+
throw 'Excel did not return a workbook when opening the source file.'
|
|
4983
|
+
}
|
|
4984
|
+
|
|
4985
|
+
$workbook.SaveAs($outputPath, $fileFormat)
|
|
4986
|
+
} catch {
|
|
4987
|
+
$exitCode = 1
|
|
4988
|
+
[Console]::Error.WriteLine($_.Exception.ToString())
|
|
4989
|
+
} finally {
|
|
4990
|
+
if ($null -ne $workbook) {
|
|
4991
|
+
try { $workbook.Close($false) } catch { }
|
|
4992
|
+
try { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($workbook) | Out-Null } catch { }
|
|
4993
|
+
}
|
|
4994
|
+
if ($null -ne $excel) {
|
|
4995
|
+
try { $excel.Quit() } catch { }
|
|
4996
|
+
try { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel) | Out-Null } catch { }
|
|
4997
|
+
}
|
|
4998
|
+
[GC]::Collect()
|
|
4999
|
+
[GC]::WaitForPendingFinalizers()
|
|
5000
|
+
}
|
|
5001
|
+
|
|
5002
|
+
exit $exitCode
|
|
5003
|
+
`;
|
|
5004
|
+
function errorMessage2(error) {
|
|
5005
|
+
return error instanceof Error ? error.message : String(error);
|
|
5006
|
+
}
|
|
5007
|
+
function validateConversionPaths(inputPath, outputPath, inputExtension, outputExtension, overwrite) {
|
|
5008
|
+
const input = path2.resolve(inputPath);
|
|
5009
|
+
const output = path2.resolve(outputPath);
|
|
5010
|
+
if (path2.extname(input).toLowerCase() !== inputExtension) {
|
|
5011
|
+
throw new Error(
|
|
5012
|
+
`Excel conversion: source must have the ${inputExtension} extension: ${inputPath}`
|
|
5013
|
+
);
|
|
5014
|
+
}
|
|
5015
|
+
if (path2.extname(output).toLowerCase() !== outputExtension) {
|
|
5016
|
+
throw new Error(
|
|
5017
|
+
`Excel conversion: destination must have the ${outputExtension} extension: ${outputPath}`
|
|
5018
|
+
);
|
|
5019
|
+
}
|
|
5020
|
+
if (!fs6.existsSync(input)) {
|
|
5021
|
+
throw new Error(`Excel conversion: source file not found: ${inputPath}`);
|
|
5022
|
+
}
|
|
5023
|
+
if (!fs6.statSync(input).isFile()) {
|
|
5024
|
+
throw new Error(`Excel conversion: source path is not a file: ${inputPath}`);
|
|
5025
|
+
}
|
|
5026
|
+
if (!fs6.existsSync(path2.dirname(output))) {
|
|
5027
|
+
throw new Error(`Excel conversion: destination directory not found: ${path2.dirname(output)}`);
|
|
5028
|
+
}
|
|
5029
|
+
if (fs6.existsSync(output)) {
|
|
5030
|
+
if (fs6.statSync(output).isDirectory()) {
|
|
5031
|
+
throw new Error(`Excel conversion: destination path is a directory: ${outputPath}`);
|
|
5032
|
+
}
|
|
5033
|
+
if (!overwrite) {
|
|
5034
|
+
throw new Error(
|
|
5035
|
+
`Excel conversion: destination already exists (pass { overwrite: true } to replace it): ${outputPath}`
|
|
5036
|
+
);
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
5039
|
+
if (process.platform === "win32" && input.toLowerCase() === output.toLowerCase()) {
|
|
5040
|
+
throw new Error("Excel conversion: source and destination must be different files.");
|
|
5041
|
+
}
|
|
5042
|
+
return { input, output };
|
|
5043
|
+
}
|
|
5044
|
+
function runPowerShellConversion(inputPath, outputPath, fileFormat) {
|
|
5045
|
+
const encodedCommand = Buffer.from(POWERSHELL_CONVERSION_SCRIPT, "utf16le").toString("base64");
|
|
5046
|
+
const environment = {
|
|
5047
|
+
...process.env,
|
|
5048
|
+
JUSTYBASE_EXCEL_INPUT: inputPath,
|
|
5049
|
+
JUSTYBASE_EXCEL_OUTPUT: outputPath,
|
|
5050
|
+
JUSTYBASE_EXCEL_FORMAT: String(fileFormat)
|
|
5051
|
+
};
|
|
5052
|
+
return new Promise((resolve2, reject) => {
|
|
5053
|
+
var _a, _b, _c, _d;
|
|
5054
|
+
let stdout = "";
|
|
5055
|
+
let stderr = "";
|
|
5056
|
+
let settled = false;
|
|
5057
|
+
const child = spawn(
|
|
5058
|
+
"powershell.exe",
|
|
5059
|
+
[
|
|
5060
|
+
"-NoLogo",
|
|
5061
|
+
"-NoProfile",
|
|
5062
|
+
"-NonInteractive",
|
|
5063
|
+
"-ExecutionPolicy",
|
|
5064
|
+
"Bypass",
|
|
5065
|
+
"-EncodedCommand",
|
|
5066
|
+
encodedCommand
|
|
5067
|
+
],
|
|
5068
|
+
{ env: environment, windowsHide: true }
|
|
5069
|
+
);
|
|
5070
|
+
(_a = child.stdout) == null ? void 0 : _a.setEncoding("utf8");
|
|
5071
|
+
(_b = child.stderr) == null ? void 0 : _b.setEncoding("utf8");
|
|
5072
|
+
(_c = child.stdout) == null ? void 0 : _c.on("data", (chunk) => {
|
|
5073
|
+
stdout += chunk;
|
|
5074
|
+
});
|
|
5075
|
+
(_d = child.stderr) == null ? void 0 : _d.on("data", (chunk) => {
|
|
5076
|
+
stderr += chunk;
|
|
5077
|
+
});
|
|
5078
|
+
child.once("error", (error) => {
|
|
5079
|
+
if (settled) return;
|
|
5080
|
+
settled = true;
|
|
5081
|
+
reject(new Error(`Excel conversion: unable to start PowerShell/COM: ${error.message}`));
|
|
5082
|
+
});
|
|
5083
|
+
child.once("close", (code) => {
|
|
5084
|
+
if (settled) return;
|
|
5085
|
+
settled = true;
|
|
5086
|
+
if (code === 0) {
|
|
5087
|
+
resolve2();
|
|
5088
|
+
return;
|
|
5089
|
+
}
|
|
5090
|
+
const details = (stderr || stdout).replace(/\s+/g, " ").trim();
|
|
5091
|
+
reject(new Error(
|
|
5092
|
+
`Excel conversion failed (PowerShell exit code ${code ?? "unknown"})${details ? `: ${details}` : "."}`
|
|
5093
|
+
));
|
|
5094
|
+
});
|
|
5095
|
+
});
|
|
5096
|
+
}
|
|
5097
|
+
async function convertExcelFile(inputPath, outputPath, inputExtension, outputExtension, fileFormat, options = {}) {
|
|
5098
|
+
const { input, output } = validateConversionPaths(
|
|
5099
|
+
inputPath,
|
|
5100
|
+
outputPath,
|
|
5101
|
+
inputExtension,
|
|
5102
|
+
outputExtension,
|
|
5103
|
+
options.overwrite === true
|
|
5104
|
+
);
|
|
5105
|
+
if (process.platform !== "win32") {
|
|
5106
|
+
throw new Error("Excel conversion requires Windows with desktop Microsoft Excel and COM automation.");
|
|
5107
|
+
}
|
|
5108
|
+
const temporaryOutput = path2.join(
|
|
5109
|
+
path2.dirname(output),
|
|
5110
|
+
`.${path2.basename(output, outputExtension)}.${randomUUID2()}.conversion${outputExtension}`
|
|
5111
|
+
);
|
|
5112
|
+
try {
|
|
5113
|
+
await runPowerShellConversion(input, temporaryOutput, fileFormat);
|
|
5114
|
+
if (!fs6.existsSync(temporaryOutput)) {
|
|
5115
|
+
throw new Error("Excel conversion completed without creating the destination file.");
|
|
5116
|
+
}
|
|
5117
|
+
installTemporaryOutput(temporaryOutput, output, options.overwrite === true);
|
|
5118
|
+
} catch (error) {
|
|
5119
|
+
throw new Error(`Excel conversion ${inputExtension} -> ${outputExtension}: ${errorMessage2(error)}`);
|
|
5120
|
+
} finally {
|
|
5121
|
+
if (fs6.existsSync(temporaryOutput)) {
|
|
5122
|
+
try {
|
|
5123
|
+
fs6.rmSync(temporaryOutput);
|
|
5124
|
+
} catch {
|
|
5125
|
+
}
|
|
5126
|
+
}
|
|
5127
|
+
}
|
|
5128
|
+
}
|
|
5129
|
+
function convertXlsbToXlsx(inputPath, outputPath, options) {
|
|
5130
|
+
return convertExcelFile(inputPath, outputPath, ".xlsb", ".xlsx", 51, options);
|
|
5131
|
+
}
|
|
5132
|
+
function convertXlsxToXlsb(inputPath, outputPath, options) {
|
|
5133
|
+
return convertExcelFile(inputPath, outputPath, ".xlsx", ".xlsb", 50, options);
|
|
5134
|
+
}
|
|
4891
5135
|
export {
|
|
4892
5136
|
BiffReaderWriter,
|
|
4893
5137
|
BigBuffer,
|
|
@@ -4903,6 +5147,8 @@ export {
|
|
|
4903
5147
|
XlsxUpdater,
|
|
4904
5148
|
XlsxWriter,
|
|
4905
5149
|
applyHeaderWidths,
|
|
5150
|
+
convertXlsbToXlsx,
|
|
5151
|
+
convertXlsxToXlsb,
|
|
4906
5152
|
defaultColWidth,
|
|
4907
5153
|
getFormat,
|
|
4908
5154
|
initColWidths,
|