forked from sheetjs/sheetjs
		
	version bump 0.18.3
- XLSX / XLSB dynamic array formulae - use Uint8Array when available in write (fixes #2539 h/t @RScherzer) - mini build cleanup to satiate webpack (fixes #2526 #2530)
This commit is contained in:
		
							parent
							
								
									4f6a849a59
								
							
						
					
					
						commit
						e14aee3e51
					
				| @ -41,6 +41,7 @@ ExtendScript | ||||
| IndexedDB | ||||
| JavaScriptCore | ||||
| LocalStorage | ||||
| NestJS | ||||
| NPM | ||||
| Nuxt.js | ||||
| Redis | ||||
|  | ||||
							
								
								
									
										7
									
								
								Makefile
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								Makefile
									
									
									
									
									
								
							| @ -18,6 +18,7 @@ ESMJSDEPS=$(shell cat misc/mjs.lst) | ||||
| ULIB=$(shell echo $(LIB) | tr a-z A-Z) | ||||
| DEPS=$(sort $(wildcard bits/*.js)) | ||||
| TSBITS=$(patsubst modules/%,bits/%,$(wildcard modules/[0-9][0-9]_*.js)) | ||||
| MTSBITS=$(patsubst modules/%,misc/%,$(wildcard modules/[0-9][0-9]_*.js)) | ||||
| TARGET=$(LIB).js | ||||
| FLOWTARGET=$(LIB).flow.js | ||||
| FLOWAUX=$(patsubst %.js,%.flow.js,$(AUXTARGETS)) | ||||
| @ -52,6 +53,9 @@ bits/18_cfb.js: node_modules/cfb/xlscfb.flow.js | ||||
| $(TSBITS): bits/%: modules/% | ||||
| 	cp $^ $@ | ||||
| 
 | ||||
| $(MTSBITS): misc/%: modules/% | ||||
| 	cp $^ $@ | ||||
| 
 | ||||
| 
 | ||||
| .PHONY: clean | ||||
| clean: ## Remove targets and build artifacts
 | ||||
| @ -82,6 +86,7 @@ dist: dist-deps $(TARGET) bower.json ## Prepare JS files for distribution | ||||
| 	uglifyjs $(REQS) dist/$(TARGET) $(UGLIFYOPTS) -o dist/$(LIB).core.min.js --source-map dist/$(LIB).core.min.map --preamble "$$(head -n 1 bits/00_header.js)" | ||||
| 	misc/strip_sourcemap.sh dist/$(LIB).core.min.js | ||||
| 	@# full | ||||
| 	#cat <(head -n 1 bits/00_header.js) $(DISTHDR) $(REQS) $(ADDONS) dist/$(TARGET) $(AUXTARGETS) > dist/$(LIB).full.js | ||||
| 	uglifyjs $(DISTHDR) $(REQS) $(ADDONS) dist/$(TARGET) $(AUXTARGETS) $(UGLIFYOPTS) -o dist/$(LIB).full.min.js --source-map dist/$(LIB).full.min.map --preamble "$$(head -n 1 bits/00_header.js)" | ||||
| 	misc/strip_sourcemap.sh dist/$(LIB).full.min.js | ||||
| 	@# mini | ||||
| @ -101,7 +106,7 @@ dist-deps: ## Copy dependencies for distribution | ||||
| aux: $(AUXTARGETS) | ||||
| 
 | ||||
| BYTEFILEC=dist/xlsx.{full,core,mini}.min.js | ||||
| BYTEFILER=dist/xlsx.extendscript.js | ||||
| BYTEFILER=dist/xlsx.extendscript.js xlsx.mjs | ||||
| .PHONY: bytes | ||||
| bytes: ## Display minified and gzipped file sizes
 | ||||
| 	@for i in $(BYTEFILEC); do printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done | ||||
|  | ||||
							
								
								
									
										572
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										572
									
								
								README.md
									
									
									
									
									
								
							| @ -24,12 +24,8 @@ port calculations to web apps; automate common spreadsheet tasks, and much more! | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| <details><summary><b>Diagram Legend</b> (click to show)</summary> | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ## Table of Contents | ||||
| 
 | ||||
| <details> | ||||
| @ -46,14 +42,17 @@ port calculations to web apps; automate common spreadsheet tasks, and much more! | ||||
|   * [Parsing Workbooks](#parsing-workbooks) | ||||
|   * [Processing JSON and JS Data](#processing-json-and-js-data) | ||||
|   * [Processing HTML Tables](#processing-html-tables) | ||||
| - [Working with the Workbook](#working-with-the-workbook) | ||||
|   * [Parsing and Writing Examples](#parsing-and-writing-examples) | ||||
| - [Processing Data](#processing-data) | ||||
|   * [Modifying Workbook Structure](#modifying-workbook-structure) | ||||
|   * [Modifying Cell Values](#modifying-cell-values) | ||||
|   * [Modifying Other Worksheet / Workbook / Cell Properties](#modifying-other-worksheet--workbook--cell-properties) | ||||
| - [Packaging and Releasing Data](#packaging-and-releasing-data) | ||||
|   * [Writing Workbooks](#writing-workbooks) | ||||
|   * [Writing Examples](#writing-examples) | ||||
|   * [Streaming Write](#streaming-write) | ||||
|   * [Generating JSON and JS Data](#generating-json-and-js-data) | ||||
|   * [Generating HTML Tables](#generating-html-tables) | ||||
|   * [Generating Single-Worksheet Snapshots](#generating-single-worksheet-snapshots) | ||||
| - [Interface](#interface) | ||||
|   * [Parsing functions](#parsing-functions) | ||||
|   * [Writing functions](#writing-functions) | ||||
| @ -150,10 +149,11 @@ For example, `unpkg` makes the latest version available at: | ||||
| 
 | ||||
| The complete single-file version is generated at `dist/xlsx.full.min.js` | ||||
| 
 | ||||
| `dist/xlsx.core.min.js` omits codepage library (no support for XLS encodings) | ||||
| 
 | ||||
| A slimmer build is generated at `dist/xlsx.mini.min.js`. Compared to full build: | ||||
| - codepage library skipped (no support for XLS encodings) | ||||
| - XLSX compression option not currently available | ||||
| - no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 | ||||
| - no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 / Numbers | ||||
| - node stream utils removed | ||||
| 
 | ||||
| </details> | ||||
| @ -317,6 +317,18 @@ and approaches for steps 1 and 5. | ||||
| 
 | ||||
| Utility functions help with step 3. | ||||
| 
 | ||||
| ["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes | ||||
| solutions for common data import scenarios. | ||||
| 
 | ||||
| ["Packaging and Releasing Data"](#packaging-and-releasing-data) describes | ||||
| solutions for common data export scenarios. | ||||
| 
 | ||||
| ["Processing Data"](#packaging-and-releasing-data) describes solutions for | ||||
| common workbook processing and manipulation scenarios. | ||||
| 
 | ||||
| ["Utility Functions"](#utility-functions) details utility functions for | ||||
| translating JSON Arrays and other common JS structures into worksheet objects. | ||||
| 
 | ||||
| ### The Zen of SheetJS | ||||
| 
 | ||||
| _Data processing should fit in any workflow_ | ||||
| @ -325,15 +337,6 @@ The library does not impose a separate lifecycle.  It fits nicely in websites | ||||
| and apps built using any framework.  The plain JS data objects play nice with | ||||
| Web Workers and future APIs. | ||||
| 
 | ||||
| ["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes | ||||
| solutions for common data import scenarios. | ||||
| 
 | ||||
| ["Writing Workbooks"](#writing-workbooks) describes solutions for common data | ||||
| export scenarios involving actual spreadsheet files. | ||||
| 
 | ||||
| ["Utility Functions"](#utility-functions) details utility functions for | ||||
| translating JSON Arrays and other common JS structures into worksheet objects. | ||||
| 
 | ||||
| _JavaScript is a powerful language for data processing_ | ||||
| 
 | ||||
| The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object | ||||
| @ -576,6 +579,12 @@ The [`demos` directory](demos/) includes sample projects for: | ||||
| 
 | ||||
| Other examples are included in the [showcase](demos/showcase/). | ||||
| 
 | ||||
| <https://sheetjs.com/demos/modify.html> shows a complete example of reading, | ||||
| modifying, and writing files. | ||||
| 
 | ||||
| <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> is the command-line | ||||
| tool included with node installations, reading spreadsheet files and exporting | ||||
| the contents in various formats. | ||||
| ## Acquiring and Extracting Data | ||||
| 
 | ||||
| ### Parsing Workbooks | ||||
| @ -1018,12 +1027,13 @@ const workbook = XLSX.read(data); | ||||
| </details> | ||||
| 
 | ||||
| More detailed examples are covered in the [included demos](demos/) | ||||
| 
 | ||||
| ### Processing JSON and JS Data | ||||
| 
 | ||||
| JSON and JS data tend to represent single worksheets.  This section will use a | ||||
| few utility functions to generate workbooks: | ||||
| few utility functions to generate workbooks. | ||||
| 
 | ||||
| _Create a new Worksheet_ | ||||
| _Create a new Workbook_ | ||||
| 
 | ||||
| ```js | ||||
| var workbook = XLSX.utils.book_new(); | ||||
| @ -1031,16 +1041,9 @@ var workbook = XLSX.utils.book_new(); | ||||
| 
 | ||||
| The `book_new` utility function creates an empty workbook with no worksheets. | ||||
| 
 | ||||
| 
 | ||||
| _Append a Worksheet to a Workbook_ | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name); | ||||
| ``` | ||||
| 
 | ||||
| The `book_append_sheet` utility function appends a worksheet to the workbook. | ||||
| The third argument specifies the desired worksheet name. Multiple worksheets can | ||||
| be added to a workbook by calling the function multiple times. | ||||
| Spreadsheet software generally require at least one worksheet and enforce the | ||||
| requirement in the user interface.  This library enforces the requirement at | ||||
| write time, throwing errors if an empty workbook is passed to write functions. | ||||
| 
 | ||||
| 
 | ||||
| **API** | ||||
| @ -1053,14 +1056,14 @@ var worksheet = XLSX.utils.aoa_to_sheet(aoa, opts); | ||||
| 
 | ||||
| The `aoa_to_sheet` utility function walks an "array of arrays" in row-major | ||||
| order, generating a worksheet object.  The following snippet generates a sheet | ||||
| with cell `A1` set to the string `A1`, cell `B1` set to `B2`, etc: | ||||
| with cell `A1` set to the string `A1`, cell `B1` set to `B1`, etc: | ||||
| 
 | ||||
| ```js | ||||
| var worksheet = XLSX.utils.aoa_to_sheet([ | ||||
|   ["A1", "B1", "C1"], | ||||
|   ["A2", "B2", "C2"], | ||||
|   ["A3", "B3", "C3"] | ||||
| ]) | ||||
| ]); | ||||
| ``` | ||||
| 
 | ||||
| ["Array of Arrays Input"](#array-of-arrays-input) describes the function and the | ||||
| @ -1361,41 +1364,57 @@ const workbook = XLSX.utils.table_to_book(doc); | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ## Working with the Workbook | ||||
| ## Processing Data | ||||
| 
 | ||||
| The full object format is described later in this README. | ||||
| The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object | ||||
| representation of the core concepts of a workbook.  The utility functions work | ||||
| with the object representation and are intended to handle common use cases. | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Reading a specific cell </b> (click to show)</summary> | ||||
| ### Modifying Workbook Structure | ||||
| 
 | ||||
| This example extracts the value stored in cell A1 from the first worksheet: | ||||
| **API** | ||||
| 
 | ||||
| _Append a Worksheet to a Workbook_ | ||||
| 
 | ||||
| ```js | ||||
| var first_sheet_name = workbook.SheetNames[0]; | ||||
| var address_of_cell = 'A1'; | ||||
| 
 | ||||
| /* Get worksheet */ | ||||
| var worksheet = workbook.Sheets[first_sheet_name]; | ||||
| 
 | ||||
| /* Find desired cell */ | ||||
| var desired_cell = worksheet[address_of_cell]; | ||||
| 
 | ||||
| /* Get the value */ | ||||
| var desired_value = (desired_cell ? desired_cell.v : undefined); | ||||
| XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name); | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| The `book_append_sheet` utility function appends a worksheet to the workbook. | ||||
| The third argument specifies the desired worksheet name. Multiple worksheets can | ||||
| be added to a workbook by calling the function multiple times. | ||||
| 
 | ||||
| _List the Worksheet names in tab order_ | ||||
| 
 | ||||
| ```js | ||||
| var wsnames = workbook.SheetNames; | ||||
| ``` | ||||
| 
 | ||||
| The `SheetNames` property of the workbook object is a list of the worksheet | ||||
| names in "tab order".  API functions will look at this array. | ||||
| 
 | ||||
| _Replace a Worksheet in place_ | ||||
| 
 | ||||
| ```js | ||||
| workbook.Sheets[sheet_name] = new_worksheet; | ||||
| ``` | ||||
| 
 | ||||
| The `Sheets` property of the workbook object is an object whose keys are names | ||||
| and whose values are worksheet objects.  By reassigning to a property of the | ||||
| `Sheets` object, the worksheet object can be changed without disrupting the | ||||
| rest of the worksheet structure. | ||||
| 
 | ||||
| **Examples** | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Adding a new worksheet to a workbook</b> (click to show)</summary> | ||||
|   <summary><b>Add a new worksheet to a workbook</b> (click to show)</summary> | ||||
| 
 | ||||
| This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input) to make a | ||||
| sheet and `XLSX.utils.book_append_sheet` to append the sheet to the workbook: | ||||
| This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input). | ||||
| 
 | ||||
| ```js | ||||
| var ws_name = "SheetJS"; | ||||
| 
 | ||||
| /* make worksheet */ | ||||
| /* Create worksheet */ | ||||
| var ws_data = [ | ||||
|   [ "S", "h", "e", "e", "t", "J", "S" ], | ||||
|   [  1 ,  2 ,  3 ,  4 ,  5 ] | ||||
| @ -1408,41 +1427,60 @@ XLSX.utils.book_append_sheet(wb, ws, ws_name); | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Creating a new workbook from scratch</b> (click to show)</summary> | ||||
| ### Modifying Cell Values | ||||
| 
 | ||||
| The workbook object contains a `SheetNames` array of names and a `Sheets` object | ||||
| mapping sheet names to sheet objects. The `XLSX.utils.book_new` utility function | ||||
| creates a new workbook object: | ||||
| **API** | ||||
| 
 | ||||
| _Modify a single cell value in a worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| /* create a new blank workbook */ | ||||
| var wb = XLSX.utils.book_new(); | ||||
| XLSX.utils.sheet_add_aoa(worksheet, [[new_value]], { origin: address }); | ||||
| ``` | ||||
| 
 | ||||
| The new workbook is blank and contains no worksheets. The write functions will | ||||
| error if the workbook is empty. | ||||
| _Modify multiple cell values in a worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_add_aoa(worksheet, aoa, opts); | ||||
| ``` | ||||
| 
 | ||||
| The `sheet_add_aoa` utility function modifies cell values in a worksheet.  The | ||||
| first argument is the worksheet object.  The second argument is an array of | ||||
| arrays of values.  The `origin` key of the third argument controls where cells | ||||
| will be written.  The following snippet sets `B3=1` and `E5="abc"`: | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_add_aoa(worksheet, [ | ||||
|   [1],                             // <-- Write 1 to cell B3 | ||||
|   ,                                // <-- Do nothing in row 4 | ||||
|   [/*B5*/, /*C5*/, /*D5*/, "abc"]  // <-- Write "abc" to cell E5 | ||||
| ], { origin: "B3" }); | ||||
| ``` | ||||
| 
 | ||||
