Supply an existing XLSX file and a new output path:
Terminal window
npxtsxroundtrip.mtsinput.xlsxoutput.xlsx
Server ownership and errors
These workbook codec functions operate on a WorkbookSnapshot. They do not create a Grid, initialize a formula engine, evaluate formulas, access the DOM or call downloadBytes. Formula source is preserved where supported, not recalculated by this script. Node's Buffer is a Uint8Array, so readFile bytes can go directly to fromXlsxWorkbook.
The script never substitutes a mock workbook. Missing or invalid files fail. flag: "wx" refuses to overwrite an existing output; use a separate output path. File helpers close their own file handles. The finally block removes the process listener, and SIGINT requests codec cancellation between bounded stages. It does not interrupt writeFile once that write has started.
Options and resource limits
Option
Effect in this command
maxCells: 100_000
Rejects inputs or outputs beyond this accepted-cell budget.
maxInputBytes: 8 * 1024 * 1024
Bounds codec input bytes; the pre-read size check avoids reading an already oversized file.
onWarning
Prints structured fidelity losses instead of hiding them.
signal
Requests cancellation before or between codec stages.
The stat check is not a security boundary for a file another process can modify. The codec also checks the bytes it actually receives. ZIP expansion, entry count, compression ratio and XML depth retain their default limits. XlsxResourceError also satisfies isSheetwriteError; report its stable code and resource details rather than parsing a message.
Buffered import holds input bytes and the resulting snapshot; buffered export also holds output bytes. Streaming workbook export can bound output chunks, but it does not make the snapshot disappear. Do not promise constant-memory processing for large workbooks. See streaming and kept-part rules before using this as a fidelity-sensitive round trip. An unchanged chart or pivot graph can be kept; that is not a chart-authoring or pivot-calculation API.
function readFile<T extends NodeJS.ArrayBufferView>(path: PathLike | FileHandle, options: ReadFileOptionsWithBuffer<T>): Promise<BufferView<T>> (+3 overloads)functionreadFile<TextendsNodeJS.ArrayBufferView>(path:PathLike|FileHandle, options:ReadFileOptionsWithBuffer<T>):Promise<BufferView<T>> (+3overloads)functionreadFile<TextendsNodeJS.ArrayBufferView>(path:PathLike|FileHandle, options:ReadFileOptionsWithBuffer<T>):Promise<BufferView<T>> (+3overloads)Asynchronously reads the entire contents of a file. If no encoding is specified (using options.encoding), the data is returned as a Buffer object. Otherwise, the data will be a string. If options is a string, then it specifies the encoding. When the path is a directory, the behavior of fsPromises.readFile() is platform-specific. On macOS, Linux, and Windows, the promise will be rejected with an error. On FreeBSD, a representation of the directory's contents will be returned. An example of reading a package.json file located in the same directory of the running code: import { readFile } from 'node:fs/promises'; try { const filePath = new URL('./package.json', import.meta.url); const contents = await readFile(filePath, { encoding: 'utf8' }); console.log(contents); } catch (err) { console.error(err.message); } It is possible to abort an ongoing readFile using an AbortSignal. If a request is aborted the promise returned is rejected with an AbortError: import { readFile } from 'node:fs/promises'; try { const controller = new AbortController(); const { signal } = controller; const promise = readFile(fileName, { signal }); // Abort the request before the promise settles. controller.abort(); await promise; } catch (err) { // When a request is aborted - err is an AbortError console.error(err); } Aborting an ongoing request does not abort individual operating system requests but rather the internal buffering fs.readFile performs. Any specified FileHandle has to support reading.@since v10.0.0@param path filename or FileHandle@return Fulfills with the contents of the file.function writeFile(file: PathLike | FileHandle, data: string | NodeJS.ArrayBufferView | Iterable<string | NodeJS.ArrayBufferView> | AsyncIterable<string | NodeJS.ArrayBufferView>, options?: (ObjectEncodingOptions & {
mode?: Mode | undefined;
flag?: OpenMode | undefined;
flush?: boolean | undefined;
} & EventEmitter<T extends EventMap<T> = any>.Abortable) | BufferEncoding | null): Promise<void>functionwriteFile(file:PathLike|FileHandle, data:string|NodeJS.ArrayBufferView|Iterable<string|NodeJS.ArrayBufferView> |AsyncIterable<string|NodeJS.ArrayBufferView>, options?: (ObjectEncodingOptions& {mode?:Mode|undefined;flag?:OpenMode|undefined;flush?:boolean|undefined;} &EventEmitter<TextendsEventMap<T> = any>.Abortable) |BufferEncoding|null):Promise<void>functionwriteFile(file:PathLike|FileHandle, data:string|NodeJS.ArrayBufferView|Iterable<string|NodeJS.ArrayBufferView> |AsyncIterable<string|NodeJS.ArrayBufferView>, options?: (ObjectEncodingOptions& {mode?:Mode|undefined;flag?:OpenMode|undefined;flush?:boolean|undefined;} &EventEmitter<TextendsEventMap<T> = any>.Abortable) |BufferEncoding|null):Promise<void>Asynchronously writes data to a file, replacing the file if it already exists. data can be a string, a buffer, an AsyncIterable, or an Iterable object. The encoding option is ignored if data is a buffer. If options is a string, then it specifies the encoding. The mode option only affects the newly created file. See fs.open() for more details. Any specified FileHandle has to support writing. It is unsafe to use fsPromises.writeFile() multiple times on the same file without waiting for the promise to be settled. Similarly to fsPromises.readFile \- fsPromises.writeFile is a convenience method that performs multiple write calls internally to write the buffer passed to it. For performance sensitive code consider using fs.createWriteStream() or filehandle.createWriteStream(). It is possible to use an AbortSignal to cancel an fsPromises.writeFile(). Cancelation is "best effort", and some amount of data is likely still to be written. import { writeFile } from 'node:fs/promises'; import { Buffer } from 'node:buffer'; try { const controller = new AbortController(); const { signal } = controller; const data = new Uint8Array(Buffer.from('Hello Node.js')); const promise = writeFile('message.txt', data, { signal }); // Abort the request before the promise settles. controller.abort(); await promise; } catch (err) { // When a request is aborted - err is an AbortError console.error(err); } Aborting an ongoing request does not abort individual operating system requests but rather the internal buffering fs.writeFile performs.@since v10.0.0@param file filename or FileHandle@return Fulfills with undefined upon success.function fromXlsxWorkbook(data: ArrayBuffer | Uint8Array, options?: XlsxWorkbookOptions): Promise<WorkbookSnapshot>functionfromXlsxWorkbook(data:ArrayBuffer|Uint8Array,options?:XlsxWorkbookOptions,):Promise<WorkbookSnapshot>functionfromXlsxWorkbook(data:ArrayBuffer|Uint8Array,options?:XlsxWorkbookOptions,):Promise<WorkbookSnapshot>Formula-preserving, multi-sheet workbook import through the optional XLSX backend.Exampleimport { registerXlsxBackends } from"@sheetwrite/xlsx";import { fromXlsxWorkbook, createGridFromSnapshot, initSheetwrite } from"@sheetwrite/core";registerXlsxBackends();asyncfunctionopenWorkbook(host:HTMLElement, file:File) {awaitinitSheetwrite();constsnapshot=awaitfromXlsxWorkbook(await file.arrayBuffer());returncreateGridFromSnapshot(host, snapshot);}See alsotoXlsxWorkbookAPI reference →function toXlsxWorkbook(input: WorkbookSnapshot | Pick<Grid, "exportSnapshot">, options?: XlsxWorkbookOptions): Promise<Uint8Array>functiontoXlsxWorkbook(input:WorkbookSnapshot|Pick<Grid, "exportSnapshot">,options?:XlsxWorkbookOptions,):Promise<Uint8Array>functiontoXlsxWorkbook(input:|WorkbookSnapshot|Pick<Grid,"exportSnapshot">,options?:XlsxWorkbookOptions,):Promise<Uint8Array>Formula-preserving, multi-sheet workbook export through the optional XLSX backend.Exampleimport { registerXlsxBackends } from"@sheetwrite/xlsx";import { toXlsxWorkbook, downloadBytes, type Grid } from"@sheetwrite/core";registerXlsxBackends();asyncfunctiondownload(grid:Grid) {constbytes=awaittoXlsxWorkbook(grid);downloadBytes(bytes, "workbook.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");}See alsofromXlsxWorkbookAPI reference →interface XlsxWorkbookOptionsinterfaceXlsxWorkbookOptionsinterfaceXlsxWorkbookOptionsShared options passed to every registered table and workbook XLSX backend.API reference →const source: stringconstsource:stringconstsource:stringRemote input is observable but never belongs in outgoing local persistence.API reference →const snapshot: WorkbookSnapshotconstsnapshot:WorkbookSnapshotconstsnapshot:WorkbookSnapshotAPI reference →function readFile(path: PathLike | FileHandle, options?: ReadFileOptionsWithBufferEncoding | null): Promise<NonSharedBuffer> (+3 overloads)functionreadFile(path:PathLike|FileHandle, options?:ReadFileOptionsWithBufferEncoding|null):Promise<NonSharedBuffer> (+3overloads)functionreadFile(path:PathLike|FileHandle, options?:ReadFileOptionsWithBufferEncoding|null):Promise<NonSharedBuffer> (+3overloads)Asynchronously reads the entire contents of a file. If no encoding is specified (using options.encoding), the data is returned as a Buffer object. Otherwise, the data will be a string. If options is a string, then it specifies the encoding. When the path is a directory, the behavior of fsPromises.readFile() is platform-specific. On macOS, Linux, and Windows, the promise will be rejected with an error. On FreeBSD, a representation of the directory's contents will be returned. An example of reading a package.json file located in the same directory of the running code: import { readFile } from 'node:fs/promises'; try { const filePath = new URL('./package.json', import.meta.url); const contents = await readFile(filePath, { encoding: 'utf8' }); console.log(contents); } catch (err) { console.error(err.message); } It is possible to abort an ongoing readFile using an AbortSignal. If a request is aborted the promise returned is rejected with an AbortError: import { readFile } from 'node:fs/promises'; try { const controller = new AbortController(); const { signal } = controller; const promise = readFile(fileName, { signal }); // Abort the request before the promise settles. controller.abort(); await promise; } catch (err) { // When a request is aborted - err is an AbortError console.error(err); } Aborting an ongoing request does not abort individual operating system requests but rather the internal buffering fs.readFile performs. Any specified FileHandle has to support reading.@since v10.0.0@param path filename or FileHandle@return Fulfills with the contents of the file.const options: XlsxWorkbookOptionsconstoptions:XlsxWorkbookOptionsconstoptions:XlsxWorkbookOptionsAPI reference →const destination: stringconstdestination:stringconstdestination:stringflag?: OpenMode | undefinedflag?: OpenMode |undefinedflag?: OpenMode |undefinedfunction stat(path: PathLike): Promise<Stats> (+6 overloads)functionstat(path:PathLike):Promise<Stats> (+6overloads)functionstat(path:PathLike):Promise<Stats> (+6overloads)@since v10.0.0@return Fulfills with the {fs.Stats} object for the given path.function isSheetwriteError(value: unknown): value is SheetwriteErrorEnvelopefunctionisSheetwriteError(value:unknown,):valueisSheetwriteErrorEnvelopefunctionisSheetwriteError(value:unknown,):valueisSheetwriteErrorEnvelopeNarrow same-realm errors, cross-realm errors, and serialized failure envelopes.API reference →namespace process
var process: NodeJS.Processnamespaceprocessvar process:NodeJS.Processnamespaceprocessvar process:NodeJS.ProcessNodeJS.Process.argv: string[]NodeJS.Process.argv: string[]NodeJS.Process.argv: string[]The process.argv property returns an array containing the command-line arguments passed when the Node.js process was launched. The first element will be execPath. See process.argv0 if access to the original value of argv[0] is needed. The second element will be the path to the JavaScript file being executed. If a program entry point was provided, the second element will be the absolute path to it. The remaining elements are additional command-line arguments. For example, assuming the following script for process-args.js: import { argv } from 'node:process'; // print process.argv argv.forEach((val, index) => { console.log(${index}: ${val}); }); Launching the Node.js process as: node process-args.js one two=three four Would generate the output: 0: /usr/local/bin/node 1: /Users/mjr/work/node/process-args.js 2: one 3: two=three 4: four@since v0.1.27Array<string>.slice(start?: number, end?: number): string[]Array<string>.slice(start?: number, end?: number): string[]Array<string>.slice(start?: number, end?: number): string[]Returns a copy of a section of an array. For both start and end, a negative index can be used to indicate an offset from the end of the array. For example, -2 refers to the second to last element of the array.@param start The beginning index of the specified portion of the array. If start is undefined, then the slice begins at index 0.@param end The end index of the specified portion of the array. This is exclusive of the element at the index 'end'. If end is undefined, then the slice extends to the end of the array.var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+2 overloads)var Error:ErrorConstructornew (message?:string, options?:ErrorOptions) =>Error (+2 overloads)var Error:ErrorConstructornew (message?:string, options?:ErrorOptions) =>Error (+2 overloads)const controller: AbortControllerconstcontroller:AbortControllerconstcontroller:AbortControllervar AbortController: new () => AbortControllervar AbortController:new () =>AbortControllervar AbortController:new () =>AbortControllerThe AbortController interface represents a controller object that allows you to abort one or more Web requests as and when desired. MDN Reference An AbortController cancels one or more Web requests: pass its signal to a request, then call abort(). MDN Referenceconst cancel: () => voidconstcancel: () =>voidconstcancel: () =>voidAbortController.abort(reason?: any): void (+1 overload)AbortController.abort(reason?: any): void (+1 overload)AbortController.abort(reason?: any): void (+1 overload)The abort() method of the AbortController interface aborts an asynchronous operation before it has completed. MDN ReferenceNodeJS.Process.once<"SIGINT">(eventName: "SIGINT", listener: (signal: "SIGINT") => void): NodeJS.Process (+2 overloads)NodeJS.Process.once<"SIGINT">(eventName: "SIGINT", listener: (signal:"SIGINT") =>void): NodeJS.Process (+2 overloads)NodeJS.Process.once<"SIGINT">(eventName: "SIGINT", listener: (signal:"SIGINT") =>void): NodeJS.Process (+2 overloads)Adds a one-time listener function for the event named eventName. The next time eventName is triggered, this listener is removed and then invoked. server.once('connection', (stream) => { console.log('Ah, we have our first user!'); }); Returns a reference to the EventEmitter, so that calls can be chained. By default, event listeners are invoked in the order they are added. The emitter.prependOnceListener() method can be used as an alternative to add the event listener to the beginning of the listeners array. import { EventEmitter } from 'node:events'; const myEE = new EventEmitter(); myEE.once('foo', () => console.log('a')); myEE.prependOnceListener('foo', () => console.log('b')); myEE.emit('foo'); // Prints: // b // a@since v0.3.0@param eventName The name of the event.@param listener The callback functionXlsxWorkbookOptions.signal?: AbortSignal | undefinedinterfaceXlsxWorkbookOptions {signal?:AbortSignal|undefined;}interfaceXlsxWorkbookOptions {signal?:AbortSignal|undefined;}Abort before or between bounded codec operations.API reference →AbortController.signal: AbortSignalinterfaceAbortController {signal:AbortSignal;}interfaceAbortController {signal:AbortSignal;}The signal read-only property of the AbortController interface returns an AbortSignal object instance, which can be used to communicate with/abort an asynchronous operation as desired. MDN ReferenceAPI reference →XlsxWorkbookOptions.maxCells?: number | undefinedinterfaceXlsxWorkbookOptions {maxCells?:number|undefined;}interfaceXlsxWorkbookOptions {maxCells?:number|undefined;}Cells accounted by the active conversion path; defaults to 1,000,000.API reference →XlsxWorkbookOptions.resourceLimits?: Partial<Omit<XlsxResourceLimits, "maxCells">> | undefinedinterfaceXlsxWorkbookOptions {resourceLimits?:Partial<Omit<XlsxResourceLimits, "maxCells">> |undefined;}interfaceXlsxWorkbookOptions {resourceLimits?:|Partial<Omit<XlsxResourceLimits,"maxCells">>|undefined;}Positive overrides for every XLSX resource dimension except maxCells.API reference →maxInputBytes?: number | undefinedmaxInputBytes?: number |undefinedmaxInputBytes?: number |undefinedCompressed workbook input bytes; defaults to 32 MiB.API reference →XlsxWorkbookOptions.onWarning?: ((warning: XlsxWorkbookWarning) => void) | undefinedinterfaceXlsxWorkbookOptions {onWarning?: ((warning:XlsxWorkbookWarning) =>void) |undefined;}interfaceXlsxWorkbookOptions {onWarning?:| ((warning:XlsxWorkbookWarning,) =>void)|undefined;}warning: XlsxWorkbookWarninglet warning:XlsxWorkbookWarninglet warning:XlsxWorkbookWarningAPI reference →var console: Consolevar console:Consolevar console:ConsoleConsole.warn(...data: any[]): void (+1 overload)Console.warn(...data: any[]): void (+1 overload)Console.warn(...data: any[]): void (+1 overload)The console.warn() static method outputs a warning message to the console at the 'warning' log level. MDN ReferenceXlsxWorkbookWarning.code: "boolean-literal" | "rich-text" | "hyperlink" | "unsupported-cell-value" | "unsupported-feature" | "external-relationship" | "external-formula" | "format-loss" | "validation-loss" | "invalid-metadata"interfaceXlsxWorkbookWarning {code:|"boolean-literal"|"rich-text"|"hyperlink"|"unsupported-cell-value"|"unsupported-feature"|"external-relationship"|"external-formula"|"format-loss"|"validation-loss"|"invalid-metadata";}interfaceXlsxWorkbookWarning {code:|"boolean-literal"|"rich-text"|"hyperlink"|"unsupported-cell-value"|"unsupported-feature"|"external-relationship"|"external-formula"|"format-loss"|"validation-loss"|"invalid-metadata";}API reference →XlsxWorkbookWarning.message: stringinterfaceXlsxWorkbookWarning {message:string;}interfaceXlsxWorkbookWarning {message:string;}API reference →StatsBase<number>.size: numberinterfaceStatsBase<number> {size:number;}interfaceStatsBase<number> {size:number;}const output: Uint8Array<ArrayBufferLike>constoutput:Uint8Array<ArrayBufferLike>constoutput:Uint8Array<ArrayBufferLike>AbortSignal.aborted: booleaninterfaceAbortSignal {aborted:boolean;}interfaceAbortSignal {aborted:boolean;}The aborted read-only property returns a value that indicates whether the asynchronous operations the signal is communicating with are aborted (true) or not (false). MDN ReferenceConsole.log(...data: any[]): void (+1 overload)Console.log(...data: any[]): void (+1 overload)Console.log(...data: any[]): void (+1 overload)The console.log() static method outputs a message to the console. MDN ReferenceWorkbookSnapshot.sheets: SheetSnapshot[]interfaceWorkbookSnapshot {sheets:SheetSnapshot[];}interfaceWorkbookSnapshot {sheets:SheetSnapshot[];}Sheets in display/tab order.API reference →Array<SheetSnapshot>.length: numberinterfaceArray<SheetSnapshot> {length:number;}interfaceArray<SheetSnapshot> {length:number;}Gets or sets the length of the array. This is a number one higher than the highest index in the array.API reference →var error: unknownvar error:unknownvar error:unknownConsole.error(...data: any[]): void (+1 overload)Console.error(...data: any[]): void (+1 overload)Console.error(...data: any[]): void (+1 overload)Log to stderr in your terminal Appears in red@param data something to displayvar error: SheetwriteErrorEnvelopevar error:SheetwriteErrorEnvelopevar error:SheetwriteErrorEnvelopeAPI reference →SheetwriteErrorEnvelope.code: "conflict" | "incomplete-data" | "initialization-failed" | "initialization-required" | "datasource-request-failed" | "renderer-fallback" | "export-failed" | "xlsx-import-failed" | "optional-backend-unavailable" | "delimited-text-resource-limit" | "delimited-text-invalid-limit" | "xlsx-resource-limit" | "resource-limit" | "invalid-snapshot" | "aborted" | "not-found" | "commit-rejected" | "unavailable" | "blocked" | "quota" | "unsupported-schema" | "transaction" | "limit" | "invalid-limits" | "invalid-version" | "invalid-id" | ... 24 more ... | "shortcut-conflict"interfaceSheetwriteErrorEnvelope { code:"conflict"|"incomplete-data"|"initialization-failed"|"initialization-required"|"datasource-request-failed"|"renderer-fallback"|"export-failed"|"xlsx-import-failed"|"optional-backend-unavailable"|"delimited-text-resource-limit"|"delimited-text-invalid-limit"|"xlsx-resource-limit"|"resource-limit"|"invalid-snapshot"|"aborted"|"not-found"|"commit-rejected"|"unavailable"|"blocked"|"quota"|"unsupported-schema"|"transaction"|"limit"|"invalid-limits"|"invalid-version"|"invalid-id"| ... 24more ... |"shortcut-conflict" }interfaceSheetwriteErrorEnvelope { code:"conflict"|"incomplete-data"|"initialization-failed"|"initialization-required"|"datasource-request-failed"|"renderer-fallback"|"export-failed"|"xlsx-import-failed"|"optional-backend-unavailable"|"delimited-text-resource-limit"|"delimited-text-invalid-limit"|"xlsx-resource-limit"|"resource-limit"|"invalid-snapshot"|"aborted"|"not-found"|"commit-rejected"|"unavailable"|"blocked"|"quota"|"unsupported-schema"|"transaction"|"limit"|"invalid-limits"|"invalid-version"|"invalid-id"| ... 24more ... |"shortcut-conflict" }API reference →SheetwriteErrorEnvelope.message: stringinterfaceSheetwriteErrorEnvelope {message:string;}interfaceSheetwriteErrorEnvelope {message:string;}API reference →NodeJS.Process.exitCode: string | number | null | undefinedNodeJS.Process.exitCode: string | number |null|undefinedNodeJS.Process.exitCode: string | number |null|undefinedA number which will be the process exit code, when the process either exits gracefully, or is exited via exit without specifying a code. Specifying a code to exit will override any previous setting of process.exitCode.@default undefined@since v0.11.8NodeJS.Process.removeListener(event: string | symbol, listener: (...args: any[]) => void): NodeJS.Process (+3 overloads)NodeJS.Process.removeListener(event: string | symbol, listener: (...args:any[]) =>void): NodeJS.Process (+3 overloads)NodeJS.Process.removeListener(event: string | symbol, listener: (...args:any[]) =>void): NodeJS.Process (+3 overloads)Removes the specified listener from the listener array for the event named eventName. const callback = (stream) => { console.log('someone connected!'); }; server.on('connection', callback); // ... server.removeListener('connection', callback); removeListener() will remove, at most, one instance of a listener from the listener array. If any single listener has been added multiple times to the listener array for the specified eventName, then removeListener() must be called multiple times to remove each instance. Once an event is emitted, all listeners attached to it at the time of emitting are called in order. This implies that any removeListener() or removeAllListeners() calls _after_ emitting and _before_ the last listener finishes execution will not remove them from emit() in progress. Subsequent events behave as expected. import { EventEmitter } from 'node:events'; class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter(); const callbackA = () => { console.log('A'); myEmitter.removeListener('event', callbackB); }; const callbackB = () => { console.log('B'); }; myEmitter.on('event', callbackA); myEmitter.on('event', callbackB); // callbackA removes listener callbackB but it will still be called. // Internal listener array at time of emit [callbackA, callbackB] myEmitter.emit('event'); // Prints: // A // B // callbackB is now removed. // Internal listener array [callbackA] myEmitter.emit('event'); // Prints: // A Because listeners are managed using an internal array, calling this will change the position indexes of any listener registered _after_ the listener being removed. This will not impact the order in which listeners are called, but it means that any copies of the listener array as returned by the emitter.listeners() method will need to be recreated. When a single function has been added as a handler multiple times for a single event (as in the example below), removeListener() will remove the most recently added instance. In the example the once('ping') listener is removed: import { EventEmitter } from 'node:events'; const ee = new EventEmitter(); function pong() { console.log('pong'); } ee.on('ping', pong); ee.once('ping', pong); ee.removeListener('ping', pong); ee.emit('ping'); ee.emit('ping'); Returns a reference to the EventEmitter, so that calls can be chained.@since v0.1.26