| ["Array of Arrays Input"](#array-of-arrays-input) describes the function and the | ||||
| optional `opts` argument in more detail. | ||||
| 
 | ||||
| **Examples** | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Appending rows to a worksheet</b> (click to show)</summary> | ||||
| 
 | ||||
| The special origin value `-1` instructs `sheet_add_aoa` to start in column A of | ||||
| the row after the last row in the range, appending the data: | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_add_aoa(worksheet, [ | ||||
|   ["first row after data", 1], | ||||
|   ["second row after data", 2] | ||||
| ], { origin: -1 }); | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| 
 | ||||
| ### Parsing and Writing Examples | ||||
| ### Modifying Other Worksheet / Workbook / Cell Properties | ||||
| 
 | ||||
| - <https://sheetjs.com/demos/modify.html> read + modify + write files | ||||
| 
 | ||||
| - <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> node | ||||
| 
 | ||||
| The node version installs a command line tool `xlsx` which can read spreadsheet | ||||
| files and output the contents in various formats.  The source is available at | ||||
| `xlsx.njs` in the bin directory. | ||||
| 
 | ||||
| Some helper functions in `XLSX.utils` generate different views of the sheets: | ||||
| 
 | ||||
| - `XLSX.utils.sheet_to_csv` generates CSV | ||||
| - `XLSX.utils.sheet_to_txt` generates UTF16 Formatted Text | ||||
| - `XLSX.utils.sheet_to_html` generates HTML | ||||
| - `XLSX.utils.sheet_to_json` generates an array of objects | ||||
| - `XLSX.utils.sheet_to_formulae` generates a list of formulae | ||||
| The ["Common Spreadsheet Format"](#common-spreadsheet-format) section describes | ||||
| the object structures in greater detail. | ||||
| 
 | ||||
| ## Packaging and Releasing Data | ||||
| 
 | ||||
| @ -1963,6 +2001,45 @@ The [`vuejs` demo](demos/vue) includes more React examples. | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ### Generating Single-Worksheet Snapshots | ||||
| 
 | ||||
| The `sheet_to_*` functions accept a worksheet object. | ||||
| 
 | ||||
| **API** | ||||
| 
 | ||||
| _Generate a CSV from a single worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| var csv = XLSX.utils.sheet_to_csv(worksheet, opts); | ||||
| ``` | ||||
| 
 | ||||
| This snapshot is designed to replicate the "CSV UTF8 (`.csv`)" output type. | ||||
| ["Delimiter-Separated Output"](#delimiter-separated-output) describes the | ||||
| function and the optional `opts` argument in more detail. | ||||
| 
 | ||||
| _Generate "Text" from a single worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| var txt = XLSX.utils.sheet_to_txt(worksheet, opts); | ||||
| ``` | ||||
| 
 | ||||
| This snapshot is designed to replicate the "UTF16 Text (`.txt`)" output type. | ||||
| ["Delimiter-Separated Output"](#delimiter-separated-output) describes the | ||||
| function and the optional `opts` argument in more detail. | ||||
| 
 | ||||
| _Generate a list of formulae from a single worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| var fmla = XLSX.utils.sheet_to_formulae(worksheet); | ||||
| ``` | ||||
| 
 | ||||
| This snapshot generates an array of entries representing the embedded formulae. | ||||
| Array formulae are rendered in the form `range=formula` while plain cells are | ||||
| rendered in the form `cell=formula or value`.  String literals are prefixed with | ||||
| an apostrophe `'`, consistent with Excel's formula bar display. | ||||
| 
 | ||||
| ["Formulae Output"](#formulae-output) describes the function in more detail. | ||||
| 
 | ||||
| ## Interface | ||||
| 
 | ||||
| `XLSX` is the exposed variable in the browser and the exported node variable | ||||
| @ -2065,6 +2142,7 @@ Cell objects are plain JS objects with keys and values following the convention: | ||||
| | `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub | | ||||
| | `f` | cell formula encoded as an A1-style string (if applicable)             | | ||||
| | `F` | range of enclosing array if formula is array formula (if applicable)   | | ||||
| | `D` | if true, array formula is dynamic (if applicable)                      | | ||||
| | `r` | rich text encoding (if applicable)                                     | | ||||
| | `h` | HTML rendering of the rich text (if applicable)                        | | ||||
| | `c` | comments associated with the cell                                      | | ||||
| @ -2416,79 +2494,7 @@ Even though some formats store formulae with a leading equal sign, CSF formulae | ||||
| do not start with `=`. | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Representation of A1=1, A2=2, A3=A1+A2</b> (click to show)</summary> | ||||
| 
 | ||||
| ```js | ||||
| { | ||||
|   "!ref": "A1:A3", | ||||
|   A1: { t:'n', v:1 }, | ||||
|   A2: { t:'n', v:2 }, | ||||
|   A3: { t:'n', v:3, f:'A1+A2' } | ||||
| } | ||||
| ``` | ||||
| </details> | ||||
| 
 | ||||
| Shared formulae are decompressed and each cell has the formula corresponding to | ||||
| its cell.  Writers generally do not attempt to generate shared formulae. | ||||
| 
 | ||||
| Cells with formula entries but no value will be serialized in a way that Excel | ||||
| and other spreadsheet tools will recognize.  This library will not automatically | ||||
| compute formula results!  For example, to compute `BESSELJ` in a worksheet: | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Formula without known value</b> (click to show)</summary> | ||||
| 
 | ||||
| ```js | ||||
| { | ||||
|   "!ref": "A1:A3", | ||||
|   A1: { t:'n', v:3.14159 }, | ||||
|   A2: { t:'n', v:2 }, | ||||
|   A3: { t:'n', f:'BESSELJ(A1,A2)' } | ||||
| } | ||||
| ``` | ||||
| </details> | ||||
| 
 | ||||
| **Array Formulae** | ||||
| 
 | ||||
| Array formulae are stored in the top-left cell of the array block.  All cells | ||||
| of an array formula have a `F` field corresponding to the range.  A single-cell | ||||
| formula can be distinguished from a plain formula by the presence of `F` field. | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Array Formula examples</b> (click to show)</summary> | ||||
| 
 | ||||
| For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`: | ||||
| 
 | ||||
| ```js | ||||
| worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" }; | ||||
| ``` | ||||
| 
 | ||||
| For a multi-cell array formula, every cell has the same array range but only the | ||||
| first cell specifies the formula.  Consider `D1:D3=A1:A3*B1:B3`: | ||||
| 
 | ||||
| ```js | ||||
| worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" }; | ||||
| worksheet['D2'] = { t:'n', F:"D1:D3" }; | ||||
| worksheet['D3'] = { t:'n', F:"D1:D3" }; | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| Utilities and writers are expected to check for the presence of a `F` field and | ||||
| ignore any possible formula element `f` in cells other than the starting cell. | ||||
| They are not expected to perform validation of the formulae! | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Formula Output Utility Function</b> (click to show)</summary> | ||||
| 
 | ||||
| The `sheet_to_formulae` method generates one line per formula or array formula. | ||||
| Array formulae are rendered in the form `range=formula` while plain cells are | ||||
| rendered in the form `cell=formula or value`.  Note that string literals are | ||||
| prefixed with an apostrophe `'`, consistent with Excel's formula bar display. | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Formulae File Format Details</b> (click to show)</summary> | ||||
|   <summary><b>Formulae File Format Support</b> (click to show)</summary> | ||||
| 
 | ||||
| | Storage Representation | Formats                  | Read  | Write | | ||||
| |:-----------------------|:-------------------------|:-----:|:-----:| | ||||
| @ -2502,6 +2508,272 @@ Since Excel prohibits named cells from colliding with names of A1 or RC style | ||||
| cell references, a (not-so-simple) regex conversion is possible.  BIFF Parsed | ||||
| formulae and Lotus Parsed formulae have to be explicitly unwound.  OpenFormula | ||||
| formulae can be converted with regular expressions. | ||||
| 
 | ||||
| Shared formulae are decompressed and each cell has the formula corresponding to | ||||
| its cell.  Writers generally do not attempt to generate shared formulae. | ||||
| </details> | ||||
| 
 | ||||
| **Single-Cell Formulae** | ||||
| 
 | ||||
| For simple formulae, the `f` key of the desired cell can be set to the actual | ||||
| formula text.  This worksheet represents `A1=1`, `A2=2`, and `A3=A1+A2`: | ||||
| 
 | ||||
| ```js | ||||
| var worksheet = { | ||||
|   "!ref": "A1:A3", | ||||
|   A1: { t:'n', v:1 }, | ||||
|   A2: { t:'n', v:2 }, | ||||
|   A3: { t:'n', v:3, f:'A1+A2' } | ||||
| }; | ||||
| ``` | ||||
| 
 | ||||
| Utilities like `aoa_to_sheet` will accept cell objects in lieu of values: | ||||
| 
 | ||||
| ```js | ||||
| var worksheet = XLSX.utils.aoa_to_sheet([ | ||||
|   [ 1 ], // A1 | ||||
|   [ 2 ], // A2 | ||||
|   [ {t: "n", v: 3, f: "A1+A2"} ] // A3 | ||||
| ]); | ||||
| ``` | ||||
| 
 | ||||
| Cells with formula entries but no value will be serialized in a way that Excel | ||||
| and other spreadsheet tools will recognize.  This library will not automatically | ||||
| compute formula results!  For example, the following worksheet will include the | ||||
| `BESSELJ` function but the result will not be available in JavaScript: | ||||
| 
 | ||||
| ```js | ||||
| var worksheet = XLSX.utils.aoa_to_sheet([ | ||||
|   [ 3.14159, 2 ], // Row "1" | ||||
|   [ { t:'n', f:'BESSELJ(A1,B1)' } ] // Row "2" will be calculated on file open | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| If the actual results are needed in JS, [SheetJS Pro](https://sheetjs.com/pro) | ||||
| offers a formula calculator component for evaluating expressions, updating | ||||
| values and dependent cells, and refreshing entire workbooks. | ||||
| 
 | ||||
| 
 | ||||
| **Array Formulae** | ||||
| 
 | ||||
| _Assign an array formula_ | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, range, formula); | ||||
| ``` | ||||
| 
 | ||||
| Array formulae are stored in the top-left cell of the array block.  All cells | ||||
| of an array formula have a `F` field corresponding to the range.  A single-cell | ||||
| formula can be distinguished from a plain formula by the presence of `F` field. | ||||
| 
 | ||||
| For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`: | ||||
| 
 | ||||
| ```js | ||||
| // API function | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "C1", "SUM(A1:A3*B1:B3)"); | ||||
| 
 | ||||
| // ... OR raw operations | ||||
| worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" }; | ||||
| ``` | ||||
| 
 | ||||
| For a multi-cell array formula, every cell has the same array range but only the | ||||
| first cell specifies the formula.  Consider `D1:D3=A1:A3*B1:B3`: | ||||
| 
 | ||||
| ```js | ||||
| // API function | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "D1:D3", "A1:A3*B1:B3"); | ||||
| 
 | ||||
| // ... OR raw operations | ||||
| worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" }; | ||||
| worksheet['D2'] = { t:'n', F:"D1:D3" }; | ||||
| worksheet['D3'] = { t:'n', F:"D1:D3" }; | ||||
| ``` | ||||
| 
 | ||||
| Utilities and writers are expected to check for the presence of a `F` field and | ||||
| ignore any possible formula element `f` in cells other than the starting cell. | ||||
| They are not expected to perform validation of the formulae! | ||||
| 
 | ||||
| 
 | ||||
| **Dynamic Array Formulae** | ||||
| 
 | ||||
| _Assign a dynamic array formula_ | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true); | ||||
| ``` | ||||
| 
 | ||||
| Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB | ||||
| file formats.  They are represented like normal array formulae but have special | ||||
| cell metadata indicating that the formula should be allowed to adjust the range. | ||||
| 
 | ||||
| An array formula can be marked as dynamic by setting the cell's `D` property to | ||||
| true.  The `F` range is expected but can be the set to the current cell: | ||||
| 
 | ||||
| ```js | ||||
| // API function | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1); | ||||
| 
 | ||||
| // ... OR raw operations | ||||
| worksheet['C1'] = { t: "s", f: "_xlfn.UNIQUE(A1:A3)", F:"C1", D: 1 }; // dynamic | ||||
| ``` | ||||
| 
 | ||||
| **Localization with Function Names** | ||||
| 
 | ||||
| SheetJS operates at the file level.  Excel stores formula expressions using the | ||||
| English (United States) function names.  For non-English users, Excel uses a | ||||
| localized set of function names. | ||||
| 
 | ||||
| For example, when the computer language and region is set to French (France), | ||||
| Excel interprets `=SOMME(A1:C3)` as if `SOMME` is the `SUM` function.  However, | ||||
| in the actual file, Excel stores `SUM(A1:C3)`. | ||||
| 
 | ||||
| **Prefixed "Future Functions"** | ||||
| 
 | ||||
| Functions introduced in newer versions of Excel are prefixed with `_xlfn.` when | ||||
| stored in files.  When writing formula expressions using these functions, the | ||||
| prefix is required for maximal compatibility: | ||||
| 
 | ||||
| ```js | ||||
| // Broadest compatibility | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1); | ||||
| 
 | ||||
| // Can cause errors in spreadsheet software | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "C1", "UNIQUE(A1:A3)", 1); | ||||
| ``` | ||||
| 
 | ||||
| When reading a file, the `xlfn` option preserves the prefixes. | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b> Functions requiring `_xlfn.` prefix</b> (click to show)</summary> | ||||
| 
 | ||||
| This list is growing with each Excel release. | ||||
| 
 | ||||
| ``` | ||||
| ACOT | ||||
| ACOTH | ||||
| AGGREGATE | ||||
| ARABIC | ||||
| BASE | ||||
| BETA.DIST | ||||
| BETA.INV | ||||
| BINOM.DIST | ||||
| BINOM.DIST.RANGE | ||||
| BINOM.INV | ||||
| BITAND | ||||
| BITLSHIFT | ||||
| BITOR | ||||
| BITRSHIFT | ||||
| BITXOR | ||||
| BYCOL | ||||
| BYROW | ||||
| CEILING.MATH | ||||
| CEILING.PRECISE | ||||
| CHISQ.DIST | ||||
| CHISQ.DIST.RT | ||||
| CHISQ.INV | ||||
| CHISQ.INV.RT | ||||
| CHISQ.TEST | ||||
| COMBINA | ||||
| CONFIDENCE.NORM | ||||
| CONFIDENCE.T | ||||
| COT | ||||
| COTH | ||||
| COVARIANCE.P | ||||
| COVARIANCE.S | ||||
| CSC | ||||
| CSCH | ||||
| DAYS | ||||
| DECIMAL | ||||
| ERF.PRECISE | ||||
| ERFC.PRECISE | ||||
| EXPON.DIST | ||||
| F.DIST | ||||
| F.DIST.RT | ||||
| F.INV | ||||
| F.INV.RT | ||||
| F.TEST | ||||
| FIELDVALUE | ||||
| FILTERXML | ||||
| FLOOR.MATH | ||||
| FLOOR.PRECISE | ||||
| FORMULATEXT | ||||
| GAMMA | ||||
| GAMMA.DIST | ||||
| GAMMA.INV | ||||
| GAMMALN.PRECISE | ||||
| GAUSS | ||||
| HYPGEOM.DIST | ||||
| IFNA | ||||
| IMCOSH | ||||
| IMCOT | ||||
| IMCSC | ||||
| IMCSCH | ||||
| IMSEC | ||||
| IMSECH | ||||
| IMSINH | ||||
| IMTAN | ||||
| ISFORMULA | ||||
| ISOMITTED | ||||
| ISOWEEKNUM | ||||
| LAMBDA | ||||
| LET | ||||
| LOGNORM.DIST | ||||
| LOGNORM.INV | ||||
| MAKEARRAY | ||||
| MAP | ||||
| MODE.MULT | ||||
| MODE.SNGL | ||||
| MUNIT | ||||
| NEGBINOM.DIST | ||||
| NORM.DIST | ||||
| NORM.INV | ||||
| NORM.S.DIST | ||||
| NORM.S.INV | ||||
| NUMBERVALUE | ||||
| PDURATION | ||||
| PERCENTILE.EXC | ||||
| PERCENTILE.INC | ||||
| PERCENTRANK.EXC | ||||
| PERCENTRANK.INC | ||||
| PERMUTATIONA | ||||
| PHI | ||||
| POISSON.DIST | ||||
| QUARTILE.EXC | ||||
| QUARTILE.INC | ||||
| QUERYSTRING | ||||
| RANDARRAY | ||||
| RANK.AVG | ||||
| RANK.EQ | ||||
| REDUCE | ||||
| RRI | ||||
| SCAN | ||||
| SEC | ||||
| SECH | ||||
| SEQUENCE | ||||
| SHEET | ||||
| SHEETS | ||||
| SKEW.P | ||||
| SORTBY | ||||
| STDEV.P | ||||
| STDEV.S | ||||
| T.DIST | ||||
| T.DIST.2T | ||||
| T.DIST.RT | ||||
| T.INV | ||||
| T.INV.2T | ||||
| T.TEST | ||||
| UNICHAR | ||||
| UNICODE | ||||
| UNIQUE | ||||
| VAR.P | ||||
| VAR.S | ||||
| WEBSERVICE | ||||
| WEIBULL.DIST | ||||
| XLOOKUP | ||||
| XOR | ||||
| Z.TEST | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| #### Row and Column Properties | ||||
|  | ||||
| @ -129,6 +129,7 @@ function wb_fmt() { | ||||
| 	seen = true; | ||||
| 	opts.cellFormula = true; | ||||
| 	opts.cellNF = true; | ||||
| 	opts.xlfn = true; | ||||
| 	if(program.output) sheetname = program.output; | ||||
| } | ||||
| function isfmt(m/*:string*/)/*:boolean*/ { | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| XLSX.version = '0.18.2'; | ||||
| XLSX.version = '0.18.3'; | ||||
|  | ||||
| @ -13,7 +13,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) { | ||||
| 	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload); | ||||
| 	if(typeof Deno !== 'undefined') { | ||||
| 		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */ | ||||
| 		if(enc) switch(enc) { | ||||
| 		if(enc && typeof payload == "string") switch(enc) { | ||||
| 			case "utf8": payload = new TextEncoder(enc).encode(payload); break; | ||||
| 			case "binary": payload = s2ab(payload); break; | ||||
| 			/* TODO: binary equivalent */ | ||||
|  | ||||
| @ -1,3 +1,6 @@ | ||||
| function parse_Int32LE(data) { | ||||
| 	return data.read_shift(4, 'i'); | ||||
| } | ||||
| function write_UInt32LE(x/*:number*/, o) { | ||||
| 	if (!o) o = new_buf(4); | ||||
| 	o.write_shift(4, x); | ||||
|  | ||||
| @ -61,8 +61,8 @@ var ct2type/*{[string]:string}*/ = ({ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links", | ||||
| 
 | ||||
| 	/* Metadata */ | ||||
| 	"application/vnd.ms-excel.sheetMetadata": "TODO", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO", | ||||
| 	"application/vnd.ms-excel.sheetMetadata": "metadata", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata", | ||||
| 
 | ||||
| 	/* PivotCache */ | ||||
| 	"application/vnd.ms-excel.pivotCacheDefinition": "TODO", | ||||
| @ -179,6 +179,10 @@ var CT_LIST = (function(){ | ||||
| 			xlsx: "application/vnd.ms-excel.macrosheet+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.macrosheet" | ||||
| 		}, | ||||
| 		metadata: { /* Metadata (Stock/Geography and Dynamic Array) */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.sheetMetadata" | ||||
| 		}, | ||||
| 		styles: { /* Styles */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.styles" | ||||
| @ -198,7 +202,7 @@ function new_ct()/*:any*/ { | ||||
| 		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[], | ||||
| 		rels:[], strs:[], comments:[], links:[], | ||||
| 		coreprops:[], extprops:[], custprops:[], themes:[], styles:[], | ||||
| 		calcchains:[], vba: [], drawings: [], | ||||
| 		calcchains:[], vba: [], drawings: [], metadata: [], | ||||
| 		TODO:[], xmlns: "" }/*:any*/); | ||||
| } | ||||
| 
 | ||||
| @ -297,6 +301,7 @@ function write_ct(ct, opts)/*:string*/ { | ||||
| 	f3('vba'); | ||||
| 	f3('comments'); | ||||
| 	f3('drawings'); | ||||
| 	f2('metadata'); | ||||
| 	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
| } | ||||
|  | ||||
							
								
								
									
										151
									
								
								bits/51_xlmeta.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										151
									
								
								bits/51_xlmeta.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,151 @@ | ||||
| RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; | ||||
| function parse_xlmeta_xml(data, name, opts) { | ||||
|   var out = { Types: [] }; | ||||
|   if (!data) | ||||
|     return out; | ||||
|   var pass = false; | ||||
|   data.replace(tagregex, function(x, idx) { | ||||
|     var y = parsexmltag(x); | ||||
|     switch (strip_ns(y[0])) { | ||||
|       case "<?xml": | ||||
|         break; | ||||
|       case "<metadata": | ||||
|       case "</metadata>": | ||||
|         break; | ||||
|       case "<metadataTypes": | ||||
|       case "</metadataTypes>": | ||||
|         break; | ||||
|       case "<metadataType": | ||||
|         out.Types.push({ name: y.name }); | ||||
|         break; | ||||
|       case "<futureMetadata": | ||||
|         break; | ||||
|       case "</futureMetadata>": | ||||
|         break; | ||||
|       case "<bk>": | ||||
|         break; | ||||
|       case "</bk>": | ||||
|         break; | ||||
|       case "<rc": | ||||
|         break; | ||||
|       case "</rc>": | ||||
|         break; | ||||
|       case "<cellMetadata": | ||||
|       case "</cellMetadata>": | ||||
|         break; | ||||
|       case "<valueMetadata": | ||||
|         break; | ||||
|       case "</valueMetadata>": | ||||
|         break; | ||||
|       case "<extLst": | ||||
|       case "<extLst>": | ||||
|       case "</extLst>": | ||||
|       case "<extLst/>": | ||||
|         break; | ||||
|       case "<ext": | ||||
|         pass = true; | ||||
|         break; | ||||
|       case "</ext>": | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if (!pass && opts.WTF) | ||||
|           throw new Error("unrecognized " + y[0] + " in metadata"); | ||||
|     } | ||||
|     return x; | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_xml() { | ||||
|   var o = [XML_HEADER]; | ||||
|   o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>'); | ||||
|   return o.join(""); | ||||
| } | ||||
| function parse_BrtMdtinfo(data, length) { | ||||
|   return { | ||||
|     flags: data.read_shift(4), | ||||
|     version: data.read_shift(4), | ||||
|     name: parse_XLWideString(data, length - 8) | ||||
|   }; | ||||
| } | ||||
| function write_BrtMdtinfo(data) { | ||||
|   var o = new_buf(12 + 2 * data.name.length); | ||||
|   o.write_shift(4, data.flags); | ||||
|   o.write_shift(4, data.version); | ||||
|   write_XLWideString(data.name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtMdb(mdb) { | ||||
|   var o = new_buf(4 + 8 * mdb.length); | ||||
|   o.write_shift(4, mdb.length); | ||||
|   for (var i = 0; i < mdb.length; ++i) { | ||||
|     o.write_shift(4, mdb[i][0]); | ||||
|     o.write_shift(4, mdb[i][1]); | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| function write_BrtBeginEsfmd(cnt, name) { | ||||
|   var o = new_buf(8 + 2 * name.length); | ||||
|   o.write_shift(4, cnt); | ||||
|   write_XLWideString(name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtBeginEsmdb(cnt, cm) { | ||||
|   var o = new_buf(8); | ||||
|   o.write_shift(4, cnt); | ||||
|   o.write_shift(4, cm ? 1 : 0); | ||||
|   return o; | ||||
| } | ||||
| function parse_xlmeta_bin(data, name, _opts) { | ||||
|   var out = { Types: [] }; | ||||
|   var opts = _opts || {}; | ||||
|   var state = []; | ||||
|   var pass = false; | ||||
|   recordhopper(data, function(val, R_n, RT) { | ||||
|     switch (RT) { | ||||
|       case 335: | ||||
|         out.Types.push({ name: val.name }); | ||||
|         break; | ||||
|       case 51: | ||||
|         break; | ||||
|       case 35: | ||||
|         state.push(R_n); | ||||
|         pass = true; | ||||
|         break; | ||||
|       case 36: | ||||
|         state.pop(); | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if ((R_n || "").indexOf("Begin") > 0) { | ||||
|         } else if ((R_n || "").indexOf("End") > 0) { | ||||
|         } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin") | ||||
|           throw new Error("Unexpected record " + RT + " " + R_n); | ||||
|     } | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_bin() { | ||||
|   var ba = buf_array(); | ||||
|   write_record(ba, "BrtBeginMetadata"); | ||||
|   write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1)); | ||||
|   write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({ | ||||
|     name: "XLDAPR", | ||||
|     version: 12e4, | ||||
|     flags: 3496657072 | ||||
|   })); | ||||
|   write_record(ba, "BrtEndEsmdtinfo"); | ||||
|   write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR")); | ||||
|   write_record(ba, "BrtBeginFmd"); | ||||
|   write_record(ba, "BrtFRTBegin", write_UInt32LE(514)); | ||||
|   write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0)); | ||||
|   write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1)); | ||||
|   write_record(ba, "BrtFRTEnd"); | ||||
|   write_record(ba, "BrtEndFmd"); | ||||
|   write_record(ba, "BrtEndEsfmd"); | ||||
|   write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true)); | ||||
|   write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]])); | ||||
|   write_record(ba, "BrtEndEsmdb"); | ||||
|   write_record(ba, "BrtEndMetadata"); | ||||
|   return ba.end(); | ||||
| } | ||||
| @ -870,7 +870,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks, | ||||
| 				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx]; | ||||
| 				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx); | ||||
| 				/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */ | ||||
| 				if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6); | ||||
| 				if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6); | ||||
| 				stack.push(name); | ||||
| 				break; | ||||
| 
 | ||||
|  | ||||
| @ -300,6 +300,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string | ||||
| 	} | ||||
| 	if(cell.l) ws['!links'].push([ref, cell.l]); | ||||
| 	if(cell.c) ws['!comments'].push([ref, cell.c]); | ||||
| 	if(cell.D) o.cm = 1; | ||||
| 	return writextag('c', v, o); | ||||
| } | ||||
| 
 | ||||
| @ -476,6 +477,10 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th | ||||
| 			} | ||||
| 			safe_format(p, fmtid, fillid, opts, themes, styles); | ||||
| 			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); } | ||||
| 			if(tag.cm && opts.xlmeta) { | ||||
| 				var cm = (opts.xlmeta.Types||[])[+tag.cm-1]; | ||||
| 				if(cm && cm.name == 'XLDAPR') p.D = true; | ||||
| 			} | ||||
| 			if(dense) { | ||||
| 				var _r = decode_cell(tag.r); | ||||
| 				if(!s[_r.r]) s[_r.r] = []; | ||||
|  | ||||
| @ -538,6 +538,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 
 | ||||
| 	XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal }; | ||||
| 
 | ||||
| 	var cm, vm; | ||||
| 
 | ||||
| 	recordhopper(data, function ws_parse(val, R_n, RT) { | ||||
| 		if(end) return; | ||||
| 		switch(RT) { | ||||
| @ -595,6 +597,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 					} | ||||
| 					if(!af && val.length > 3) p.f = val[3]; | ||||
| 				} | ||||
| 
 | ||||
| 				if(refguess.s.r > row.r) refguess.s.r = row.r; | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| @ -602,12 +605,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 				if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) { | ||||
| 					var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); } | ||||
| 				} | ||||
| 				if(cm) { | ||||
| 					if(cm.name == 'XLDAPR') p.D = true; | ||||
| 					cm = void 0; | ||||
| 				} | ||||
| 				if(vm) vm = void 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0001: /* 'BrtCellBlank' */ | ||||
| 			case 0x000C: /* 'BrtShortBlank' */ | ||||
| 				if(!opts.sheetStubs || pass) break; | ||||
| 				p = ({t:'z',v:undefined}/*:any*/); | ||||
| 				p = ({t:'z',v:void 0}/*:any*/); | ||||
| 				C = val[0].c == -1 ? C + 1 : val[0].c; | ||||
| 				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; } | ||||
| 				else s[encode_col(C) + rr] = p; | ||||
| @ -615,11 +623,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| 				if(refguess.e.c < C) refguess.e.c = C; | ||||
| 				if(cm) { | ||||
| 					if(cm.name == 'XLDAPR') p.D = true; | ||||
| 					cm = void 0; | ||||
| 				} | ||||
| 				if(vm) vm = void 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x00B0: /* 'BrtMergeCell' */ | ||||
| 				merges.push(val); break; | ||||
| 
 | ||||
| 			case 0x0031: { /* 'BrtCellMeta' */ | ||||
| 				cm = ((opts.xlmeta||{}).Types||[])[val-1]; | ||||
| 			} break; | ||||
| 
 | ||||
| 			case 0x01EE: /* 'BrtHLink' */ | ||||
| 				var rel = rels['!id'][val.relId]; | ||||
| 				if(rel) { | ||||
| @ -707,7 +724,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 			case 0x041A: /* 'BrtCFVO14' */ | ||||
| 			case 0x0289: /* 'BrtCellIgnoreEC' */ | ||||
| 			case 0x0451: /* 'BrtCellIgnoreEC14' */ | ||||
| 			case 0x0031: /* 'BrtCellMeta' */ | ||||
| 			case 0x024D: /* 'BrtCellSmartTagProperty' */ | ||||
| 			case 0x025F: /* 'BrtCellWatch' */ | ||||
| 			case 0x0234: /* 'BrtColor' */ | ||||
|  | ||||
| @ -52,6 +52,11 @@ function parse_xlink(data, rel, name/*:string*/, opts) { | ||||
| 	return parse_xlink_xml((data/*:any*/), rel, name, opts); | ||||
| } | ||||
| 
 | ||||
| function parse_xlmeta(data, name/*:string*/, opts) { | ||||
| 	if(name.slice(-4)===".bin") return parse_xlmeta_bin((data/*:any*/), name, opts); | ||||
| 	return parse_xlmeta_xml((data/*:any*/), name, opts); | ||||
| } | ||||
| 
 | ||||
| function write_wb(wb, name/*:string*/, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts); | ||||
| } | ||||
| @ -81,3 +86,7 @@ function write_cc(data, name:string, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts); | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| function write_xlmeta(name/*:string*/) { | ||||
| 	return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)(); | ||||
| } | ||||
|  | ||||
| @ -48,7 +48,7 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x002E/*::]*/: { n:"BrtBorder", f:parse_BrtBorder }, | ||||
| 	/*::[*/0x002F/*::]*/: { n:"BrtXF", f:parse_BrtXF }, | ||||
| 	/*::[*/0x0030/*::]*/: { n:"BrtStyle" }, | ||||
| 	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta" }, | ||||
| 	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta", f:parse_Int32LE }, | ||||
| 	/*::[*/0x0032/*::]*/: { n:"BrtValueMeta" }, | ||||
| 	/*::[*/0x0033/*::]*/: { n:"BrtMdb" }, | ||||
| 	/*::[*/0x0034/*::]*/: { n:"BrtBeginFmd" }, | ||||
| @ -274,7 +274,7 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x014C/*::]*/: { n:"BrtBeginMetadata" }, | ||||
| 	/*::[*/0x014D/*::]*/: { n:"BrtEndMetadata" }, | ||||
| 	/*::[*/0x014E/*::]*/: { n:"BrtBeginEsmdtinfo" }, | ||||
| 	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo" }, | ||||
| 	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo", f:parse_BrtMdtinfo }, | ||||
| 	/*::[*/0x0150/*::]*/: { n:"BrtEndEsmdtinfo" }, | ||||
| 	/*::[*/0x0151/*::]*/: { n:"BrtBeginEsmdb" }, | ||||
| 	/*::[*/0x0152/*::]*/: { n:"BrtEndEsmdb" }, | ||||
| @ -795,7 +795,7 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x0835/*::]*/: { n:"BrtEndTimelineStyleElements" }, | ||||
| 	/*::[*/0x0836/*::]*/: { n:"BrtDxf15" }, | ||||
| 	/*::[*/0x0837/*::]*/: { n:"BrtBeginDxfs15" }, | ||||
| 	/*::[*/0x0838/*::]*/: { n:"brtEndDxfs15" }, | ||||
| 	/*::[*/0x0838/*::]*/: { n:"BrtEndDxfs15" }, | ||||
| 	/*::[*/0x0839/*::]*/: { n:"BrtSlicerCacheHideItemsWithNoData" }, | ||||
| 	/*::[*/0x083A/*::]*/: { n:"BrtBeginItemUniqueNames" }, | ||||
| 	/*::[*/0x083B/*::]*/: { n:"BrtEndItemUniqueNames" }, | ||||
| @ -835,9 +835,27 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x085D/*::]*/: { n:"BrtModelTimeGroupingCalcCol" }, | ||||
| 	/*::[*/0x0C00/*::]*/: { n:"BrtUid" }, | ||||
| 	/*::[*/0x0C01/*::]*/: { n:"BrtRevisionPtr" }, | ||||
| 	/*::[*/0x13e7/*::]*/: { n:"BrtBeginCalcFeatures" }, | ||||
| 	/*::[*/0x13e8/*::]*/: { n:"BrtEndCalcFeatures" }, | ||||
| 	/*::[*/0x13e9/*::]*/: { n:"BrtCalcFeature" }, | ||||
| 	/*::[*/0x1000/*::]*/: { n:"BrtBeginDynamicArrayPr" }, | ||||
| 	/*::[*/0x1001/*::]*/: { n:"BrtEndDynamicArrayPr" }, | ||||
| 	/*::[*/0x138A/*::]*/: { n:"BrtBeginRichValueBlock" }, | ||||
| 	/*::[*/0x138B/*::]*/: { n:"BrtEndRichValueBlock" }, | ||||
| 	/*::[*/0x13D9/*::]*/: { n:"BrtBeginRichFilters" }, | ||||
| 	/*::[*/0x13DA/*::]*/: { n:"BrtEndRichFilters" }, | ||||
| 	/*::[*/0x13DB/*::]*/: { n:"BrtRichFilter" }, | ||||
| 	/*::[*/0x13DC/*::]*/: { n:"BrtBeginRichFilterColumn" }, | ||||
| 	/*::[*/0x13DD/*::]*/: { n:"BrtEndRichFilterColumn" }, | ||||
| 	/*::[*/0x13DE/*::]*/: { n:"BrtBeginCustomRichFilters" }, | ||||
| 	/*::[*/0x13DF/*::]*/: { n:"BrtEndCustomRichFilters" }, | ||||
| 	/*::[*/0x13E0/*::]*/: { n:"BrtCustomRichFilter" }, | ||||
| 	/*::[*/0x13E1/*::]*/: { n:"BrtTop10RichFilter" }, | ||||
| 	/*::[*/0x13E2/*::]*/: { n:"BrtDynamicRichFilter" }, | ||||
| 	/*::[*/0x13E4/*::]*/: { n:"BrtBeginRichSortCondition" }, | ||||
| 	/*::[*/0x13E5/*::]*/: { n:"BrtEndRichSortCondition" }, | ||||
| 	/*::[*/0x13E6/*::]*/: { n:"BrtRichFilterDateGroupItem" }, | ||||
| 	/*::[*/0x13E7/*::]*/: { n:"BrtBeginCalcFeatures" }, | ||||
| 	/*::[*/0x13E8/*::]*/: { n:"BrtEndCalcFeatures" }, | ||||
| 	/*::[*/0x13E9/*::]*/: { n:"BrtCalcFeature" }, | ||||
| 	/*::[*/0x13EB/*::]*/: { n:"BrtExternalLinksPr" }, | ||||
| 	/*::[*/0xFFFF/*::]*/: { n:"" } | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -161,9 +161,16 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	var wbrelsi = dir.workbooks[0].lastIndexOf("/"); | ||||
| 	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,""); | ||||
| 	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels'; | ||||
| 	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile); | ||||
| 	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s")); | ||||
| 
 | ||||
| 	if((dir.metadata || []).length >= 1) { | ||||
| 		/* TODO: MDX and other types of metadata */ | ||||
| 		opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts); | ||||
| 	} | ||||
| 
 | ||||
| 	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets); | ||||
| 
 | ||||
| 
 | ||||
| 	/* Numbers iOS hack */ | ||||
| 	var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0; | ||||
| 	wsloop: for(i = 0; i != props.Worksheets; ++i) { | ||||
|  | ||||
| @ -124,6 +124,11 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/metadata." + wbext; | ||||
| 	zip_add_file(zip, f, write_xlmeta(f)); | ||||
| 	ct.metadata.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); | ||||
| 
 | ||||
| 	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
| @ -132,7 +137,7 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	return zip; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* this version does not reference XLSB write functions */ | ||||
| function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	_shapeid = 1024; | ||||
| 	if(wb && !wb.SSF) { | ||||
| @ -254,6 +259,11 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/metadata." + wbext; | ||||
| 	zip_add_file(zip, f, write_xlmeta_xml()); | ||||
| 	ct.metadata.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); | ||||
| 
 | ||||
| 	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
|  | ||||
| @ -45,14 +45,15 @@ function write_zip_typeXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ { | ||||
| } | ||||
| function write_zip_denouement(z/*:any*/, o/*:?WriteOpts*/)/*:any*/ { | ||||
| 	var oopts = {}; | ||||
| 	var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string"); | ||||
| 	if(o.compression) oopts.compression = 'DEFLATE'; | ||||
| 	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string"; | ||||
| 	if(o.password) oopts.type = ftype; | ||||
| 	else switch(o.type) { | ||||
| 		case "base64": oopts.type = "base64"; break; | ||||
| 		case "binary": oopts.type = "string"; break; | ||||
| 		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files"); | ||||
| 		case "buffer": | ||||
| 		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break; | ||||
| 		case "file": oopts.type = ftype; break; | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: /*::(*/{"nodebuffer": "buffer", "string": "binary"}/*:: :any)*/[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts); | ||||
|  | ||||
| @ -98,7 +98,7 @@ utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?stri | ||||
| }; | ||||
| 
 | ||||
| /* set array formula and flush related cells */ | ||||
| utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/) { | ||||
| utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/, dynamic/*:boolean*/) { | ||||
| 	var rng = typeof range != "string" ? range : safe_decode_range(range); | ||||
| 	var rngstr = typeof range == "string" ? range : encode_range(range); | ||||
| 	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) { | ||||
| @ -106,7 +106,10 @@ utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:stri | ||||
| 		cell.t = 'n'; | ||||
| 		cell.F = rngstr; | ||||
| 		delete cell.v; | ||||
| 		if(R == rng.s.r && C == rng.s.c) cell.f = formula; | ||||
| 		if(R == rng.s.r && C == rng.s.c) { | ||||
| 			cell.f = formula; | ||||
| 			if(dynamic) cell.D = true; | ||||
| 		} | ||||
| 	} | ||||
| 	return ws; | ||||
| }; | ||||
|  | ||||
| @ -169,8 +169,8 @@ curl -X GET http://localhost:7262/?f=sheetjs.xlsb | ||||
| 
 | ||||
| [NestJS](https://nestjs.com/) is a Node.js framework for server-side web applications. | ||||
| 
 | ||||
| This demo uses SheetJS to injest a spreadsheet via a POST API endpoint. The file | ||||
| arrive to the endpoint as body `form-data`, accessible using the `file` key. | ||||
| This demo uses SheetJS to parse a spreadsheet via a POST API endpoint. The file | ||||
| arrives to the endpoint as body `form-data`, accessible using the `file` key. | ||||
| After parsing the file, CSV contents of the first worksheet will be returned. | ||||
| [Body parsing uses `multer`](https://docs.nestjs.com/techniques/file-upload). | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										30
									
								
								dist/xlsx.core.min.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										30
									
								
								dist/xlsx.core.min.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/xlsx.core.min.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/xlsx.core.min.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										322
									
								
								dist/xlsx.extendscript.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										322
									
								
								dist/xlsx.extendscript.js
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -160,7 +160,7 @@ var DO_NOT_EXPORT_CODEPAGE = true; | ||||
| /*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */ | ||||
| var XLSX = {}; | ||||
| function make_xlsx_lib(XLSX){ | ||||
| XLSX.version = '0.18.2'; | ||||
| XLSX.version = '0.18.3'; | ||||
| var current_codepage = 1200, current_ansi = 1252; | ||||
| /*global cptable:true, window */ | ||||
| if(typeof module !== "undefined" && typeof require !== 'undefined') { | ||||
| @ -288,7 +288,7 @@ var Base64 = function() { | ||||
|     } | ||||
|   }; | ||||
| }(); | ||||
| var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node); | ||||
| var has_buf = (typeof Buffer !== 'undefined' && typeof undefined !== 'undefined' && typeof ({}) !== 'undefined' && !!({}).node); | ||||
| 
 | ||||
| var Buffer_from = function(){}; | ||||
| 
 | ||||
| @ -1640,7 +1640,7 @@ function parse_extra_field(blob) { | ||||
| 	return o; | ||||
| } | ||||
| var fs; | ||||
| function get_fs() { return fs || (fs = require('fs')); } | ||||
| function get_fs() { return fs || (fs = undefined); } | ||||
| function parse(file, options) { | ||||
| if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options); | ||||
| if((file[0] | 0x20) == 0x6d && (file[1]|0x20) == 0x69) return parse_mad(file, options); | ||||
| @ -3256,7 +3256,7 @@ return exports; | ||||
| 
 | ||||
| if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; } | ||||
| var _fs; | ||||
| if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {} | ||||
| if(typeof require !== 'undefined') try { _fs = undefined; } catch(e) {} | ||||
| 
 | ||||
| /* normalize data for blob ctor */ | ||||
| function blobify(data) { | ||||
| @ -3270,7 +3270,7 @@ function write_dl(fname, payload, enc) { | ||||
| 	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload); | ||||
| 	if(typeof Deno !== 'undefined') { | ||||
| 		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */ | ||||
| 		if(enc) switch(enc) { | ||||
| 		if(enc && typeof payload == "string") switch(enc) { | ||||
| 			case "utf8": payload = new TextEncoder(enc).encode(payload); break; | ||||
| 			case "binary": payload = s2ab(payload); break; | ||||
| 			/* TODO: binary equivalent */ | ||||
| @ -4213,43 +4213,6 @@ function encode_range_xls(r, opts) { | ||||
| 	} | ||||
| 	return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff); | ||||
| } | ||||
| var OFFCRYPTO = {}; | ||||
| 
 | ||||
| var make_offcrypto = function(O, _crypto) { | ||||
| 	var crypto; | ||||
| 	if(typeof _crypto !== 'undefined') crypto = _crypto; | ||||
| 	else if(typeof require !== 'undefined') { | ||||
| 		try { crypto = undefined; } | ||||
| 		catch(e) { crypto = null; } | ||||
| 	} | ||||
| 
 | ||||
| 	O.rc4 = function(key, data) { | ||||
| 		var S = new Array(256); | ||||
| 		var c = 0, i = 0, j = 0, t = 0; | ||||
| 		for(i = 0; i != 256; ++i) S[i] = i; | ||||
| 		for(i = 0; i != 256; ++i) { | ||||
| 			j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255; | ||||
| 			t = S[i]; S[i] = S[j]; S[j] = t; | ||||
| 		} | ||||
| 		// $FlowIgnore
 | ||||
| 		i = j = 0; var out = new_raw_buf(data.length); | ||||
| 		for(c = 0; c != data.length; ++c) { | ||||
| 			i = (i + 1)&255; | ||||
| 			j = (j + S[i])%256; | ||||
| 			t = S[i]; S[i] = S[j]; S[j] = t; | ||||
| 			out[c] = (data[c] ^ S[(S[i]+S[j])&255]); | ||||
| 		} | ||||
| 		return out; | ||||
| 	}; | ||||
| 
 | ||||
| 	O.md5 = function(hex) { | ||||
| 		if(!crypto) throw new Error("Unsupported crypto"); | ||||
| 		return crypto.createHash('md5').update(hex).digest('hex'); | ||||
| 	}; | ||||
| }; | ||||
| /*global crypto:true */ | ||||
| make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined); | ||||
| 
 | ||||
| function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; } | ||||
| function encode_row(row) { return "" + (row + 1); } | ||||
| function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); } | ||||
| @ -4414,6 +4377,9 @@ function sheet_add_aoa(_ws, data, opts) { | ||||
| } | ||||
| function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); } | ||||
| 
 | ||||
| function parse_Int32LE(data) { | ||||
| 	return data.read_shift(4, 'i'); | ||||
| } | ||||
| function write_UInt32LE(x, o) { | ||||
| 	if (!o) o = new_buf(4); | ||||
| 	o.write_shift(4, x); | ||||
| @ -5079,8 +5045,8 @@ var ct2type/*{[string]:string}*/ = ({ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links", | ||||
| 
 | ||||
| 	/* Metadata */ | ||||
| 	"application/vnd.ms-excel.sheetMetadata": "TODO", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO", | ||||
| 	"application/vnd.ms-excel.sheetMetadata": "metadata", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata", | ||||
| 
 | ||||
| 	/* PivotCache */ | ||||
| 	"application/vnd.ms-excel.pivotCacheDefinition": "TODO", | ||||
| @ -5197,6 +5163,10 @@ var CT_LIST = (function(){ | ||||
| 			xlsx: "application/vnd.ms-excel.macrosheet+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.macrosheet" | ||||
| 		}, | ||||
| 		metadata: { /* Metadata (Stock/Geography and Dynamic Array) */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.sheetMetadata" | ||||
| 		}, | ||||
| 		styles: { /* Styles */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.styles" | ||||
| @ -5216,7 +5186,7 @@ function new_ct() { | ||||
| 		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[], | ||||
| 		rels:[], strs:[], comments:[], links:[], | ||||
| 		coreprops:[], extprops:[], custprops:[], themes:[], styles:[], | ||||
| 		calcchains:[], vba: [], drawings: [], | ||||
| 		calcchains:[], vba: [], drawings: [], metadata: [], | ||||
| 		TODO:[], xmlns: "" }); | ||||
| } | ||||
| 
 | ||||
| @ -5315,6 +5285,7 @@ function write_ct(ct, opts) { | ||||
| 	f3('vba'); | ||||
| 	f3('comments'); | ||||
| 	f3('drawings'); | ||||
| 	f2('metadata'); | ||||
| 	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
| } | ||||
| @ -5381,7 +5352,9 @@ var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS]; | ||||
| function add_rels(rels, rId, f, type, relobj, targetmode) { | ||||
| 	if(!relobj) relobj = {}; | ||||
| 	if(!rels['!id']) rels['!id'] = {}; | ||||
| 	if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */} | ||||
| 	if(!rels['!idx']) rels['!idx'] = 1; | ||||
| 	if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */} | ||||
| 	rels['!idx'] = rId + 1; | ||||
| 	relobj.Id = 'rId' + rId; | ||||
| 	relobj.Type = type; | ||||
| 	relobj.Target = f; | ||||
| @ -11365,6 +11338,157 @@ function update_xfext(xf, xfext) { | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; | ||||
| function parse_xlmeta_xml(data, name, opts) { | ||||
|   var out = { Types: [] }; | ||||
|   if (!data) | ||||
|     return out; | ||||
|   var pass = false; | ||||
|   data.replace(tagregex, function(x, idx) { | ||||
|     var y = parsexmltag(x); | ||||
|     switch (strip_ns(y[0])) { | ||||
|       case "<?xml": | ||||
|         break; | ||||
|       case "<metadata": | ||||
|       case "</metadata>": | ||||
|         break; | ||||
|       case "<metadataTypes": | ||||
|       case "</metadataTypes>": | ||||
|         break; | ||||
|       case "<metadataType": | ||||
|         out.Types.push({ name: y.name }); | ||||
|         break; | ||||
|       case "<futureMetadata": | ||||
|         break; | ||||
|       case "</futureMetadata>": | ||||
|         break; | ||||
|       case "<bk>": | ||||
|         break; | ||||
|       case "</bk>": | ||||
|         break; | ||||
|       case "<rc": | ||||
|         break; | ||||
|       case "</rc>": | ||||
|         break; | ||||
|       case "<cellMetadata": | ||||
|       case "</cellMetadata>": | ||||
|         break; | ||||
|       case "<valueMetadata": | ||||
|         break; | ||||
|       case "</valueMetadata>": | ||||
|         break; | ||||
|       case "<extLst": | ||||
|       case "<extLst>": | ||||
|       case "</extLst>": | ||||
|       case "<extLst/>": | ||||
|         break; | ||||
|       case "<ext": | ||||
|         pass = true; | ||||
|         break; | ||||
|       case "</ext>": | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if (!pass && opts.WTF) | ||||
|           throw new Error("unrecognized " + y[0] + " in metadata"); | ||||
|     } | ||||
|     return x; | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_xml() { | ||||
|   var o = [XML_HEADER]; | ||||
|   o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>'); | ||||
|   return o.join(""); | ||||
| } | ||||
| function parse_BrtMdtinfo(data, length) { | ||||
|   return { | ||||
|     flags: data.read_shift(4), | ||||
|     version: data.read_shift(4), | ||||
|     name: parse_XLWideString(data, length - 8) | ||||
|   }; | ||||
| } | ||||
| function write_BrtMdtinfo(data) { | ||||
|   var o = new_buf(12 + 2 * data.name.length); | ||||
|   o.write_shift(4, data.flags); | ||||
|   o.write_shift(4, data.version); | ||||
|   write_XLWideString(data.name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtMdb(mdb) { | ||||
|   var o = new_buf(4 + 8 * mdb.length); | ||||
|   o.write_shift(4, mdb.length); | ||||
|   for (var i = 0; i < mdb.length; ++i) { | ||||
|     o.write_shift(4, mdb[i][0]); | ||||
|     o.write_shift(4, mdb[i][1]); | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| function write_BrtBeginEsfmd(cnt, name) { | ||||
|   var o = new_buf(8 + 2 * name.length); | ||||
|   o.write_shift(4, cnt); | ||||
|   write_XLWideString(name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtBeginEsmdb(cnt, cm) { | ||||
|   var o = new_buf(8); | ||||
|   o.write_shift(4, cnt); | ||||
|   o.write_shift(4, cm ? 1 : 0); | ||||
|   return o; | ||||
| } | ||||
| function parse_xlmeta_bin(data, name, _opts) { | ||||
|   var out = { Types: [] }; | ||||
|   var opts = _opts || {}; | ||||
|   var state = []; | ||||
|   var pass = false; | ||||
|   recordhopper(data, function(val, R_n, RT) { | ||||
|     switch (RT) { | ||||
|       case 335: | ||||
|         out.Types.push({ name: val.name }); | ||||
|         break; | ||||
|       case 51: | ||||
|         break; | ||||
|       case 35: | ||||
|         state.push(R_n); | ||||
|         pass = true; | ||||
|         break; | ||||
|       case 36: | ||||
|         state.pop(); | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if ((R_n || "").indexOf("Begin") > 0) { | ||||
|         } else if ((R_n || "").indexOf("End") > 0) { | ||||
|         } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin") | ||||
|           throw new Error("Unexpected record " + RT + " " + R_n); | ||||
|     } | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_bin() { | ||||
|   var ba = buf_array(); | ||||
|   write_record(ba, "BrtBeginMetadata"); | ||||
|   write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1)); | ||||
|   write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({ | ||||
|     name: "XLDAPR", | ||||
|     version: 12e4, | ||||
|     flags: 3496657072 | ||||
|   })); | ||||
|   write_record(ba, "BrtEndEsmdtinfo"); | ||||
|   write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR")); | ||||
|   write_record(ba, "BrtBeginFmd"); | ||||
|   write_record(ba, "BrtFRTBegin", write_UInt32LE(514)); | ||||
|   write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0)); | ||||
|   write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1)); | ||||
|   write_record(ba, "BrtFRTEnd"); | ||||
|   write_record(ba, "BrtEndFmd"); | ||||
|   write_record(ba, "BrtEndEsfmd"); | ||||
|   write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true)); | ||||
|   write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]])); | ||||
|   write_record(ba, "BrtEndEsmdb"); | ||||
|   write_record(ba, "BrtEndMetadata"); | ||||
|   return ba.end(); | ||||
| } | ||||
| /* 18.6 Calculation Chain */ | ||||
| function parse_cc_xml(data) { | ||||
| 	var d = []; | ||||
| @ -12690,7 +12814,7 @@ ixti = f[1][1]; r = f[1][2]; | ||||
| 				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx]; | ||||
| 				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx); | ||||
| 				/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */ | ||||
| 				if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6); | ||||
| 				if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6); | ||||
| 				stack.push(name); | ||||
| 				break; | ||||
| 
 | ||||
| @ -14588,6 +14712,7 @@ function write_ws_xml_cell(cell, ref, ws, opts) { | ||||
| 	} | ||||
| 	if(cell.l) ws['!links'].push([ref, cell.l]); | ||||
| 	if(cell.c) ws['!comments'].push([ref, cell.c]); | ||||
| 	if(cell.D) o.cm = 1; | ||||
| 	return writextag('c', v, o); | ||||
| } | ||||
| 
 | ||||
| @ -14764,6 +14889,10 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) { | ||||
| 			} | ||||
| 			safe_format(p, fmtid, fillid, opts, themes, styles); | ||||
| 			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); } | ||||
| 			if(tag.cm && opts.xlmeta) { | ||||
| 				var cm = (opts.xlmeta.Types||[])[+tag.cm-1]; | ||||
| 				if(cm && cm.name == 'XLDAPR') p.D = true; | ||||
| 			} | ||||
| 			if(dense) { | ||||
| 				var _r = decode_cell(tag.r); | ||||
| 				if(!s[_r.r]) s[_r.r] = []; | ||||
| @ -14846,7 +14975,7 @@ function write_ws_xml(idx, opts, wb, rels) { | ||||
| 
 | ||||
| 	o[o.length] = write_ws_xml_sheetviews(ws, opts, idx, wb); | ||||
| 
 | ||||
| 	/* TODO: store in WB, process styles */ | ||||
| 	/* TODO: store in WB, undefined styles */ | ||||
| 	if(opts.sheetFormat) o[o.length] = (writextag('sheetFormatPr', null, { | ||||
| 		defaultRowHeight:opts.sheetFormat.defaultRowHeight||'16', | ||||
| 		baseColWidth:opts.sheetFormat.baseColWidth||'10', | ||||
| @ -15477,6 +15606,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) { | ||||
| 
 | ||||
| 	XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal }; | ||||
| 
 | ||||
| 	var cm, vm; | ||||
| 
 | ||||
| 	recordhopper(data, function ws_parse(val, R_n, RT) { | ||||
| 		if(end) return; | ||||
| 		switch(RT) { | ||||
| @ -15534,6 +15665,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) { | ||||
| 					} | ||||
| 					if(!af && val.length > 3) p.f = val[3]; | ||||
| 				} | ||||
| 
 | ||||
| 				if(refguess.s.r > row.r) refguess.s.r = row.r; | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| @ -15541,12 +15673,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) { | ||||
| 				if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) { | ||||
| 					var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); } | ||||
| 				} | ||||
| 				if(cm) { | ||||
| 					if(cm.name == 'XLDAPR') p.D = true; | ||||
| 					cm = void 0; | ||||
| 				} | ||||
| 				if(vm) vm = void 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0001: /* 'BrtCellBlank' */ | ||||
| 			case 0x000C: /* 'BrtShortBlank' */ | ||||
| 				if(!opts.sheetStubs || pass) break; | ||||
| 				p = ({t:'z',v:undefined}); | ||||
| 				p = ({t:'z',v:void 0}); | ||||
| 				C = val[0].c == -1 ? C + 1 : val[0].c; | ||||
| 				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; } | ||||
| 				else s[encode_col(C) + rr] = p; | ||||
| @ -15554,11 +15691,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) { | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| 				if(refguess.e.c < C) refguess.e.c = C; | ||||
| 				if(cm) { | ||||
| 					if(cm.name == 'XLDAPR') p.D = true; | ||||
| 					cm = void 0; | ||||
| 				} | ||||
| 				if(vm) vm = void 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x00B0: /* 'BrtMergeCell' */ | ||||
| 				merges.push(val); break; | ||||
| 
 | ||||
| 			case 0x0031: { /* 'BrtCellMeta' */ | ||||
| 				cm = ((opts.xlmeta||{}).Types||[])[val-1]; | ||||
| 			} break; | ||||
| 
 | ||||
| 			case 0x01EE: /* 'BrtHLink' */ | ||||
| 				var rel = rels['!id'][val.relId]; | ||||
| 				if(rel) { | ||||
| @ -15646,7 +15792,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) { | ||||
| 			case 0x041A: /* 'BrtCFVO14' */ | ||||
| 			case 0x0289: /* 'BrtCellIgnoreEC' */ | ||||
| 			case 0x0451: /* 'BrtCellIgnoreEC14' */ | ||||
| 			case 0x0031: /* 'BrtCellMeta' */ | ||||
| 			case 0x024D: /* 'BrtCellSmartTagProperty' */ | ||||
| 			case 0x025F: /* 'BrtCellWatch' */ | ||||
| 			case 0x0234: /* 'BrtColor' */ | ||||
| @ -16851,6 +16996,11 @@ function parse_xlink(data, rel, name, opts) { | ||||
| 	return parse_xlink_xml((data), rel, name, opts); | ||||
| } | ||||
| 
 | ||||
| function parse_xlmeta(data, name, opts) { | ||||
| 	if(name.slice(-4)===".bin") return parse_xlmeta_bin((data), name, opts); | ||||
| 	return parse_xlmeta_xml((data), name, opts); | ||||
| } | ||||
| 
 | ||||
| function write_wb(wb, name, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts); | ||||
| } | ||||
| @ -16880,6 +17030,10 @@ function write_cc(data, name:string, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts); | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| function write_xlmeta(name) { | ||||
| 	return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)(); | ||||
| } | ||||
| var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g; | ||||
| var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/; | ||||
| function xlml_parsexmltag(tag, skip_root) { | ||||
| @ -18294,7 +18448,7 @@ function parse_workbook(blob, options) { | ||||
| 	var last_Rn = ''; | ||||
| 	var file_depth = 0; /* TODO: make a real stack */ | ||||
| 	var BIFF2Fmt = 0, BIFF2FmtTable = []; | ||||
| 	var FilterDatabases = []; /* TODO: sort out supbooks and process elsewhere */ | ||||
| 	var FilterDatabases = []; /* TODO: sort out supbooks and undefined elsewhere */ | ||||
| 	var last_lbl; | ||||
| 
 | ||||
| 	/* explicit override for some broken writers */ | ||||
| @ -19136,7 +19290,7 @@ var XLSBRecordEnum = { | ||||
| 0x002E: { n:"BrtBorder", f:parse_BrtBorder }, | ||||
| 0x002F: { n:"BrtXF", f:parse_BrtXF }, | ||||
| 0x0030: { n:"BrtStyle" }, | ||||
| 0x0031: { n:"BrtCellMeta" }, | ||||
| 0x0031: { n:"BrtCellMeta", f:parse_Int32LE }, | ||||
| 0x0032: { n:"BrtValueMeta" }, | ||||
| 0x0033: { n:"BrtMdb" }, | ||||
| 0x0034: { n:"BrtBeginFmd" }, | ||||
| @ -19362,7 +19516,7 @@ var XLSBRecordEnum = { | ||||
| 0x014C: { n:"BrtBeginMetadata" }, | ||||
| 0x014D: { n:"BrtEndMetadata" }, | ||||
| 0x014E: { n:"BrtBeginEsmdtinfo" }, | ||||
| 0x014F: { n:"BrtMdtinfo" }, | ||||
| 0x014F: { n:"BrtMdtinfo", f:parse_BrtMdtinfo }, | ||||
| 0x0150: { n:"BrtEndEsmdtinfo" }, | ||||
| 0x0151: { n:"BrtBeginEsmdb" }, | ||||
| 0x0152: { n:"BrtEndEsmdb" }, | ||||
| @ -19883,7 +20037,7 @@ var XLSBRecordEnum = { | ||||
| 0x0835: { n:"BrtEndTimelineStyleElements" }, | ||||
| 0x0836: { n:"BrtDxf15" }, | ||||
| 0x0837: { n:"BrtBeginDxfs15" }, | ||||
| 0x0838: { n:"brtEndDxfs15" }, | ||||
| 0x0838: { n:"BrtEndDxfs15" }, | ||||
| 0x0839: { n:"BrtSlicerCacheHideItemsWithNoData" }, | ||||
| 0x083A: { n:"BrtBeginItemUniqueNames" }, | ||||
| 0x083B: { n:"BrtEndItemUniqueNames" }, | ||||
| @ -19923,9 +20077,27 @@ var XLSBRecordEnum = { | ||||
| 0x085D: { n:"BrtModelTimeGroupingCalcCol" }, | ||||
| 0x0C00: { n:"BrtUid" }, | ||||
| 0x0C01: { n:"BrtRevisionPtr" }, | ||||
| 0x13e7: { n:"BrtBeginCalcFeatures" }, | ||||
| 0x13e8: { n:"BrtEndCalcFeatures" }, | ||||
| 0x13e9: { n:"BrtCalcFeature" }, | ||||
| 0x1000: { n:"BrtBeginDynamicArrayPr" }, | ||||
| 0x1001: { n:"BrtEndDynamicArrayPr" }, | ||||
| 0x138A: { n:"BrtBeginRichValueBlock" }, | ||||
| 0x138B: { n:"BrtEndRichValueBlock" }, | ||||
| 0x13D9: { n:"BrtBeginRichFilters" }, | ||||
| 0x13DA: { n:"BrtEndRichFilters" }, | ||||
| 0x13DB: { n:"BrtRichFilter" }, | ||||
| 0x13DC: { n:"BrtBeginRichFilterColumn" }, | ||||
| 0x13DD: { n:"BrtEndRichFilterColumn" }, | ||||
| 0x13DE: { n:"BrtBeginCustomRichFilters" }, | ||||
| 0x13DF: { n:"BrtEndCustomRichFilters" }, | ||||
| 0x13E0: { n:"BrtCustomRichFilter" }, | ||||
| 0x13E1: { n:"BrtTop10RichFilter" }, | ||||
| 0x13E2: { n:"BrtDynamicRichFilter" }, | ||||
| 0x13E4: { n:"BrtBeginRichSortCondition" }, | ||||
| 0x13E5: { n:"BrtEndRichSortCondition" }, | ||||
| 0x13E6: { n:"BrtRichFilterDateGroupItem" }, | ||||
| 0x13E7: { n:"BrtBeginCalcFeatures" }, | ||||
| 0x13E8: { n:"BrtEndCalcFeatures" }, | ||||
| 0x13E9: { n:"BrtCalcFeature" }, | ||||
| 0x13EB: { n:"BrtExternalLinksPr" }, | ||||
| 0xFFFF: { n:"" } | ||||
| }; | ||||
| 
 | ||||
| @ -20992,7 +21164,7 @@ function sheet_add_dom(ws, table, _opts) { | ||||
| 			} | ||||
| 			if(o.z === undefined && z != null) o.z = z; | ||||
| 			/* The first link is used.  Links are assumed to be fully specified. | ||||
| 			 * TODO: The right way to process relative links is to make a new <a> */ | ||||
| 			 * TODO: The right way to undefined relative links is to make a new <a> */ | ||||
| 			var l = "", Aelts = elt.getElementsByTagName("A"); | ||||
| 			if(Aelts && Aelts.length) for(var Aelti = 0; Aelti < Aelts.length; ++Aelti)	if(Aelts[Aelti].hasAttribute("href")) { | ||||
| 				l = Aelts[Aelti].getAttribute("href"); if(l.charAt(0) != "#") break; | ||||
| @ -22778,9 +22950,16 @@ function parse_zip(zip, opts) { | ||||
| 	var wbrelsi = dir.workbooks[0].lastIndexOf("/"); | ||||
| 	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,""); | ||||
| 	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels'; | ||||
| 	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile); | ||||
| 	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s")); | ||||
| 
 | ||||
| 	if((dir.metadata || []).length >= 1) { | ||||
| 		/* TODO: MDX and other types of metadata */ | ||||
| 		opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts); | ||||
| 	} | ||||
| 
 | ||||
| 	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets); | ||||
| 
 | ||||
| 
 | ||||
| 	/* Numbers iOS hack */ | ||||
| 	var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0; | ||||
| 	wsloop: for(i = 0; i != props.Worksheets; ++i) { | ||||
| @ -23013,6 +23192,11 @@ f = "docProps/app.xml"; | ||||
| 		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/metadata." + wbext; | ||||
| 	zip_add_file(zip, f, write_xlmeta(f)); | ||||
| 	ct.metadata.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); | ||||
| 
 | ||||
| 	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
| @ -23021,7 +23205,7 @@ f = "docProps/app.xml"; | ||||
| 	return zip; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* this version does not reference XLSB write functions */ | ||||
| function write_zip_xlsx(wb, opts) { | ||||
| 	_shapeid = 1024; | ||||
| 	if(wb && !wb.SSF) { | ||||
| @ -23142,6 +23326,11 @@ f = "docProps/app.xml"; | ||||
| 		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/metadata." + wbext; | ||||
| 	zip_add_file(zip, f, write_xlmeta_xml()); | ||||
| 	ct.metadata.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); | ||||
| 
 | ||||
| 	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
| @ -23195,6 +23384,7 @@ function read_plaintext_raw(data, o) { | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str); | ||||
| 	o.type = "binary"; | ||||
| 	return read_plaintext(str, o); | ||||
| } | ||||
| 
 | ||||
| @ -23313,14 +23503,15 @@ function write_zip_typeXLSX(wb, opts) { | ||||
| } | ||||
| function write_zip_denouement(z, o) { | ||||
| 	var oopts = {}; | ||||
| 	var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string"); | ||||
| 	if(o.compression) oopts.compression = 'DEFLATE'; | ||||
| 	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string"; | ||||
| 	if(o.password) oopts.type = ftype; | ||||
| 	else switch(o.type) { | ||||
| 		case "base64": oopts.type = "base64"; break; | ||||
| 		case "binary": oopts.type = "string"; break; | ||||
| 		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files"); | ||||
| 		case "buffer": | ||||
| 		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break; | ||||
| 		case "file": oopts.type = ftype; break; | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: {"nodebuffer": "buffer", "string": "binary"}[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts); | ||||
| @ -23838,7 +24029,7 @@ utils.cell_add_comment = function(cell, text, author) { | ||||
| }; | ||||
| 
 | ||||
| /* set array formula and flush related cells */ | ||||
| utils.sheet_set_array_formula = function(ws, range, formula) { | ||||
| utils.sheet_set_array_formula = function(ws, range, formula, dynamic) { | ||||
| 	var rng = typeof range != "string" ? range : safe_decode_range(range); | ||||
| 	var rngstr = typeof range == "string" ? range : encode_range(range); | ||||
| 	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) { | ||||
| @ -23846,7 +24037,10 @@ utils.sheet_set_array_formula = function(ws, range, formula) { | ||||
| 		cell.t = 'n'; | ||||
| 		cell.F = rngstr; | ||||
| 		delete cell.v; | ||||
| 		if(R == rng.s.r && C == rng.s.c) cell.f = formula; | ||||
| 		if(R == rng.s.r && C == rng.s.c) { | ||||
| 			cell.f = formula; | ||||
| 			if(dynamic) cell.D = true; | ||||
| 		} | ||||
| 	} | ||||
| 	return ws; | ||||
| }; | ||||
|  | ||||
							
								
								
									
										30
									
								
								dist/xlsx.full.min.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										30
									
								
								dist/xlsx.full.min.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/xlsx.full.min.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/xlsx.full.min.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										16
									
								
								dist/xlsx.mini.min.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										16
									
								
								dist/xlsx.mini.min.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/xlsx.mini.min.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/xlsx.mini.min.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -24,9 +24,5 @@ port calculations to web apps; automate common spreadsheet tasks, and much more! | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| <details><summary><b>Diagram Legend</b> (click to show)</summary> | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
|  | ||||
| @ -38,7 +38,6 @@ The complete single-file version is generated at `dist/xlsx.full.min.js` | ||||
| 
 | ||||
| A slimmer build is generated at `dist/xlsx.mini.min.js`. Compared to full build: | ||||
| - codepage library skipped (no support for XLS encodings) | ||||
| - XLSX compression option not currently available | ||||
| - no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 / Numbers | ||||
| - node stream utils removed | ||||
| 
 | ||||
|  | ||||
| @ -48,6 +48,18 @@ and approaches for steps 1 and 5. | ||||
| 
 | ||||
| Utility functions help with step 3. | ||||
| 
 | ||||
| ["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes | ||||
| solutions for common data import scenarios. | ||||
| 
 | ||||
| ["Packaging and Releasing Data"](#packaging-and-releasing-data) describes | ||||
| solutions for common data export scenarios. | ||||
| 
 | ||||
| ["Processing Data"](#packaging-and-releasing-data) describes solutions for | ||||
| common workbook processing and manipulation scenarios. | ||||
| 
 | ||||
| ["Utility Functions"](#utility-functions) details utility functions for | ||||
| translating JSON Arrays and other common JS structures into worksheet objects. | ||||
| 
 | ||||
| ### The Zen of SheetJS | ||||
| 
 | ||||
| _Data processing should fit in any workflow_ | ||||
| @ -56,15 +68,6 @@ The library does not impose a separate lifecycle.  It fits nicely in websites | ||||
| and apps built using any framework.  The plain JS data objects play nice with | ||||
| Web Workers and future APIs. | ||||
| 
 | ||||
| ["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes | ||||
| solutions for common data import scenarios. | ||||
| 
 | ||||
| ["Writing Workbooks"](#writing-workbooks) describes solutions for common data | ||||
| export scenarios involving actual spreadsheet files. | ||||
| 
 | ||||
| ["Utility Functions"](#utility-functions) details utility functions for | ||||
| translating JSON Arrays and other common JS structures into worksheet objects. | ||||
| 
 | ||||
| _JavaScript is a powerful language for data processing_ | ||||
| 
 | ||||
| The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object | ||||
|  | ||||
| @ -40,3 +40,9 @@ The [`demos` directory](demos/) includes sample projects for: | ||||
| 
 | ||||
| Other examples are included in the [showcase](demos/showcase/). | ||||
| 
 | ||||
| <https://sheetjs.com/demos/modify.html> shows a complete example of reading, | ||||
| modifying, and writing files. | ||||
| 
 | ||||
| <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> is the command-line | ||||
| tool included with node installations, reading spreadsheet files and exporting | ||||
| the contents in various formats. | ||||
|  | ||||
| @ -440,3 +440,4 @@ const workbook = XLSX.read(data); | ||||
| </details> | ||||
| 
 | ||||
| More detailed examples are covered in the [included demos](demos/) | ||||
| 
 | ||||
|  | ||||
| @ -1,9 +1,9 @@ | ||||
| ### Processing JSON and JS Data | ||||
| 
 | ||||
| JSON and JS data tend to represent single worksheets.  This section will use a | ||||
| few utility functions to generate workbooks: | ||||
| few utility functions to generate workbooks. | ||||
| 
 | ||||
| _Create a new Worksheet_ | ||||
| _Create a new Workbook_ | ||||
| 
 | ||||
| ```js | ||||
| var workbook = XLSX.utils.book_new(); | ||||
| @ -11,16 +11,9 @@ var workbook = XLSX.utils.book_new(); | ||||
| 
 | ||||
| The `book_new` utility function creates an empty workbook with no worksheets. | ||||
| 
 | ||||
| 
 | ||||
| _Append a Worksheet to a Workbook_ | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name); | ||||
| ``` | ||||
| 
 | ||||
| The `book_append_sheet` utility function appends a worksheet to the workbook. | ||||
| The third argument specifies the desired worksheet name. Multiple worksheets can | ||||
| be added to a workbook by calling the function multiple times. | ||||
| Spreadsheet software generally require at least one worksheet and enforce the | ||||
| requirement in the user interface.  This library enforces the requirement at | ||||
| write time, throwing errors if an empty workbook is passed to write functions. | ||||
| 
 | ||||
| 
 | ||||
| **API** | ||||
| @ -33,14 +26,14 @@ var worksheet = XLSX.utils.aoa_to_sheet(aoa, opts); | ||||
| 
 | ||||
| The `aoa_to_sheet` utility function walks an "array of arrays" in row-major | ||||
| order, generating a worksheet object.  The following snippet generates a sheet | ||||
| with cell `A1` set to the string `A1`, cell `B1` set to `B2`, etc: | ||||
| with cell `A1` set to the string `A1`, cell `B1` set to `B1`, etc: | ||||
| 
 | ||||
| ```js | ||||
| var worksheet = XLSX.utils.aoa_to_sheet([ | ||||
|   ["A1", "B1", "C1"], | ||||
|   ["A2", "B2", "C2"], | ||||
|   ["A3", "B3", "C3"] | ||||
| ]) | ||||
| ]); | ||||
| ``` | ||||
| 
 | ||||
| ["Array of Arrays Input"](#array-of-arrays-input) describes the function and the | ||||
|  | ||||
| @ -1,38 +1,54 @@ | ||||
| ## Working with the Workbook | ||||
| ## Processing Data | ||||
| 
 | ||||
| The full object format is described later in this README. | ||||
| The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object | ||||
| representation of the core concepts of a workbook.  The utility functions work | ||||
| with the object representation and are intended to handle common use cases. | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Reading a specific cell </b> (click to show)</summary> | ||||
| ### Modifying Workbook Structure | ||||
| 
 | ||||
| This example extracts the value stored in cell A1 from the first worksheet: | ||||
| **API** | ||||
| 
 | ||||
| _Append a Worksheet to a Workbook_ | ||||
| 
 | ||||
| ```js | ||||
| var first_sheet_name = workbook.SheetNames[0]; | ||||
| var address_of_cell = 'A1'; | ||||
| 
 | ||||
| /* Get worksheet */ | ||||
| var worksheet = workbook.Sheets[first_sheet_name]; | ||||
| 
 | ||||
| /* Find desired cell */ | ||||
| var desired_cell = worksheet[address_of_cell]; | ||||
| 
 | ||||
| /* Get the value */ | ||||
| var desired_value = (desired_cell ? desired_cell.v : undefined); | ||||
| XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name); | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| The `book_append_sheet` utility function appends a worksheet to the workbook. | ||||
| The third argument specifies the desired worksheet name. Multiple worksheets can | ||||
| be added to a workbook by calling the function multiple times. | ||||
| 
 | ||||
| _List the Worksheet names in tab order_ | ||||
| 
 | ||||
| ```js | ||||
| var wsnames = workbook.SheetNames; | ||||
| ``` | ||||
| 
 | ||||
| The `SheetNames` property of the workbook object is a list of the worksheet | ||||
| names in "tab order".  API functions will look at this array. | ||||
| 
 | ||||
| _Replace a Worksheet in place_ | ||||
| 
 | ||||
| ```js | ||||
| workbook.Sheets[sheet_name] = new_worksheet; | ||||
| ``` | ||||
| 
 | ||||
| The `Sheets` property of the workbook object is an object whose keys are names | ||||
| and whose values are worksheet objects.  By reassigning to a property of the | ||||
| `Sheets` object, the worksheet object can be changed without disrupting the | ||||
| rest of the worksheet structure. | ||||
| 
 | ||||
| **Examples** | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Adding a new worksheet to a workbook</b> (click to show)</summary> | ||||
|   <summary><b>Add a new worksheet to a workbook</b> (click to show)</summary> | ||||
| 
 | ||||
| This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input) to make a | ||||
| sheet and `XLSX.utils.book_append_sheet` to append the sheet to the workbook: | ||||
| This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input). | ||||
| 
 | ||||
| ```js | ||||
| var ws_name = "SheetJS"; | ||||
| 
 | ||||
| /* make worksheet */ | ||||
| /* Create worksheet */ | ||||
| var ws_data = [ | ||||
|   [ "S", "h", "e", "e", "t", "J", "S" ], | ||||
|   [  1 ,  2 ,  3 ,  4 ,  5 ] | ||||
| @ -45,39 +61,58 @@ XLSX.utils.book_append_sheet(wb, ws, ws_name); | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Creating a new workbook from scratch</b> (click to show)</summary> | ||||
| ### Modifying Cell Values | ||||
| 
 | ||||
| The workbook object contains a `SheetNames` array of names and a `Sheets` object | ||||
| mapping sheet names to sheet objects. The `XLSX.utils.book_new` utility function | ||||
| creates a new workbook object: | ||||
| **API** | ||||
| 
 | ||||
| _Modify a single cell value in a worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| /* create a new blank workbook */ | ||||
| var wb = XLSX.utils.book_new(); | ||||
| XLSX.utils.sheet_add_aoa(worksheet, [[new_value]], { origin: address }); | ||||
| ``` | ||||
| 
 | ||||
| The new workbook is blank and contains no worksheets. The write functions will | ||||
| error if the workbook is empty. | ||||
| _Modify multiple cell values in a worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_add_aoa(worksheet, aoa, opts); | ||||
| ``` | ||||
| 
 | ||||
| The `sheet_add_aoa` utility function modifies cell values in a worksheet.  The | ||||
| first argument is the worksheet object.  The second argument is an array of | ||||
| arrays of values.  The `origin` key of the third argument controls where cells | ||||
| will be written.  The following snippet sets `B3=1` and `E5="abc"`: | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_add_aoa(worksheet, [ | ||||
|   [1],                             // <-- Write 1 to cell B3 | ||||
|   ,                                // <-- Do nothing in row 4 | ||||
|   [/*B5*/, /*C5*/, /*D5*/, "abc"]  // <-- Write "abc" to cell E5 | ||||
| ], { origin: "B3" }); | ||||
| ``` | ||||
| 
 | ||||
| ["Array of Arrays Input"](#array-of-arrays-input) describes the function and the | ||||
| optional `opts` argument in more detail. | ||||
| 
 | ||||
| **Examples** | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Appending rows to a worksheet</b> (click to show)</summary> | ||||
| 
 | ||||
| The special origin value `-1` instructs `sheet_add_aoa` to start in column A of | ||||
| the row after the last row in the range, appending the data: | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_add_aoa(worksheet, [ | ||||
|   ["first row after data", 1], | ||||
|   ["second row after data", 2] | ||||
| ], { origin: -1 }); | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| 
 | ||||
| ### Parsing and Writing Examples | ||||
| ### Modifying Other Worksheet / Workbook / Cell Properties | ||||
| 
 | ||||
| - <https://sheetjs.com/demos/modify.html> read + modify + write files | ||||
| 
 | ||||
| - <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> node | ||||
| 
 | ||||
| The node version installs a command line tool `xlsx` which can read spreadsheet | ||||
| files and output the contents in various formats.  The source is available at | ||||
| `xlsx.njs` in the bin directory. | ||||
| 
 | ||||
| Some helper functions in `XLSX.utils` generate different views of the sheets: | ||||
| 
 | ||||
| - `XLSX.utils.sheet_to_csv` generates CSV | ||||
| - `XLSX.utils.sheet_to_txt` generates UTF16 Formatted Text | ||||
| - `XLSX.utils.sheet_to_html` generates HTML | ||||
| - `XLSX.utils.sheet_to_json` generates an array of objects | ||||
| - `XLSX.utils.sheet_to_formulae` generates a list of formulae | ||||
| The ["Common Spreadsheet Format"](#common-spreadsheet-format) section describes | ||||
| the object structures in greater detail. | ||||
| 
 | ||||
|  | ||||
| @ -255,3 +255,42 @@ The [`vuejs` demo](demos/vue) includes more React examples. | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ### Generating Single-Worksheet Snapshots | ||||
| 
 | ||||
| The `sheet_to_*` functions accept a worksheet object. | ||||
| 
 | ||||
| **API** | ||||
| 
 | ||||
| _Generate a CSV from a single worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| var csv = XLSX.utils.sheet_to_csv(worksheet, opts); | ||||
| ``` | ||||
| 
 | ||||
| This snapshot is designed to replicate the "CSV UTF8 (`.csv`)" output type. | ||||
| ["Delimiter-Separated Output"](#delimiter-separated-output) describes the | ||||
| function and the optional `opts` argument in more detail. | ||||
| 
 | ||||
| _Generate "Text" from a single worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| var txt = XLSX.utils.sheet_to_txt(worksheet, opts); | ||||
| ``` | ||||
| 
 | ||||
| This snapshot is designed to replicate the "UTF16 Text (`.txt`)" output type. | ||||
| ["Delimiter-Separated Output"](#delimiter-separated-output) describes the | ||||
| function and the optional `opts` argument in more detail. | ||||
| 
 | ||||
| _Generate a list of formulae from a single worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| var fmla = XLSX.utils.sheet_to_formulae(worksheet); | ||||
| ``` | ||||
| 
 | ||||
| This snapshot generates an array of entries representing the embedded formulae. | ||||
| Array formulae are rendered in the form `range=formula` while plain cells are | ||||
| rendered in the form `cell=formula or value`.  String literals are prefixed with | ||||
| an apostrophe `'`, consistent with Excel's formula bar display. | ||||
| 
 | ||||
| ["Formulae Output"](#formulae-output) describes the function in more detail. | ||||
| 
 | ||||
|  | ||||
| @ -9,6 +9,7 @@ Cell objects are plain JS objects with keys and values following the convention: | ||||
| | `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub | | ||||
| | `f` | cell formula encoded as an A1-style string (if applicable)             | | ||||
| | `F` | range of enclosing array if formula is array formula (if applicable)   | | ||||
| | `D` | if true, array formula is dynamic (if applicable)                      | | ||||
| | `r` | rich text encoding (if applicable)                                     | | ||||
| | `h` | HTML rendering of the rich text (if applicable)                        | | ||||
| | `c` | comments associated with the cell                                      | | ||||
|  | ||||
| @ -6,79 +6,7 @@ Even though some formats store formulae with a leading equal sign, CSF formulae | ||||
| do not start with `=`. | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Representation of A1=1, A2=2, A3=A1+A2</b> (click to show)</summary> | ||||
| 
 | ||||
| ```js | ||||
| { | ||||
|   "!ref": "A1:A3", | ||||
|   A1: { t:'n', v:1 }, | ||||
|   A2: { t:'n', v:2 }, | ||||
|   A3: { t:'n', v:3, f:'A1+A2' } | ||||
| } | ||||
| ``` | ||||
| </details> | ||||
| 
 | ||||
| Shared formulae are decompressed and each cell has the formula corresponding to | ||||
| its cell.  Writers generally do not attempt to generate shared formulae. | ||||
| 
 | ||||
| Cells with formula entries but no value will be serialized in a way that Excel | ||||
| and other spreadsheet tools will recognize.  This library will not automatically | ||||
| compute formula results!  For example, to compute `BESSELJ` in a worksheet: | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Formula without known value</b> (click to show)</summary> | ||||
| 
 | ||||
| ```js | ||||
| { | ||||
|   "!ref": "A1:A3", | ||||
|   A1: { t:'n', v:3.14159 }, | ||||
|   A2: { t:'n', v:2 }, | ||||
|   A3: { t:'n', f:'BESSELJ(A1,A2)' } | ||||
| } | ||||
| ``` | ||||
| </details> | ||||
| 
 | ||||
| **Array Formulae** | ||||
| 
 | ||||
| Array formulae are stored in the top-left cell of the array block.  All cells | ||||
| of an array formula have a `F` field corresponding to the range.  A single-cell | ||||
| formula can be distinguished from a plain formula by the presence of `F` field. | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Array Formula examples</b> (click to show)</summary> | ||||
| 
 | ||||
| For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`: | ||||
| 
 | ||||
| ```js | ||||
| worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" }; | ||||
| ``` | ||||
| 
 | ||||
| For a multi-cell array formula, every cell has the same array range but only the | ||||
| first cell specifies the formula.  Consider `D1:D3=A1:A3*B1:B3`: | ||||
| 
 | ||||
| ```js | ||||
| worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" }; | ||||
| worksheet['D2'] = { t:'n', F:"D1:D3" }; | ||||
| worksheet['D3'] = { t:'n', F:"D1:D3" }; | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| Utilities and writers are expected to check for the presence of a `F` field and | ||||
| ignore any possible formula element `f` in cells other than the starting cell. | ||||
| They are not expected to perform validation of the formulae! | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Formula Output Utility Function</b> (click to show)</summary> | ||||
| 
 | ||||
| The `sheet_to_formulae` method generates one line per formula or array formula. | ||||
| Array formulae are rendered in the form `range=formula` while plain cells are | ||||
| rendered in the form `cell=formula or value`.  Note that string literals are | ||||
| prefixed with an apostrophe `'`, consistent with Excel's formula bar display. | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Formulae File Format Details</b> (click to show)</summary> | ||||
|   <summary><b>Formulae File Format Support</b> (click to show)</summary> | ||||
| 
 | ||||
| | Storage Representation | Formats                  | Read  | Write | | ||||
| |:-----------------------|:-------------------------|:-----:|:-----:| | ||||
| @ -92,5 +20,271 @@ Since Excel prohibits named cells from colliding with names of A1 or RC style | ||||
| cell references, a (not-so-simple) regex conversion is possible.  BIFF Parsed | ||||
| formulae and Lotus Parsed formulae have to be explicitly unwound.  OpenFormula | ||||
| formulae can be converted with regular expressions. | ||||
| 
 | ||||
| Shared formulae are decompressed and each cell has the formula corresponding to | ||||
| its cell.  Writers generally do not attempt to generate shared formulae. | ||||
| </details> | ||||
| 
 | ||||
| **Single-Cell Formulae** | ||||
| 
 | ||||
| For simple formulae, the `f` key of the desired cell can be set to the actual | ||||
| formula text.  This worksheet represents `A1=1`, `A2=2`, and `A3=A1+A2`: | ||||
| 
 | ||||
| ```js | ||||
| var worksheet = { | ||||
|   "!ref": "A1:A3", | ||||
|   A1: { t:'n', v:1 }, | ||||
|   A2: { t:'n', v:2 }, | ||||
|   A3: { t:'n', v:3, f:'A1+A2' } | ||||
| }; | ||||
| ``` | ||||
| 
 | ||||
| Utilities like `aoa_to_sheet` will accept cell objects in lieu of values: | ||||
| 
 | ||||
| ```js | ||||
| var worksheet = XLSX.utils.aoa_to_sheet([ | ||||
|   [ 1 ], // A1 | ||||
|   [ 2 ], // A2 | ||||
|   [ {t: "n", v: 3, f: "A1+A2"} ] // A3 | ||||
| ]); | ||||
| ``` | ||||
| 
 | ||||
| Cells with formula entries but no value will be serialized in a way that Excel | ||||
| and other spreadsheet tools will recognize.  This library will not automatically | ||||
| compute formula results!  For example, the following worksheet will include the | ||||
| `BESSELJ` function but the result will not be available in JavaScript: | ||||
| 
 | ||||
| ```js | ||||
| var worksheet = XLSX.utils.aoa_to_sheet([ | ||||
|   [ 3.14159, 2 ], // Row "1" | ||||
|   [ { t:'n', f:'BESSELJ(A1,B1)' } ] // Row "2" will be calculated on file open | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| If the actual results are needed in JS, [SheetJS Pro](https://sheetjs.com/pro) | ||||
| offers a formula calculator component for evaluating expressions, updating | ||||
| values and dependent cells, and refreshing entire workbooks. | ||||
| 
 | ||||
| 
 | ||||
| **Array Formulae** | ||||
| 
 | ||||
| _Assign an array formula_ | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, range, formula); | ||||
| ``` | ||||
| 
 | ||||
| Array formulae are stored in the top-left cell of the array block.  All cells | ||||
| of an array formula have a `F` field corresponding to the range.  A single-cell | ||||
| formula can be distinguished from a plain formula by the presence of `F` field. | ||||
| 
 | ||||
| For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`: | ||||
| 
 | ||||
| ```js | ||||
| // API function | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "C1", "SUM(A1:A3*B1:B3)"); | ||||
| 
 | ||||
| // ... OR raw operations | ||||
| worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" }; | ||||
| ``` | ||||
| 
 | ||||
| For a multi-cell array formula, every cell has the same array range but only the | ||||
| first cell specifies the formula.  Consider `D1:D3=A1:A3*B1:B3`: | ||||
| 
 | ||||
| ```js | ||||
| // API function | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "D1:D3", "A1:A3*B1:B3"); | ||||
| 
 | ||||
| // ... OR raw operations | ||||
| worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" }; | ||||
| worksheet['D2'] = { t:'n', F:"D1:D3" }; | ||||
| worksheet['D3'] = { t:'n', F:"D1:D3" }; | ||||
| ``` | ||||
| 
 | ||||
| Utilities and writers are expected to check for the presence of a `F` field and | ||||
| ignore any possible formula element `f` in cells other than the starting cell. | ||||
| They are not expected to perform validation of the formulae! | ||||
| 
 | ||||
| 
 | ||||
| **Dynamic Array Formulae** | ||||
| 
 | ||||
| _Assign a dynamic array formula_ | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true); | ||||
| ``` | ||||
| 
 | ||||
| Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB | ||||
| file formats.  They are represented like normal array formulae but have special | ||||
| cell metadata indicating that the formula should be allowed to adjust the range. | ||||
| 
 | ||||
| An array formula can be marked as dynamic by setting the cell's `D` property to | ||||
| true.  The `F` range is expected but can be the set to the current cell: | ||||
| 
 | ||||
| ```js | ||||
| // API function | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1); | ||||
| 
 | ||||
| // ... OR raw operations | ||||
| worksheet['C1'] = { t: "s", f: "_xlfn.UNIQUE(A1:A3)", F:"C1", D: 1 }; // dynamic | ||||
| ``` | ||||
| 
 | ||||
| **Localization with Function Names** | ||||
| 
 | ||||
| SheetJS operates at the file level.  Excel stores formula expressions using the | ||||
| English (United States) function names.  For non-English users, Excel uses a | ||||
| localized set of function names. | ||||
| 
 | ||||
| For example, when the computer language and region is set to French (France), | ||||
| Excel interprets `=SOMME(A1:C3)` as if `SOMME` is the `SUM` function.  However, | ||||
| in the actual file, Excel stores `SUM(A1:C3)`. | ||||
| 
 | ||||
| **Prefixed "Future Functions"** | ||||
| 
 | ||||
| Functions introduced in newer versions of Excel are prefixed with `_xlfn.` when | ||||
| stored in files.  When writing formula expressions using these functions, the | ||||
| prefix is required for maximal compatibility: | ||||
| 
 | ||||
| ```js | ||||
| // Broadest compatibility | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1); | ||||
| 
 | ||||
| // Can cause errors in spreadsheet software | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "C1", "UNIQUE(A1:A3)", 1); | ||||
| ``` | ||||
| 
 | ||||
| When reading a file, the `xlfn` option preserves the prefixes. | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b> Functions requiring `_xlfn.` prefix</b> (click to show)</summary> | ||||
| 
 | ||||
| This list is growing with each Excel release. | ||||
| 
 | ||||
| ``` | ||||
| ACOT | ||||
| ACOTH | ||||
| AGGREGATE | ||||
| ARABIC | ||||
| BASE | ||||
| BETA.DIST | ||||
| BETA.INV | ||||
| BINOM.DIST | ||||
| BINOM.DIST.RANGE | ||||
| BINOM.INV | ||||
| BITAND | ||||
| BITLSHIFT | ||||
| BITOR | ||||
| BITRSHIFT | ||||
| BITXOR | ||||
| BYCOL | ||||
| BYROW | ||||
| CEILING.MATH | ||||
| CEILING.PRECISE | ||||
| CHISQ.DIST | ||||
| CHISQ.DIST.RT | ||||
| CHISQ.INV | ||||
| CHISQ.INV.RT | ||||
| CHISQ.TEST | ||||
| COMBINA | ||||
| CONFIDENCE.NORM | ||||
| CONFIDENCE.T | ||||
| COT | ||||
| COTH | ||||
| COVARIANCE.P | ||||
| COVARIANCE.S | ||||
| CSC | ||||
| CSCH | ||||
| DAYS | ||||
| DECIMAL | ||||
| ERF.PRECISE | ||||
| ERFC.PRECISE | ||||
| EXPON.DIST | ||||
| F.DIST | ||||
| F.DIST.RT | ||||
| F.INV | ||||
| F.INV.RT | ||||
| F.TEST | ||||
| FIELDVALUE | ||||
| FILTERXML | ||||
| FLOOR.MATH | ||||
| FLOOR.PRECISE | ||||
| FORMULATEXT | ||||
| GAMMA | ||||
| GAMMA.DIST | ||||
| GAMMA.INV | ||||
| GAMMALN.PRECISE | ||||
| GAUSS | ||||
| HYPGEOM.DIST | ||||
| IFNA | ||||
| IMCOSH | ||||
| IMCOT | ||||
| IMCSC | ||||
| IMCSCH | ||||
| IMSEC | ||||
| IMSECH | ||||
| IMSINH | ||||
| IMTAN | ||||
| ISFORMULA | ||||
| ISOMITTED | ||||
| ISOWEEKNUM | ||||
| LAMBDA | ||||
| LET | ||||
| LOGNORM.DIST | ||||
| LOGNORM.INV | ||||
| MAKEARRAY | ||||
| MAP | ||||
| MODE.MULT | ||||
| MODE.SNGL | ||||
| MUNIT | ||||
| NEGBINOM.DIST | ||||
| NORM.DIST | ||||
| NORM.INV | ||||
| NORM.S.DIST | ||||
| NORM.S.INV | ||||
| NUMBERVALUE | ||||
| PDURATION | ||||
| PERCENTILE.EXC | ||||
| PERCENTILE.INC | ||||
| PERCENTRANK.EXC | ||||
| PERCENTRANK.INC | ||||
| PERMUTATIONA | ||||
| PHI | ||||
| POISSON.DIST | ||||
| QUARTILE.EXC | ||||
| QUARTILE.INC | ||||
| QUERYSTRING | ||||
| RANDARRAY | ||||
| RANK.AVG | ||||
| RANK.EQ | ||||
| REDUCE | ||||
| RRI | ||||
| SCAN | ||||
| SEC | ||||
| SECH | ||||
| SEQUENCE | ||||
| SHEET | ||||
| SHEETS | ||||
| SKEW.P | ||||
| SORTBY | ||||
| STDEV.P | ||||
| STDEV.S | ||||
| T.DIST | ||||
| T.DIST.2T | ||||
| T.DIST.RT | ||||
| T.INV | ||||
| T.INV.2T | ||||
| T.TEST | ||||
| UNICHAR | ||||
| UNICODE | ||||
| UNIQUE | ||||
| VAR.P | ||||
| VAR.S | ||||
| WEBSERVICE | ||||
| WEIBULL.DIST | ||||
| XLOOKUP | ||||
| XOR | ||||
| Z.TEST | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										1
									
								
								mini.lst
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								mini.lst
									
									
									
									
									
								
							| @ -28,6 +28,7 @@ bits/42_sstxml.js | ||||
| bits/46_stycommon.js | ||||
| bits/47_styxml.js | ||||
| bits/49_theme.js | ||||
| misc/51_xlsxmeta.js | ||||
| bits/53_externlink.js | ||||
| bits/54_drawing.js | ||||
| bits/55_vml.js | ||||
|  | ||||
| @ -14,7 +14,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) { | ||||
| 	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload); | ||||
| 	if(typeof Deno !== 'undefined') { | ||||
| 		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */ | ||||
| 		if(enc) switch(enc) { | ||||
| 		if(enc && typeof payload == "string") switch(enc) { | ||||
| 			case "utf8": payload = new TextEncoder(enc).encode(payload); break; | ||||
| 			case "binary": payload = s2ab(payload); break; | ||||
| 			/* TODO: binary equivalent */ | ||||
|  | ||||
							
								
								
									
										63
									
								
								misc/51_xlsxmeta.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										63
									
								
								misc/51_xlsxmeta.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; | ||||
| function parse_xlmeta_xml(data, name, opts) { | ||||
|   var out = { Types: [] }; | ||||
|   if (!data) | ||||
|     return out; | ||||
|   var pass = false; | ||||
|   data.replace(tagregex, function(x, idx) { | ||||
|     var y = parsexmltag(x); | ||||
|     switch (strip_ns(y[0])) { | ||||
|       case "<?xml": | ||||
|         break; | ||||
|       case "<metadata": | ||||
|       case "</metadata>": | ||||
|         break; | ||||
|       case "<metadataTypes": | ||||
|       case "</metadataTypes>": | ||||
|         break; | ||||
|       case "<metadataType": | ||||
|         out.Types.push({ name: y.name }); | ||||
|         break; | ||||
|       case "<futureMetadata": | ||||
|         break; | ||||
|       case "</futureMetadata>": | ||||
|         break; | ||||
|       case "<bk>": | ||||
|         break; | ||||
|       case "</bk>": | ||||
|         break; | ||||
|       case "<rc": | ||||
|         break; | ||||
|       case "</rc>": | ||||
|         break; | ||||
|       case "<cellMetadata": | ||||
|       case "</cellMetadata>": | ||||
|         break; | ||||
|       case "<valueMetadata": | ||||
|         break; | ||||
|       case "</valueMetadata>": | ||||
|         break; | ||||
|       case "<extLst": | ||||
|       case "<extLst>": | ||||
|       case "</extLst>": | ||||
|       case "<extLst/>": | ||||
|         break; | ||||
|       case "<ext": | ||||
|         pass = true; | ||||
|         break; | ||||
|       case "</ext>": | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if (!pass && opts.WTF) | ||||
|           throw new Error("unrecognized " + y[0] + " in metadata"); | ||||
|     } | ||||
|     return x; | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_xml() { | ||||
|   var o = [XML_HEADER]; | ||||
|   o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>'); | ||||
|   return o.join(""); | ||||
| } | ||||
| @ -24,10 +24,8 @@ port calculations to web apps; automate common spreadsheet tasks, and much more! | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| 
 | ||||
| ## Table of Contents | ||||
| 
 | ||||
| 
 | ||||
| @ -42,14 +40,17 @@ port calculations to web apps; automate common spreadsheet tasks, and much more! | ||||
|   * [Parsing Workbooks](#parsing-workbooks) | ||||
|   * [Processing JSON and JS Data](#processing-json-and-js-data) | ||||
|   * [Processing HTML Tables](#processing-html-tables) | ||||
| - [Working with the Workbook](#working-with-the-workbook) | ||||
|   * [Parsing and Writing Examples](#parsing-and-writing-examples) | ||||
| - [Processing Data](#processing-data) | ||||
|   * [Modifying Workbook Structure](#modifying-workbook-structure) | ||||
|   * [Modifying Cell Values](#modifying-cell-values) | ||||
|   * [Modifying Other Worksheet / Workbook / Cell Properties](#modifying-other-worksheet--workbook--cell-properties) | ||||
| - [Packaging and Releasing Data](#packaging-and-releasing-data) | ||||
|   * [Writing Workbooks](#writing-workbooks) | ||||
|   * [Writing Examples](#writing-examples) | ||||
|   * [Streaming Write](#streaming-write) | ||||
|   * [Generating JSON and JS Data](#generating-json-and-js-data) | ||||
|   * [Generating HTML Tables](#generating-html-tables) | ||||
|   * [Generating Single-Worksheet Snapshots](#generating-single-worksheet-snapshots) | ||||
| - [Interface](#interface) | ||||
|   * [Parsing functions](#parsing-functions) | ||||
|   * [Writing functions](#writing-functions) | ||||
| @ -140,10 +141,11 @@ For example, `unpkg` makes the latest version available at: | ||||
| 
 | ||||
| The complete single-file version is generated at `dist/xlsx.full.min.js` | ||||
| 
 | ||||
| `dist/xlsx.core.min.js` omits codepage library (no support for XLS encodings) | ||||
| 
 | ||||
| A slimmer build is generated at `dist/xlsx.mini.min.js`. Compared to full build: | ||||
| - codepage library skipped (no support for XLS encodings) | ||||
| - XLSX compression option not currently available | ||||
| - no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 | ||||
| - no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 / Numbers | ||||
| - node stream utils removed | ||||
| 
 | ||||
| 
 | ||||
| @ -303,6 +305,18 @@ and approaches for steps 1 and 5. | ||||
| 
 | ||||
| Utility functions help with step 3. | ||||
| 
 | ||||
| ["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes | ||||
| solutions for common data import scenarios. | ||||
| 
 | ||||
| ["Packaging and Releasing Data"](#packaging-and-releasing-data) describes | ||||
| solutions for common data export scenarios. | ||||
| 
 | ||||
| ["Processing Data"](#packaging-and-releasing-data) describes solutions for | ||||
| common workbook processing and manipulation scenarios. | ||||
| 
 | ||||
| ["Utility Functions"](#utility-functions) details utility functions for | ||||
| translating JSON Arrays and other common JS structures into worksheet objects. | ||||
| 
 | ||||
| ### The Zen of SheetJS | ||||
| 
 | ||||
| _Data processing should fit in any workflow_ | ||||
| @ -311,15 +325,6 @@ The library does not impose a separate lifecycle.  It fits nicely in websites | ||||
| and apps built using any framework.  The plain JS data objects play nice with | ||||
| Web Workers and future APIs. | ||||
| 
 | ||||
| ["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes | ||||
| solutions for common data import scenarios. | ||||
| 
 | ||||
| ["Writing Workbooks"](#writing-workbooks) describes solutions for common data | ||||
| export scenarios involving actual spreadsheet files. | ||||
| 
 | ||||
| ["Utility Functions"](#utility-functions) details utility functions for | ||||
| translating JSON Arrays and other common JS structures into worksheet objects. | ||||
| 
 | ||||
| _JavaScript is a powerful language for data processing_ | ||||
| 
 | ||||
| The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object | ||||
| @ -559,6 +564,12 @@ The [`demos` directory](demos/) includes sample projects for: | ||||
| 
 | ||||
| Other examples are included in the [showcase](demos/showcase/). | ||||
| 
 | ||||
| <https://sheetjs.com/demos/modify.html> shows a complete example of reading, | ||||
| modifying, and writing files. | ||||
| 
 | ||||
| <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> is the command-line | ||||
| tool included with node installations, reading spreadsheet files and exporting | ||||
| the contents in various formats. | ||||
| ## Acquiring and Extracting Data | ||||
| 
 | ||||
| ### Parsing Workbooks | ||||
| @ -962,12 +973,13 @@ const workbook = XLSX.read(data); | ||||
| 
 | ||||
| 
 | ||||
| More detailed examples are covered in the [included demos](demos/) | ||||
| 
 | ||||
| ### Processing JSON and JS Data | ||||
| 
 | ||||
| JSON and JS data tend to represent single worksheets.  This section will use a | ||||
| few utility functions to generate workbooks: | ||||
| few utility functions to generate workbooks. | ||||
| 
 | ||||
| _Create a new Worksheet_ | ||||
| _Create a new Workbook_ | ||||
| 
 | ||||
| ```js | ||||
| var workbook = XLSX.utils.book_new(); | ||||
| @ -975,16 +987,9 @@ var workbook = XLSX.utils.book_new(); | ||||
| 
 | ||||
| The `book_new` utility function creates an empty workbook with no worksheets. | ||||
| 
 | ||||
| 
 | ||||
| _Append a Worksheet to a Workbook_ | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name); | ||||
| ``` | ||||
| 
 | ||||
| The `book_append_sheet` utility function appends a worksheet to the workbook. | ||||
| The third argument specifies the desired worksheet name. Multiple worksheets can | ||||
| be added to a workbook by calling the function multiple times. | ||||
| Spreadsheet software generally require at least one worksheet and enforce the | ||||
| requirement in the user interface.  This library enforces the requirement at | ||||
| write time, throwing errors if an empty workbook is passed to write functions. | ||||
| 
 | ||||
| 
 | ||||
| **API** | ||||
| @ -997,14 +1002,14 @@ var worksheet = XLSX.utils.aoa_to_sheet(aoa, opts); | ||||
| 
 | ||||
| The `aoa_to_sheet` utility function walks an "array of arrays" in row-major | ||||
| order, generating a worksheet object.  The following snippet generates a sheet | ||||
| with cell `A1` set to the string `A1`, cell `B1` set to `B2`, etc: | ||||
| with cell `A1` set to the string `A1`, cell `B1` set to `B1`, etc: | ||||
| 
 | ||||
| ```js | ||||
| var worksheet = XLSX.utils.aoa_to_sheet([ | ||||
|   ["A1", "B1", "C1"], | ||||
|   ["A2", "B2", "C2"], | ||||
|   ["A3", "B3", "C3"] | ||||
| ]) | ||||
| ]); | ||||
| ``` | ||||
| 
 | ||||
| ["Array of Arrays Input"](#array-of-arrays-input) describes the function and the | ||||
| @ -1284,36 +1289,55 @@ const workbook = XLSX.utils.table_to_book(doc); | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| ## Working with the Workbook | ||||
| ## Processing Data | ||||
| 
 | ||||
| The full object format is described later in this README. | ||||
| The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object | ||||
| representation of the core concepts of a workbook.  The utility functions work | ||||
| with the object representation and are intended to handle common use cases. | ||||
| 
 | ||||
| ### Modifying Workbook Structure | ||||
| 
 | ||||
| This example extracts the value stored in cell A1 from the first worksheet: | ||||
| **API** | ||||
| 
 | ||||
| _Append a Worksheet to a Workbook_ | ||||
| 
 | ||||
| ```js | ||||
| var first_sheet_name = workbook.SheetNames[0]; | ||||
| var address_of_cell = 'A1'; | ||||
| 
 | ||||
| /* Get worksheet */ | ||||
| var worksheet = workbook.Sheets[first_sheet_name]; | ||||
| 
 | ||||
| /* Find desired cell */ | ||||
| var desired_cell = worksheet[address_of_cell]; | ||||
| 
 | ||||
| /* Get the value */ | ||||
| var desired_value = (desired_cell ? desired_cell.v : undefined); | ||||
| XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name); | ||||
| ``` | ||||
| 
 | ||||
| The `book_append_sheet` utility function appends a worksheet to the workbook. | ||||
| The third argument specifies the desired worksheet name. Multiple worksheets can | ||||
| be added to a workbook by calling the function multiple times. | ||||
| 
 | ||||
| _List the Worksheet names in tab order_ | ||||
| 
 | ||||
| ```js | ||||
| var wsnames = workbook.SheetNames; | ||||
| ``` | ||||
| 
 | ||||
| The `SheetNames` property of the workbook object is a list of the worksheet | ||||
| names in "tab order".  API functions will look at this array. | ||||
| 
 | ||||
| _Replace a Worksheet in place_ | ||||
| 
 | ||||
| ```js | ||||
| workbook.Sheets[sheet_name] = new_worksheet; | ||||
| ``` | ||||
| 
 | ||||
| The `Sheets` property of the workbook object is an object whose keys are names | ||||
| and whose values are worksheet objects.  By reassigning to a property of the | ||||
| `Sheets` object, the worksheet object can be changed without disrupting the | ||||
| rest of the worksheet structure. | ||||
| 
 | ||||
| **Examples** | ||||
| 
 | ||||
| 
 | ||||
| This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input) to make a | ||||
| sheet and `XLSX.utils.book_append_sheet` to append the sheet to the workbook: | ||||
| This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input). | ||||
| 
 | ||||
| ```js | ||||
| var ws_name = "SheetJS"; | ||||
| 
 | ||||
| /* make worksheet */ | ||||
| /* Create worksheet */ | ||||
| var ws_data = [ | ||||
|   [ "S", "h", "e", "e", "t", "J", "S" ], | ||||
|   [  1 ,  2 ,  3 ,  4 ,  5 ] | ||||
| @ -1325,38 +1349,57 @@ XLSX.utils.book_append_sheet(wb, ws, ws_name); | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| ### Modifying Cell Values | ||||
| 
 | ||||
| The workbook object contains a `SheetNames` array of names and a `Sheets` object | ||||
| mapping sheet names to sheet objects. The `XLSX.utils.book_new` utility function | ||||
| creates a new workbook object: | ||||
| **API** | ||||
| 
 | ||||
| _Modify a single cell value in a worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| /* create a new blank workbook */ | ||||
| var wb = XLSX.utils.book_new(); | ||||
| XLSX.utils.sheet_add_aoa(worksheet, [[new_value]], { origin: address }); | ||||
| ``` | ||||
| 
 | ||||
| The new workbook is blank and contains no worksheets. The write functions will | ||||
| error if the workbook is empty. | ||||
| _Modify multiple cell values in a worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_add_aoa(worksheet, aoa, opts); | ||||
| ``` | ||||
| 
 | ||||
| The `sheet_add_aoa` utility function modifies cell values in a worksheet.  The | ||||
| first argument is the worksheet object.  The second argument is an array of | ||||
| arrays of values.  The `origin` key of the third argument controls where cells | ||||
| will be written.  The following snippet sets `B3=1` and `E5="abc"`: | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_add_aoa(worksheet, [ | ||||
|   [1],                             // <-- Write 1 to cell B3 | ||||
|   ,                                // <-- Do nothing in row 4 | ||||
|   [/*B5*/, /*C5*/, /*D5*/, "abc"]  // <-- Write "abc" to cell E5 | ||||
| ], { origin: "B3" }); | ||||
| ``` | ||||
| 
 | ||||
| ["Array of Arrays Input"](#array-of-arrays-input) describes the function and the | ||||
| optional `opts` argument in more detail. | ||||
| 
 | ||||
| **Examples** | ||||
| 
 | ||||
| 
 | ||||
| The special origin value `-1` instructs `sheet_add_aoa` to start in column A of | ||||
| the row after the last row in the range, appending the data: | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_add_aoa(worksheet, [ | ||||
|   ["first row after data", 1], | ||||
|   ["second row after data", 2] | ||||
| ], { origin: -1 }); | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| ### Parsing and Writing Examples | ||||
| ### Modifying Other Worksheet / Workbook / Cell Properties | ||||
| 
 | ||||
| - <https://sheetjs.com/demos/modify.html> read + modify + write files | ||||
| 
 | ||||
| - <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> node | ||||
| 
 | ||||
| The node version installs a command line tool `xlsx` which can read spreadsheet | ||||
| files and output the contents in various formats.  The source is available at | ||||
| `xlsx.njs` in the bin directory. | ||||
| 
 | ||||
| Some helper functions in `XLSX.utils` generate different views of the sheets: | ||||
| 
 | ||||
| - `XLSX.utils.sheet_to_csv` generates CSV | ||||
| - `XLSX.utils.sheet_to_txt` generates UTF16 Formatted Text | ||||
| - `XLSX.utils.sheet_to_html` generates HTML | ||||
| - `XLSX.utils.sheet_to_json` generates an array of objects | ||||
| - `XLSX.utils.sheet_to_formulae` generates a list of formulae | ||||
| The ["Common Spreadsheet Format"](#common-spreadsheet-format) section describes | ||||
| the object structures in greater detail. | ||||
| 
 | ||||
| ## Packaging and Releasing Data | ||||
| 
 | ||||
| @ -1832,6 +1875,45 @@ const S5SComponent = { | ||||
| The [`vuejs` demo](demos/vue) includes more React examples. | ||||
| 
 | ||||
| 
 | ||||
| ### Generating Single-Worksheet Snapshots | ||||
| 
 | ||||
| The `sheet_to_*` functions accept a worksheet object. | ||||
| 
 | ||||
| **API** | ||||
| 
 | ||||
| _Generate a CSV from a single worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| var csv = XLSX.utils.sheet_to_csv(worksheet, opts); | ||||
| ``` | ||||
| 
 | ||||
| This snapshot is designed to replicate the "CSV UTF8 (`.csv`)" output type. | ||||
| ["Delimiter-Separated Output"](#delimiter-separated-output) describes the | ||||
| function and the optional `opts` argument in more detail. | ||||
| 
 | ||||
| _Generate "Text" from a single worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| var txt = XLSX.utils.sheet_to_txt(worksheet, opts); | ||||
| ``` | ||||
| 
 | ||||
| This snapshot is designed to replicate the "UTF16 Text (`.txt`)" output type. | ||||
| ["Delimiter-Separated Output"](#delimiter-separated-output) describes the | ||||
| function and the optional `opts` argument in more detail. | ||||
| 
 | ||||
| _Generate a list of formulae from a single worksheet_ | ||||
| 
 | ||||
| ```js | ||||
| var fmla = XLSX.utils.sheet_to_formulae(worksheet); | ||||
| ``` | ||||
| 
 | ||||
| This snapshot generates an array of entries representing the embedded formulae. | ||||
| Array formulae are rendered in the form `range=formula` while plain cells are | ||||
| rendered in the form `cell=formula or value`.  String literals are prefixed with | ||||
| an apostrophe `'`, consistent with Excel's formula bar display. | ||||
| 
 | ||||
| ["Formulae Output"](#formulae-output) describes the function in more detail. | ||||
| 
 | ||||
| ## Interface | ||||
| 
 | ||||
| `XLSX` is the exposed variable in the browser and the exported node variable | ||||
| @ -1934,6 +2016,7 @@ Cell objects are plain JS objects with keys and values following the convention: | ||||
| | `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub | | ||||
| | `f` | cell formula encoded as an A1-style string (if applicable)             | | ||||
| | `F` | range of enclosing array if formula is array formula (if applicable)   | | ||||
| | `D` | if true, array formula is dynamic (if applicable)                      | | ||||
| | `r` | rich text encoding (if applicable)                                     | | ||||
| | `h` | HTML rendering of the rich text (if applicable)                        | | ||||
| | `c` | comments associated with the cell                                      | | ||||
| @ -2261,66 +2344,6 @@ Even though some formats store formulae with a leading equal sign, CSF formulae | ||||
| do not start with `=`. | ||||
| 
 | ||||
| 
 | ||||
| ```js | ||||
| { | ||||
|   "!ref": "A1:A3", | ||||
|   A1: { t:'n', v:1 }, | ||||
|   A2: { t:'n', v:2 }, | ||||
|   A3: { t:'n', v:3, f:'A1+A2' } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Shared formulae are decompressed and each cell has the formula corresponding to | ||||
| its cell.  Writers generally do not attempt to generate shared formulae. | ||||
| 
 | ||||
| Cells with formula entries but no value will be serialized in a way that Excel | ||||
| and other spreadsheet tools will recognize.  This library will not automatically | ||||
| compute formula results!  For example, to compute `BESSELJ` in a worksheet: | ||||
| 
 | ||||
| 
 | ||||
| ```js | ||||
| { | ||||
|   "!ref": "A1:A3", | ||||
|   A1: { t:'n', v:3.14159 }, | ||||
|   A2: { t:'n', v:2 }, | ||||
|   A3: { t:'n', f:'BESSELJ(A1,A2)' } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| **Array Formulae** | ||||
| 
 | ||||
| Array formulae are stored in the top-left cell of the array block.  All cells | ||||
| of an array formula have a `F` field corresponding to the range.  A single-cell | ||||
| formula can be distinguished from a plain formula by the presence of `F` field. | ||||
| 
 | ||||
| 
 | ||||
| For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`: | ||||
| 
 | ||||
| ```js | ||||
| worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" }; | ||||
| ``` | ||||
| 
 | ||||
| For a multi-cell array formula, every cell has the same array range but only the | ||||
| first cell specifies the formula.  Consider `D1:D3=A1:A3*B1:B3`: | ||||
| 
 | ||||
| ```js | ||||
| worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" }; | ||||
| worksheet['D2'] = { t:'n', F:"D1:D3" }; | ||||
| worksheet['D3'] = { t:'n', F:"D1:D3" }; | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| Utilities and writers are expected to check for the presence of a `F` field and | ||||
| ignore any possible formula element `f` in cells other than the starting cell. | ||||
| They are not expected to perform validation of the formulae! | ||||
| 
 | ||||
| 
 | ||||
| The `sheet_to_formulae` method generates one line per formula or array formula. | ||||
| Array formulae are rendered in the form `range=formula` while plain cells are | ||||
| rendered in the form `cell=formula or value`.  Note that string literals are | ||||
| prefixed with an apostrophe `'`, consistent with Excel's formula bar display. | ||||
| 
 | ||||
| 
 | ||||
| | Storage Representation | Formats                  | Read  | Write | | ||||
| |:-----------------------|:-------------------------|:-----:|:-----:| | ||||
| | A1-style strings       | XLSX                     |   ✔   |   ✔   | | ||||
| @ -2334,6 +2357,269 @@ cell references, a (not-so-simple) regex conversion is possible.  BIFF Parsed | ||||
| formulae and Lotus Parsed formulae have to be explicitly unwound.  OpenFormula | ||||
| formulae can be converted with regular expressions. | ||||
| 
 | ||||
| Shared formulae are decompressed and each cell has the formula corresponding to | ||||
| its cell.  Writers generally do not attempt to generate shared formulae. | ||||
| 
 | ||||
| **Single-Cell Formulae** | ||||
| 
 | ||||
| For simple formulae, the `f` key of the desired cell can be set to the actual | ||||
| formula text.  This worksheet represents `A1=1`, `A2=2`, and `A3=A1+A2`: | ||||
| 
 | ||||
| ```js | ||||
| var worksheet = { | ||||
|   "!ref": "A1:A3", | ||||
|   A1: { t:'n', v:1 }, | ||||
|   A2: { t:'n', v:2 }, | ||||
|   A3: { t:'n', v:3, f:'A1+A2' } | ||||
| }; | ||||
| ``` | ||||
| 
 | ||||
| Utilities like `aoa_to_sheet` will accept cell objects in lieu of values: | ||||
| 
 | ||||
| ```js | ||||
| var worksheet = XLSX.utils.aoa_to_sheet([ | ||||
|   [ 1 ], // A1 | ||||
|   [ 2 ], // A2 | ||||
|   [ {t: "n", v: 3, f: "A1+A2"} ] // A3 | ||||
| ]); | ||||
| ``` | ||||
| 
 | ||||
| Cells with formula entries but no value will be serialized in a way that Excel | ||||
| and other spreadsheet tools will recognize.  This library will not automatically | ||||
| compute formula results!  For example, the following worksheet will include the | ||||
| `BESSELJ` function but the result will not be available in JavaScript: | ||||
| 
 | ||||
| ```js | ||||
| var worksheet = XLSX.utils.aoa_to_sheet([ | ||||
|   [ 3.14159, 2 ], // Row "1" | ||||
|   [ { t:'n', f:'BESSELJ(A1,B1)' } ] // Row "2" will be calculated on file open | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| If the actual results are needed in JS, [SheetJS Pro](https://sheetjs.com/pro) | ||||
| offers a formula calculator component for evaluating expressions, updating | ||||
| values and dependent cells, and refreshing entire workbooks. | ||||
| 
 | ||||
| 
 | ||||
| **Array Formulae** | ||||
| 
 | ||||
| _Assign an array formula_ | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, range, formula); | ||||
| ``` | ||||
| 
 | ||||
| Array formulae are stored in the top-left cell of the array block.  All cells | ||||
| of an array formula have a `F` field corresponding to the range.  A single-cell | ||||
| formula can be distinguished from a plain formula by the presence of `F` field. | ||||
| 
 | ||||
| For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`: | ||||
| 
 | ||||
| ```js | ||||
| // API function | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "C1", "SUM(A1:A3*B1:B3)"); | ||||
| 
 | ||||
| // ... OR raw operations | ||||
| worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" }; | ||||
| ``` | ||||
| 
 | ||||
| For a multi-cell array formula, every cell has the same array range but only the | ||||
| first cell specifies the formula.  Consider `D1:D3=A1:A3*B1:B3`: | ||||
| 
 | ||||
| ```js | ||||
| // API function | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "D1:D3", "A1:A3*B1:B3"); | ||||
| 
 | ||||
| // ... OR raw operations | ||||
| worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" }; | ||||
| worksheet['D2'] = { t:'n', F:"D1:D3" }; | ||||
| worksheet['D3'] = { t:'n', F:"D1:D3" }; | ||||
| ``` | ||||
| 
 | ||||
| Utilities and writers are expected to check for the presence of a `F` field and | ||||
| ignore any possible formula element `f` in cells other than the starting cell. | ||||
| They are not expected to perform validation of the formulae! | ||||
| 
 | ||||
| 
 | ||||
| **Dynamic Array Formulae** | ||||
| 
 | ||||
| _Assign a dynamic array formula_ | ||||
| 
 | ||||
| ```js | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true); | ||||
| ``` | ||||
| 
 | ||||
| Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB | ||||
| file formats.  They are represented like normal array formulae but have special | ||||
| cell metadata indicating that the formula should be allowed to adjust the range. | ||||
| 
 | ||||
| An array formula can be marked as dynamic by setting the cell's `D` property to | ||||
| true.  The `F` range is expected but can be the set to the current cell: | ||||
| 
 | ||||
| ```js | ||||
| // API function | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1); | ||||
| 
 | ||||
| // ... OR raw operations | ||||
| worksheet['C1'] = { t: "s", f: "_xlfn.UNIQUE(A1:A3)", F:"C1", D: 1 }; // dynamic | ||||
| ``` | ||||
| 
 | ||||
| **Localization with Function Names** | ||||
| 
 | ||||
| SheetJS operates at the file level.  Excel stores formula expressions using the | ||||
| English (United States) function names.  For non-English users, Excel uses a | ||||
| localized set of function names. | ||||
| 
 | ||||
| For example, when the computer language and region is set to French (France), | ||||
| Excel interprets `=SOMME(A1:C3)` as if `SOMME` is the `SUM` function.  However, | ||||
| in the actual file, Excel stores `SUM(A1:C3)`. | ||||
| 
 | ||||
| **Prefixed "Future Functions"** | ||||
| 
 | ||||
| Functions introduced in newer versions of Excel are prefixed with `_xlfn.` when | ||||
| stored in files.  When writing formula expressions using these functions, the | ||||
| prefix is required for maximal compatibility: | ||||
| 
 | ||||
| ```js | ||||
| // Broadest compatibility | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1); | ||||
| 
 | ||||
| // Can cause errors in spreadsheet software | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, "C1", "UNIQUE(A1:A3)", 1); | ||||
| ``` | ||||
| 
 | ||||
| When reading a file, the `xlfn` option preserves the prefixes. | ||||
| 
 | ||||
| 
 | ||||
| This list is growing with each Excel release. | ||||
| 
 | ||||
| ``` | ||||
| ACOT | ||||
| ACOTH | ||||
| AGGREGATE | ||||
| ARABIC | ||||
| BASE | ||||
| BETA.DIST | ||||
| BETA.INV | ||||
| BINOM.DIST | ||||
| BINOM.DIST.RANGE | ||||
| BINOM.INV | ||||
| BITAND | ||||
| BITLSHIFT | ||||
| BITOR | ||||
| BITRSHIFT | ||||
| BITXOR | ||||
| BYCOL | ||||
| BYROW | ||||
| CEILING.MATH | ||||
| CEILING.PRECISE | ||||
| CHISQ.DIST | ||||
| CHISQ.DIST.RT | ||||
| CHISQ.INV | ||||
| CHISQ.INV.RT | ||||
| CHISQ.TEST | ||||
| COMBINA | ||||
| CONFIDENCE.NORM | ||||
| CONFIDENCE.T | ||||
| COT | ||||
| COTH | ||||
| COVARIANCE.P | ||||
| COVARIANCE.S | ||||
| CSC | ||||
| CSCH | ||||
| DAYS | ||||
| DECIMAL | ||||
| ERF.PRECISE | ||||
| ERFC.PRECISE | ||||
| EXPON.DIST | ||||
| F.DIST | ||||
| F.DIST.RT | ||||
| F.INV | ||||
| F.INV.RT | ||||
| F.TEST | ||||
| FIELDVALUE | ||||
| FILTERXML | ||||
| FLOOR.MATH | ||||
| FLOOR.PRECISE | ||||
| FORMULATEXT | ||||
| GAMMA | ||||
| GAMMA.DIST | ||||
| GAMMA.INV | ||||
| GAMMALN.PRECISE | ||||
| GAUSS | ||||
| HYPGEOM.DIST | ||||
| IFNA | ||||
| IMCOSH | ||||
| IMCOT | ||||
| IMCSC | ||||
| IMCSCH | ||||
| IMSEC | ||||
| IMSECH | ||||
| IMSINH | ||||
| IMTAN | ||||
| ISFORMULA | ||||
| ISOMITTED | ||||
| ISOWEEKNUM | ||||
| LAMBDA | ||||
| LET | ||||
| LOGNORM.DIST | ||||
| LOGNORM.INV | ||||
| MAKEARRAY | ||||
| MAP | ||||
| MODE.MULT | ||||
| MODE.SNGL | ||||
| MUNIT | ||||
| NEGBINOM.DIST | ||||
| NORM.DIST | ||||
| NORM.INV | ||||
| NORM.S.DIST | ||||
| NORM.S.INV | ||||
| NUMBERVALUE | ||||
| PDURATION | ||||
| PERCENTILE.EXC | ||||
| PERCENTILE.INC | ||||
| PERCENTRANK.EXC | ||||
| PERCENTRANK.INC | ||||
| PERMUTATIONA | ||||
| PHI | ||||
| POISSON.DIST | ||||
| QUARTILE.EXC | ||||
| QUARTILE.INC | ||||
| QUERYSTRING | ||||
| RANDARRAY | ||||
| RANK.AVG | ||||
| RANK.EQ | ||||
| REDUCE | ||||
| RRI | ||||
| SCAN | ||||
| SEC | ||||
| SECH | ||||
| SEQUENCE | ||||
| SHEET | ||||
| SHEETS | ||||
| SKEW.P | ||||
| SORTBY | ||||
| STDEV.P | ||||
| STDEV.S | ||||
| T.DIST | ||||
| T.DIST.2T | ||||
| T.DIST.RT | ||||
| T.INV | ||||
| T.INV.2T | ||||
| T.TEST | ||||
| UNICHAR | ||||
| UNICODE | ||||
| UNIQUE | ||||
| VAR.P | ||||
| VAR.S | ||||
| WEBSERVICE | ||||
| WEIBULL.DIST | ||||
| XLOOKUP | ||||
| XOR | ||||
| Z.TEST | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| #### Row and Column Properties | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -10,14 +10,17 @@ | ||||
|   * [Parsing Workbooks](README.md#parsing-workbooks) | ||||
|   * [Processing JSON and JS Data](README.md#processing-json-and-js-data) | ||||
|   * [Processing HTML Tables](README.md#processing-html-tables) | ||||
| - [Working with the Workbook](README.md#working-with-the-workbook) | ||||
|   * [Parsing and Writing Examples](README.md#parsing-and-writing-examples) | ||||
| - [Processing Data](README.md#processing-data) | ||||
|   * [Modifying Workbook Structure](README.md#modifying-workbook-structure) | ||||
|   * [Modifying Cell Values](README.md#modifying-cell-values) | ||||
|   * [Modifying Other Worksheet / Workbook / Cell Properties](README.md#modifying-other-worksheet--workbook--cell-properties) | ||||
| - [Packaging and Releasing Data](README.md#packaging-and-releasing-data) | ||||
|   * [Writing Workbooks](README.md#writing-workbooks) | ||||
|   * [Writing Examples](README.md#writing-examples) | ||||
|   * [Streaming Write](README.md#streaming-write) | ||||
|   * [Generating JSON and JS Data](README.md#generating-json-and-js-data) | ||||
|   * [Generating HTML Tables](README.md#generating-html-tables) | ||||
|   * [Generating Single-Worksheet Snapshots](README.md#generating-single-worksheet-snapshots) | ||||
| - [Interface](README.md#interface) | ||||
|   * [Parsing functions](README.md#parsing-functions) | ||||
|   * [Writing functions](README.md#writing-functions) | ||||
|  | ||||
| @ -38,6 +38,7 @@ bits/47_styxml.js | ||||
| bits/48_stybin.js | ||||
| bits/49_theme.js | ||||
| bits/50_styxls.js | ||||
| bits/51_xlmeta.js | ||||
| bits/52_calcchain.js | ||||
| bits/53_externlink.js | ||||
| bits/54_drawing.js | ||||
|  | ||||
							
								
								
									
										151
									
								
								modules/51_xlmeta.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										151
									
								
								modules/51_xlmeta.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,151 @@ | ||||
| RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; | ||||
| function parse_xlmeta_xml(data, name, opts) { | ||||
|   var out = { Types: [] }; | ||||
|   if (!data) | ||||
|     return out; | ||||
|   var pass = false; | ||||
|   data.replace(tagregex, function(x, idx) { | ||||
|     var y = parsexmltag(x); | ||||
|     switch (strip_ns(y[0])) { | ||||
|       case "<?xml": | ||||
|         break; | ||||
|       case "<metadata": | ||||
|       case "</metadata>": | ||||
|         break; | ||||
|       case "<metadataTypes": | ||||
|       case "</metadataTypes>": | ||||
|         break; | ||||
|       case "<metadataType": | ||||
|         out.Types.push({ name: y.name }); | ||||
|         break; | ||||
|       case "<futureMetadata": | ||||
|         break; | ||||
|       case "</futureMetadata>": | ||||
|         break; | ||||
|       case "<bk>": | ||||
|         break; | ||||
|       case "</bk>": | ||||
|         break; | ||||
|       case "<rc": | ||||
|         break; | ||||
|       case "</rc>": | ||||
|         break; | ||||
|       case "<cellMetadata": | ||||
|       case "</cellMetadata>": | ||||
|         break; | ||||
|       case "<valueMetadata": | ||||
|         break; | ||||
|       case "</valueMetadata>": | ||||
|         break; | ||||
|       case "<extLst": | ||||
|       case "<extLst>": | ||||
|       case "</extLst>": | ||||
|       case "<extLst/>": | ||||
|         break; | ||||
|       case "<ext": | ||||
|         pass = true; | ||||
|         break; | ||||
|       case "</ext>": | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if (!pass && opts.WTF) | ||||
|           throw new Error("unrecognized " + y[0] + " in metadata"); | ||||
|     } | ||||
|     return x; | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_xml() { | ||||
|   var o = [XML_HEADER]; | ||||
|   o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>'); | ||||
|   return o.join(""); | ||||
| } | ||||
| function parse_BrtMdtinfo(data, length) { | ||||
|   return { | ||||
|     flags: data.read_shift(4), | ||||
|     version: data.read_shift(4), | ||||
|     name: parse_XLWideString(data, length - 8) | ||||
|   }; | ||||
| } | ||||
| function write_BrtMdtinfo(data) { | ||||
|   var o = new_buf(12 + 2 * data.name.length); | ||||
|   o.write_shift(4, data.flags); | ||||
|   o.write_shift(4, data.version); | ||||
|   write_XLWideString(data.name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtMdb(mdb) { | ||||
|   var o = new_buf(4 + 8 * mdb.length); | ||||
|   o.write_shift(4, mdb.length); | ||||
|   for (var i = 0; i < mdb.length; ++i) { | ||||
|     o.write_shift(4, mdb[i][0]); | ||||
|     o.write_shift(4, mdb[i][1]); | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| function write_BrtBeginEsfmd(cnt, name) { | ||||
|   var o = new_buf(8 + 2 * name.length); | ||||
|   o.write_shift(4, cnt); | ||||
|   write_XLWideString(name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtBeginEsmdb(cnt, cm) { | ||||
|   var o = new_buf(8); | ||||
|   o.write_shift(4, cnt); | ||||
|   o.write_shift(4, cm ? 1 : 0); | ||||
|   return o; | ||||
| } | ||||
| function parse_xlmeta_bin(data, name, _opts) { | ||||
|   var out = { Types: [] }; | ||||
|   var opts = _opts || {}; | ||||
|   var state = []; | ||||
|   var pass = false; | ||||
|   recordhopper(data, function(val, R_n, RT) { | ||||
|     switch (RT) { | ||||
|       case 335: | ||||
|         out.Types.push({ name: val.name }); | ||||
|         break; | ||||
|       case 51: | ||||
|         break; | ||||
|       case 35: | ||||
|         state.push(R_n); | ||||
|         pass = true; | ||||
|         break; | ||||
|       case 36: | ||||
|         state.pop(); | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if ((R_n || "").indexOf("Begin") > 0) { | ||||
|         } else if ((R_n || "").indexOf("End") > 0) { | ||||
|         } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin") | ||||
|           throw new Error("Unexpected record " + RT + " " + R_n); | ||||
|     } | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_bin() { | ||||
|   var ba = buf_array(); | ||||
|   write_record(ba, "BrtBeginMetadata"); | ||||
|   write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1)); | ||||
|   write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({ | ||||
|     name: "XLDAPR", | ||||
|     version: 12e4, | ||||
|     flags: 3496657072 | ||||
|   })); | ||||
|   write_record(ba, "BrtEndEsmdtinfo"); | ||||
|   write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR")); | ||||
|   write_record(ba, "BrtBeginFmd"); | ||||
|   write_record(ba, "BrtFRTBegin", write_UInt32LE(514)); | ||||
|   write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0)); | ||||
|   write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1)); | ||||
|   write_record(ba, "BrtFRTEnd"); | ||||
|   write_record(ba, "BrtEndFmd"); | ||||
|   write_record(ba, "BrtEndEsfmd"); | ||||
|   write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true)); | ||||
|   write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]])); | ||||
|   write_record(ba, "BrtEndEsmdb"); | ||||
|   write_record(ba, "BrtEndMetadata"); | ||||
|   return ba.end(); | ||||
| } | ||||
							
								
								
									
										88
									
								
								modules/51_xlsbmeta.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										88
									
								
								modules/51_xlsbmeta.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | ||||
| function parse_BrtMdtinfo(data, length) { | ||||
|   return { | ||||
|     flags: data.read_shift(4), | ||||
|     version: data.read_shift(4), | ||||
|     name: parse_XLWideString(data, length - 8) | ||||
|   }; | ||||
| } | ||||
| function write_BrtMdtinfo(data) { | ||||
|   var o = new_buf(12 + 2 * data.name.length); | ||||
|   o.write_shift(4, data.flags); | ||||
|   o.write_shift(4, data.version); | ||||
|   write_XLWideString(data.name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtMdb(mdb) { | ||||
|   var o = new_buf(4 + 8 * mdb.length); | ||||
|   o.write_shift(4, mdb.length); | ||||
|   for (var i = 0; i < mdb.length; ++i) { | ||||
|     o.write_shift(4, mdb[i][0]); | ||||
|     o.write_shift(4, mdb[i][1]); | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| function write_BrtBeginEsfmd(cnt, name) { | ||||
|   var o = new_buf(8 + 2 * name.length); | ||||
|   o.write_shift(4, cnt); | ||||
|   write_XLWideString(name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtBeginEsmdb(cnt, cm) { | ||||
|   var o = new_buf(8); | ||||
|   o.write_shift(4, cnt); | ||||
|   o.write_shift(4, cm ? 1 : 0); | ||||
|   return o; | ||||
| } | ||||
| function parse_xlmeta_bin(data, name, _opts) { | ||||
|   var out = { Types: [] }; | ||||
|   var opts = _opts || {}; | ||||
|   var state = []; | ||||
|   var pass = false; | ||||
|   recordhopper(data, function(val, R_n, RT) { | ||||
|     switch (RT) { | ||||
|       case 335: | ||||
|         out.Types.push({ name: val.name }); | ||||
|         break; | ||||
|       case 51: | ||||
|         break; | ||||
|       case 35: | ||||
|         state.push(R_n); | ||||
|         pass = true; | ||||
|         break; | ||||
|       case 36: | ||||
|         state.pop(); | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if ((R_n || "").indexOf("Begin") > 0) { | ||||
|         } else if ((R_n || "").indexOf("End") > 0) { | ||||
|         } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin") | ||||
|           throw new Error("Unexpected record " + RT + " " + R_n); | ||||
|     } | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_bin() { | ||||
|   var ba = buf_array(); | ||||
|   write_record(ba, "BrtBeginMetadata"); | ||||
|   write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1)); | ||||
|   write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({ | ||||
|     name: "XLDAPR", | ||||
|     version: 12e4, | ||||
|     flags: 3496657072 | ||||
|   })); | ||||
|   write_record(ba, "BrtEndEsmdtinfo"); | ||||
|   write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR")); | ||||
|   write_record(ba, "BrtBeginFmd"); | ||||
|   write_record(ba, "BrtFRTBegin", write_UInt32LE(514)); | ||||
|   write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0)); | ||||
|   write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1)); | ||||
|   write_record(ba, "BrtFRTEnd"); | ||||
|   write_record(ba, "BrtEndFmd"); | ||||
|   write_record(ba, "BrtEndEsfmd"); | ||||
|   write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true)); | ||||
|   write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]])); | ||||
|   write_record(ba, "BrtEndEsmdb"); | ||||
|   write_record(ba, "BrtEndMetadata"); | ||||
|   return ba.end(); | ||||
| } | ||||
							
								
								
									
										120
									
								
								modules/51_xlsbmeta.ts
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										120
									
								
								modules/51_xlsbmeta.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,120 @@ | ||||
| /// <reference path="src/types.ts"/>
 | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.698 BrtMdtinfo */ | ||||
| interface BrtMdtinfo { | ||||
| 	flags: number; | ||||
| 	version: number; | ||||
| 	name: string; | ||||
| } | ||||
| function parse_BrtMdtinfo(data: ReadableData, length: number): BrtMdtinfo { | ||||
| 	return { | ||||
| 		flags: data.read_shift(4), | ||||
| 		version: data.read_shift(4), | ||||
| 		name: parse_XLWideString(data, length - 8) | ||||
| 	}; | ||||
| } | ||||
| function write_BrtMdtinfo(data: BrtMdtinfo): RawData { | ||||
| 	var o = new_buf(12 + 2 * data.name.length); | ||||
| 	o.write_shift(4, data.flags); | ||||
| 	o.write_shift(4, data.version); | ||||
| 	write_XLWideString(data.name, o); | ||||
| 	return o.slice(0, o.l); | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.697 BrtMdb */ | ||||
| type Mdir = [number, number]; // "t", "v" in XLSX parlance
 | ||||
| type BrtMdb = Mdir[]; | ||||
| function write_BrtMdb(mdb: BrtMdb): RawData { | ||||
| 	var o = new_buf(4 + 8 * mdb.length); | ||||
| 	o.write_shift(4, mdb.length); | ||||
| 	for(var i = 0; i < mdb.length; ++i) { | ||||
| 		o.write_shift(4, mdb[i][0]); | ||||
| 		o.write_shift(4, mdb[i][1]); | ||||
| 	} | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.72 BrtBeginEsfmd */ | ||||
| function write_BrtBeginEsfmd(cnt: number, name: string): RawData { | ||||
| 	var o = new_buf(8 + 2 * name.length); | ||||
| 	o.write_shift(4, cnt); | ||||
| 	write_XLWideString(name, o); | ||||
| 	return o.slice(0, o.l); | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.73 BrtBeginEsmdb */ | ||||
| function write_BrtBeginEsmdb(cnt: number, cm: boolean): RawData { | ||||
| 	var o = new_buf(8); | ||||
| 	o.write_shift(4, cnt); | ||||
| 	o.write_shift(4, cm ? 1 : 0); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.1.7.34 Metadata */ | ||||
| function parse_xlmeta_bin(data, name: string, _opts?: ParseXLMetaOptions): XLMeta { | ||||
| 	var out: XLMeta = { Types: [] }; | ||||
| 	var opts = _opts || {}; | ||||
| 	var state: string[] = []; | ||||
| 	var pass = false; | ||||
| 
 | ||||
| 	recordhopper(data, (val, R_n, RT) => { | ||||
| 		switch(RT) { | ||||
| 			// case 0x014C: /* 'BrtBeginMetadata' */
 | ||||
| 			// case 0x014D: /* 'BrtEndMetadata' */
 | ||||
| 			// case 0x014E: /* 'BrtBeginEsmdtinfo' */
 | ||||
| 			// case 0x0150: /* 'BrtEndEsmdtinfo' */
 | ||||
| 			// case 0x0151: /* 'BrtBeginEsmdb' */
 | ||||
| 			// case 0x0152: /* 'BrtEndEsmdb' */
 | ||||
| 			// case 0x0153: /* 'BrtBeginEsfmd' */
 | ||||
| 			// case 0x0154: /* 'BrtEndEsfmd' */
 | ||||
| 			// case 0x0034: /* 'BrtBeginFmd' */
 | ||||
| 			// case 0x0035: /* 'BrtEndFmd' */
 | ||||
| 			// case 0x1000: /* 'BrtBeginDynamicArrayPr' */
 | ||||
| 			// case 0x1001: /* 'BrtEndDynamicArrayPr' */
 | ||||
| 			// case 0x138A: /* 'BrtBeginRichValueBlock' */
 | ||||
| 			// case 0x138B: /* 'BrtEndRichValueBlock' */
 | ||||
| 
 | ||||
| 			case 0x014F: /* 'BrtMdtinfo' */ | ||||
| 				out.Types.push({name: (val as BrtMdtinfo).name}); | ||||
| 				break; | ||||
| 			case 0x0033: /* 'BrtMdb' */ | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0023: /* 'BrtFRTBegin' */ | ||||
| 				state.push(R_n); pass = true; break; | ||||
| 			case 0x0024: /* 'BrtFRTEnd' */ | ||||
| 				state.pop(); pass = false; break; | ||||
| 			default: | ||||
| 				if((R_n||"").indexOf("Begin") > 0){/* empty */} | ||||
| 				else if((R_n||"").indexOf("End") > 0){/* empty */} | ||||
| 				else if(!pass || (opts.WTF && state[state.length-1] != "BrtFRTBegin")) throw new Error("Unexpected record " + RT + " " + R_n); | ||||
| 		} | ||||
| 	}); | ||||
| 	return out; | ||||
| } | ||||
| function write_xlmeta_bin() { | ||||
| 	var ba = buf_array(); | ||||
| 	write_record(ba, "BrtBeginMetadata"); | ||||
| 	write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1)); | ||||
| 	write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({ | ||||
| 		name: "XLDAPR", | ||||
| 		version: 120000, | ||||
| 		flags: 0xD06AC0B0 | ||||
| 	})); | ||||
| 	write_record(ba, "BrtEndEsmdtinfo"); | ||||
| 	/* [ESSTR] [ESMDX] */ | ||||
| 	write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR")); | ||||
| 	write_record(ba, "BrtBeginFmd"); | ||||
| 	write_record(ba, "BrtFRTBegin", write_UInt32LE(0x0202)); | ||||
| 	write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0)); | ||||
| 	write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1)); | ||||
| 	write_record(ba, "BrtFRTEnd"); | ||||
| 	write_record(ba, "BrtEndFmd"); | ||||
| 	write_record(ba, "BrtEndEsfmd"); | ||||
| 	write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true)); | ||||
| 	write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]])); | ||||
| 	write_record(ba, "BrtEndEsmdb"); | ||||
| 	/* *FRT */ | ||||
| 	write_record(ba, "BrtEndMetadata"); | ||||
| 	return ba.end(); | ||||
| } | ||||
							
								
								
									
										63
									
								
								modules/51_xlsxmeta.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										63
									
								
								modules/51_xlsxmeta.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; | ||||
| function parse_xlmeta_xml(data, name, opts) { | ||||
|   var out = { Types: [] }; | ||||
|   if (!data) | ||||
|     return out; | ||||
|   var pass = false; | ||||
|   data.replace(tagregex, function(x, idx) { | ||||
|     var y = parsexmltag(x); | ||||
|     switch (strip_ns(y[0])) { | ||||
|       case "<?xml": | ||||
|         break; | ||||
|       case "<metadata": | ||||
|       case "</metadata>": | ||||
|         break; | ||||
|       case "<metadataTypes": | ||||
|       case "</metadataTypes>": | ||||
|         break; | ||||
|       case "<metadataType": | ||||
|         out.Types.push({ name: y.name }); | ||||
|         break; | ||||
|       case "<futureMetadata": | ||||
|         break; | ||||
|       case "</futureMetadata>": | ||||
|         break; | ||||
|       case "<bk>": | ||||
|         break; | ||||
|       case "</bk>": | ||||
|         break; | ||||
|       case "<rc": | ||||
|         break; | ||||
|       case "</rc>": | ||||
|         break; | ||||
|       case "<cellMetadata": | ||||
|       case "</cellMetadata>": | ||||
|         break; | ||||
|       case "<valueMetadata": | ||||
|         break; | ||||
|       case "</valueMetadata>": | ||||
|         break; | ||||
|       case "<extLst": | ||||
|       case "<extLst>": | ||||
|       case "</extLst>": | ||||
|       case "<extLst/>": | ||||
|         break; | ||||
|       case "<ext": | ||||
|         pass = true; | ||||
|         break; | ||||
|       case "</ext>": | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if (!pass && opts.WTF) | ||||
|           throw new Error("unrecognized " + y[0] + " in metadata"); | ||||
|     } | ||||
|     return x; | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_xml() { | ||||
|   var o = [XML_HEADER]; | ||||
|   o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>'); | ||||
|   return o.join(""); | ||||
| } | ||||
							
								
								
									
										85
									
								
								modules/51_xlsxmeta.ts
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										85
									
								
								modules/51_xlsxmeta.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | ||||
| /// <reference path="src/types.ts"/>
 | ||||
| 
 | ||||
| RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; | ||||
| 
 | ||||
| /* 12.3.10 Metadata Part */ | ||||
| function parse_xlmeta_xml(data: string, name: string, opts?: ParseXLMetaOptions): XLMeta { | ||||
| 	var out: XLMeta = { Types: [] }; | ||||
| 	if(!data) return out; | ||||
| 	var pass = false; | ||||
| 
 | ||||
| 	data.replace(tagregex, (x: string, idx: number) => { | ||||
| 		var y: any = parsexmltag(x); | ||||
| 		switch(strip_ns(y[0])) { | ||||
| 			case '<?xml': break; | ||||
| 
 | ||||
| 			/* 18.9.8 */ | ||||
| 			case '<metadata': case '</metadata>': break; | ||||
| 
 | ||||
| 			/* 18.9.11 */ | ||||
| 			case '<metadataTypes': case '</metadataTypes>': break; | ||||
| 
 | ||||
| 			/* 18.9.10 */ | ||||
| 			case '<metadataType': | ||||
| 				out.Types.push({ name: y.name }); | ||||
| 				break; | ||||
| 
 | ||||
| 			/* 18.9.4 */ | ||||
| 			case '<futureMetadata': break; | ||||
| 			case '</futureMetadata>': break; | ||||
| 
 | ||||
| 			/* 18.9.1 */ | ||||
| 			case '<bk>': break; | ||||
| 			case '</bk>': break; | ||||
| 
 | ||||
| 			/* 18.9.15 */ | ||||
| 			case '<rc': break; | ||||
| 			case '</rc>': break; | ||||
| 
 | ||||
| 			/* 18.9.3 */ | ||||
| 			case '<cellMetadata': | ||||
| 			case '</cellMetadata>': break; | ||||
| 
 | ||||
| 			/* 18.9.17 */ | ||||
| 			case '<valueMetadata': break; | ||||
| 			case '</valueMetadata>': break; | ||||
| 
 | ||||
| 			/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 			case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break; | ||||
| 
 | ||||
| 			/* 18.2.7  ext CT_Extension + */ | ||||
| 			case '<ext': pass=true; break; //TODO: check with versions of excel
 | ||||
| 			case '</ext>': pass=false; break; | ||||
| 
 | ||||
| 			default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in metadata'); | ||||
| 		} | ||||
| 		return x; | ||||
| 	}); | ||||
| 	return out; | ||||
| } | ||||
| /* TODO: coordinate with cell writing, pass flags */ | ||||
| function write_xlmeta_xml(): string { | ||||
| 	var o = [XML_HEADER]; | ||||
| 	o.push(`\ | ||||
| <metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray"> | ||||
|   <metadataTypes count="1"> | ||||
|     <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/> | ||||
|   </metadataTypes> | ||||
|   <futureMetadata name="XLDAPR" count="1"> | ||||
|     <bk> | ||||
|       <extLst> | ||||
|         <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}"> | ||||
|           <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/> | ||||
|         </ext> | ||||
|       </extLst> | ||||
|     </bk> | ||||
|   </futureMetadata> | ||||
|   <cellMetadata count="1"> | ||||
|     <bk> | ||||
|       <rc t="1" v="0"/> | ||||
|     </bk> | ||||
|   </cellMetadata> | ||||
| </metadata>`);
 | ||||
| 
 | ||||
| 	return o.join(""); | ||||
| } | ||||
| @ -2,10 +2,13 @@ LIBFILES=$(wildcard src/*.ts) | ||||
| TSFILES=$(wildcard *.ts) | ||||
| ENTRIES=$(subst .ts,.js,$(TSFILES)) | ||||
| 
 | ||||
| BAREJS=04_base64.js 59_vba.js 64_ftab.js | ||||
| BAREJS=04_base64.js 51_xlsxmeta.js 51_xlsbmeta.js 59_vba.js 64_ftab.js | ||||
| 
 | ||||
| .PHONY: all | ||||
| all: $(ENTRIES) | ||||
| all: $(ENTRIES) 51_xlmeta.js | ||||
| 
 | ||||
| 51_xlmeta.js: 51_xlsxmeta.js 51_xlsbmeta.js | ||||
| 	cat $^ > $@ | ||||
| 
 | ||||
| $(BAREJS): %.js: %.ts $(LIBFILES) | ||||
| 	npx esbuild $< --outfile=$@ --platform=browser --target=es5 | ||||
|  | ||||
							
								
								
									
										44
									
								
								modules/src/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										44
									
								
								modules/src/types.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| declare type RawData = Uint8Array | number[]; | ||||
| declare function recordhopper(data: RawData, cb:(val: any, R_n: string, RT: number)=>void): void; | ||||
| declare interface ReadableData { | ||||
| 	l: number; | ||||
| 	read_shift(t: 4): number; | ||||
| 	read_shift(t: any): any; | ||||
| } | ||||
| declare type ParseFunc<T> = (data: ReadableData, length: number) => T; | ||||
| declare var parse_XLWideString: ParseFunc<string>; | ||||
| 
 | ||||
| declare interface WritableData { | ||||
| 	l: number; | ||||
| 	write_shift(t: 4, val: number): void; | ||||
| 	write_shift(t: number, val: string|number, f?: string): any; | ||||
| } | ||||
| declare type WritableRawData = WritableData & RawData; | ||||
| interface BufArray { | ||||
| 	end(): RawData; | ||||
| 	next(sz: number): WritableData; | ||||
| 	push(buf: RawData): void; | ||||
| } | ||||
| declare function buf_array(): BufArray; | ||||
| declare function write_record(ba: BufArray, type: string, payload?: RawData, length?: number): void; | ||||
| declare function new_buf(sz: number): RawData & WritableData & ReadableData; | ||||
| 
 | ||||
| declare var tagregex: RegExp; | ||||
| declare var XML_HEADER: string; | ||||
| declare var RELS: any; | ||||
| declare function parsexmltag(tag: string, skip_root?: boolean, skip_LC?: boolean): object; | ||||
| declare function strip_ns(x: string): string; | ||||
| declare function write_UInt32LE(x: number, o?: WritableData): RawData; | ||||
| declare function write_XLWideString(data: string, o?: WritableData): RawData; | ||||
| declare function writeuint16(x: number): RawData; | ||||
| 
 | ||||
| 
 | ||||
| interface ParseXLMetaOptions { | ||||
| 	WTF?: number|boolean; | ||||
| } | ||||
| interface XLMDT { | ||||
| 	name: string; | ||||
| } | ||||
| interface XLMeta { | ||||
| 	Types: XLMDT[]; | ||||
| } | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
| 	"name": "xlsx", | ||||
| 	"version": "0.18.2", | ||||
| 	"version": "0.18.3", | ||||
| 	"author": "sheetjs", | ||||
| 	"description": "SheetJS Spreadsheet data parser and writer", | ||||
| 	"keywords": [ | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Subproject commit c8fe8a48a8cfc3c480b02f0a6df75cc2aff1932d | ||||
| Subproject commit 8203afea252b2817ec0a67e18f3b7c9503d50b97 | ||||
							
								
								
									
										2
									
								
								types/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								types/index.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -833,7 +833,7 @@ export interface XLSX$Utils { | ||||
|     cell_add_comment(cell: CellObject, text: string, author?: string): void; | ||||
| 
 | ||||
|     /** Assign an Array Formula to a range */ | ||||
|     sheet_set_array_formula(ws: WorkSheet, range: Range|string, formula: string): WorkSheet; | ||||
|     sheet_set_array_formula(ws: WorkSheet, range: Range|string, formula: string, dynamic?: boolean): WorkSheet; | ||||
| 
 | ||||
|     /** Add an array of arrays of JS data to a worksheet */ | ||||
|     sheet_add_aoa<T>(ws: WorkSheet, data: T[][], opts?: SheetAOAOpts): WorkSheet; | ||||
|  | ||||
							
								
								
									
										311
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										311
									
								
								xlsx.flow.js
									
									
									
									
									
								
							| @ -4,7 +4,7 @@ | ||||
| /*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */ | ||||
| var XLSX = {}; | ||||
| function make_xlsx_lib(XLSX){ | ||||
| XLSX.version = '0.18.2'; | ||||
| XLSX.version = '0.18.3'; | ||||
| var current_codepage = 1200, current_ansi = 1252; | ||||
| /*:: declare var cptable:any; */ | ||||
| /*global cptable:true, window */ | ||||
| @ -3189,7 +3189,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) { | ||||
| 	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload); | ||||
| 	if(typeof Deno !== 'undefined') { | ||||
| 		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */ | ||||
| 		if(enc) switch(enc) { | ||||
| 		if(enc && typeof payload == "string") switch(enc) { | ||||
| 			case "utf8": payload = new TextEncoder(enc).encode(payload); break; | ||||
| 			case "binary": payload = s2ab(payload); break; | ||||
| 			/* TODO: binary equivalent */ | ||||
| @ -4144,44 +4144,6 @@ function encode_range_xls(r, opts)/*:string*/ { | ||||
| 	} | ||||
| 	return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff); | ||||
| } | ||||
| var OFFCRYPTO = {}; | ||||
| 
 | ||||
| var make_offcrypto = function(O, _crypto) { | ||||
| 	var crypto; | ||||
| 	if(typeof _crypto !== 'undefined') crypto = _crypto; | ||||
| 	else if(typeof require !== 'undefined') { | ||||
| 		try { crypto = require('crypto'); } | ||||
| 		catch(e) { crypto = null; } | ||||
| 	} | ||||
| 
 | ||||
| 	O.rc4 = function(key, data) { | ||||
| 		var S = new Array(256); | ||||
| 		var c = 0, i = 0, j = 0, t = 0; | ||||
| 		for(i = 0; i != 256; ++i) S[i] = i; | ||||
| 		for(i = 0; i != 256; ++i) { | ||||
| 			j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255; | ||||
| 			t = S[i]; S[i] = S[j]; S[j] = t; | ||||
| 		} | ||||
| 		// $FlowIgnore
 | ||||
| 		i = j = 0; var out = new_raw_buf(data.length); | ||||
| 		for(c = 0; c != data.length; ++c) { | ||||
| 			i = (i + 1)&255; | ||||
| 			j = (j + S[i])%256; | ||||
| 			t = S[i]; S[i] = S[j]; S[j] = t; | ||||
| 			out[c] = (data[c] ^ S[(S[i]+S[j])&255]); | ||||
| 		} | ||||
| 		return out; | ||||
| 	}; | ||||
| 
 | ||||
| 	O.md5 = function(hex) { | ||||
| 		if(!crypto) throw new Error("Unsupported crypto"); | ||||
| 		return crypto.createHash('md5').update(hex).digest('hex'); | ||||
| 	}; | ||||
| }; | ||||
| /*:: declare var crypto:any; */ | ||||
| /*global crypto:true */ | ||||
| make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined); | ||||
| 
 | ||||
| function decode_row(rowstr/*:string*/)/*:number*/ { return parseInt(unfix_row(rowstr),10) - 1; } | ||||
| function encode_row(row/*:number*/)/*:string*/ { return "" + (row + 1); } | ||||
| function fix_row(cstr/*:string*/)/*:string*/ { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); } | ||||
| @ -4351,6 +4313,9 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh | ||||
| } | ||||
| function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { return sheet_add_aoa(null, data, opts); } | ||||
| 
 | ||||
| function parse_Int32LE(data) { | ||||
| 	return data.read_shift(4, 'i'); | ||||
| } | ||||
| function write_UInt32LE(x/*:number*/, o) { | ||||
| 	if (!o) o = new_buf(4); | ||||
| 	o.write_shift(4, x); | ||||
| @ -5016,8 +4981,8 @@ var ct2type/*{[string]:string}*/ = ({ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links", | ||||
| 
 | ||||
| 	/* Metadata */ | ||||
| 	"application/vnd.ms-excel.sheetMetadata": "TODO", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO", | ||||
| 	"application/vnd.ms-excel.sheetMetadata": "metadata", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata", | ||||
| 
 | ||||
| 	/* PivotCache */ | ||||
| 	"application/vnd.ms-excel.pivotCacheDefinition": "TODO", | ||||
| @ -5134,6 +5099,10 @@ var CT_LIST = (function(){ | ||||
| 			xlsx: "application/vnd.ms-excel.macrosheet+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.macrosheet" | ||||
| 		}, | ||||
| 		metadata: { /* Metadata (Stock/Geography and Dynamic Array) */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.sheetMetadata" | ||||
| 		}, | ||||
| 		styles: { /* Styles */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.styles" | ||||
| @ -5153,7 +5122,7 @@ function new_ct()/*:any*/ { | ||||
| 		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[], | ||||
| 		rels:[], strs:[], comments:[], links:[], | ||||
| 		coreprops:[], extprops:[], custprops:[], themes:[], styles:[], | ||||
| 		calcchains:[], vba: [], drawings: [], | ||||
| 		calcchains:[], vba: [], drawings: [], metadata: [], | ||||
| 		TODO:[], xmlns: "" }/*:any*/); | ||||
| } | ||||
| 
 | ||||
| @ -5252,6 +5221,7 @@ function write_ct(ct, opts)/*:string*/ { | ||||
| 	f3('vba'); | ||||
| 	f3('comments'); | ||||
| 	f3('drawings'); | ||||
| 	f2('metadata'); | ||||
| 	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
| } | ||||
| @ -5318,7 +5288,9 @@ var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS]; | ||||
| function add_rels(rels, rId/*:number*/, f, type, relobj, targetmode/*:?string*/)/*:number*/ { | ||||
| 	if(!relobj) relobj = {}; | ||||
| 	if(!rels['!id']) rels['!id'] = {}; | ||||
| 	if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */} | ||||
| 	if(!rels['!idx']) rels['!idx'] = 1; | ||||
| 	if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */} | ||||
| 	rels['!idx'] = rId + 1; | ||||
| 	relobj.Id = 'rId' + rId; | ||||
| 	relobj.Type = type; | ||||
| 	relobj.Target = f; | ||||
| @ -11310,6 +11282,157 @@ function update_xfext(xf, xfext) { | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; | ||||
| function parse_xlmeta_xml(data, name, opts) { | ||||
|   var out = { Types: [] }; | ||||
|   if (!data) | ||||
|     return out; | ||||
|   var pass = false; | ||||
|   data.replace(tagregex, function(x, idx) { | ||||
|     var y = parsexmltag(x); | ||||
|     switch (strip_ns(y[0])) { | ||||
|       case "<?xml": | ||||
|         break; | ||||
|       case "<metadata": | ||||
|       case "</metadata>": | ||||
|         break; | ||||
|       case "<metadataTypes": | ||||
|       case "</metadataTypes>": | ||||
|         break; | ||||
|       case "<metadataType": | ||||
|         out.Types.push({ name: y.name }); | ||||
|         break; | ||||
|       case "<futureMetadata": | ||||
|         break; | ||||
|       case "</futureMetadata>": | ||||
|         break; | ||||
|       case "<bk>": | ||||
|         break; | ||||
|       case "</bk>": | ||||
|         break; | ||||
|       case "<rc": | ||||
|         break; | ||||
|       case "</rc>": | ||||
|         break; | ||||
|       case "<cellMetadata": | ||||
|       case "</cellMetadata>": | ||||
|         break; | ||||
|       case "<valueMetadata": | ||||
|         break; | ||||
|       case "</valueMetadata>": | ||||
|         break; | ||||
|       case "<extLst": | ||||
|       case "<extLst>": | ||||
|       case "</extLst>": | ||||
|       case "<extLst/>": | ||||
|         break; | ||||
|       case "<ext": | ||||
|         pass = true; | ||||
|         break; | ||||
|       case "</ext>": | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if (!pass && opts.WTF) | ||||
|           throw new Error("unrecognized " + y[0] + " in metadata"); | ||||
|     } | ||||
|     return x; | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_xml() { | ||||
|   var o = [XML_HEADER]; | ||||
|   o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>'); | ||||
|   return o.join(""); | ||||
| } | ||||
| function parse_BrtMdtinfo(data, length) { | ||||
|   return { | ||||
|     flags: data.read_shift(4), | ||||
|     version: data.read_shift(4), | ||||
|     name: parse_XLWideString(data, length - 8) | ||||
|   }; | ||||
| } | ||||
| function write_BrtMdtinfo(data) { | ||||
|   var o = new_buf(12 + 2 * data.name.length); | ||||
|   o.write_shift(4, data.flags); | ||||
|   o.write_shift(4, data.version); | ||||
|   write_XLWideString(data.name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtMdb(mdb) { | ||||
|   var o = new_buf(4 + 8 * mdb.length); | ||||
|   o.write_shift(4, mdb.length); | ||||
|   for (var i = 0; i < mdb.length; ++i) { | ||||
|     o.write_shift(4, mdb[i][0]); | ||||
|     o.write_shift(4, mdb[i][1]); | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| function write_BrtBeginEsfmd(cnt, name) { | ||||
|   var o = new_buf(8 + 2 * name.length); | ||||
|   o.write_shift(4, cnt); | ||||
|   write_XLWideString(name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtBeginEsmdb(cnt, cm) { | ||||
|   var o = new_buf(8); | ||||
|   o.write_shift(4, cnt); | ||||
|   o.write_shift(4, cm ? 1 : 0); | ||||
|   return o; | ||||
| } | ||||
| function parse_xlmeta_bin(data, name, _opts) { | ||||
|   var out = { Types: [] }; | ||||
|   var opts = _opts || {}; | ||||
|   var state = []; | ||||
|   var pass = false; | ||||
|   recordhopper(data, function(val, R_n, RT) { | ||||
|     switch (RT) { | ||||
|       case 335: | ||||
|         out.Types.push({ name: val.name }); | ||||
|         break; | ||||
|       case 51: | ||||
|         break; | ||||
|       case 35: | ||||
|         state.push(R_n); | ||||
|         pass = true; | ||||
|         break; | ||||
|       case 36: | ||||
|         state.pop(); | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if ((R_n || "").indexOf("Begin") > 0) { | ||||
|         } else if ((R_n || "").indexOf("End") > 0) { | ||||
|         } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin") | ||||
|           throw new Error("Unexpected record " + RT + " " + R_n); | ||||
|     } | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_bin() { | ||||
|   var ba = buf_array(); | ||||
|   write_record(ba, "BrtBeginMetadata"); | ||||
|   write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1)); | ||||
|   write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({ | ||||
|     name: "XLDAPR", | ||||
|     version: 12e4, | ||||
|     flags: 3496657072 | ||||
|   })); | ||||
|   write_record(ba, "BrtEndEsmdtinfo"); | ||||
|   write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR")); | ||||
|   write_record(ba, "BrtBeginFmd"); | ||||
|   write_record(ba, "BrtFRTBegin", write_UInt32LE(514)); | ||||
|   write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0)); | ||||
|   write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1)); | ||||
|   write_record(ba, "BrtFRTEnd"); | ||||
|   write_record(ba, "BrtEndFmd"); | ||||
|   write_record(ba, "BrtEndEsfmd"); | ||||
|   write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true)); | ||||
|   write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]])); | ||||
|   write_record(ba, "BrtEndEsmdb"); | ||||
|   write_record(ba, "BrtEndMetadata"); | ||||
|   return ba.end(); | ||||
| } | ||||
| /* 18.6 Calculation Chain */ | ||||
| function parse_cc_xml(data/*::, name, opts*/)/*:Array<any>*/ { | ||||
| 	var d = []; | ||||
| @ -12636,7 +12759,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks, | ||||
| 				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx]; | ||||
| 				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx); | ||||
| 				/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */ | ||||
| 				if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6); | ||||
| 				if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6); | ||||
| 				stack.push(name); | ||||
| 				break; | ||||
| 
 | ||||
| @ -14534,6 +14657,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string | ||||
| 	} | ||||
| 	if(cell.l) ws['!links'].push([ref, cell.l]); | ||||
| 	if(cell.c) ws['!comments'].push([ref, cell.c]); | ||||
| 	if(cell.D) o.cm = 1; | ||||
| 	return writextag('c', v, o); | ||||
| } | ||||
| 
 | ||||
| @ -14710,6 +14834,10 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th | ||||
| 			} | ||||
| 			safe_format(p, fmtid, fillid, opts, themes, styles); | ||||
| 			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); } | ||||
| 			if(tag.cm && opts.xlmeta) { | ||||
| 				var cm = (opts.xlmeta.Types||[])[+tag.cm-1]; | ||||
| 				if(cm && cm.name == 'XLDAPR') p.D = true; | ||||
| 			} | ||||
| 			if(dense) { | ||||
| 				var _r = decode_cell(tag.r); | ||||
| 				if(!s[_r.r]) s[_r.r] = []; | ||||
| @ -15424,6 +15552,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 
 | ||||
| 	XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal }; | ||||
| 
 | ||||
| 	var cm, vm; | ||||
| 
 | ||||
| 	recordhopper(data, function ws_parse(val, R_n, RT) { | ||||
| 		if(end) return; | ||||
| 		switch(RT) { | ||||
| @ -15481,6 +15611,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 					} | ||||
| 					if(!af && val.length > 3) p.f = val[3]; | ||||
| 				} | ||||
| 
 | ||||
| 				if(refguess.s.r > row.r) refguess.s.r = row.r; | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| @ -15488,12 +15619,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 				if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) { | ||||
| 					var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); } | ||||
| 				} | ||||
| 				if(cm) { | ||||
| 					if(cm.name == 'XLDAPR') p.D = true; | ||||
| 					cm = void 0; | ||||
| 				} | ||||
| 				if(vm) vm = void 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0001: /* 'BrtCellBlank' */ | ||||
| 			case 0x000C: /* 'BrtShortBlank' */ | ||||
| 				if(!opts.sheetStubs || pass) break; | ||||
| 				p = ({t:'z',v:undefined}/*:any*/); | ||||
| 				p = ({t:'z',v:void 0}/*:any*/); | ||||
| 				C = val[0].c == -1 ? C + 1 : val[0].c; | ||||
| 				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; } | ||||
| 				else s[encode_col(C) + rr] = p; | ||||
| @ -15501,11 +15637,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| 				if(refguess.e.c < C) refguess.e.c = C; | ||||
| 				if(cm) { | ||||
| 					if(cm.name == 'XLDAPR') p.D = true; | ||||
| 					cm = void 0; | ||||
| 				} | ||||
| 				if(vm) vm = void 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x00B0: /* 'BrtMergeCell' */ | ||||
| 				merges.push(val); break; | ||||
| 
 | ||||
| 			case 0x0031: { /* 'BrtCellMeta' */ | ||||
| 				cm = ((opts.xlmeta||{}).Types||[])[val-1]; | ||||
| 			} break; | ||||
| 
 | ||||
| 			case 0x01EE: /* 'BrtHLink' */ | ||||
| 				var rel = rels['!id'][val.relId]; | ||||
| 				if(rel) { | ||||
| @ -15593,7 +15738,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 			case 0x041A: /* 'BrtCFVO14' */ | ||||
| 			case 0x0289: /* 'BrtCellIgnoreEC' */ | ||||
| 			case 0x0451: /* 'BrtCellIgnoreEC14' */ | ||||
| 			case 0x0031: /* 'BrtCellMeta' */ | ||||
| 			case 0x024D: /* 'BrtCellSmartTagProperty' */ | ||||
| 			case 0x025F: /* 'BrtCellWatch' */ | ||||
| 			case 0x0234: /* 'BrtColor' */ | ||||
| @ -16800,6 +16944,11 @@ function parse_xlink(data, rel, name/*:string*/, opts) { | ||||
| 	return parse_xlink_xml((data/*:any*/), rel, name, opts); | ||||
| } | ||||
| 
 | ||||
| function parse_xlmeta(data, name/*:string*/, opts) { | ||||
| 	if(name.slice(-4)===".bin") return parse_xlmeta_bin((data/*:any*/), name, opts); | ||||
| 	return parse_xlmeta_xml((data/*:any*/), name, opts); | ||||
| } | ||||
| 
 | ||||
| function write_wb(wb, name/*:string*/, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts); | ||||
| } | ||||
| @ -16829,6 +16978,10 @@ function write_cc(data, name:string, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts); | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| function write_xlmeta(name/*:string*/) { | ||||
| 	return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)(); | ||||
| } | ||||
| var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g; | ||||
| var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/; | ||||
| function xlml_parsexmltag(tag/*:string*/, skip_root/*:?boolean*/) { | ||||
| @ -19097,7 +19250,7 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x002E/*::]*/: { n:"BrtBorder", f:parse_BrtBorder }, | ||||
| 	/*::[*/0x002F/*::]*/: { n:"BrtXF", f:parse_BrtXF }, | ||||
| 	/*::[*/0x0030/*::]*/: { n:"BrtStyle" }, | ||||
| 	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta" }, | ||||
| 	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta", f:parse_Int32LE }, | ||||
| 	/*::[*/0x0032/*::]*/: { n:"BrtValueMeta" }, | ||||
| 	/*::[*/0x0033/*::]*/: { n:"BrtMdb" }, | ||||
| 	/*::[*/0x0034/*::]*/: { n:"BrtBeginFmd" }, | ||||
| @ -19323,7 +19476,7 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x014C/*::]*/: { n:"BrtBeginMetadata" }, | ||||
| 	/*::[*/0x014D/*::]*/: { n:"BrtEndMetadata" }, | ||||
| 	/*::[*/0x014E/*::]*/: { n:"BrtBeginEsmdtinfo" }, | ||||
| 	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo" }, | ||||
| 	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo", f:parse_BrtMdtinfo }, | ||||
| 	/*::[*/0x0150/*::]*/: { n:"BrtEndEsmdtinfo" }, | ||||
| 	/*::[*/0x0151/*::]*/: { n:"BrtBeginEsmdb" }, | ||||
| 	/*::[*/0x0152/*::]*/: { n:"BrtEndEsmdb" }, | ||||
| @ -19844,7 +19997,7 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x0835/*::]*/: { n:"BrtEndTimelineStyleElements" }, | ||||
| 	/*::[*/0x0836/*::]*/: { n:"BrtDxf15" }, | ||||
| 	/*::[*/0x0837/*::]*/: { n:"BrtBeginDxfs15" }, | ||||
| 	/*::[*/0x0838/*::]*/: { n:"brtEndDxfs15" }, | ||||
| 	/*::[*/0x0838/*::]*/: { n:"BrtEndDxfs15" }, | ||||
| 	/*::[*/0x0839/*::]*/: { n:"BrtSlicerCacheHideItemsWithNoData" }, | ||||
| 	/*::[*/0x083A/*::]*/: { n:"BrtBeginItemUniqueNames" }, | ||||
| 	/*::[*/0x083B/*::]*/: { n:"BrtEndItemUniqueNames" }, | ||||
| @ -19884,9 +20037,27 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x085D/*::]*/: { n:"BrtModelTimeGroupingCalcCol" }, | ||||
| 	/*::[*/0x0C00/*::]*/: { n:"BrtUid" }, | ||||
| 	/*::[*/0x0C01/*::]*/: { n:"BrtRevisionPtr" }, | ||||
| 	/*::[*/0x13e7/*::]*/: { n:"BrtBeginCalcFeatures" }, | ||||
| 	/*::[*/0x13e8/*::]*/: { n:"BrtEndCalcFeatures" }, | ||||
| 	/*::[*/0x13e9/*::]*/: { n:"BrtCalcFeature" }, | ||||
| 	/*::[*/0x1000/*::]*/: { n:"BrtBeginDynamicArrayPr" }, | ||||
| 	/*::[*/0x1001/*::]*/: { n:"BrtEndDynamicArrayPr" }, | ||||
| 	/*::[*/0x138A/*::]*/: { n:"BrtBeginRichValueBlock" }, | ||||
| 	/*::[*/0x138B/*::]*/: { n:"BrtEndRichValueBlock" }, | ||||
| 	/*::[*/0x13D9/*::]*/: { n:"BrtBeginRichFilters" }, | ||||
| 	/*::[*/0x13DA/*::]*/: { n:"BrtEndRichFilters" }, | ||||
| 	/*::[*/0x13DB/*::]*/: { n:"BrtRichFilter" }, | ||||
| 	/*::[*/0x13DC/*::]*/: { n:"BrtBeginRichFilterColumn" }, | ||||
| 	/*::[*/0x13DD/*::]*/: { n:"BrtEndRichFilterColumn" }, | ||||
| 	/*::[*/0x13DE/*::]*/: { n:"BrtBeginCustomRichFilters" }, | ||||
| 	/*::[*/0x13DF/*::]*/: { n:"BrtEndCustomRichFilters" }, | ||||
| 	/*::[*/0x13E0/*::]*/: { n:"BrtCustomRichFilter" }, | ||||
| 	/*::[*/0x13E1/*::]*/: { n:"BrtTop10RichFilter" }, | ||||
| 	/*::[*/0x13E2/*::]*/: { n:"BrtDynamicRichFilter" }, | ||||
| 	/*::[*/0x13E4/*::]*/: { n:"BrtBeginRichSortCondition" }, | ||||
| 	/*::[*/0x13E5/*::]*/: { n:"BrtEndRichSortCondition" }, | ||||
| 	/*::[*/0x13E6/*::]*/: { n:"BrtRichFilterDateGroupItem" }, | ||||
| 	/*::[*/0x13E7/*::]*/: { n:"BrtBeginCalcFeatures" }, | ||||
| 	/*::[*/0x13E8/*::]*/: { n:"BrtEndCalcFeatures" }, | ||||
| 	/*::[*/0x13E9/*::]*/: { n:"BrtCalcFeature" }, | ||||
| 	/*::[*/0x13EB/*::]*/: { n:"BrtExternalLinksPr" }, | ||||
| 	/*::[*/0xFFFF/*::]*/: { n:"" } | ||||
| }; | ||||
| 
 | ||||
| @ -22740,9 +22911,16 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	var wbrelsi = dir.workbooks[0].lastIndexOf("/"); | ||||
| 	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,""); | ||||
| 	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels'; | ||||
| 	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile); | ||||
| 	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s")); | ||||
| 
 | ||||
| 	if((dir.metadata || []).length >= 1) { | ||||
| 		/* TODO: MDX and other types of metadata */ | ||||
| 		opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts); | ||||
| 	} | ||||
| 
 | ||||
| 	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets); | ||||
| 
 | ||||
| 
 | ||||
| 	/* Numbers iOS hack */ | ||||
| 	var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0; | ||||
| 	wsloop: for(i = 0; i != props.Worksheets; ++i) { | ||||
| @ -22978,6 +23156,11 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/metadata." + wbext; | ||||
| 	zip_add_file(zip, f, write_xlmeta(f)); | ||||
| 	ct.metadata.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); | ||||
| 
 | ||||
| 	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
| @ -22986,7 +23169,7 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	return zip; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* this version does not reference XLSB write functions */ | ||||
| function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	_shapeid = 1024; | ||||
| 	if(wb && !wb.SSF) { | ||||
| @ -23108,6 +23291,11 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/metadata." + wbext; | ||||
| 	zip_add_file(zip, f, write_xlmeta_xml()); | ||||
| 	ct.metadata.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); | ||||
| 
 | ||||
| 	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
| @ -23161,6 +23349,7 @@ function read_plaintext_raw(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str); | ||||
| 	o.type = "binary"; | ||||
| 	return read_plaintext(str, o); | ||||
| } | ||||
| 
 | ||||
| @ -23280,14 +23469,15 @@ function write_zip_typeXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ { | ||||
| } | ||||
| function write_zip_denouement(z/*:any*/, o/*:?WriteOpts*/)/*:any*/ { | ||||
| 	var oopts = {}; | ||||
| 	var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string"); | ||||
| 	if(o.compression) oopts.compression = 'DEFLATE'; | ||||
| 	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string"; | ||||
| 	if(o.password) oopts.type = ftype; | ||||
| 	else switch(o.type) { | ||||
| 		case "base64": oopts.type = "base64"; break; | ||||
| 		case "binary": oopts.type = "string"; break; | ||||
| 		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files"); | ||||
| 		case "buffer": | ||||
| 		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break; | ||||
| 		case "file": oopts.type = ftype; break; | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: /*::(*/{"nodebuffer": "buffer", "string": "binary"}/*:: :any)*/[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts); | ||||
| @ -23811,7 +24001,7 @@ utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?stri | ||||
| }; | ||||
| 
 | ||||
| /* set array formula and flush related cells */ | ||||
| utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/) { | ||||
| utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/, dynamic/*:boolean*/) { | ||||
| 	var rng = typeof range != "string" ? range : safe_decode_range(range); | ||||
| 	var rngstr = typeof range == "string" ? range : encode_range(range); | ||||
| 	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) { | ||||
| @ -23819,7 +24009,10 @@ utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:stri | ||||
| 		cell.t = 'n'; | ||||
| 		cell.F = rngstr; | ||||
| 		delete cell.v; | ||||
| 		if(R == rng.s.r && C == rng.s.c) cell.f = formula; | ||||
| 		if(R == rng.s.r && C == rng.s.c) { | ||||
| 			cell.f = formula; | ||||
| 			if(dynamic) cell.D = true; | ||||
| 		} | ||||
| 	} | ||||
| 	return ws; | ||||
| }; | ||||
|  | ||||
							
								
								
									
										310
									
								
								xlsx.js
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										310
									
								
								xlsx.js
									
									
									
										generated
									
									
									
								
							| @ -4,7 +4,7 @@ | ||||
| /*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */ | ||||
| var XLSX = {}; | ||||
| function make_xlsx_lib(XLSX){ | ||||
| XLSX.version = '0.18.2'; | ||||
| XLSX.version = '0.18.3'; | ||||
| var current_codepage = 1200, current_ansi = 1252; | ||||
| /*global cptable:true, window */ | ||||
| if(typeof module !== "undefined" && typeof require !== 'undefined') { | ||||
| @ -3114,7 +3114,7 @@ function write_dl(fname, payload, enc) { | ||||
| 	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload); | ||||
| 	if(typeof Deno !== 'undefined') { | ||||
| 		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */ | ||||
| 		if(enc) switch(enc) { | ||||
| 		if(enc && typeof payload == "string") switch(enc) { | ||||
| 			case "utf8": payload = new TextEncoder(enc).encode(payload); break; | ||||
| 			case "binary": payload = s2ab(payload); break; | ||||
| 			/* TODO: binary equivalent */ | ||||
| @ -4057,43 +4057,6 @@ function encode_range_xls(r, opts) { | ||||
| 	} | ||||
| 	return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff); | ||||
| } | ||||
| var OFFCRYPTO = {}; | ||||
| 
 | ||||
| var make_offcrypto = function(O, _crypto) { | ||||
| 	var crypto; | ||||
| 	if(typeof _crypto !== 'undefined') crypto = _crypto; | ||||
| 	else if(typeof require !== 'undefined') { | ||||
| 		try { crypto = require('crypto'); } | ||||
| 		catch(e) { crypto = null; } | ||||
| 	} | ||||
| 
 | ||||
| 	O.rc4 = function(key, data) { | ||||
| 		var S = new Array(256); | ||||
| 		var c = 0, i = 0, j = 0, t = 0; | ||||
| 		for(i = 0; i != 256; ++i) S[i] = i; | ||||
| 		for(i = 0; i != 256; ++i) { | ||||
| 			j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255; | ||||
| 			t = S[i]; S[i] = S[j]; S[j] = t; | ||||
| 		} | ||||
| 		// $FlowIgnore
 | ||||
| 		i = j = 0; var out = new_raw_buf(data.length); | ||||
| 		for(c = 0; c != data.length; ++c) { | ||||
| 			i = (i + 1)&255; | ||||
| 			j = (j + S[i])%256; | ||||
| 			t = S[i]; S[i] = S[j]; S[j] = t; | ||||
| 			out[c] = (data[c] ^ S[(S[i]+S[j])&255]); | ||||
| 		} | ||||
| 		return out; | ||||
| 	}; | ||||
| 
 | ||||
| 	O.md5 = function(hex) { | ||||
| 		if(!crypto) throw new Error("Unsupported crypto"); | ||||
| 		return crypto.createHash('md5').update(hex).digest('hex'); | ||||
| 	}; | ||||
| }; | ||||
| /*global crypto:true */ | ||||
| make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined); | ||||
| 
 | ||||
| function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; } | ||||
| function encode_row(row) { return "" + (row + 1); } | ||||
| function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); } | ||||
| @ -4258,6 +4221,9 @@ function sheet_add_aoa(_ws, data, opts) { | ||||
| } | ||||
| function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); } | ||||
| 
 | ||||
| function parse_Int32LE(data) { | ||||
| 	return data.read_shift(4, 'i'); | ||||
| } | ||||
| function write_UInt32LE(x, o) { | ||||
| 	if (!o) o = new_buf(4); | ||||
| 	o.write_shift(4, x); | ||||
| @ -4923,8 +4889,8 @@ var ct2type/*{[string]:string}*/ = ({ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links", | ||||
| 
 | ||||
| 	/* Metadata */ | ||||
| 	"application/vnd.ms-excel.sheetMetadata": "TODO", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO", | ||||
| 	"application/vnd.ms-excel.sheetMetadata": "metadata", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata", | ||||
| 
 | ||||
| 	/* PivotCache */ | ||||
| 	"application/vnd.ms-excel.pivotCacheDefinition": "TODO", | ||||
| @ -5041,6 +5007,10 @@ var CT_LIST = (function(){ | ||||
| 			xlsx: "application/vnd.ms-excel.macrosheet+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.macrosheet" | ||||
| 		}, | ||||
| 		metadata: { /* Metadata (Stock/Geography and Dynamic Array) */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.sheetMetadata" | ||||
| 		}, | ||||
| 		styles: { /* Styles */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.styles" | ||||
| @ -5060,7 +5030,7 @@ function new_ct() { | ||||
| 		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[], | ||||
| 		rels:[], strs:[], comments:[], links:[], | ||||
| 		coreprops:[], extprops:[], custprops:[], themes:[], styles:[], | ||||
| 		calcchains:[], vba: [], drawings: [], | ||||
| 		calcchains:[], vba: [], drawings: [], metadata: [], | ||||
| 		TODO:[], xmlns: "" }); | ||||
| } | ||||
| 
 | ||||
| @ -5159,6 +5129,7 @@ function write_ct(ct, opts) { | ||||
| 	f3('vba'); | ||||
| 	f3('comments'); | ||||
| 	f3('drawings'); | ||||
| 	f2('metadata'); | ||||
| 	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
| } | ||||
| @ -5225,7 +5196,9 @@ var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS]; | ||||
| function add_rels(rels, rId, f, type, relobj, targetmode) { | ||||
| 	if(!relobj) relobj = {}; | ||||
| 	if(!rels['!id']) rels['!id'] = {}; | ||||
| 	if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */} | ||||
| 	if(!rels['!idx']) rels['!idx'] = 1; | ||||
| 	if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */} | ||||
| 	rels['!idx'] = rId + 1; | ||||
| 	relobj.Id = 'rId' + rId; | ||||
| 	relobj.Type = type; | ||||
| 	relobj.Target = f; | ||||
| @ -11209,6 +11182,157 @@ function update_xfext(xf, xfext) { | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; | ||||
| function parse_xlmeta_xml(data, name, opts) { | ||||
|   var out = { Types: [] }; | ||||
|   if (!data) | ||||
|     return out; | ||||
|   var pass = false; | ||||
|   data.replace(tagregex, function(x, idx) { | ||||
|     var y = parsexmltag(x); | ||||
|     switch (strip_ns(y[0])) { | ||||
|       case "<?xml": | ||||
|         break; | ||||
|       case "<metadata": | ||||
|       case "</metadata>": | ||||
|         break; | ||||
|       case "<metadataTypes": | ||||
|       case "</metadataTypes>": | ||||
|         break; | ||||
|       case "<metadataType": | ||||
|         out.Types.push({ name: y.name }); | ||||
|         break; | ||||
|       case "<futureMetadata": | ||||
|         break; | ||||
|       case "</futureMetadata>": | ||||
|         break; | ||||
|       case "<bk>": | ||||
|         break; | ||||
|       case "</bk>": | ||||
|         break; | ||||
|       case "<rc": | ||||
|         break; | ||||
|       case "</rc>": | ||||
|         break; | ||||
|       case "<cellMetadata": | ||||
|       case "</cellMetadata>": | ||||
|         break; | ||||
|       case "<valueMetadata": | ||||
|         break; | ||||
|       case "</valueMetadata>": | ||||
|         break; | ||||
|       case "<extLst": | ||||
|       case "<extLst>": | ||||
|       case "</extLst>": | ||||
|       case "<extLst/>": | ||||
|         break; | ||||
|       case "<ext": | ||||
|         pass = true; | ||||
|         break; | ||||
|       case "</ext>": | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if (!pass && opts.WTF) | ||||
|           throw new Error("unrecognized " + y[0] + " in metadata"); | ||||
|     } | ||||
|     return x; | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_xml() { | ||||
|   var o = [XML_HEADER]; | ||||
|   o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>'); | ||||
|   return o.join(""); | ||||
| } | ||||
| function parse_BrtMdtinfo(data, length) { | ||||
|   return { | ||||
|     flags: data.read_shift(4), | ||||
|     version: data.read_shift(4), | ||||
|     name: parse_XLWideString(data, length - 8) | ||||
|   }; | ||||
| } | ||||
| function write_BrtMdtinfo(data) { | ||||
|   var o = new_buf(12 + 2 * data.name.length); | ||||
|   o.write_shift(4, data.flags); | ||||
|   o.write_shift(4, data.version); | ||||
|   write_XLWideString(data.name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtMdb(mdb) { | ||||
|   var o = new_buf(4 + 8 * mdb.length); | ||||
|   o.write_shift(4, mdb.length); | ||||
|   for (var i = 0; i < mdb.length; ++i) { | ||||
|     o.write_shift(4, mdb[i][0]); | ||||
|     o.write_shift(4, mdb[i][1]); | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| function write_BrtBeginEsfmd(cnt, name) { | ||||
|   var o = new_buf(8 + 2 * name.length); | ||||
|   o.write_shift(4, cnt); | ||||
|   write_XLWideString(name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtBeginEsmdb(cnt, cm) { | ||||
|   var o = new_buf(8); | ||||
|   o.write_shift(4, cnt); | ||||
|   o.write_shift(4, cm ? 1 : 0); | ||||
|   return o; | ||||
| } | ||||
| function parse_xlmeta_bin(data, name, _opts) { | ||||
|   var out = { Types: [] }; | ||||
|   var opts = _opts || {}; | ||||
|   var state = []; | ||||
|   var pass = false; | ||||
|   recordhopper(data, function(val, R_n, RT) { | ||||
|     switch (RT) { | ||||
|       case 335: | ||||
|         out.Types.push({ name: val.name }); | ||||
|         break; | ||||
|       case 51: | ||||
|         break; | ||||
|       case 35: | ||||
|         state.push(R_n); | ||||
|         pass = true; | ||||
|         break; | ||||
|       case 36: | ||||
|         state.pop(); | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if ((R_n || "").indexOf("Begin") > 0) { | ||||
|         } else if ((R_n || "").indexOf("End") > 0) { | ||||
|         } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin") | ||||
|           throw new Error("Unexpected record " + RT + " " + R_n); | ||||
|     } | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_bin() { | ||||
|   var ba = buf_array(); | ||||
|   write_record(ba, "BrtBeginMetadata"); | ||||
|   write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1)); | ||||
|   write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({ | ||||
|     name: "XLDAPR", | ||||
|     version: 12e4, | ||||
|     flags: 3496657072 | ||||
|   })); | ||||
|   write_record(ba, "BrtEndEsmdtinfo"); | ||||
|   write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR")); | ||||
|   write_record(ba, "BrtBeginFmd"); | ||||
|   write_record(ba, "BrtFRTBegin", write_UInt32LE(514)); | ||||
|   write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0)); | ||||
|   write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1)); | ||||
|   write_record(ba, "BrtFRTEnd"); | ||||
|   write_record(ba, "BrtEndFmd"); | ||||
|   write_record(ba, "BrtEndEsfmd"); | ||||
|   write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true)); | ||||
|   write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]])); | ||||
|   write_record(ba, "BrtEndEsmdb"); | ||||
|   write_record(ba, "BrtEndMetadata"); | ||||
|   return ba.end(); | ||||
| } | ||||
| /* 18.6 Calculation Chain */ | ||||
| function parse_cc_xml(data) { | ||||
| 	var d = []; | ||||
| @ -12534,7 +12658,7 @@ ixti = f[1][1]; r = f[1][2]; | ||||
| 				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx]; | ||||
| 				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx); | ||||
| 				/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */ | ||||
| 				if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6); | ||||
| 				if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6); | ||||
| 				stack.push(name); | ||||
| 				break; | ||||
| 
 | ||||
| @ -14432,6 +14556,7 @@ function write_ws_xml_cell(cell, ref, ws, opts) { | ||||
| 	} | ||||
| 	if(cell.l) ws['!links'].push([ref, cell.l]); | ||||
| 	if(cell.c) ws['!comments'].push([ref, cell.c]); | ||||
| 	if(cell.D) o.cm = 1; | ||||
| 	return writextag('c', v, o); | ||||
| } | ||||
| 
 | ||||
| @ -14608,6 +14733,10 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) { | ||||
| 			} | ||||
| 			safe_format(p, fmtid, fillid, opts, themes, styles); | ||||
| 			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); } | ||||
| 			if(tag.cm && opts.xlmeta) { | ||||
| 				var cm = (opts.xlmeta.Types||[])[+tag.cm-1]; | ||||
| 				if(cm && cm.name == 'XLDAPR') p.D = true; | ||||
| 			} | ||||
| 			if(dense) { | ||||
| 				var _r = decode_cell(tag.r); | ||||
| 				if(!s[_r.r]) s[_r.r] = []; | ||||
| @ -15321,6 +15450,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) { | ||||
| 
 | ||||
| 	XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal }; | ||||
| 
 | ||||
| 	var cm, vm; | ||||
| 
 | ||||
| 	recordhopper(data, function ws_parse(val, R_n, RT) { | ||||
| 		if(end) return; | ||||
| 		switch(RT) { | ||||
| @ -15378,6 +15509,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) { | ||||
| 					} | ||||
| 					if(!af && val.length > 3) p.f = val[3]; | ||||
| 				} | ||||
| 
 | ||||
| 				if(refguess.s.r > row.r) refguess.s.r = row.r; | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| @ -15385,12 +15517,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) { | ||||
| 				if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) { | ||||
| 					var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); } | ||||
| 				} | ||||
| 				if(cm) { | ||||
| 					if(cm.name == 'XLDAPR') p.D = true; | ||||
| 					cm = void 0; | ||||
| 				} | ||||
| 				if(vm) vm = void 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0001: /* 'BrtCellBlank' */ | ||||
| 			case 0x000C: /* 'BrtShortBlank' */ | ||||
| 				if(!opts.sheetStubs || pass) break; | ||||
| 				p = ({t:'z',v:undefined}); | ||||
| 				p = ({t:'z',v:void 0}); | ||||
| 				C = val[0].c == -1 ? C + 1 : val[0].c; | ||||
| 				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; } | ||||
| 				else s[encode_col(C) + rr] = p; | ||||
| @ -15398,11 +15535,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) { | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| 				if(refguess.e.c < C) refguess.e.c = C; | ||||
| 				if(cm) { | ||||
| 					if(cm.name == 'XLDAPR') p.D = true; | ||||
| 					cm = void 0; | ||||
| 				} | ||||
| 				if(vm) vm = void 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x00B0: /* 'BrtMergeCell' */ | ||||
| 				merges.push(val); break; | ||||
| 
 | ||||
| 			case 0x0031: { /* 'BrtCellMeta' */ | ||||
| 				cm = ((opts.xlmeta||{}).Types||[])[val-1]; | ||||
| 			} break; | ||||
| 
 | ||||
| 			case 0x01EE: /* 'BrtHLink' */ | ||||
| 				var rel = rels['!id'][val.relId]; | ||||
| 				if(rel) { | ||||
| @ -15490,7 +15636,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) { | ||||
| 			case 0x041A: /* 'BrtCFVO14' */ | ||||
| 			case 0x0289: /* 'BrtCellIgnoreEC' */ | ||||
| 			case 0x0451: /* 'BrtCellIgnoreEC14' */ | ||||
| 			case 0x0031: /* 'BrtCellMeta' */ | ||||
| 			case 0x024D: /* 'BrtCellSmartTagProperty' */ | ||||
| 			case 0x025F: /* 'BrtCellWatch' */ | ||||
| 			case 0x0234: /* 'BrtColor' */ | ||||
| @ -16695,6 +16840,11 @@ function parse_xlink(data, rel, name, opts) { | ||||
| 	return parse_xlink_xml((data), rel, name, opts); | ||||
| } | ||||
| 
 | ||||
| function parse_xlmeta(data, name, opts) { | ||||
| 	if(name.slice(-4)===".bin") return parse_xlmeta_bin((data), name, opts); | ||||
| 	return parse_xlmeta_xml((data), name, opts); | ||||
| } | ||||
| 
 | ||||
| function write_wb(wb, name, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts); | ||||
| } | ||||
| @ -16724,6 +16874,10 @@ function write_cc(data, name:string, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts); | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| function write_xlmeta(name) { | ||||
| 	return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)(); | ||||
| } | ||||
| var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g; | ||||
| var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/; | ||||
| function xlml_parsexmltag(tag, skip_root) { | ||||
| @ -18980,7 +19134,7 @@ var XLSBRecordEnum = { | ||||
| 0x002E: { n:"BrtBorder", f:parse_BrtBorder }, | ||||
| 0x002F: { n:"BrtXF", f:parse_BrtXF }, | ||||
| 0x0030: { n:"BrtStyle" }, | ||||
| 0x0031: { n:"BrtCellMeta" }, | ||||
| 0x0031: { n:"BrtCellMeta", f:parse_Int32LE }, | ||||
| 0x0032: { n:"BrtValueMeta" }, | ||||
| 0x0033: { n:"BrtMdb" }, | ||||
| 0x0034: { n:"BrtBeginFmd" }, | ||||
| @ -19206,7 +19360,7 @@ var XLSBRecordEnum = { | ||||
| 0x014C: { n:"BrtBeginMetadata" }, | ||||
| 0x014D: { n:"BrtEndMetadata" }, | ||||
| 0x014E: { n:"BrtBeginEsmdtinfo" }, | ||||
| 0x014F: { n:"BrtMdtinfo" }, | ||||
| 0x014F: { n:"BrtMdtinfo", f:parse_BrtMdtinfo }, | ||||
| 0x0150: { n:"BrtEndEsmdtinfo" }, | ||||
| 0x0151: { n:"BrtBeginEsmdb" }, | ||||
| 0x0152: { n:"BrtEndEsmdb" }, | ||||
| @ -19727,7 +19881,7 @@ var XLSBRecordEnum = { | ||||
| 0x0835: { n:"BrtEndTimelineStyleElements" }, | ||||
| 0x0836: { n:"BrtDxf15" }, | ||||
| 0x0837: { n:"BrtBeginDxfs15" }, | ||||
| 0x0838: { n:"brtEndDxfs15" }, | ||||
| 0x0838: { n:"BrtEndDxfs15" }, | ||||
| 0x0839: { n:"BrtSlicerCacheHideItemsWithNoData" }, | ||||
| 0x083A: { n:"BrtBeginItemUniqueNames" }, | ||||
| 0x083B: { n:"BrtEndItemUniqueNames" }, | ||||
| @ -19767,9 +19921,27 @@ var XLSBRecordEnum = { | ||||
| 0x085D: { n:"BrtModelTimeGroupingCalcCol" }, | ||||
| 0x0C00: { n:"BrtUid" }, | ||||
| 0x0C01: { n:"BrtRevisionPtr" }, | ||||
| 0x13e7: { n:"BrtBeginCalcFeatures" }, | ||||
| 0x13e8: { n:"BrtEndCalcFeatures" }, | ||||
| 0x13e9: { n:"BrtCalcFeature" }, | ||||
| 0x1000: { n:"BrtBeginDynamicArrayPr" }, | ||||
| 0x1001: { n:"BrtEndDynamicArrayPr" }, | ||||
| 0x138A: { n:"BrtBeginRichValueBlock" }, | ||||
| 0x138B: { n:"BrtEndRichValueBlock" }, | ||||
| 0x13D9: { n:"BrtBeginRichFilters" }, | ||||
| 0x13DA: { n:"BrtEndRichFilters" }, | ||||
| 0x13DB: { n:"BrtRichFilter" }, | ||||
| 0x13DC: { n:"BrtBeginRichFilterColumn" }, | ||||
| 0x13DD: { n:"BrtEndRichFilterColumn" }, | ||||
| 0x13DE: { n:"BrtBeginCustomRichFilters" }, | ||||
| 0x13DF: { n:"BrtEndCustomRichFilters" }, | ||||
| 0x13E0: { n:"BrtCustomRichFilter" }, | ||||
| 0x13E1: { n:"BrtTop10RichFilter" }, | ||||
| 0x13E2: { n:"BrtDynamicRichFilter" }, | ||||
| 0x13E4: { n:"BrtBeginRichSortCondition" }, | ||||
| 0x13E5: { n:"BrtEndRichSortCondition" }, | ||||
| 0x13E6: { n:"BrtRichFilterDateGroupItem" }, | ||||
| 0x13E7: { n:"BrtBeginCalcFeatures" }, | ||||
| 0x13E8: { n:"BrtEndCalcFeatures" }, | ||||
| 0x13E9: { n:"BrtCalcFeature" }, | ||||
| 0x13EB: { n:"BrtExternalLinksPr" }, | ||||
| 0xFFFF: { n:"" } | ||||
| }; | ||||
| 
 | ||||
| @ -22622,9 +22794,16 @@ function parse_zip(zip, opts) { | ||||
| 	var wbrelsi = dir.workbooks[0].lastIndexOf("/"); | ||||
| 	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,""); | ||||
| 	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels'; | ||||
| 	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile); | ||||
| 	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s")); | ||||
| 
 | ||||
| 	if((dir.metadata || []).length >= 1) { | ||||
| 		/* TODO: MDX and other types of metadata */ | ||||
| 		opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts); | ||||
| 	} | ||||
| 
 | ||||
| 	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets); | ||||
| 
 | ||||
| 
 | ||||
| 	/* Numbers iOS hack */ | ||||
| 	var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0; | ||||
| 	wsloop: for(i = 0; i != props.Worksheets; ++i) { | ||||
| @ -22857,6 +23036,11 @@ f = "docProps/app.xml"; | ||||
| 		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/metadata." + wbext; | ||||
| 	zip_add_file(zip, f, write_xlmeta(f)); | ||||
| 	ct.metadata.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); | ||||
| 
 | ||||
| 	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
| @ -22865,7 +23049,7 @@ f = "docProps/app.xml"; | ||||
| 	return zip; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* this version does not reference XLSB write functions */ | ||||
| function write_zip_xlsx(wb, opts) { | ||||
| 	_shapeid = 1024; | ||||
| 	if(wb && !wb.SSF) { | ||||
| @ -22986,6 +23170,11 @@ f = "docProps/app.xml"; | ||||
| 		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/metadata." + wbext; | ||||
| 	zip_add_file(zip, f, write_xlmeta_xml()); | ||||
| 	ct.metadata.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); | ||||
| 
 | ||||
| 	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
| @ -23039,6 +23228,7 @@ function read_plaintext_raw(data, o) { | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str); | ||||
| 	o.type = "binary"; | ||||
| 	return read_plaintext(str, o); | ||||
| } | ||||
| 
 | ||||
| @ -23157,14 +23347,15 @@ function write_zip_typeXLSX(wb, opts) { | ||||
| } | ||||
| function write_zip_denouement(z, o) { | ||||
| 	var oopts = {}; | ||||
| 	var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string"); | ||||
| 	if(o.compression) oopts.compression = 'DEFLATE'; | ||||
| 	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string"; | ||||
| 	if(o.password) oopts.type = ftype; | ||||
| 	else switch(o.type) { | ||||
| 		case "base64": oopts.type = "base64"; break; | ||||
| 		case "binary": oopts.type = "string"; break; | ||||
| 		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files"); | ||||
| 		case "buffer": | ||||
| 		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break; | ||||
| 		case "file": oopts.type = ftype; break; | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: {"nodebuffer": "buffer", "string": "binary"}[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts); | ||||
| @ -23682,7 +23873,7 @@ utils.cell_add_comment = function(cell, text, author) { | ||||
| }; | ||||
| 
 | ||||
| /* set array formula and flush related cells */ | ||||
| utils.sheet_set_array_formula = function(ws, range, formula) { | ||||
| utils.sheet_set_array_formula = function(ws, range, formula, dynamic) { | ||||
| 	var rng = typeof range != "string" ? range : safe_decode_range(range); | ||||
| 	var rngstr = typeof range == "string" ? range : encode_range(range); | ||||
| 	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) { | ||||
| @ -23690,7 +23881,10 @@ utils.sheet_set_array_formula = function(ws, range, formula) { | ||||
| 		cell.t = 'n'; | ||||
| 		cell.F = rngstr; | ||||
| 		delete cell.v; | ||||
| 		if(R == rng.s.r && C == rng.s.c) cell.f = formula; | ||||
| 		if(R == rng.s.r && C == rng.s.c) { | ||||
| 			cell.f = formula; | ||||
| 			if(dynamic) cell.D = true; | ||||
| 		} | ||||
| 	} | ||||
| 	return ws; | ||||
| }; | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										989
									
								
								xlsx.mini.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										989
									
								
								xlsx.mini.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										273
									
								
								xlsx.mjs
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										273
									
								
								xlsx.mjs
									
									
									
										generated
									
									
									
								
							| @ -3,7 +3,7 @@ | ||||
| /*exported XLSX */ | ||||
| /*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */ | ||||
| var XLSX = {}; | ||||
| XLSX.version = '0.18.2'; | ||||
| XLSX.version = '0.18.3'; | ||||
| var current_codepage = 1200, current_ansi = 1252; | ||||
| 
 | ||||
| var VALID_ANSI = [ 874, 932, 936, 949, 950, 10000 ]; | ||||
| @ -3186,7 +3186,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) { | ||||
| 	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload); | ||||
| 	if(typeof Deno !== 'undefined') { | ||||
| 		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */ | ||||
| 		if(enc) switch(enc) { | ||||
| 		if(enc && typeof payload == "string") switch(enc) { | ||||
| 			case "utf8": payload = new TextEncoder(enc).encode(payload); break; | ||||
| 			case "binary": payload = s2ab(payload); break; | ||||
| 			/* TODO: binary equivalent */ | ||||
| @ -4310,6 +4310,9 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh | ||||
| } | ||||
| function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { return sheet_add_aoa(null, data, opts); } | ||||
| 
 | ||||
| function parse_Int32LE(data) { | ||||
| 	return data.read_shift(4, 'i'); | ||||
| } | ||||
| function write_UInt32LE(x/*:number*/, o) { | ||||
| 	if (!o) o = new_buf(4); | ||||
| 	o.write_shift(4, x); | ||||
| @ -4975,8 +4978,8 @@ var ct2type/*{[string]:string}*/ = ({ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links", | ||||
| 
 | ||||
| 	/* Metadata */ | ||||
| 	"application/vnd.ms-excel.sheetMetadata": "TODO", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO", | ||||
| 	"application/vnd.ms-excel.sheetMetadata": "metadata", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata", | ||||
| 
 | ||||
| 	/* PivotCache */ | ||||
| 	"application/vnd.ms-excel.pivotCacheDefinition": "TODO", | ||||
| @ -5093,6 +5096,10 @@ var CT_LIST = (function(){ | ||||
| 			xlsx: "application/vnd.ms-excel.macrosheet+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.macrosheet" | ||||
| 		}, | ||||
| 		metadata: { /* Metadata (Stock/Geography and Dynamic Array) */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.sheetMetadata" | ||||
| 		}, | ||||
| 		styles: { /* Styles */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.styles" | ||||
| @ -5112,7 +5119,7 @@ function new_ct()/*:any*/ { | ||||
| 		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[], | ||||
| 		rels:[], strs:[], comments:[], links:[], | ||||
| 		coreprops:[], extprops:[], custprops:[], themes:[], styles:[], | ||||
| 		calcchains:[], vba: [], drawings: [], | ||||
| 		calcchains:[], vba: [], drawings: [], metadata: [], | ||||
| 		TODO:[], xmlns: "" }/*:any*/); | ||||
| } | ||||
| 
 | ||||
| @ -5211,6 +5218,7 @@ function write_ct(ct, opts)/*:string*/ { | ||||
| 	f3('vba'); | ||||
| 	f3('comments'); | ||||
| 	f3('drawings'); | ||||
| 	f2('metadata'); | ||||
| 	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
| } | ||||
| @ -5277,7 +5285,9 @@ var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS]; | ||||
| function add_rels(rels, rId/*:number*/, f, type, relobj, targetmode/*:?string*/)/*:number*/ { | ||||
| 	if(!relobj) relobj = {}; | ||||
| 	if(!rels['!id']) rels['!id'] = {}; | ||||
| 	if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */} | ||||
| 	if(!rels['!idx']) rels['!idx'] = 1; | ||||
| 	if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */} | ||||
| 	rels['!idx'] = rId + 1; | ||||
| 	relobj.Id = 'rId' + rId; | ||||
| 	relobj.Type = type; | ||||
| 	relobj.Target = f; | ||||
| @ -11269,6 +11279,157 @@ function update_xfext(xf, xfext) { | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; | ||||
| function parse_xlmeta_xml(data, name, opts) { | ||||
|   var out = { Types: [] }; | ||||
|   if (!data) | ||||
|     return out; | ||||
|   var pass = false; | ||||
|   data.replace(tagregex, function(x, idx) { | ||||
|     var y = parsexmltag(x); | ||||
|     switch (strip_ns(y[0])) { | ||||
|       case "<?xml": | ||||
|         break; | ||||
|       case "<metadata": | ||||
|       case "</metadata>": | ||||
|         break; | ||||
|       case "<metadataTypes": | ||||
|       case "</metadataTypes>": | ||||
|         break; | ||||
|       case "<metadataType": | ||||
|         out.Types.push({ name: y.name }); | ||||
|         break; | ||||
|       case "<futureMetadata": | ||||
|         break; | ||||
|       case "</futureMetadata>": | ||||
|         break; | ||||
|       case "<bk>": | ||||
|         break; | ||||
|       case "</bk>": | ||||
|         break; | ||||
|       case "<rc": | ||||
|         break; | ||||
|       case "</rc>": | ||||
|         break; | ||||
|       case "<cellMetadata": | ||||
|       case "</cellMetadata>": | ||||
|         break; | ||||
|       case "<valueMetadata": | ||||
|         break; | ||||
|       case "</valueMetadata>": | ||||
|         break; | ||||
|       case "<extLst": | ||||
|       case "<extLst>": | ||||
|       case "</extLst>": | ||||
|       case "<extLst/>": | ||||
|         break; | ||||
|       case "<ext": | ||||
|         pass = true; | ||||
|         break; | ||||
|       case "</ext>": | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if (!pass && opts.WTF) | ||||
|           throw new Error("unrecognized " + y[0] + " in metadata"); | ||||
|     } | ||||
|     return x; | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_xml() { | ||||
|   var o = [XML_HEADER]; | ||||
|   o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>'); | ||||
|   return o.join(""); | ||||
| } | ||||
| function parse_BrtMdtinfo(data, length) { | ||||
|   return { | ||||
|     flags: data.read_shift(4), | ||||
|     version: data.read_shift(4), | ||||
|     name: parse_XLWideString(data, length - 8) | ||||
|   }; | ||||
| } | ||||
| function write_BrtMdtinfo(data) { | ||||
|   var o = new_buf(12 + 2 * data.name.length); | ||||
|   o.write_shift(4, data.flags); | ||||
|   o.write_shift(4, data.version); | ||||
|   write_XLWideString(data.name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtMdb(mdb) { | ||||
|   var o = new_buf(4 + 8 * mdb.length); | ||||
|   o.write_shift(4, mdb.length); | ||||
|   for (var i = 0; i < mdb.length; ++i) { | ||||
|     o.write_shift(4, mdb[i][0]); | ||||
|     o.write_shift(4, mdb[i][1]); | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| function write_BrtBeginEsfmd(cnt, name) { | ||||
|   var o = new_buf(8 + 2 * name.length); | ||||
|   o.write_shift(4, cnt); | ||||
|   write_XLWideString(name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function write_BrtBeginEsmdb(cnt, cm) { | ||||
|   var o = new_buf(8); | ||||
|   o.write_shift(4, cnt); | ||||
|   o.write_shift(4, cm ? 1 : 0); | ||||
|   return o; | ||||
| } | ||||
| function parse_xlmeta_bin(data, name, _opts) { | ||||
|   var out = { Types: [] }; | ||||
|   var opts = _opts || {}; | ||||
|   var state = []; | ||||
|   var pass = false; | ||||
|   recordhopper(data, function(val, R_n, RT) { | ||||
|     switch (RT) { | ||||
|       case 335: | ||||
|         out.Types.push({ name: val.name }); | ||||
|         break; | ||||
|       case 51: | ||||
|         break; | ||||
|       case 35: | ||||
|         state.push(R_n); | ||||
|         pass = true; | ||||
|         break; | ||||
|       case 36: | ||||
|         state.pop(); | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if ((R_n || "").indexOf("Begin") > 0) { | ||||
|         } else if ((R_n || "").indexOf("End") > 0) { | ||||
|         } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin") | ||||
|           throw new Error("Unexpected record " + RT + " " + R_n); | ||||
|     } | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_bin() { | ||||
|   var ba = buf_array(); | ||||
|   write_record(ba, "BrtBeginMetadata"); | ||||
|   write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1)); | ||||
|   write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({ | ||||
|     name: "XLDAPR", | ||||
|     version: 12e4, | ||||
|     flags: 3496657072 | ||||
|   })); | ||||
|   write_record(ba, "BrtEndEsmdtinfo"); | ||||
|   write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR")); | ||||
|   write_record(ba, "BrtBeginFmd"); | ||||
|   write_record(ba, "BrtFRTBegin", write_UInt32LE(514)); | ||||
|   write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0)); | ||||
|   write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1)); | ||||
|   write_record(ba, "BrtFRTEnd"); | ||||
|   write_record(ba, "BrtEndFmd"); | ||||
|   write_record(ba, "BrtEndEsfmd"); | ||||
|   write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true)); | ||||
|   write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]])); | ||||
|   write_record(ba, "BrtEndEsmdb"); | ||||
|   write_record(ba, "BrtEndMetadata"); | ||||
|   return ba.end(); | ||||
| } | ||||
| /* 18.6 Calculation Chain */ | ||||
| function parse_cc_xml(data/*::, name, opts*/)/*:Array<any>*/ { | ||||
| 	var d = []; | ||||
| @ -12595,7 +12756,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks, | ||||
| 				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx]; | ||||
| 				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx); | ||||
| 				/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */ | ||||
| 				if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6); | ||||
| 				if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6); | ||||
| 				stack.push(name); | ||||
| 				break; | ||||
| 
 | ||||
| @ -14493,6 +14654,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string | ||||
| 	} | ||||
| 	if(cell.l) ws['!links'].push([ref, cell.l]); | ||||
| 	if(cell.c) ws['!comments'].push([ref, cell.c]); | ||||
| 	if(cell.D) o.cm = 1; | ||||
| 	return writextag('c', v, o); | ||||
| } | ||||
| 
 | ||||
| @ -14669,6 +14831,10 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th | ||||
| 			} | ||||
| 			safe_format(p, fmtid, fillid, opts, themes, styles); | ||||
| 			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); } | ||||
| 			if(tag.cm && opts.xlmeta) { | ||||
| 				var cm = (opts.xlmeta.Types||[])[+tag.cm-1]; | ||||
| 				if(cm && cm.name == 'XLDAPR') p.D = true; | ||||
| 			} | ||||
| 			if(dense) { | ||||
| 				var _r = decode_cell(tag.r); | ||||
| 				if(!s[_r.r]) s[_r.r] = []; | ||||
| @ -15383,6 +15549,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 
 | ||||
| 	XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal }; | ||||
| 
 | ||||
| 	var cm, vm; | ||||
| 
 | ||||
| 	recordhopper(data, function ws_parse(val, R_n, RT) { | ||||
| 		if(end) return; | ||||
| 		switch(RT) { | ||||
| @ -15440,6 +15608,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 					} | ||||
| 					if(!af && val.length > 3) p.f = val[3]; | ||||
| 				} | ||||
| 
 | ||||
| 				if(refguess.s.r > row.r) refguess.s.r = row.r; | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| @ -15447,12 +15616,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 				if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) { | ||||
| 					var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); } | ||||
| 				} | ||||
| 				if(cm) { | ||||
| 					if(cm.name == 'XLDAPR') p.D = true; | ||||
| 					cm = void 0; | ||||
| 				} | ||||
| 				if(vm) vm = void 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0001: /* 'BrtCellBlank' */ | ||||
| 			case 0x000C: /* 'BrtShortBlank' */ | ||||
| 				if(!opts.sheetStubs || pass) break; | ||||
| 				p = ({t:'z',v:undefined}/*:any*/); | ||||
| 				p = ({t:'z',v:void 0}/*:any*/); | ||||
| 				C = val[0].c == -1 ? C + 1 : val[0].c; | ||||
| 				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; } | ||||
| 				else s[encode_col(C) + rr] = p; | ||||
| @ -15460,11 +15634,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| 				if(refguess.e.c < C) refguess.e.c = C; | ||||
| 				if(cm) { | ||||
| 					if(cm.name == 'XLDAPR') p.D = true; | ||||
| 					cm = void 0; | ||||
| 				} | ||||
| 				if(vm) vm = void 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x00B0: /* 'BrtMergeCell' */ | ||||
| 				merges.push(val); break; | ||||
| 
 | ||||
| 			case 0x0031: { /* 'BrtCellMeta' */ | ||||
| 				cm = ((opts.xlmeta||{}).Types||[])[val-1]; | ||||
| 			} break; | ||||
| 
 | ||||
| 			case 0x01EE: /* 'BrtHLink' */ | ||||
| 				var rel = rels['!id'][val.relId]; | ||||
| 				if(rel) { | ||||
| @ -15552,7 +15735,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 			case 0x041A: /* 'BrtCFVO14' */ | ||||
| 			case 0x0289: /* 'BrtCellIgnoreEC' */ | ||||
| 			case 0x0451: /* 'BrtCellIgnoreEC14' */ | ||||
| 			case 0x0031: /* 'BrtCellMeta' */ | ||||
| 			case 0x024D: /* 'BrtCellSmartTagProperty' */ | ||||
| 			case 0x025F: /* 'BrtCellWatch' */ | ||||
| 			case 0x0234: /* 'BrtColor' */ | ||||
| @ -16759,6 +16941,11 @@ function parse_xlink(data, rel, name/*:string*/, opts) { | ||||
| 	return parse_xlink_xml((data/*:any*/), rel, name, opts); | ||||
| } | ||||
| 
 | ||||
| function parse_xlmeta(data, name/*:string*/, opts) { | ||||
| 	if(name.slice(-4)===".bin") return parse_xlmeta_bin((data/*:any*/), name, opts); | ||||
| 	return parse_xlmeta_xml((data/*:any*/), name, opts); | ||||
| } | ||||
| 
 | ||||
| function write_wb(wb, name/*:string*/, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts); | ||||
| } | ||||
| @ -16788,6 +16975,10 @@ function write_cc(data, name:string, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts); | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| function write_xlmeta(name/*:string*/) { | ||||
| 	return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)(); | ||||
| } | ||||
| var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g; | ||||
| var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/; | ||||
| function xlml_parsexmltag(tag/*:string*/, skip_root/*:?boolean*/) { | ||||
| @ -19056,7 +19247,7 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x002E/*::]*/: { n:"BrtBorder", f:parse_BrtBorder }, | ||||
| 	/*::[*/0x002F/*::]*/: { n:"BrtXF", f:parse_BrtXF }, | ||||
| 	/*::[*/0x0030/*::]*/: { n:"BrtStyle" }, | ||||
| 	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta" }, | ||||
| 	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta", f:parse_Int32LE }, | ||||
| 	/*::[*/0x0032/*::]*/: { n:"BrtValueMeta" }, | ||||
| 	/*::[*/0x0033/*::]*/: { n:"BrtMdb" }, | ||||
| 	/*::[*/0x0034/*::]*/: { n:"BrtBeginFmd" }, | ||||
| @ -19282,7 +19473,7 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x014C/*::]*/: { n:"BrtBeginMetadata" }, | ||||
| 	/*::[*/0x014D/*::]*/: { n:"BrtEndMetadata" }, | ||||
| 	/*::[*/0x014E/*::]*/: { n:"BrtBeginEsmdtinfo" }, | ||||
| 	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo" }, | ||||
| 	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo", f:parse_BrtMdtinfo }, | ||||
| 	/*::[*/0x0150/*::]*/: { n:"BrtEndEsmdtinfo" }, | ||||
| 	/*::[*/0x0151/*::]*/: { n:"BrtBeginEsmdb" }, | ||||
| 	/*::[*/0x0152/*::]*/: { n:"BrtEndEsmdb" }, | ||||
| @ -19803,7 +19994,7 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x0835/*::]*/: { n:"BrtEndTimelineStyleElements" }, | ||||
| 	/*::[*/0x0836/*::]*/: { n:"BrtDxf15" }, | ||||
| 	/*::[*/0x0837/*::]*/: { n:"BrtBeginDxfs15" }, | ||||
| 	/*::[*/0x0838/*::]*/: { n:"brtEndDxfs15" }, | ||||
| 	/*::[*/0x0838/*::]*/: { n:"BrtEndDxfs15" }, | ||||
| 	/*::[*/0x0839/*::]*/: { n:"BrtSlicerCacheHideItemsWithNoData" }, | ||||
| 	/*::[*/0x083A/*::]*/: { n:"BrtBeginItemUniqueNames" }, | ||||
| 	/*::[*/0x083B/*::]*/: { n:"BrtEndItemUniqueNames" }, | ||||
| @ -19843,9 +20034,27 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x085D/*::]*/: { n:"BrtModelTimeGroupingCalcCol" }, | ||||
| 	/*::[*/0x0C00/*::]*/: { n:"BrtUid" }, | ||||
| 	/*::[*/0x0C01/*::]*/: { n:"BrtRevisionPtr" }, | ||||
| 	/*::[*/0x13e7/*::]*/: { n:"BrtBeginCalcFeatures" }, | ||||
| 	/*::[*/0x13e8/*::]*/: { n:"BrtEndCalcFeatures" }, | ||||
| 	/*::[*/0x13e9/*::]*/: { n:"BrtCalcFeature" }, | ||||
| 	/*::[*/0x1000/*::]*/: { n:"BrtBeginDynamicArrayPr" }, | ||||
| 	/*::[*/0x1001/*::]*/: { n:"BrtEndDynamicArrayPr" }, | ||||
| 	/*::[*/0x138A/*::]*/: { n:"BrtBeginRichValueBlock" }, | ||||
| 	/*::[*/0x138B/*::]*/: { n:"BrtEndRichValueBlock" }, | ||||
| 	/*::[*/0x13D9/*::]*/: { n:"BrtBeginRichFilters" }, | ||||
| 	/*::[*/0x13DA/*::]*/: { n:"BrtEndRichFilters" }, | ||||
| 	/*::[*/0x13DB/*::]*/: { n:"BrtRichFilter" }, | ||||
| 	/*::[*/0x13DC/*::]*/: { n:"BrtBeginRichFilterColumn" }, | ||||
| 	/*::[*/0x13DD/*::]*/: { n:"BrtEndRichFilterColumn" }, | ||||
| 	/*::[*/0x13DE/*::]*/: { n:"BrtBeginCustomRichFilters" }, | ||||
| 	/*::[*/0x13DF/*::]*/: { n:"BrtEndCustomRichFilters" }, | ||||
| 	/*::[*/0x13E0/*::]*/: { n:"BrtCustomRichFilter" }, | ||||
| 	/*::[*/0x13E1/*::]*/: { n:"BrtTop10RichFilter" }, | ||||
| 	/*::[*/0x13E2/*::]*/: { n:"BrtDynamicRichFilter" }, | ||||
| 	/*::[*/0x13E4/*::]*/: { n:"BrtBeginRichSortCondition" }, | ||||
| 	/*::[*/0x13E5/*::]*/: { n:"BrtEndRichSortCondition" }, | ||||
| 	/*::[*/0x13E6/*::]*/: { n:"BrtRichFilterDateGroupItem" }, | ||||
| 	/*::[*/0x13E7/*::]*/: { n:"BrtBeginCalcFeatures" }, | ||||
| 	/*::[*/0x13E8/*::]*/: { n:"BrtEndCalcFeatures" }, | ||||
| 	/*::[*/0x13E9/*::]*/: { n:"BrtCalcFeature" }, | ||||
| 	/*::[*/0x13EB/*::]*/: { n:"BrtExternalLinksPr" }, | ||||
| 	/*::[*/0xFFFF/*::]*/: { n:"" } | ||||
| }; | ||||
| 
 | ||||
| @ -22699,9 +22908,16 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	var wbrelsi = dir.workbooks[0].lastIndexOf("/"); | ||||
| 	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,""); | ||||
| 	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels'; | ||||
| 	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile); | ||||
| 	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s")); | ||||
| 
 | ||||
| 	if((dir.metadata || []).length >= 1) { | ||||
| 		/* TODO: MDX and other types of metadata */ | ||||
| 		opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts); | ||||
| 	} | ||||
| 
 | ||||
| 	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets); | ||||
| 
 | ||||
| 
 | ||||
| 	/* Numbers iOS hack */ | ||||
| 	var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0; | ||||
| 	wsloop: for(i = 0; i != props.Worksheets; ++i) { | ||||
| @ -22937,6 +23153,11 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/metadata." + wbext; | ||||
| 	zip_add_file(zip, f, write_xlmeta(f)); | ||||
| 	ct.metadata.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); | ||||
| 
 | ||||
| 	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
| @ -22945,7 +23166,7 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	return zip; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* this version does not reference XLSB write functions */ | ||||
| function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	_shapeid = 1024; | ||||
| 	if(wb && !wb.SSF) { | ||||
| @ -23067,6 +23288,11 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/metadata." + wbext; | ||||
| 	zip_add_file(zip, f, write_xlmeta_xml()); | ||||
| 	ct.metadata.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); | ||||
| 
 | ||||
| 	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
| @ -23120,6 +23346,7 @@ function read_plaintext_raw(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str); | ||||
| 	o.type = "binary"; | ||||
| 	return read_plaintext(str, o); | ||||
| } | ||||
| 
 | ||||
| @ -23239,14 +23466,15 @@ function write_zip_typeXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ { | ||||
| } | ||||
| function write_zip_denouement(z/*:any*/, o/*:?WriteOpts*/)/*:any*/ { | ||||
| 	var oopts = {}; | ||||
| 	var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string"); | ||||
| 	if(o.compression) oopts.compression = 'DEFLATE'; | ||||
| 	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string"; | ||||
| 	if(o.password) oopts.type = ftype; | ||||
| 	else switch(o.type) { | ||||
| 		case "base64": oopts.type = "base64"; break; | ||||
| 		case "binary": oopts.type = "string"; break; | ||||
| 		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files"); | ||||
| 		case "buffer": | ||||
| 		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break; | ||||
| 		case "file": oopts.type = ftype; break; | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: /*::(*/{"nodebuffer": "buffer", "string": "binary"}/*:: :any)*/[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts); | ||||
| @ -23770,7 +23998,7 @@ utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?stri | ||||
| }; | ||||
| 
 | ||||
| /* set array formula and flush related cells */ | ||||
| utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/) { | ||||
| utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/, dynamic/*:boolean*/) { | ||||
| 	var rng = typeof range != "string" ? range : safe_decode_range(range); | ||||
| 	var rngstr = typeof range == "string" ? range : encode_range(range); | ||||
| 	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) { | ||||
| @ -23778,7 +24006,10 @@ utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:stri | ||||
| 		cell.t = 'n'; | ||||
| 		cell.F = rngstr; | ||||
| 		delete cell.v; | ||||
| 		if(R == rng.s.r && C == rng.s.c) cell.f = formula; | ||||
| 		if(R == rng.s.r && C == rng.s.c) { | ||||
| 			cell.f = formula; | ||||
| 			if(dynamic) cell.D = true; | ||||
| 		} | ||||
| 	} | ||||
| 	return ws; | ||||
| }; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user