@origints/xlsx 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/convert.d.ts +85 -0
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.es.js +2257 -0
- package/dist/index.es.js.map +1 -0
- package/dist/parse.d.ts +85 -0
- package/dist/util.d.ts +68 -0
- package/dist/xlsx-cell.d.ts +212 -0
- package/dist/xlsx-cursor.d.ts +203 -0
- package/dist/xlsx-query.d.ts +155 -0
- package/dist/xlsx-range.d.ts +166 -0
- package/dist/xlsx-result.d.ts +94 -0
- package/dist/xlsx-sheet.d.ts +149 -0
- package/dist/xlsx-workbook.d.ts +128 -0
- package/package.json +46 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { XlsxWorkbook } from './xlsx-workbook';
|
|
2
|
+
import { XlsxSheet } from './xlsx-sheet';
|
|
3
|
+
import { XlsxRange } from './xlsx-range';
|
|
4
|
+
import { XlsxCell } from './xlsx-cell';
|
|
5
|
+
import { CellValue } from './xlsx-result';
|
|
6
|
+
/**
|
|
7
|
+
* JSON-compatible value types.
|
|
8
|
+
*/
|
|
9
|
+
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
10
|
+
[key: string]: JsonValue;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Options for converting to JSON.
|
|
14
|
+
*/
|
|
15
|
+
export interface ToJsonOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Include sheet names as keys.
|
|
18
|
+
* Default: true
|
|
19
|
+
*/
|
|
20
|
+
includeSheetNames?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Include cell addresses in output.
|
|
23
|
+
* Default: false
|
|
24
|
+
*/
|
|
25
|
+
includeCellAddresses?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Convert dates to ISO strings.
|
|
28
|
+
* Default: true
|
|
29
|
+
*/
|
|
30
|
+
dateAsIsoString?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Include empty cells.
|
|
33
|
+
* Default: false
|
|
34
|
+
*/
|
|
35
|
+
includeEmpty?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Use first row as headers for object conversion.
|
|
38
|
+
* Default: false
|
|
39
|
+
*/
|
|
40
|
+
firstRowAsHeaders?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Convert a cell value to a JSON-compatible value.
|
|
44
|
+
*/
|
|
45
|
+
export declare function cellValueToJson(value: CellValue, options?: ToJsonOptions): JsonValue;
|
|
46
|
+
/**
|
|
47
|
+
* Convert a cell to a JSON representation.
|
|
48
|
+
*/
|
|
49
|
+
export declare function cellToJson(cell: XlsxCell, options?: ToJsonOptions): JsonValue;
|
|
50
|
+
/**
|
|
51
|
+
* Convert a range to a JSON representation.
|
|
52
|
+
*/
|
|
53
|
+
export declare function rangeToJson(range: XlsxRange, options?: ToJsonOptions): JsonValue;
|
|
54
|
+
/**
|
|
55
|
+
* Convert a range to a 2D array.
|
|
56
|
+
*/
|
|
57
|
+
export declare function rangeToArray(range: XlsxRange, options?: ToJsonOptions): JsonValue[][];
|
|
58
|
+
/**
|
|
59
|
+
* Convert a range to an array of objects using the first row as headers.
|
|
60
|
+
*/
|
|
61
|
+
export declare function rangeToObjects(range: XlsxRange, options?: ToJsonOptions): JsonValue;
|
|
62
|
+
/**
|
|
63
|
+
* Convert a sheet to a JSON representation.
|
|
64
|
+
*/
|
|
65
|
+
export declare function sheetToJson(sheet: XlsxSheet, options?: ToJsonOptions): JsonValue;
|
|
66
|
+
/**
|
|
67
|
+
* Convert a workbook to a JSON representation.
|
|
68
|
+
*/
|
|
69
|
+
export declare function workbookToJson(workbook: XlsxWorkbook, options?: ToJsonOptions): JsonValue;
|
|
70
|
+
/**
|
|
71
|
+
* Convert a range to CSV format.
|
|
72
|
+
*/
|
|
73
|
+
export declare function rangeToCsv(range: XlsxRange, options?: {
|
|
74
|
+
delimiter?: string;
|
|
75
|
+
lineEnding?: string;
|
|
76
|
+
quoteStrings?: boolean;
|
|
77
|
+
}): string;
|
|
78
|
+
/**
|
|
79
|
+
* Convert a sheet to CSV format.
|
|
80
|
+
*/
|
|
81
|
+
export declare function sheetToCsv(sheet: XlsxSheet, options?: {
|
|
82
|
+
delimiter?: string;
|
|
83
|
+
lineEnding?: string;
|
|
84
|
+
quoteStrings?: boolean;
|
|
85
|
+
}): string;
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const N=require("exceljs");function i(s,t){return{ok:!0,value:s,path:t}}function a(s,t,e,r){return{ok:!1,failure:{kind:s,message:t,path:e,sourceLocation:r}}}function F(s){const t=[];return s.file&&t.push(s.file),s.sheet&&t.push(`[${s.sheet}]`),s.range?t.push(`!${s.range}`):s.cell&&t.push(`!${s.cell}`),t.join("")||"workbook"}function z(s){if(s.sheet)return{kind:"excel",file:s.file??"",sheet:s.sheet,range:s.range??s.cell??""}}function b(s){return typeof s=="object"&&s!==null&&!(s instanceof Date)&&"formula"in s}function R(s){return typeof s=="object"&&s!==null&&!(s instanceof Date)&&"error"in s}async function I(s){const t=s.getReader(),e=[];try{for(;;){const{done:r,value:n}=await t.read();if(r)break;e.push(n)}return Buffer.concat(e)}finally{t.releaseLock()}}function S(s){let t=0;for(let e=0;e<s.length;e++)t=t*26+(s.charCodeAt(e)-64);return t}function V(s){let t="";for(;s>0;){const e=(s-1)%26;t=String.fromCharCode(65+e)+t,s=Math.floor((s-1)/26)}return t}function w(s){const t=s.match(/^([A-Z]+)(\d+)$/i);if(!t)throw new Error(`Invalid cell address: ${s}`);const e=t[1].toUpperCase();return{row:parseInt(t[2],10),col:S(e),colLetter:e}}function C(s,t){return`${V(t)}${s}`}function y(s){const t=s.split(":");if(t.length===1){const n=w(t[0]);return{start:{row:n.row,col:n.col},end:{row:n.row,col:n.col}}}if(t.length!==2)throw new Error(`Invalid range: ${s}`);const e=w(t[0]),r=w(t[1]);return{start:{row:e.row,col:e.col},end:{row:r.row,col:r.col}}}function $(s,t,e,r){const n=C(s,t),o=C(e,r);return n===o?n:`${n}:${o}`}function O(s,t,e){return s>=e.start.row&&s<=e.end.row&&t>=e.start.col&&t<=e.end.col}class p{constructor(t,e,r){this.cell=t,this._path=e,this._sheetName=r}static fromExcelJS(t,e,r){const n={file:r,sheet:e,cell:t.address};return new p(t,n,e)}get address(){return this.cell.address}get row(){return typeof this.cell.row=="number"?this.cell.row:parseInt(String(this.cell.row),10)}get col(){return typeof this.cell.col=="number"?this.cell.col:parseInt(String(this.cell.col),10)}get colLetter(){return this.address.replace(/\d+$/,"")}get path(){return this._path}get sheetName(){return this._sheetName}value(){const t=this.getRawValue();return b(t)?i(t.result??null,this._path):R(t)?a("formula",`Cell contains error: ${t.error}`,this._path):i(t,this._path)}extendedValue(){return i(this.getRawValue(),this._path)}string(){const t=this.getResolvedValue();return t==null?a("type","Expected string, got null",this._path):typeof t=="string"?i(t,this._path):typeof t=="number"||typeof t=="boolean"?i(String(t),this._path):t instanceof Date?i(t.toISOString(),this._path):a("type",`Expected string, got ${typeof t}`,this._path)}number(){const t=this.getResolvedValue();if(typeof t=="number")return i(t,this._path);if(typeof t=="string"){const e=parseFloat(t);if(!isNaN(e))return i(e,this._path)}return a("type",`Expected number, got ${E(t)}`,this._path)}boolean(){const t=this.getResolvedValue();return typeof t=="boolean"?i(t,this._path):a("type",`Expected boolean, got ${E(t)}`,this._path)}date(){const t=this.getResolvedValue();if(t instanceof Date)return i(t,this._path);if(typeof t=="number"){const e=this.excelDateToJS(t);return i(e,this._path)}if(typeof t=="string"){const e=new Date(t);if(!isNaN(e.getTime()))return i(e,this._path)}return a("type",`Expected date, got ${E(t)}`,this._path)}formula(){const t=this.getRawValue();return b(t)?i(t.formula,this._path):a("type","Cell does not contain a formula",this._path)}richText(){const t=this.cell.value,e=this.cell.hyperlink;if(t&&typeof t=="object"&&"richText"in t){const u=t.richText.map(c=>({text:c.text,bold:c.font?.bold,italic:c.font?.italic,underline:c.font?.underline===!0||c.font?.underline==="single",strikethrough:c.font?.strike,color:c.font?.color?.argb,size:c.font?.size,font:c.font?.name}));return i({segments:u,hyperlink:e},this._path)}if(t&&typeof t=="object"&&"text"in t&&"hyperlink"in t){const h=t,u=this.style(),c={text:h.text,bold:u.font?.bold,italic:u.font?.italic,underline:u.font?.underline,strikethrough:u.font?.strikethrough,color:u.font?.color,size:u.font?.size,font:u.font?.name};return i({segments:[c],hyperlink:h.hyperlink},this._path)}const r=this.getResolvedValue(),n=r!==null?String(r):"",o=this.style(),l={text:n,bold:o.font?.bold,italic:o.font?.italic,underline:o.font?.underline,strikethrough:o.font?.strikethrough,color:o.font?.color,size:o.font?.size,font:o.font?.name};return i({segments:[l],hyperlink:e},this._path)}markdown(){const t=this.richText();if(!t.ok)return t;const{segments:e,hyperlink:r}=t.value;let n="";for(const o of e){let l=o.text;o.strikethrough&&(l=`~~${l}~~`),o.bold&&(l=`**${l}**`),o.italic&&(l=`*${l}*`),n+=l}return r&&(n=`[${n}](${r})`),i(n,this._path)}isRichText(){const t=this.cell.value;return t!==null&&typeof t=="object"&&"richText"in t}isEmpty(){const t=this.cell.value;return t==null||t===""}isFormula(){return b(this.getRawValue())}isMerged(){return this.cell.isMerged}isMergedMaster(){return this.cell.isMerged?this.cell.master.address===this.cell.address:!1}isString(){return typeof this.getResolvedValue()=="string"}isNumber(){return typeof this.getResolvedValue()=="number"}isBoolean(){return typeof this.getResolvedValue()=="boolean"}isDate(){return this.getResolvedValue()instanceof Date}isError(){return R(this.getRawValue())}style(){const t=this.cell.font,e=this.cell.fill,r=this.cell.border,n=this.cell.alignment;return{font:t?{name:t.name,size:t.size,bold:t.bold,italic:t.italic,underline:t.underline===!0||t.underline==="single",strikethrough:t.strike,color:t.color?.argb??(t.color?.theme!==void 0?`theme:${t.color.theme}`:void 0)}:void 0,fill:e&&e.type==="pattern"?{type:e.pattern,color:e.fgColor?.argb}:void 0,border:r?{top:!!r.top,bottom:!!r.bottom,left:!!r.left,right:!!r.right}:void 0,alignment:n?{horizontal:n.horizontal,vertical:n.vertical,wrapText:n.wrapText}:void 0,numFmt:this.cell.numFmt}}hyperlink(){const t=this.cell.hyperlink;return t?i(t,this._path):a("missing","Cell does not contain a hyperlink",this._path)}comment(){const t=this.cell.note;return t?typeof t=="string"?i(t,this._path):t.texts?i(t.texts.map(e=>e.text).join(""),this._path):a("format","Unable to extract comment text",this._path):a("missing","Cell does not contain a comment",this._path)}getOffsetCell(t,e,r){const n=this.row+t,o=this.col+e;if(n<1||o<1)return a("bounds",`Cell offset (${t}, ${e}) from ${this.address} is out of bounds`,this._path);const l=r(n,o);return l?i(l,l.path):a("missing",`Cell at ${C(n,o)} not found`,this._path)}getRawValue(){const t=this.cell.value;if(t==null)return null;if(typeof t=="object"){if("error"in t)return{error:String(t.error)};if("formula"in t){const e=t;return{formula:e.formula,result:this.normalizeResult(e.result)}}if("sharedFormula"in t){const e=t;return{formula:e.sharedFormula,result:this.normalizeResult(e.result)}}if("richText"in t)return t.richText.map(r=>r.text).join("");if(t instanceof Date)return t}return typeof t=="string"||typeof t=="number"||typeof t=="boolean"?t:null}getResolvedValue(){const t=this.getRawValue();return b(t)?t.result??null:R(t)?null:t}normalizeResult(t){return t==null?null:typeof t=="string"||typeof t=="number"||typeof t=="boolean"||t instanceof Date?t:null}excelDateToJS(t){const e=t>60?-1:0,r=t+e-1,n=new Date(1900,0,1);return new Date(n.getTime()+r*24*60*60*1e3)}}function E(s){return s===null?"null":s===void 0?"undefined":s instanceof Date?"date":Array.isArray(s)?"array":typeof s}class m{constructor(t,e,r,n,o,l,h,u){this.worksheet=t,this._startRow=e,this._startCol=r,this._endRow=n,this._endCol=o,this._path=l,this._sheetName=h,this._file=u}static fromCoords(t,e,r,n,o,l,h){const u=$(e,r,n,o),c={file:h,sheet:l,range:u};return new m(t,e,r,n,o,c,l,h)}static fromAddress(t,e,r,n){try{const{start:o,end:l}=y(e);return i(m.fromCoords(t,o.row,o.col,l.row,l.col,r,n),{file:n,sheet:r,range:e})}catch{return a("range",`Invalid range address: ${e}`,{file:n,sheet:r})}}get address(){return $(this._startRow,this._startCol,this._endRow,this._endCol)}get startRow(){return this._startRow}get startCol(){return this._startCol}get endRow(){return this._endRow}get endCol(){return this._endCol}get path(){return this._path}get rowCount(){return this._endRow-this._startRow+1}get colCount(){return this._endCol-this._startCol+1}get cellCount(){return this.rowCount*this.colCount}cellAt(t,e){const r=this._startRow+t,n=this._startCol+e;if(r<this._startRow||r>this._endRow||n<this._startCol||n>this._endCol)return a("bounds",`Offset (${t}, ${e}) is outside range ${this.address}`,this._path);const o=this.worksheet.getCell(r,n);return i(p.fromExcelJS(o,this._sheetName,this._file),{...this._path,cell:o.address,range:void 0})}cell(t){try{const{start:e}=y(t);if(e.row<this._startRow||e.row>this._endRow||e.col<this._startCol||e.col>this._endCol)return a("bounds",`Cell ${t} is outside range ${this.address}`,this._path);const r=this.worksheet.getCell(t);return i(p.fromExcelJS(r,this._sheetName,this._file),{...this._path,cell:t,range:void 0})}catch{return a("range",`Invalid cell address: ${t}`,this._path)}}*cells(){for(let t=this._startRow;t<=this._endRow;t++)for(let e=this._startCol;e<=this._endCol;e++){const r=this.worksheet.getCell(t,e);yield p.fromExcelJS(r,this._sheetName,this._file)}}*rows(){for(let t=this._startRow;t<=this._endRow;t++){const e=[];for(let r=this._startCol;r<=this._endCol;r++){const n=this.worksheet.getCell(t,r);e.push(p.fromExcelJS(n,this._sheetName,this._file))}yield e}}*cols(){for(let t=this._startCol;t<=this._endCol;t++){const e=[];for(let r=this._startRow;r<=this._endRow;r++){const n=this.worksheet.getCell(r,t);e.push(p.fromExcelJS(n,this._sheetName,this._file))}yield e}}values(){const t=[];for(const e of this.rows()){const r=[];for(const n of e){const o=n.value();r.push(o.ok?o.value:null)}t.push(r)}return t}cellsArray(){return[...this.cells()]}subRange(t){try{const{start:e,end:r}=y(t);return e.row<this._startRow||r.row>this._endRow||e.col<this._startCol||r.col>this._endCol?a("bounds",`Subrange ${t} extends outside range ${this.address}`,this._path):i(m.fromCoords(this.worksheet,e.row,e.col,r.row,r.col,this._sheetName,this._file),{...this._path,range:t})}catch{return a("range",`Invalid range address: ${t}`,this._path)}}firstRow(){return m.fromCoords(this.worksheet,this._startRow,this._startCol,this._startRow,this._endCol,this._sheetName,this._file)}lastRow(){return m.fromCoords(this.worksheet,this._endRow,this._startCol,this._endRow,this._endCol,this._sheetName,this._file)}firstCol(){return m.fromCoords(this.worksheet,this._startRow,this._startCol,this._endRow,this._startCol,this._sheetName,this._file)}lastCol(){return m.fromCoords(this.worksheet,this._startRow,this._endCol,this._endRow,this._endCol,this._sheetName,this._file)}rowAt(t){const e=this._startRow+t;return e<this._startRow||e>this._endRow?a("bounds",`Row offset ${t} is outside range ${this.address}`,this._path):i(m.fromCoords(this.worksheet,e,this._startCol,e,this._endCol,this._sheetName,this._file),this._path)}colAt(t){const e=this._startCol+t;return e<this._startCol||e>this._endCol?a("bounds",`Column offset ${t} is outside range ${this.address}`,this._path):i(m.fromCoords(this.worksheet,this._startRow,e,this._endRow,e,this._sheetName,this._file),this._path)}find(t){for(const e of this.cells())if(t(e))return i(e,e.path);return a("missing",`No cell matching predicate found in range ${this.address}`,this._path)}findAll(t){const e=[];for(const r of this.cells())t(r)&&e.push(r);return e}findValue(t){for(const e of this.cells()){const r=e.value();if(r.ok&&r.value===t)return i(e,e.path)}return a("missing",`Value "${t}" not found in range ${this.address}`,this._path)}some(t){for(const e of this.cells())if(t(e))return!0;return!1}every(t){for(const e of this.cells())if(!t(e))return!1;return!0}count(t){let e=0;for(const r of this.cells())t(r)&&e++;return e}toArray(){return this.values()}toObjects(t=0,e=1){const r=[...this.rows()];if(r.length===0)return[];const n=r[t];if(!n)return[];const o=n.map(h=>{const u=h.value();return u.ok&&u.value!==null?String(u.value):""}),l=[];for(let h=e;h<r.length;h++){const u=r[h],c={};for(let f=0;f<o.length;f++){const k=o[f];if(k){const v=u[f]?.value();c[k]=v?.ok?v.value:null}}l.push(c)}return l}toJson(){return{address:this.address,rows:this.values()}}}class d{constructor(t,e,r,n="right"){this.sheet=t,this._row=e,this._col=r,this._direction=n}static create(t,e){const{row:r,col:n}=w(e);return new d(t,r,n)}static createAt(t,e,r){return new d(t,Math.max(1,e),Math.max(1,r))}get row(){return this._row}get col(){return this._col}get address(){return C(this._row,this._col)}get colLetter(){return V(this._col)}get direction(){return this._direction}get path(){return{...this.sheet.path,cell:this.address}}move(t,e){return new d(this.sheet,Math.max(1,this._row+t),Math.max(1,this._col+e),this._direction)}moveTo(t){const{row:e,col:r}=w(t);return new d(this.sheet,e,r,this._direction)}moveToRow(t){return new d(this.sheet,Math.max(1,t),this._col,this._direction)}moveToCol(t){const e=typeof t=="string"?S(t.toUpperCase()):t;return new d(this.sheet,this._row,Math.max(1,e),this._direction)}left(t=1){return new d(this.sheet,this._row,Math.max(1,this._col-t),"left")}right(t=1){return new d(this.sheet,this._row,this._col+t,"right")}up(t=1){return new d(this.sheet,Math.max(1,this._row-t),this._col,"up")}down(t=1){return new d(this.sheet,this._row+t,this._col,"down")}setDirection(t){return new d(this.sheet,this._row,this._col,t)}forward(t=1){switch(this._direction){case"right":return this.right(t);case"left":return this.left(t);case"down":return this.down(t);case"up":return this.up(t)}}startOfRow(){return new d(this.sheet,this._row,1,this._direction)}startOfCol(){return new d(this.sheet,1,this._col,this._direction)}skipEmpty(){return this.skipWhile(t=>t.isEmpty())}skipWhile(t){let e=this;const r=this.sheet.dimensions(),n=Math.max(r.rowCount,r.colCount)*2;for(let o=0;o<n;o++){const l=e.cell();if(!l.ok||!t(l.value))break;e=e.forward()}return e}skipUntil(t){return this.skipWhile(e=>!t(e))}skipToValue(t){return this.skipUntil(e=>{const r=e.value();return r.ok&&r.value===t})}skip(t){return this.forward(t)}grab(){const t=this.cell();return t.ok?i({cell:t.value,cursor:this.forward()},this.path):t}grabN(t){const e=[];let r=this;for(let n=0;n<t;n++){const o=r.cell();if(!o.ok)break;e.push(o.value),r=r.forward()}return e.length===0?a("bounds","No cells to grab",this.path):i({cells:e,cursor:r},this.path)}grabWhile(t){const e=[];let r=this;const n=this.sheet.dimensions(),o=Math.max(n.rowCount,n.colCount)*2;for(let l=0;l<o;l++){const h=r.cell();if(!h.ok||!t(h.value))break;e.push(h.value),r=r.forward()}return i({cells:e,cursor:r},this.path)}grabUntil(t){return this.grabWhile(e=>!t(e))}grabRow(){const t=[],e=this.sheet.dimensions();let r=this.setDirection("right");for(let n=this._col;n<=e.endCol;n++){const o=r.cell();if(!o.ok)break;t.push(o.value),r=r.forward()}return i({cells:t,cursor:r},this.path)}grabCol(){const t=[],e=this.sheet.dimensions();let r=this.setDirection("down");for(let n=this._row;n<=e.endRow;n++){const o=r.cell();if(!o.ok)break;t.push(o.value),r=r.forward()}return i({cells:t,cursor:r},this.path)}grabNonEmpty(){return this.grabWhile(t=>!t.isEmpty())}peek(){return this.cell()}peekAhead(t){const e=[];let r=this;for(let n=0;n<t;n++){const o=r.cell();if(!o.ok)break;e.push(o.value),r=r.forward()}return i(e,this.path)}peekAt(t,e){return this.move(t,e).cell()}cell(){return this.sheet.cellAt(this._row,this._col)}value(){const t=this.cell();return t.ok?t.value.value():t}isValid(){return this.cell().ok}isEmpty(){const t=this.cell();return t.ok&&t.value.isEmpty()}isNotEmpty(){const t=this.cell();return t.ok&&!t.value.isEmpty()}clone(){return new d(this.sheet,this._row,this._col,this._direction)}}class g{constructor(t,e,r){this.worksheet=t,this._path=e,this._file=r}static fromExcelJS(t,e){const r={file:e,sheet:t.name};return new g(t,r,e)}get name(){return this.worksheet.name}get index(){return this.worksheet.id}get path(){return this._path}cell(t){try{w(t);const e=this.worksheet.getCell(t);return i(p.fromExcelJS(e,this.name,this._file),{...this._path,cell:t})}catch{return a("range",`Invalid cell address: ${t}`,this._path)}}cellAt(t,e){if(t<1||e<1)return a("bounds",`Invalid cell coordinates: row=${t}, col=${e}`,this._path);const r=this.worksheet.getCell(t,e);return i(p.fromExcelJS(r,this.name,this._file),{...this._path,cell:r.address})}getValue(t){const e=this.cell(t);return e.ok?e.value.value():e}range(t){return m.fromAddress(this.worksheet,t,this.name,this._file)}rangeFrom(t,e){return this.range(`${t}:${e}`)}rangeAt(t,e,r,n){return t<1||e<1||r<1||n<1?a("bounds","Invalid range coordinates",this._path):i(m.fromCoords(this.worksheet,t,e,r,n,this.name,this._file),this._path)}usedRange(){const t=this.dimensions();return t.rowCount===0||t.colCount===0?a("missing","Sheet has no used cells",this._path):i(m.fromCoords(this.worksheet,t.startRow,t.startCol,t.endRow,t.endCol,this.name,this._file),this._path)}row(t){const e=this.dimensions();if(t<1)return a("bounds",`Invalid row number: ${t}`,this._path);const r=Math.max(e.endCol,1);return i(m.fromCoords(this.worksheet,t,1,t,r,this.name,this._file),this._path)}col(t){const e=typeof t=="string"?S(t.toUpperCase()):t;if(e<1)return a("bounds",`Invalid column: ${t}`,this._path);const r=this.dimensions(),n=Math.max(r.endRow,1);return i(m.fromCoords(this.worksheet,1,e,n,e,this.name,this._file),this._path)}*rows(){const t=this.dimensions();for(let e=t.startRow;e<=t.endRow;e++)yield m.fromCoords(this.worksheet,e,t.startCol,e,t.endCol,this.name,this._file)}*cols(){const t=this.dimensions();for(let e=t.startCol;e<=t.endCol;e++)yield m.fromCoords(this.worksheet,t.startRow,e,t.endRow,e,this.name,this._file)}cursor(t){const e=t??"A1";return d.create(this,e)}cursorAt(t,e){return d.createAt(this,t,e)}find(t){const e=this.usedRange();return e.ok?e.value.find(t):e}findAll(t){const e=this.usedRange();return e.ok?e.value.findAll(t):[]}findValue(t){const e=this.usedRange();return e.ok?e.value.findValue(t):e}findInRange(t,e){const r=this.range(t);return r.ok?r.value.find(e):r}findAllInRange(t,e){const r=this.range(t);return r.ok?r.value.findAll(e):[]}dimensions(){const t=this.worksheet.rowCount,e=this.worksheet.columnCount;let r=1,n=t,o=1,l=e;if(this.worksheet.dimensions){const h=this.worksheet.dimensions;if(typeof h=="string")try{const u=y(h);r=u.start.row,o=u.start.col,n=u.end.row,l=u.end.col}catch{}}return{startRow:r,endRow:n,startCol:o,endCol:l,rowCount:n-r+1,colCount:l-o+1}}rowCount(){return this.dimensions().rowCount}colCount(){return this.dimensions().colCount}mergedRanges(){const t=this.worksheet._merges;return t?Object.keys(t):[]}isMerged(t){const e=this.cell(t);return e.ok?e.value.isMerged():!1}getWorksheet(){return this.worksheet}getCellInternal(t,e){if(t<1||e<1)return;const r=this.worksheet.getCell(t,e);return p.fromExcelJS(r,this.name,this._file)}}class _{constructor(t,e){this.workbook=t,this._path=e,this.sheetsCache=new Map}static fromExcelJS(t,e){const r={file:e};return new _(t,r)}get path(){return this._path}get file(){return this._path.file}sheet(t){const e=this.sheetsCache.get(t);if(e)return i(e,{...this._path,sheet:t});const r=this.workbook.getWorksheet(t);if(!r)return a("missing",`Sheet "${t}" not found`,this._path);const n=g.fromExcelJS(r,this._path.file);return this.sheetsCache.set(t,n),i(n,n.path)}sheetAt(t){if(t<1)return a("bounds",`Sheet index must be >= 1, got ${t}`,this._path);const e=this.workbook.getWorksheet(t);if(!e)return a("missing",`Sheet at index ${t} not found`,this._path);const r=this.sheetsCache.get(e.name);if(r)return i(r,r.path);const n=g.fromExcelJS(e,this._path.file);return this.sheetsCache.set(e.name,n),i(n,n.path)}sheets(){const t=[];return this.workbook.eachSheet(e=>{const r=this.sheetsCache.get(e.name);if(r)t.push(r);else{const n=g.fromExcelJS(e,this._path.file);this.sheetsCache.set(e.name,n),t.push(n)}}),t}sheetNames(){const t=[];return this.workbook.eachSheet(e=>{t.push(e.name)}),t}sheetCount(){return this.workbook.worksheets.length}firstSheet(){return this.sheetAt(1)}lastSheet(){const t=this.sheetCount();return t===0?a("missing","Workbook has no sheets",this._path):this.sheetAt(t)}hasSheet(t){return this.workbook.getWorksheet(t)!==void 0}findSheet(t){for(const e of this.sheets())if(t(e))return i(e,e.path);return a("missing","No sheet matching predicate found",this._path)}filterSheets(t){return this.sheets().filter(t)}findSheetByPattern(t){return this.findSheet(e=>t.test(e.name))}filterSheetsByPattern(t){return this.filterSheets(e=>t.test(e.name))}properties(){return{title:this.workbook.title,subject:this.workbook.subject,creator:this.workbook.creator,lastModifiedBy:this.workbook.lastModifiedBy,created:this.workbook.created,modified:this.workbook.modified}}creator(){return this.workbook.creator}created(){return this.workbook.created}modified(){return this.workbook.modified}definedNames(){return[]}*[Symbol.iterator](){for(const t of this.sheets())yield t}forEach(t){this.sheets().forEach(t)}map(t){return this.sheets().map(t)}getWorkbook(){return this.workbook}}const U={equals:s=>t=>{const e=t.value();return e.ok?s===null?e.value===null:e.value===null?!1:s instanceof Date&&e.value instanceof Date?s.getTime()===e.value.getTime():e.value===s:!1},contains:(s,t=!1)=>e=>{const r=e.string();return r.ok?t?r.value.includes(s):r.value.toLowerCase().includes(s.toLowerCase()):!1},matches:s=>t=>{const e=t.string();return e.ok?s.test(e.value):!1},startsWith:(s,t=!1)=>e=>{const r=e.string();return r.ok?t?r.value.startsWith(s):r.value.toLowerCase().startsWith(s.toLowerCase()):!1},endsWith:(s,t=!1)=>e=>{const r=e.string();return r.ok?t?r.value.endsWith(s):r.value.toLowerCase().endsWith(s.toLowerCase()):!1},isString:()=>s=>s.isString(),isNumber:()=>s=>s.isNumber(),isBoolean:()=>s=>s.isBoolean(),isDate:()=>s=>s.isDate(),isEmpty:()=>s=>s.isEmpty(),isNotEmpty:()=>s=>!s.isEmpty(),isFormula:()=>s=>s.isFormula(),isError:()=>s=>s.isError(),isMerged:()=>s=>s.isMerged(),greaterThan:s=>t=>{const e=t.number();return e.ok&&e.value>s},greaterThanOrEqual:s=>t=>{const e=t.number();return e.ok&&e.value>=s},lessThan:s=>t=>{const e=t.number();return e.ok&&e.value<s},lessThanOrEqual:s=>t=>{const e=t.number();return e.ok&&e.value<=s},between:(s,t)=>e=>{const r=e.number();return r.ok&&r.value>=s&&r.value<=t},dateBefore:s=>t=>{const e=t.date();return e.ok&&e.value.getTime()<s.getTime()},dateAfter:s=>t=>{const e=t.date();return e.ok&&e.value.getTime()>s.getTime()},dateBetween:(s,t)=>e=>{const r=e.date();if(!r.ok)return!1;const n=r.value.getTime();return n>=s.getTime()&&n<=t.getTime()},inRow:s=>t=>t.row===s,inCol:s=>t=>t.col===s,inColLetter:s=>t=>t.colLetter.toUpperCase()===s.toUpperCase(),and:(...s)=>t=>s.every(e=>e(t)),or:(...s)=>t=>s.some(e=>e(t)),not:s=>t=>!s(t),isBold:()=>s=>s.style().font?.bold===!0,isItalic:()=>s=>s.style().font?.italic===!0,hasHyperlink:()=>s=>s.hyperlink().ok,hasComment:()=>s=>s.comment().ok,always:()=>()=>!0,never:()=>()=>!1,custom:s=>s};function q(s){return{kind:"transform",namespace:"@origints/xlsx",name:"parseXlsx",args:s}}const P={namespace:"@origints/xlsx",name:"parseXlsx",execute(s,t){throw new Error("parseXlsx requires async execution. Use parseXlsxAsyncImpl instead.")}};function x(s){return new Uint8Array(s).buffer}const M={namespace:"@origints/xlsx",name:"parseXlsx",async execute(s,t){const e=t??{};let r;if(s instanceof ReadableStream){const o=await I(s);r=x(o)}else if(Buffer.isBuffer(s))r=x(s);else if(s instanceof ArrayBuffer)r=s;else if(s instanceof Uint8Array)r=x(s);else throw new Error(`parseXlsx expects stream or buffer input, got ${typeof s}`);const n=new N.Workbook;return await n.xlsx.load(r),_.fromExcelJS(n,e.fileName)}};async function X(s,t){const e=new N.Workbook;let r;return s instanceof ArrayBuffer?r=s:r=x(s),await e.xlsx.load(r),_.fromExcelJS(e,t?.fileName)}async function H(s,t){const e=new N.Workbook;return await e.xlsx.readFile(s),_.fromExcelJS(e,t?.fileName??s)}function j(s,t){return s==null?null:s instanceof Date?t?.dateAsIsoString!==!1?s.toISOString():s.getTime():typeof s=="string"||typeof s=="number"||typeof s=="boolean"?s:null}function J(s,t){const e=s.value(),r=e.ok?j(e.value,t):null;return t?.includeCellAddresses?{address:s.address,value:r}:r}function D(s,t){return t?.firstRowAsHeaders?B(s,t):W(s,t)}function W(s,t){const e=[];for(const r of s.rows()){const n=[];for(const o of r){const l=J(o,t);l!==null||t?.includeEmpty?n.push(l):(n.length>0||t?.includeEmpty)&&n.push(null)}(n.length>0||t?.includeEmpty)&&e.push(n)}return e}function B(s,t){const e=[...s.rows()];if(e.length===0)return[];const n=e[0].map(l=>{const h=l.value();return h.ok&&h.value!==null?String(h.value):`col_${l.col}`}),o=[];for(let l=1;l<e.length;l++){const h=e[l],u={};let c=!1;for(let f=0;f<n.length;f++){const k=n[f],T=h[f];if(T){const v=J(T,t);v!==null&&(c=!0),u[k]=v}else u[k]=null}(c||t?.includeEmpty)&&o.push(u)}return o}function A(s,t){const e=s.usedRange();return e.ok?D(e.value,t):t?.firstRowAsHeaders?[]:[[]]}function Z(s,t){const e=s.sheets();if(t?.includeSheetNames!==!1){const r={};for(const n of e)r[n.name]=A(n,t);return r}return e.map(r=>A(r,t))}function L(s,t){const e=t?.delimiter??",",r=t?.lineEnding??`
|
|
2
|
+
`,n=t?.quoteStrings??!0,o=[];for(const l of s.rows()){const h=[];for(const u of l){const c=u.value();let f;!c.ok||c.value===null?f="":c.value instanceof Date?f=c.value.toISOString():f=String(c.value),n&&(f.includes(e)||f.includes(`
|
|
3
|
+
`)||f.includes("\r")||f.includes('"'))&&(f='"'+f.replace(/"/g,'""')+'"'),h.push(f)}o.push(h.join(e))}return o.join(r)}function G(s,t){const e=s.usedRange();return e.ok?L(e.value,t):""}function K(s){s.register(M)}exports.XlsxCell=p;exports.XlsxCursor=d;exports.XlsxRange=m;exports.XlsxSheet=g;exports.XlsxWorkbook=_;exports.cellToJson=J;exports.cellValueToJson=j;exports.columnLetterToNumber=S;exports.columnNumberToLetter=V;exports.fail=a;exports.formatAddress=C;exports.formatRange=$;exports.formatXlsxPath=F;exports.isError=R;exports.isFormula=b;exports.isInRange=O;exports.ok=i;exports.parseAddress=w;exports.parseRange=y;exports.parseXlsx=q;exports.parseXlsxAsyncImpl=M;exports.parseXlsxBuffer=X;exports.parseXlsxFile=H;exports.parseXlsxImpl=P;exports.predicates=U;exports.rangeToArray=W;exports.rangeToCsv=L;exports.rangeToJson=D;exports.rangeToObjects=B;exports.registerXlsxTransforms=K;exports.sheetToCsv=G;exports.sheetToJson=A;exports.streamToBuffer=I;exports.toExcelLocation=z;exports.workbookToJson=Z;
|
|
4
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/xlsx-result.ts","../src/util.ts","../src/xlsx-cell.ts","../src/xlsx-range.ts","../src/xlsx-cursor.ts","../src/xlsx-sheet.ts","../src/xlsx-workbook.ts","../src/xlsx-query.ts","../src/parse.ts","../src/convert.ts","../src/index.ts"],"sourcesContent":["/**\n * Result types for XLSX operations.\n *\n * @module xlsx/xlsx-result\n */\n\n/**\n * Excel source location for lineage tracking.\n * Compatible with @origints/core ExcelLocation.\n */\nexport interface ExcelLocation {\n readonly kind: 'excel'\n readonly file: string\n readonly sheet: string\n readonly range: string\n}\n\n/**\n * Path through an XLSX structure, tracking how we arrived at a value.\n */\nexport interface XlsxPath {\n /** Source file name (if known) */\n readonly file?: string\n /** Sheet name */\n readonly sheet?: string\n /** Cell address (e.g., \"A1\") */\n readonly cell?: string\n /** Range address (e.g., \"A1:C10\") */\n readonly range?: string\n}\n\n/**\n * Failure kinds specific to XLSX operations.\n */\nexport type XlsxFailureKind =\n | 'parse' // XLSX parsing error\n | 'type' // Wrong type at location\n | 'missing' // Sheet, row, column, or cell not found\n | 'range' // Invalid range specification\n | 'format' // Invalid format (e.g., date format)\n | 'bounds' // Out of bounds access\n | 'merged' // Merged cell access issue\n | 'formula' // Formula evaluation error\n\n/**\n * A failure during XLSX traversal or extraction.\n */\nexport interface XlsxFailure {\n readonly kind: XlsxFailureKind\n readonly message: string\n readonly path: XlsxPath\n readonly sourceLocation?: ExcelLocation\n}\n\n/**\n * Result of an XLSX extraction - either a successful value or a failure.\n */\nexport type XlsxResult<T> =\n | { readonly ok: true; readonly value: T; readonly path: XlsxPath }\n | { readonly ok: false; readonly failure: XlsxFailure }\n\n/**\n * Creates a success result.\n */\nexport function ok<T>(value: T, path: XlsxPath): XlsxResult<T> {\n return { ok: true, value, path }\n}\n\n/**\n * Creates a failure result.\n */\nexport function fail(\n kind: XlsxFailureKind,\n message: string,\n path: XlsxPath,\n sourceLocation?: ExcelLocation\n): XlsxResult<never> {\n return {\n ok: false,\n failure: { kind, message, path, sourceLocation },\n }\n}\n\n/**\n * Formats a path for display.\n */\nexport function formatXlsxPath(path: XlsxPath): string {\n const parts: string[] = []\n if (path.file) parts.push(path.file)\n if (path.sheet) parts.push(`[${path.sheet}]`)\n if (path.range) parts.push(`!${path.range}`)\n else if (path.cell) parts.push(`!${path.cell}`)\n return parts.join('') || 'workbook'\n}\n\n/**\n * Creates an ExcelLocation from a path.\n */\nexport function toExcelLocation(\n path: XlsxPath\n): ExcelLocation | undefined {\n if (!path.sheet) return undefined\n return {\n kind: 'excel',\n file: path.file ?? '',\n sheet: path.sheet,\n range: path.range ?? path.cell ?? '',\n }\n}\n\n/**\n * Cell value types in XLSX.\n */\nexport type CellValue = string | number | boolean | Date | null\n\n/**\n * Extended cell value including formula and error types.\n */\nexport type ExtendedCellValue =\n | CellValue\n | { readonly formula: string; readonly result?: CellValue }\n | { readonly error: string }\n\n/**\n * Type guard for formula values.\n */\nexport function isFormula(\n value: ExtendedCellValue\n): value is { formula: string; result?: CellValue } {\n return (\n typeof value === 'object' &&\n value !== null &&\n !(value instanceof Date) &&\n 'formula' in value\n )\n}\n\n/**\n * Type guard for error values.\n */\nexport function isError(\n value: ExtendedCellValue\n): value is { error: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n !(value instanceof Date) &&\n 'error' in value\n )\n}\n","/**\n * Utility functions for XLSX package.\n *\n * @module xlsx/util\n */\n\n/**\n * Convert a ReadableStream<Uint8Array> to a Buffer.\n */\nexport async function streamToBuffer(\n stream: ReadableStream<Uint8Array>\n): Promise<Buffer> {\n const reader = stream.getReader()\n const chunks: Uint8Array[] = []\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n chunks.push(value)\n }\n return Buffer.concat(chunks)\n } finally {\n reader.releaseLock()\n }\n}\n\n/**\n * Convert column letter(s) to 1-based column number.\n * e.g., \"A\" -> 1, \"B\" -> 2, \"Z\" -> 26, \"AA\" -> 27\n */\nexport function columnLetterToNumber(col: string): number {\n let result = 0\n for (let i = 0; i < col.length; i++) {\n result = result * 26 + (col.charCodeAt(i) - 64)\n }\n return result\n}\n\n/**\n * Convert 1-based column number to column letter(s).\n * e.g., 1 -> \"A\", 2 -> \"B\", 26 -> \"Z\", 27 -> \"AA\"\n */\nexport function columnNumberToLetter(num: number): string {\n let result = ''\n while (num > 0) {\n const remainder = (num - 1) % 26\n result = String.fromCharCode(65 + remainder) + result\n num = Math.floor((num - 1) / 26)\n }\n return result\n}\n\n/**\n * Parse a cell address into row and column numbers.\n * e.g., \"A1\" -> { row: 1, col: 1 }, \"B10\" -> { row: 10, col: 2 }\n */\nexport function parseAddress(address: string): {\n row: number\n col: number\n colLetter: string\n} {\n const match = address.match(/^([A-Z]+)(\\d+)$/i)\n if (!match) {\n throw new Error(`Invalid cell address: ${address}`)\n }\n const colLetter = match[1].toUpperCase()\n return {\n row: parseInt(match[2], 10),\n col: columnLetterToNumber(colLetter),\n colLetter,\n }\n}\n\n/**\n * Format row and column numbers into a cell address.\n * e.g., { row: 1, col: 1 } -> \"A1\"\n */\nexport function formatAddress(row: number, col: number): string {\n return `${columnNumberToLetter(col)}${row}`\n}\n\n/**\n * Parse a range address into start and end coordinates.\n * e.g., \"A1:C10\" -> { start: { row: 1, col: 1 }, end: { row: 10, col: 3 } }\n */\nexport function parseRange(range: string): {\n start: { row: number; col: number }\n end: { row: number; col: number }\n} {\n const parts = range.split(':')\n if (parts.length === 1) {\n // Single cell address\n const addr = parseAddress(parts[0])\n return {\n start: { row: addr.row, col: addr.col },\n end: { row: addr.row, col: addr.col },\n }\n }\n if (parts.length !== 2) {\n throw new Error(`Invalid range: ${range}`)\n }\n const start = parseAddress(parts[0])\n const end = parseAddress(parts[1])\n return {\n start: { row: start.row, col: start.col },\n end: { row: end.row, col: end.col },\n }\n}\n\n/**\n * Format start and end coordinates into a range address.\n */\nexport function formatRange(\n startRow: number,\n startCol: number,\n endRow: number,\n endCol: number\n): string {\n const start = formatAddress(startRow, startCol)\n const end = formatAddress(endRow, endCol)\n return start === end ? start : `${start}:${end}`\n}\n\n/**\n * Check if a cell address is within a range.\n */\nexport function isInRange(\n row: number,\n col: number,\n range: { start: { row: number; col: number }; end: { row: number; col: number } }\n): boolean {\n return (\n row >= range.start.row &&\n row <= range.end.row &&\n col >= range.start.col &&\n col <= range.end.col\n )\n}\n\n/**\n * Type helper for ExcelJS cell values.\n */\nexport function normalizeValue(value: unknown): unknown {\n if (value === undefined || value === null) return null\n if (typeof value === 'object' && 'error' in (value as object)) {\n return { error: (value as { error: string }).error }\n }\n if (typeof value === 'object' && 'formula' in (value as object)) {\n const formulaValue = value as { formula: string; result?: unknown }\n return {\n formula: formulaValue.formula,\n result: normalizeValue(formulaValue.result),\n }\n }\n return value\n}\n","/**\n * XlsxCell - wrapper around ExcelJS cell with path tracking and typed extraction.\n *\n * @module xlsx/xlsx-cell\n */\n\nimport type { Cell as ExcelJSCell, CellValue as ExcelJSValue } from 'exceljs'\nimport {\n XlsxResult,\n XlsxPath,\n CellValue,\n ExtendedCellValue,\n ok,\n fail,\n isFormula,\n isError,\n} from './xlsx-result'\nimport { formatAddress } from './util'\n\n/**\n * Cell style information.\n */\nexport interface CellStyle {\n readonly font?: {\n readonly name?: string\n readonly size?: number\n readonly bold?: boolean\n readonly italic?: boolean\n readonly underline?: boolean\n readonly strikethrough?: boolean\n readonly color?: string\n }\n readonly fill?: {\n readonly type?: string\n readonly color?: string\n }\n readonly border?: {\n readonly top?: boolean\n readonly bottom?: boolean\n readonly left?: boolean\n readonly right?: boolean\n }\n readonly alignment?: {\n readonly horizontal?: string\n readonly vertical?: string\n readonly wrapText?: boolean\n }\n readonly numFmt?: string\n}\n\n/**\n * A segment of rich text with its formatting.\n */\nexport interface RichTextSegment {\n readonly text: string\n readonly bold?: boolean\n readonly italic?: boolean\n readonly underline?: boolean\n readonly strikethrough?: boolean\n readonly color?: string\n readonly size?: number\n readonly font?: string\n}\n\n/**\n * Rich text content with all formatting preserved.\n */\nexport interface RichTextContent {\n readonly segments: readonly RichTextSegment[]\n readonly hyperlink?: string\n}\n\n/**\n * A wrapper around ExcelJS Cell with full metadata preservation.\n *\n * XlsxCell enables typed extraction of cell values while maintaining\n * provenance information. Each cell knows its exact location in the\n * workbook, allowing full traceability.\n */\nexport class XlsxCell {\n private constructor(\n private readonly cell: ExcelJSCell,\n private readonly _path: XlsxPath,\n private readonly _sheetName: string\n ) {}\n\n /**\n * Creates an XlsxCell from an ExcelJS cell.\n * @internal\n */\n static fromExcelJS(\n cell: ExcelJSCell,\n sheetName: string,\n file?: string\n ): XlsxCell {\n const path: XlsxPath = {\n file,\n sheet: sheetName,\n cell: cell.address,\n }\n return new XlsxCell(cell, path, sheetName)\n }\n\n // ---------------------------------------------------------------------------\n // IDENTITY & LOCATION\n // ---------------------------------------------------------------------------\n\n /**\n * Returns the cell address (e.g., \"A1\").\n */\n get address(): string {\n return this.cell.address\n }\n\n /**\n * Returns the 1-based row number.\n */\n get row(): number {\n return typeof this.cell.row === 'number' ? this.cell.row : parseInt(String(this.cell.row), 10)\n }\n\n /**\n * Returns the 1-based column number.\n */\n get col(): number {\n return typeof this.cell.col === 'number' ? this.cell.col : parseInt(String(this.cell.col), 10)\n }\n\n /**\n * Returns the column letter(s) (e.g., \"A\", \"AA\").\n */\n get colLetter(): string {\n return this.address.replace(/\\d+$/, '')\n }\n\n /**\n * Returns the current path for lineage tracking.\n */\n get path(): XlsxPath {\n return this._path\n }\n\n /**\n * Returns the sheet name this cell belongs to.\n */\n get sheetName(): string {\n return this._sheetName\n }\n\n // ---------------------------------------------------------------------------\n // VALUE EXTRACTION\n // ---------------------------------------------------------------------------\n\n /**\n * Returns the raw cell value.\n */\n value(): XlsxResult<CellValue> {\n const val = this.getRawValue()\n if (isFormula(val)) {\n return ok(val.result ?? null, this._path)\n }\n if (isError(val)) {\n return fail('formula', `Cell contains error: ${val.error}`, this._path)\n }\n // At this point val is CellValue (not formula or error)\n return ok(val as CellValue, this._path)\n }\n\n /**\n * Returns the extended cell value (including formula info).\n */\n extendedValue(): XlsxResult<ExtendedCellValue> {\n return ok(this.getRawValue(), this._path)\n }\n\n /**\n * Extract value as a string.\n */\n string(): XlsxResult<string> {\n const val = this.getResolvedValue()\n if (val === null || val === undefined) {\n return fail('type', 'Expected string, got null', this._path)\n }\n if (typeof val === 'string') {\n return ok(val, this._path)\n }\n // Convert to string\n if (typeof val === 'number' || typeof val === 'boolean') {\n return ok(String(val), this._path)\n }\n if (val instanceof Date) {\n return ok(val.toISOString(), this._path)\n }\n return fail('type', `Expected string, got ${typeof val}`, this._path)\n }\n\n /**\n * Extract value as a number.\n */\n number(): XlsxResult<number> {\n const val = this.getResolvedValue()\n if (typeof val === 'number') {\n return ok(val, this._path)\n }\n if (typeof val === 'string') {\n const num = parseFloat(val)\n if (!isNaN(num)) {\n return ok(num, this._path)\n }\n }\n return fail('type', `Expected number, got ${typeOf(val)}`, this._path)\n }\n\n /**\n * Extract value as a boolean.\n */\n boolean(): XlsxResult<boolean> {\n const val = this.getResolvedValue()\n if (typeof val === 'boolean') {\n return ok(val, this._path)\n }\n return fail('type', `Expected boolean, got ${typeOf(val)}`, this._path)\n }\n\n /**\n * Extract value as a Date.\n */\n date(): XlsxResult<Date> {\n const val = this.getResolvedValue()\n if (val instanceof Date) {\n return ok(val, this._path)\n }\n if (typeof val === 'number') {\n // Excel stores dates as numbers (days since 1900-01-01)\n const date = this.excelDateToJS(val)\n return ok(date, this._path)\n }\n if (typeof val === 'string') {\n const date = new Date(val)\n if (!isNaN(date.getTime())) {\n return ok(date, this._path)\n }\n }\n return fail('type', `Expected date, got ${typeOf(val)}`, this._path)\n }\n\n /**\n * Get the formula if this cell contains one.\n */\n formula(): XlsxResult<string> {\n const val = this.getRawValue()\n if (isFormula(val)) {\n return ok(val.formula, this._path)\n }\n return fail('type', 'Cell does not contain a formula', this._path)\n }\n\n // ---------------------------------------------------------------------------\n // RICH TEXT & MARKDOWN\n // ---------------------------------------------------------------------------\n\n /**\n * Get the cell content as rich text with formatting preserved.\n * Returns segments with their individual formatting properties.\n */\n richText(): XlsxResult<RichTextContent> {\n const rawVal = this.cell.value as ExcelJSValue\n const hyperlink = this.cell.hyperlink\n\n // Handle rich text cells\n if (rawVal && typeof rawVal === 'object' && 'richText' in rawVal) {\n const rt = rawVal as {\n richText: Array<{\n text: string\n font?: {\n bold?: boolean\n italic?: boolean\n underline?: boolean | string\n strike?: boolean\n color?: { argb?: string; theme?: number }\n size?: number\n name?: string\n }\n }>\n }\n\n const segments: RichTextSegment[] = rt.richText.map(segment => ({\n text: segment.text,\n bold: segment.font?.bold,\n italic: segment.font?.italic,\n underline: segment.font?.underline === true || segment.font?.underline === 'single',\n strikethrough: segment.font?.strike,\n color: segment.font?.color?.argb,\n size: segment.font?.size,\n font: segment.font?.name,\n }))\n\n return ok({ segments, hyperlink }, this._path)\n }\n\n // Handle hyperlink with text\n if (rawVal && typeof rawVal === 'object' && 'text' in rawVal && 'hyperlink' in rawVal) {\n const linkVal = rawVal as { text: string; hyperlink: string }\n const style = this.style()\n const segment: RichTextSegment = {\n text: linkVal.text,\n bold: style.font?.bold,\n italic: style.font?.italic,\n underline: style.font?.underline,\n strikethrough: style.font?.strikethrough,\n color: style.font?.color,\n size: style.font?.size,\n font: style.font?.name,\n }\n return ok(\n {\n segments: [segment],\n hyperlink: linkVal.hyperlink,\n },\n this._path\n )\n }\n\n // Plain value - wrap in single segment with cell-level formatting\n const plainValue = this.getResolvedValue()\n const text = plainValue !== null ? String(plainValue) : ''\n const style = this.style()\n\n const segment: RichTextSegment = {\n text,\n bold: style.font?.bold,\n italic: style.font?.italic,\n underline: style.font?.underline,\n strikethrough: style.font?.strikethrough,\n color: style.font?.color,\n size: style.font?.size,\n font: style.font?.name,\n }\n\n return ok({ segments: [segment], hyperlink }, this._path)\n }\n\n /**\n * Get the cell content as Markdown.\n *\n * Converts cell content including:\n * - Bold text -> **text**\n * - Italic text -> *text*\n * - Strikethrough -> ~~text~~\n * - Hyperlinks -> [text](url)\n * - Rich text segments with mixed formatting\n */\n markdown(): XlsxResult<string> {\n const rtResult = this.richText()\n if (!rtResult.ok) {\n return rtResult as XlsxResult<string>\n }\n\n const { segments, hyperlink } = rtResult.value\n let result = ''\n\n for (const segment of segments) {\n let text = segment.text\n\n // Apply formatting in order: strikethrough, then bold, then italic\n if (segment.strikethrough) {\n text = `~~${text}~~`\n }\n if (segment.bold) {\n text = `**${text}**`\n }\n if (segment.italic) {\n text = `*${text}*`\n }\n\n result += text\n }\n\n // Wrap in hyperlink if present\n if (hyperlink) {\n result = `[${result}](${hyperlink})`\n }\n\n return ok(result, this._path)\n }\n\n /**\n * Check if the cell contains rich text (multiple formatted segments).\n */\n isRichText(): boolean {\n const rawVal = this.cell.value as ExcelJSValue\n return rawVal !== null && typeof rawVal === 'object' && 'richText' in rawVal\n }\n\n // ---------------------------------------------------------------------------\n // TYPE CHECKING\n // ---------------------------------------------------------------------------\n\n /**\n * Check if the cell is empty.\n */\n isEmpty(): boolean {\n const val = this.cell.value\n return val === null || val === undefined || val === ''\n }\n\n /**\n * Check if the cell contains a formula.\n */\n isFormula(): boolean {\n return isFormula(this.getRawValue())\n }\n\n /**\n * Check if the cell is part of a merged range.\n */\n isMerged(): boolean {\n return this.cell.isMerged\n }\n\n /**\n * Check if this is the master cell of a merged range.\n */\n isMergedMaster(): boolean {\n if (!this.cell.isMerged) return false\n const master = this.cell.master\n return master.address === this.cell.address\n }\n\n /**\n * Check if the cell contains a string.\n */\n isString(): boolean {\n return typeof this.getResolvedValue() === 'string'\n }\n\n /**\n * Check if the cell contains a number.\n */\n isNumber(): boolean {\n return typeof this.getResolvedValue() === 'number'\n }\n\n /**\n * Check if the cell contains a boolean.\n */\n isBoolean(): boolean {\n return typeof this.getResolvedValue() === 'boolean'\n }\n\n /**\n * Check if the cell contains a date.\n */\n isDate(): boolean {\n const val = this.getResolvedValue()\n return val instanceof Date\n }\n\n /**\n * Check if the cell contains an error.\n */\n isError(): boolean {\n return isError(this.getRawValue())\n }\n\n // ---------------------------------------------------------------------------\n // METADATA\n // ---------------------------------------------------------------------------\n\n /**\n * Get the cell's style information.\n */\n style(): CellStyle {\n const font = this.cell.font\n const fill = this.cell.fill\n const border = this.cell.border\n const alignment = this.cell.alignment\n\n return {\n font: font\n ? {\n name: font.name,\n size: font.size,\n bold: font.bold,\n italic: font.italic,\n underline: font.underline === true || font.underline === 'single',\n strikethrough: font.strike,\n color:\n font.color?.argb ??\n (font.color?.theme !== undefined\n ? `theme:${font.color.theme}`\n : undefined),\n }\n : undefined,\n fill:\n fill && fill.type === 'pattern'\n ? {\n type: (fill as { pattern?: string }).pattern,\n color: (fill as { fgColor?: { argb?: string } }).fgColor?.argb,\n }\n : undefined,\n border: border\n ? {\n top: !!border.top,\n bottom: !!border.bottom,\n left: !!border.left,\n right: !!border.right,\n }\n : undefined,\n alignment: alignment\n ? {\n horizontal: alignment.horizontal,\n vertical: alignment.vertical,\n wrapText: alignment.wrapText,\n }\n : undefined,\n numFmt: this.cell.numFmt,\n }\n }\n\n /**\n * Get the hyperlink URL if the cell contains one.\n */\n hyperlink(): XlsxResult<string> {\n const link = this.cell.hyperlink\n if (!link) {\n return fail('missing', 'Cell does not contain a hyperlink', this._path)\n }\n return ok(link, this._path)\n }\n\n /**\n * Get the comment/note if the cell has one.\n */\n comment(): XlsxResult<string> {\n const note = this.cell.note\n if (!note) {\n return fail('missing', 'Cell does not contain a comment', this._path)\n }\n if (typeof note === 'string') {\n return ok(note, this._path)\n }\n // RichText note\n if (note.texts) {\n return ok(\n note.texts.map((t: { text: string }) => t.text).join(''),\n this._path\n )\n }\n return fail('format', 'Unable to extract comment text', this._path)\n }\n\n // ---------------------------------------------------------------------------\n // NAVIGATION FROM CELL\n // ---------------------------------------------------------------------------\n\n /**\n * Get a cell offset from this one.\n * @internal Used by navigation methods\n */\n getOffsetCell(\n rowDelta: number,\n colDelta: number,\n getCell: (row: number, col: number) => XlsxCell | undefined\n ): XlsxResult<XlsxCell> {\n const newRow = this.row + rowDelta\n const newCol = this.col + colDelta\n if (newRow < 1 || newCol < 1) {\n return fail(\n 'bounds',\n `Cell offset (${rowDelta}, ${colDelta}) from ${this.address} is out of bounds`,\n this._path\n )\n }\n const cell = getCell(newRow, newCol)\n if (!cell) {\n return fail(\n 'missing',\n `Cell at ${formatAddress(newRow, newCol)} not found`,\n this._path\n )\n }\n return ok(cell, cell.path)\n }\n\n // ---------------------------------------------------------------------------\n // INTERNAL HELPERS\n // ---------------------------------------------------------------------------\n\n /**\n * Get the raw value, handling ExcelJS value types.\n */\n private getRawValue(): ExtendedCellValue {\n const val = this.cell.value as ExcelJSValue\n if (val === null || val === undefined) {\n return null\n }\n\n // Handle different ExcelJS value types\n if (typeof val === 'object') {\n // Error value\n if ('error' in val) {\n return { error: String((val as { error: unknown }).error) }\n }\n // Formula value\n if ('formula' in val) {\n const formulaVal = val as {\n formula: string\n result?: ExcelJSValue\n }\n return {\n formula: formulaVal.formula,\n result: this.normalizeResult(formulaVal.result),\n }\n }\n // Shared formula\n if ('sharedFormula' in val) {\n const sharedVal = val as {\n sharedFormula: string\n result?: ExcelJSValue\n }\n return {\n formula: sharedVal.sharedFormula,\n result: this.normalizeResult(sharedVal.result),\n }\n }\n // Rich text\n if ('richText' in val) {\n const richText = val as {\n richText: Array<{ text: string }>\n }\n return richText.richText.map(r => r.text).join('')\n }\n // Date\n if (val instanceof Date) {\n return val\n }\n }\n\n // Primitive values\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n return val\n }\n\n return null\n }\n\n /**\n * Get the resolved value (formula result or plain value).\n */\n private getResolvedValue(): CellValue {\n const val = this.getRawValue()\n if (isFormula(val)) {\n return val.result ?? null\n }\n if (isError(val)) {\n return null\n }\n // At this point val is CellValue (not formula or error)\n return val as CellValue\n }\n\n /**\n * Normalize a formula result value.\n */\n private normalizeResult(result: unknown): CellValue {\n if (result === null || result === undefined) return null\n if (\n typeof result === 'string' ||\n typeof result === 'number' ||\n typeof result === 'boolean'\n ) {\n return result\n }\n if (result instanceof Date) {\n return result\n }\n return null\n }\n\n /**\n * Convert Excel date number to JavaScript Date.\n * Excel dates are days since 1900-01-01 (with a leap year bug).\n */\n private excelDateToJS(excelDate: number): Date {\n // Excel incorrectly treats 1900 as a leap year\n // Dates before March 1, 1900 need adjustment\n const offset = excelDate > 60 ? -1 : 0\n const days = excelDate + offset - 1\n\n // Excel epoch is 1900-01-01\n const excelEpoch = new Date(1900, 0, 1)\n const jsDate = new Date(excelEpoch.getTime() + days * 24 * 60 * 60 * 1000)\n\n return jsDate\n }\n}\n\n/**\n * Returns a human-readable type name.\n */\nfunction typeOf(value: unknown): string {\n if (value === null) return 'null'\n if (value === undefined) return 'undefined'\n if (value instanceof Date) return 'date'\n if (Array.isArray(value)) return 'array'\n return typeof value\n}\n","/**\n * XlsxRange - represents a range of cells with iteration and query capabilities.\n *\n * @module xlsx/xlsx-range\n */\n\nimport type { Worksheet } from 'exceljs'\nimport { XlsxCell } from './xlsx-cell'\nimport {\n XlsxResult,\n XlsxPath,\n CellValue,\n ok,\n fail,\n} from './xlsx-result'\nimport { formatRange, parseRange } from './util'\nimport type { CellPredicate } from './xlsx-query'\n\n/**\n * A range of cells in an XLSX sheet.\n *\n * XlsxRange enables iteration over cells, rows, and columns within\n * a defined rectangular region. It supports predicate-based queries\n * and conversion to various formats.\n */\nexport class XlsxRange {\n private constructor(\n private readonly worksheet: Worksheet,\n private readonly _startRow: number,\n private readonly _startCol: number,\n private readonly _endRow: number,\n private readonly _endCol: number,\n private readonly _path: XlsxPath,\n private readonly _sheetName: string,\n private readonly _file?: string\n ) {}\n\n /**\n * Creates an XlsxRange from coordinates.\n * @internal\n */\n static fromCoords(\n worksheet: Worksheet,\n startRow: number,\n startCol: number,\n endRow: number,\n endCol: number,\n sheetName: string,\n file?: string\n ): XlsxRange {\n const rangeAddr = formatRange(startRow, startCol, endRow, endCol)\n const path: XlsxPath = {\n file,\n sheet: sheetName,\n range: rangeAddr,\n }\n return new XlsxRange(\n worksheet,\n startRow,\n startCol,\n endRow,\n endCol,\n path,\n sheetName,\n file\n )\n }\n\n /**\n * Creates an XlsxRange from an address string.\n * @internal\n */\n static fromAddress(\n worksheet: Worksheet,\n address: string,\n sheetName: string,\n file?: string\n ): XlsxResult<XlsxRange> {\n try {\n const { start, end } = parseRange(address)\n return ok(\n XlsxRange.fromCoords(\n worksheet,\n start.row,\n start.col,\n end.row,\n end.col,\n sheetName,\n file\n ),\n { file, sheet: sheetName, range: address }\n )\n } catch {\n return fail(\n 'range',\n `Invalid range address: ${address}`,\n { file, sheet: sheetName }\n )\n }\n }\n\n // ---------------------------------------------------------------------------\n // IDENTITY\n // ---------------------------------------------------------------------------\n\n /**\n * Returns the range address (e.g., \"A1:C10\").\n */\n get address(): string {\n return formatRange(\n this._startRow,\n this._startCol,\n this._endRow,\n this._endCol\n )\n }\n\n /**\n * Returns the start row (1-based).\n */\n get startRow(): number {\n return this._startRow\n }\n\n /**\n * Returns the start column (1-based).\n */\n get startCol(): number {\n return this._startCol\n }\n\n /**\n * Returns the end row (1-based).\n */\n get endRow(): number {\n return this._endRow\n }\n\n /**\n * Returns the end column (1-based).\n */\n get endCol(): number {\n return this._endCol\n }\n\n /**\n * Returns the current path for lineage tracking.\n */\n get path(): XlsxPath {\n return this._path\n }\n\n /**\n * Returns the number of rows in the range.\n */\n get rowCount(): number {\n return this._endRow - this._startRow + 1\n }\n\n /**\n * Returns the number of columns in the range.\n */\n get colCount(): number {\n return this._endCol - this._startCol + 1\n }\n\n /**\n * Returns the total number of cells in the range.\n */\n get cellCount(): number {\n return this.rowCount * this.colCount\n }\n\n // ---------------------------------------------------------------------------\n // CELL ACCESS\n // ---------------------------------------------------------------------------\n\n /**\n * Get a cell at specific row and column within this range.\n * Coordinates are relative to the range start (0-indexed).\n */\n cellAt(rowOffset: number, colOffset: number): XlsxResult<XlsxCell> {\n const row = this._startRow + rowOffset\n const col = this._startCol + colOffset\n if (\n row < this._startRow ||\n row > this._endRow ||\n col < this._startCol ||\n col > this._endCol\n ) {\n return fail(\n 'bounds',\n `Offset (${rowOffset}, ${colOffset}) is outside range ${this.address}`,\n this._path\n )\n }\n const cell = this.worksheet.getCell(row, col)\n return ok(XlsxCell.fromExcelJS(cell, this._sheetName, this._file), {\n ...this._path,\n cell: cell.address,\n range: undefined,\n })\n }\n\n /**\n * Get a cell by its address within this range.\n */\n cell(address: string): XlsxResult<XlsxCell> {\n try {\n const { start } = parseRange(address)\n if (\n start.row < this._startRow ||\n start.row > this._endRow ||\n start.col < this._startCol ||\n start.col > this._endCol\n ) {\n return fail(\n 'bounds',\n `Cell ${address} is outside range ${this.address}`,\n this._path\n )\n }\n const cell = this.worksheet.getCell(address)\n return ok(XlsxCell.fromExcelJS(cell, this._sheetName, this._file), {\n ...this._path,\n cell: address,\n range: undefined,\n })\n } catch {\n return fail('range', `Invalid cell address: ${address}`, this._path)\n }\n }\n\n // ---------------------------------------------------------------------------\n // ITERATION\n // ---------------------------------------------------------------------------\n\n /**\n * Iterate over all cells in the range (row by row).\n */\n *cells(): Iterable<XlsxCell> {\n for (let row = this._startRow; row <= this._endRow; row++) {\n for (let col = this._startCol; col <= this._endCol; col++) {\n const cell = this.worksheet.getCell(row, col)\n yield XlsxCell.fromExcelJS(cell, this._sheetName, this._file)\n }\n }\n }\n\n /**\n * Iterate over rows, returning arrays of cells.\n */\n *rows(): Iterable<XlsxCell[]> {\n for (let row = this._startRow; row <= this._endRow; row++) {\n const rowCells: XlsxCell[] = []\n for (let col = this._startCol; col <= this._endCol; col++) {\n const cell = this.worksheet.getCell(row, col)\n rowCells.push(XlsxCell.fromExcelJS(cell, this._sheetName, this._file))\n }\n yield rowCells\n }\n }\n\n /**\n * Iterate over columns, returning arrays of cells.\n */\n *cols(): Iterable<XlsxCell[]> {\n for (let col = this._startCol; col <= this._endCol; col++) {\n const colCells: XlsxCell[] = []\n for (let row = this._startRow; row <= this._endRow; row++) {\n const cell = this.worksheet.getCell(row, col)\n colCells.push(XlsxCell.fromExcelJS(cell, this._sheetName, this._file))\n }\n yield colCells\n }\n }\n\n /**\n * Get all values in the range as a 2D array.\n */\n values(): CellValue[][] {\n const result: CellValue[][] = []\n for (const rowCells of this.rows()) {\n const rowValues: CellValue[] = []\n for (const cell of rowCells) {\n const val = cell.value()\n rowValues.push(val.ok ? val.value : null)\n }\n result.push(rowValues)\n }\n return result\n }\n\n /**\n * Get all cells as a flat array.\n */\n cellsArray(): XlsxCell[] {\n return [...this.cells()]\n }\n\n // ---------------------------------------------------------------------------\n // SUBRANGE\n // ---------------------------------------------------------------------------\n\n /**\n * Get a subrange within this range.\n */\n subRange(address: string): XlsxResult<XlsxRange> {\n try {\n const { start, end } = parseRange(address)\n if (\n start.row < this._startRow ||\n end.row > this._endRow ||\n start.col < this._startCol ||\n end.col > this._endCol\n ) {\n return fail(\n 'bounds',\n `Subrange ${address} extends outside range ${this.address}`,\n this._path\n )\n }\n return ok(\n XlsxRange.fromCoords(\n this.worksheet,\n start.row,\n start.col,\n end.row,\n end.col,\n this._sheetName,\n this._file\n ),\n { ...this._path, range: address }\n )\n } catch {\n return fail('range', `Invalid range address: ${address}`, this._path)\n }\n }\n\n /**\n * Get the first row as a range.\n */\n firstRow(): XlsxRange {\n return XlsxRange.fromCoords(\n this.worksheet,\n this._startRow,\n this._startCol,\n this._startRow,\n this._endCol,\n this._sheetName,\n this._file\n )\n }\n\n /**\n * Get the last row as a range.\n */\n lastRow(): XlsxRange {\n return XlsxRange.fromCoords(\n this.worksheet,\n this._endRow,\n this._startCol,\n this._endRow,\n this._endCol,\n this._sheetName,\n this._file\n )\n }\n\n /**\n * Get the first column as a range.\n */\n firstCol(): XlsxRange {\n return XlsxRange.fromCoords(\n this.worksheet,\n this._startRow,\n this._startCol,\n this._endRow,\n this._startCol,\n this._sheetName,\n this._file\n )\n }\n\n /**\n * Get the last column as a range.\n */\n lastCol(): XlsxRange {\n return XlsxRange.fromCoords(\n this.worksheet,\n this._startRow,\n this._endCol,\n this._endRow,\n this._endCol,\n this._sheetName,\n this._file\n )\n }\n\n /**\n * Get a specific row as a range (0-indexed offset from start).\n */\n rowAt(offset: number): XlsxResult<XlsxRange> {\n const row = this._startRow + offset\n if (row < this._startRow || row > this._endRow) {\n return fail(\n 'bounds',\n `Row offset ${offset} is outside range ${this.address}`,\n this._path\n )\n }\n return ok(\n XlsxRange.fromCoords(\n this.worksheet,\n row,\n this._startCol,\n row,\n this._endCol,\n this._sheetName,\n this._file\n ),\n this._path\n )\n }\n\n /**\n * Get a specific column as a range (0-indexed offset from start).\n */\n colAt(offset: number): XlsxResult<XlsxRange> {\n const col = this._startCol + offset\n if (col < this._startCol || col > this._endCol) {\n return fail(\n 'bounds',\n `Column offset ${offset} is outside range ${this.address}`,\n this._path\n )\n }\n return ok(\n XlsxRange.fromCoords(\n this.worksheet,\n this._startRow,\n col,\n this._endRow,\n col,\n this._sheetName,\n this._file\n ),\n this._path\n )\n }\n\n // ---------------------------------------------------------------------------\n // QUERY\n // ---------------------------------------------------------------------------\n\n /**\n * Find the first cell matching the predicate.\n */\n find(predicate: CellPredicate): XlsxResult<XlsxCell> {\n for (const cell of this.cells()) {\n if (predicate(cell)) {\n return ok(cell, cell.path)\n }\n }\n return fail(\n 'missing',\n `No cell matching predicate found in range ${this.address}`,\n this._path\n )\n }\n\n /**\n * Find all cells matching the predicate.\n */\n findAll(predicate: CellPredicate): XlsxCell[] {\n const results: XlsxCell[] = []\n for (const cell of this.cells()) {\n if (predicate(cell)) {\n results.push(cell)\n }\n }\n return results\n }\n\n /**\n * Find the first cell with the specified value.\n */\n findValue(value: CellValue): XlsxResult<XlsxCell> {\n for (const cell of this.cells()) {\n const cellVal = cell.value()\n if (cellVal.ok && cellVal.value === value) {\n return ok(cell, cell.path)\n }\n }\n return fail(\n 'missing',\n `Value \"${value}\" not found in range ${this.address}`,\n this._path\n )\n }\n\n /**\n * Check if any cell matches the predicate.\n */\n some(predicate: CellPredicate): boolean {\n for (const cell of this.cells()) {\n if (predicate(cell)) {\n return true\n }\n }\n return false\n }\n\n /**\n * Check if all cells match the predicate.\n */\n every(predicate: CellPredicate): boolean {\n for (const cell of this.cells()) {\n if (!predicate(cell)) {\n return false\n }\n }\n return true\n }\n\n /**\n * Count cells matching the predicate.\n */\n count(predicate: CellPredicate): number {\n let count = 0\n for (const cell of this.cells()) {\n if (predicate(cell)) {\n count++\n }\n }\n return count\n }\n\n // ---------------------------------------------------------------------------\n // CONVERSION\n // ---------------------------------------------------------------------------\n\n /**\n * Convert range to a 2D array of values.\n */\n toArray(): CellValue[][] {\n return this.values()\n }\n\n /**\n * Convert range to array of objects using a header row.\n * @param headerRowOffset - Row offset for headers (default: 0, first row)\n * @param dataStartOffset - Row offset where data starts (default: 1, second row)\n */\n toObjects(\n headerRowOffset: number = 0,\n dataStartOffset: number = 1\n ): Record<string, CellValue>[] {\n const allRows = [...this.rows()]\n if (allRows.length === 0) return []\n\n // Get headers from the specified row\n const headerRow = allRows[headerRowOffset]\n if (!headerRow) return []\n\n const headers: string[] = headerRow.map(cell => {\n const val = cell.value()\n return val.ok && val.value !== null ? String(val.value) : ''\n })\n\n // Convert data rows to objects\n const result: Record<string, CellValue>[] = []\n for (let i = dataStartOffset; i < allRows.length; i++) {\n const row = allRows[i]\n const obj: Record<string, CellValue> = {}\n for (let j = 0; j < headers.length; j++) {\n const header = headers[j]\n if (header) {\n const cell = row[j]\n const val = cell?.value()\n obj[header] = val?.ok ? val.value : null\n }\n }\n result.push(obj)\n }\n return result\n }\n\n /**\n * Convert range to JSON-compatible structure.\n */\n toJson(): {\n address: string\n rows: Array<Array<CellValue>>\n } {\n return {\n address: this.address,\n rows: this.values(),\n }\n }\n}\n","/**\n * XlsxCursor - immutable cursor for navigating through cells.\n *\n * @module xlsx/xlsx-cursor\n */\n\nimport type { XlsxSheet } from './xlsx-sheet'\nimport { XlsxCell } from './xlsx-cell'\nimport {\n XlsxResult,\n XlsxPath,\n ok,\n fail,\n} from './xlsx-result'\nimport {\n parseAddress,\n formatAddress,\n columnLetterToNumber,\n columnNumberToLetter,\n} from './util'\nimport type { CellPredicate } from './xlsx-query'\n\n/**\n * Direction for cursor movement.\n */\nexport type CursorDirection = 'right' | 'left' | 'down' | 'up'\n\n/**\n * Result of a grab operation.\n */\nexport interface GrabResult {\n readonly cells: XlsxCell[]\n readonly cursor: XlsxCursor\n}\n\n/**\n * Result of a single grab operation.\n */\nexport interface GrabOneResult {\n readonly cell: XlsxCell\n readonly cursor: XlsxCursor\n}\n\n/**\n * An immutable cursor for navigating through cells in a sheet.\n *\n * XlsxCursor provides a fluent API for moving through cells,\n * skipping cells based on predicates, and grabbing sequences\n * of cells. Each operation returns a new cursor, maintaining\n * immutability.\n */\nexport class XlsxCursor {\n private constructor(\n private readonly sheet: XlsxSheet,\n private readonly _row: number,\n private readonly _col: number,\n private readonly _direction: CursorDirection = 'right'\n ) {}\n\n /**\n * Create a cursor from an address string.\n * @internal\n */\n static create(sheet: XlsxSheet, address: string): XlsxCursor {\n const { row, col } = parseAddress(address)\n return new XlsxCursor(sheet, row, col)\n }\n\n /**\n * Create a cursor from row and column coordinates.\n * @internal\n */\n static createAt(sheet: XlsxSheet, row: number, col: number): XlsxCursor {\n return new XlsxCursor(sheet, Math.max(1, row), Math.max(1, col))\n }\n\n // ---------------------------------------------------------------------------\n // POSITION\n // ---------------------------------------------------------------------------\n\n /**\n * Get the current row (1-based).\n */\n get row(): number {\n return this._row\n }\n\n /**\n * Get the current column (1-based).\n */\n get col(): number {\n return this._col\n }\n\n /**\n * Get the current address.\n */\n get address(): string {\n return formatAddress(this._row, this._col)\n }\n\n /**\n * Get the current column letter.\n */\n get colLetter(): string {\n return columnNumberToLetter(this._col)\n }\n\n /**\n * Get the current direction.\n */\n get direction(): CursorDirection {\n return this._direction\n }\n\n /**\n * Get the path for lineage tracking.\n */\n get path(): XlsxPath {\n return {\n ...this.sheet.path,\n cell: this.address,\n }\n }\n\n // ---------------------------------------------------------------------------\n // MOVEMENT\n // ---------------------------------------------------------------------------\n\n /**\n * Move by a delta (returns new cursor).\n */\n move(rowDelta: number, colDelta: number): XlsxCursor {\n return new XlsxCursor(\n this.sheet,\n Math.max(1, this._row + rowDelta),\n Math.max(1, this._col + colDelta),\n this._direction\n )\n }\n\n /**\n * Move to a specific address.\n */\n moveTo(address: string): XlsxCursor {\n const { row, col } = parseAddress(address)\n return new XlsxCursor(this.sheet, row, col, this._direction)\n }\n\n /**\n * Move to a specific row.\n */\n moveToRow(row: number): XlsxCursor {\n return new XlsxCursor(this.sheet, Math.max(1, row), this._col, this._direction)\n }\n\n /**\n * Move to a specific column.\n */\n moveToCol(col: number | string): XlsxCursor {\n const colNum =\n typeof col === 'string' ? columnLetterToNumber(col.toUpperCase()) : col\n return new XlsxCursor(this.sheet, this._row, Math.max(1, colNum), this._direction)\n }\n\n /**\n * Move left by count cells.\n */\n left(count: number = 1): XlsxCursor {\n return new XlsxCursor(\n this.sheet,\n this._row,\n Math.max(1, this._col - count),\n 'left'\n )\n }\n\n /**\n * Move right by count cells.\n */\n right(count: number = 1): XlsxCursor {\n return new XlsxCursor(this.sheet, this._row, this._col + count, 'right')\n }\n\n /**\n * Move up by count cells.\n */\n up(count: number = 1): XlsxCursor {\n return new XlsxCursor(\n this.sheet,\n Math.max(1, this._row - count),\n this._col,\n 'up'\n )\n }\n\n /**\n * Move down by count cells.\n */\n down(count: number = 1): XlsxCursor {\n return new XlsxCursor(this.sheet, this._row + count, this._col, 'down')\n }\n\n /**\n * Set the current direction.\n */\n setDirection(direction: CursorDirection): XlsxCursor {\n return new XlsxCursor(this.sheet, this._row, this._col, direction)\n }\n\n /**\n * Move forward in the current direction.\n */\n forward(count: number = 1): XlsxCursor {\n switch (this._direction) {\n case 'right':\n return this.right(count)\n case 'left':\n return this.left(count)\n case 'down':\n return this.down(count)\n case 'up':\n return this.up(count)\n }\n }\n\n /**\n * Move to the start of the current row.\n */\n startOfRow(): XlsxCursor {\n return new XlsxCursor(this.sheet, this._row, 1, this._direction)\n }\n\n /**\n * Move to the start of the current column.\n */\n startOfCol(): XlsxCursor {\n return new XlsxCursor(this.sheet, 1, this._col, this._direction)\n }\n\n // ---------------------------------------------------------------------------\n // SKIP OPERATIONS\n // ---------------------------------------------------------------------------\n\n /**\n * Skip empty cells in the current direction.\n */\n skipEmpty(): XlsxCursor {\n return this.skipWhile(cell => cell.isEmpty())\n }\n\n /**\n * Skip cells while the predicate is true.\n */\n skipWhile(predicate: CellPredicate): XlsxCursor {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let cursor: XlsxCursor = this\n const dims = this.sheet.dimensions()\n const maxIterations = Math.max(dims.rowCount, dims.colCount) * 2\n\n for (let i = 0; i < maxIterations; i++) {\n const cellResult = cursor.cell()\n if (!cellResult.ok) break\n if (!predicate(cellResult.value)) break\n cursor = cursor.forward()\n }\n return cursor\n }\n\n /**\n * Skip cells until the predicate is true.\n */\n skipUntil(predicate: CellPredicate): XlsxCursor {\n return this.skipWhile(cell => !predicate(cell))\n }\n\n /**\n * Skip cells until a specific value is found.\n */\n skipToValue(value: unknown): XlsxCursor {\n return this.skipUntil(cell => {\n const val = cell.value()\n return val.ok && val.value === value\n })\n }\n\n /**\n * Skip a specific number of cells.\n */\n skip(count: number): XlsxCursor {\n return this.forward(count)\n }\n\n // ---------------------------------------------------------------------------\n // GRAB OPERATIONS\n // ---------------------------------------------------------------------------\n\n /**\n * Grab the current cell and move forward.\n */\n grab(): XlsxResult<GrabOneResult> {\n const cellResult = this.cell()\n if (!cellResult.ok) return cellResult\n return ok(\n {\n cell: cellResult.value,\n cursor: this.forward(),\n },\n this.path\n )\n }\n\n /**\n * Grab n cells in the current direction.\n */\n grabN(count: number): XlsxResult<GrabResult> {\n const cells: XlsxCell[] = []\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let cursor: XlsxCursor = this\n\n for (let i = 0; i < count; i++) {\n const cellResult = cursor.cell()\n if (!cellResult.ok) {\n // Return what we have so far\n break\n }\n cells.push(cellResult.value)\n cursor = cursor.forward()\n }\n\n if (cells.length === 0) {\n return fail('bounds', 'No cells to grab', this.path)\n }\n\n return ok({ cells, cursor }, this.path)\n }\n\n /**\n * Grab cells while the predicate is true.\n */\n grabWhile(predicate: CellPredicate): XlsxResult<GrabResult> {\n const cells: XlsxCell[] = []\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let cursor: XlsxCursor = this\n const dims = this.sheet.dimensions()\n const maxIterations = Math.max(dims.rowCount, dims.colCount) * 2\n\n for (let i = 0; i < maxIterations; i++) {\n const cellResult = cursor.cell()\n if (!cellResult.ok) break\n if (!predicate(cellResult.value)) break\n cells.push(cellResult.value)\n cursor = cursor.forward()\n }\n\n return ok({ cells, cursor }, this.path)\n }\n\n /**\n * Grab cells until the predicate is true (not including the matching cell).\n */\n grabUntil(predicate: CellPredicate): XlsxResult<GrabResult> {\n return this.grabWhile(cell => !predicate(cell))\n }\n\n /**\n * Grab the rest of the current row.\n */\n grabRow(): XlsxResult<GrabResult> {\n const cells: XlsxCell[] = []\n const dims = this.sheet.dimensions()\n let cursor = this.setDirection('right')\n\n for (let col = this._col; col <= dims.endCol; col++) {\n const cellResult = cursor.cell()\n if (!cellResult.ok) break\n cells.push(cellResult.value)\n cursor = cursor.forward()\n }\n\n return ok({ cells, cursor }, this.path)\n }\n\n /**\n * Grab the rest of the current column.\n */\n grabCol(): XlsxResult<GrabResult> {\n const cells: XlsxCell[] = []\n const dims = this.sheet.dimensions()\n let cursor = this.setDirection('down')\n\n for (let row = this._row; row <= dims.endRow; row++) {\n const cellResult = cursor.cell()\n if (!cellResult.ok) break\n cells.push(cellResult.value)\n cursor = cursor.forward()\n }\n\n return ok({ cells, cursor }, this.path)\n }\n\n /**\n * Grab non-empty cells in the current direction.\n */\n grabNonEmpty(): XlsxResult<GrabResult> {\n return this.grabWhile(cell => !cell.isEmpty())\n }\n\n // ---------------------------------------------------------------------------\n // PEEK OPERATIONS\n // ---------------------------------------------------------------------------\n\n /**\n * Peek at the current cell without moving.\n */\n peek(): XlsxResult<XlsxCell> {\n return this.cell()\n }\n\n /**\n * Peek at cells ahead without moving.\n */\n peekAhead(count: number): XlsxResult<XlsxCell[]> {\n const cells: XlsxCell[] = []\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let cursor: XlsxCursor = this\n\n for (let i = 0; i < count; i++) {\n const cellResult = cursor.cell()\n if (!cellResult.ok) break\n cells.push(cellResult.value)\n cursor = cursor.forward()\n }\n\n return ok(cells, this.path)\n }\n\n /**\n * Peek at a cell at an offset without moving.\n */\n peekAt(rowDelta: number, colDelta: number): XlsxResult<XlsxCell> {\n return this.move(rowDelta, colDelta).cell()\n }\n\n // ---------------------------------------------------------------------------\n // CURRENT CELL\n // ---------------------------------------------------------------------------\n\n /**\n * Get the cell at the current position.\n */\n cell(): XlsxResult<XlsxCell> {\n return this.sheet.cellAt(this._row, this._col)\n }\n\n /**\n * Get the value of the current cell.\n */\n value(): XlsxResult<unknown> {\n const cellResult = this.cell()\n if (!cellResult.ok) return cellResult\n return cellResult.value.value()\n }\n\n // ---------------------------------------------------------------------------\n // UTILITIES\n // ---------------------------------------------------------------------------\n\n /**\n * Check if the cursor is at a valid position with data.\n */\n isValid(): boolean {\n const cellResult = this.cell()\n return cellResult.ok\n }\n\n /**\n * Check if the current cell is empty.\n */\n isEmpty(): boolean {\n const cellResult = this.cell()\n return cellResult.ok && cellResult.value.isEmpty()\n }\n\n /**\n * Check if the current cell is non-empty.\n */\n isNotEmpty(): boolean {\n const cellResult = this.cell()\n return cellResult.ok && !cellResult.value.isEmpty()\n }\n\n /**\n * Create a new cursor at the same position.\n */\n clone(): XlsxCursor {\n return new XlsxCursor(this.sheet, this._row, this._col, this._direction)\n }\n}\n","/**\n * XlsxSheet - wrapper around ExcelJS worksheet with navigation and query capabilities.\n *\n * @module xlsx/xlsx-sheet\n */\n\nimport type { Worksheet } from 'exceljs'\nimport { XlsxCell } from './xlsx-cell'\nimport { XlsxRange } from './xlsx-range'\nimport { XlsxCursor } from './xlsx-cursor'\nimport {\n XlsxResult,\n XlsxPath,\n CellValue,\n ok,\n fail,\n} from './xlsx-result'\nimport {\n parseAddress,\n parseRange,\n columnLetterToNumber,\n} from './util'\nimport type { CellPredicate } from './xlsx-query'\n\n/**\n * Dimensions of a sheet's used range.\n */\nexport interface SheetDimensions {\n readonly startRow: number\n readonly endRow: number\n readonly startCol: number\n readonly endCol: number\n readonly rowCount: number\n readonly colCount: number\n}\n\n/**\n * A wrapper around ExcelJS Worksheet with navigation and query capabilities.\n *\n * XlsxSheet provides a rich API for navigating cells, ranges, and rows\n * within a worksheet. It supports predicate-based queries and cursor-based\n * navigation for complex data extraction scenarios.\n */\nexport class XlsxSheet {\n private constructor(\n private readonly worksheet: Worksheet,\n private readonly _path: XlsxPath,\n private readonly _file?: string\n ) {}\n\n /**\n * Creates an XlsxSheet from an ExcelJS worksheet.\n * @internal\n */\n static fromExcelJS(worksheet: Worksheet, file?: string): XlsxSheet {\n const path: XlsxPath = {\n file,\n sheet: worksheet.name,\n }\n return new XlsxSheet(worksheet, path, file)\n }\n\n // ---------------------------------------------------------------------------\n // IDENTITY\n // ---------------------------------------------------------------------------\n\n /**\n * Returns the sheet name.\n */\n get name(): string {\n return this.worksheet.name\n }\n\n /**\n * Returns the sheet index (1-based).\n */\n get index(): number {\n return this.worksheet.id\n }\n\n /**\n * Returns the current path for lineage tracking.\n */\n get path(): XlsxPath {\n return this._path\n }\n\n // ---------------------------------------------------------------------------\n // CELL ACCESS\n // ---------------------------------------------------------------------------\n\n /**\n * Get a cell by its address (e.g., \"A1\", \"B2\").\n */\n cell(address: string): XlsxResult<XlsxCell> {\n try {\n parseAddress(address) // Validate address\n const cell = this.worksheet.getCell(address)\n return ok(XlsxCell.fromExcelJS(cell, this.name, this._file), {\n ...this._path,\n cell: address,\n })\n } catch {\n return fail('range', `Invalid cell address: ${address}`, this._path)\n }\n }\n\n /**\n * Get a cell by row and column numbers (1-based).\n */\n cellAt(row: number, col: number): XlsxResult<XlsxCell> {\n if (row < 1 || col < 1) {\n return fail(\n 'bounds',\n `Invalid cell coordinates: row=${row}, col=${col}`,\n this._path\n )\n }\n const cell = this.worksheet.getCell(row, col)\n return ok(XlsxCell.fromExcelJS(cell, this.name, this._file), {\n ...this._path,\n cell: cell.address,\n })\n }\n\n /**\n * Get the value of a cell directly.\n */\n getValue(address: string): XlsxResult<CellValue> {\n const cellResult = this.cell(address)\n if (!cellResult.ok) return cellResult\n return cellResult.value.value()\n }\n\n // ---------------------------------------------------------------------------\n // RANGE OPERATIONS\n // ---------------------------------------------------------------------------\n\n /**\n * Get a range by its address (e.g., \"A1:C10\").\n */\n range(address: string): XlsxResult<XlsxRange> {\n return XlsxRange.fromAddress(this.worksheet, address, this.name, this._file)\n }\n\n /**\n * Get a range from start to end addresses.\n */\n rangeFrom(start: string, end: string): XlsxResult<XlsxRange> {\n return this.range(`${start}:${end}`)\n }\n\n /**\n * Get a range by coordinates (1-based).\n */\n rangeAt(\n startRow: number,\n startCol: number,\n endRow: number,\n endCol: number\n ): XlsxResult<XlsxRange> {\n if (startRow < 1 || startCol < 1 || endRow < 1 || endCol < 1) {\n return fail('bounds', 'Invalid range coordinates', this._path)\n }\n return ok(\n XlsxRange.fromCoords(\n this.worksheet,\n startRow,\n startCol,\n endRow,\n endCol,\n this.name,\n this._file\n ),\n this._path\n )\n }\n\n /**\n * Get the used range of the sheet (cells with data).\n */\n usedRange(): XlsxResult<XlsxRange> {\n const dims = this.dimensions()\n if (dims.rowCount === 0 || dims.colCount === 0) {\n return fail('missing', 'Sheet has no used cells', this._path)\n }\n return ok(\n XlsxRange.fromCoords(\n this.worksheet,\n dims.startRow,\n dims.startCol,\n dims.endRow,\n dims.endCol,\n this.name,\n this._file\n ),\n this._path\n )\n }\n\n // ---------------------------------------------------------------------------\n // ROW / COLUMN ACCESS\n // ---------------------------------------------------------------------------\n\n /**\n * Get a row as a range.\n */\n row(rowNum: number): XlsxResult<XlsxRange> {\n const dims = this.dimensions()\n if (rowNum < 1) {\n return fail('bounds', `Invalid row number: ${rowNum}`, this._path)\n }\n const endCol = Math.max(dims.endCol, 1)\n return ok(\n XlsxRange.fromCoords(\n this.worksheet,\n rowNum,\n 1,\n rowNum,\n endCol,\n this.name,\n this._file\n ),\n this._path\n )\n }\n\n /**\n * Get a column as a range.\n */\n col(colId: string | number): XlsxResult<XlsxRange> {\n const colNum =\n typeof colId === 'string' ? columnLetterToNumber(colId.toUpperCase()) : colId\n if (colNum < 1) {\n return fail('bounds', `Invalid column: ${colId}`, this._path)\n }\n const dims = this.dimensions()\n const endRow = Math.max(dims.endRow, 1)\n return ok(\n XlsxRange.fromCoords(\n this.worksheet,\n 1,\n colNum,\n endRow,\n colNum,\n this.name,\n this._file\n ),\n this._path\n )\n }\n\n /**\n * Iterate over all rows with data.\n */\n *rows(): Iterable<XlsxRange> {\n const dims = this.dimensions()\n for (let r = dims.startRow; r <= dims.endRow; r++) {\n yield XlsxRange.fromCoords(\n this.worksheet,\n r,\n dims.startCol,\n r,\n dims.endCol,\n this.name,\n this._file\n )\n }\n }\n\n /**\n * Iterate over all columns with data.\n */\n *cols(): Iterable<XlsxRange> {\n const dims = this.dimensions()\n for (let c = dims.startCol; c <= dims.endCol; c++) {\n yield XlsxRange.fromCoords(\n this.worksheet,\n dims.startRow,\n c,\n dims.endRow,\n c,\n this.name,\n this._file\n )\n }\n }\n\n // ---------------------------------------------------------------------------\n // CURSOR CREATION\n // ---------------------------------------------------------------------------\n\n /**\n * Create a cursor starting at the specified address.\n */\n cursor(startAddress?: string): XlsxCursor {\n const address = startAddress ?? 'A1'\n return XlsxCursor.create(this, address)\n }\n\n /**\n * Create a cursor starting at the specified coordinates (1-based).\n */\n cursorAt(row: number, col: number): XlsxCursor {\n return XlsxCursor.createAt(this, row, col)\n }\n\n // ---------------------------------------------------------------------------\n // QUERY METHODS\n // ---------------------------------------------------------------------------\n\n /**\n * Find the first cell matching the predicate.\n */\n find(predicate: CellPredicate): XlsxResult<XlsxCell> {\n const rangeResult = this.usedRange()\n if (!rangeResult.ok) return rangeResult as XlsxResult<XlsxCell>\n return rangeResult.value.find(predicate)\n }\n\n /**\n * Find all cells matching the predicate.\n */\n findAll(predicate: CellPredicate): XlsxCell[] {\n const rangeResult = this.usedRange()\n if (!rangeResult.ok) return []\n return rangeResult.value.findAll(predicate)\n }\n\n /**\n * Find the first cell with the specified value.\n */\n findValue(value: CellValue): XlsxResult<XlsxCell> {\n const rangeResult = this.usedRange()\n if (!rangeResult.ok) return rangeResult as XlsxResult<XlsxCell>\n return rangeResult.value.findValue(value)\n }\n\n /**\n * Find cells within a specific range matching the predicate.\n */\n findInRange(\n rangeAddress: string,\n predicate: CellPredicate\n ): XlsxResult<XlsxCell> {\n const rangeResult = this.range(rangeAddress)\n if (!rangeResult.ok) return rangeResult as XlsxResult<XlsxCell>\n return rangeResult.value.find(predicate)\n }\n\n /**\n * Find all cells within a specific range matching the predicate.\n */\n findAllInRange(rangeAddress: string, predicate: CellPredicate): XlsxCell[] {\n const rangeResult = this.range(rangeAddress)\n if (!rangeResult.ok) return []\n return rangeResult.value.findAll(predicate)\n }\n\n // ---------------------------------------------------------------------------\n // DIMENSIONS\n // ---------------------------------------------------------------------------\n\n /**\n * Get the dimensions of the used area.\n */\n dimensions(): SheetDimensions {\n // ExcelJS tracks dimensions in the worksheet\n const rowCount = this.worksheet.rowCount\n const columnCount = this.worksheet.columnCount\n\n // Find actual used range by checking rows\n let startRow = 1\n let endRow = rowCount\n let startCol = 1\n let endCol = columnCount\n\n // Try to get actual dimensions from worksheet\n if (this.worksheet.dimensions) {\n const dims = this.worksheet.dimensions\n // dims is a string like \"A1:C10\" or an object\n if (typeof dims === 'string') {\n try {\n const parsed = parseRange(dims)\n startRow = parsed.start.row\n startCol = parsed.start.col\n endRow = parsed.end.row\n endCol = parsed.end.col\n } catch {\n // Fall back to calculated dimensions\n }\n }\n }\n\n return {\n startRow,\n endRow,\n startCol,\n endCol,\n rowCount: endRow - startRow + 1,\n colCount: endCol - startCol + 1,\n }\n }\n\n /**\n * Get the number of rows with data.\n */\n rowCount(): number {\n return this.dimensions().rowCount\n }\n\n /**\n * Get the number of columns with data.\n */\n colCount(): number {\n return this.dimensions().colCount\n }\n\n // ---------------------------------------------------------------------------\n // MERGED CELLS\n // ---------------------------------------------------------------------------\n\n /**\n * Get all merged cell ranges.\n */\n mergedRanges(): string[] {\n // ExcelJS stores merged cells in the _merges property or via hasMerges\n const merges = (this.worksheet as unknown as { _merges?: Record<string, unknown> })._merges\n if (!merges) return []\n return Object.keys(merges)\n }\n\n /**\n * Check if a cell is part of a merged range.\n */\n isMerged(address: string): boolean {\n const cellResult = this.cell(address)\n if (!cellResult.ok) return false\n return cellResult.value.isMerged()\n }\n\n // ---------------------------------------------------------------------------\n // INTERNAL HELPERS\n // ---------------------------------------------------------------------------\n\n /**\n * Get the underlying ExcelJS worksheet.\n * @internal\n */\n getWorksheet(): Worksheet {\n return this.worksheet\n }\n\n /**\n * Get a cell by coordinates for internal use.\n * @internal\n */\n getCellInternal(row: number, col: number): XlsxCell | undefined {\n if (row < 1 || col < 1) return undefined\n const cell = this.worksheet.getCell(row, col)\n return XlsxCell.fromExcelJS(cell, this.name, this._file)\n }\n}\n","/**\n * XlsxWorkbook - wrapper around ExcelJS workbook with navigation and query capabilities.\n *\n * @module xlsx/xlsx-workbook\n */\n\nimport type { Workbook } from 'exceljs'\nimport { XlsxSheet } from './xlsx-sheet'\nimport {\n XlsxResult,\n XlsxPath,\n ok,\n fail,\n} from './xlsx-result'\n\n/**\n * Predicate function for matching sheets.\n */\nexport type SheetPredicate = (sheet: XlsxSheet) => boolean\n\n/**\n * Workbook properties.\n */\nexport interface WorkbookProperties {\n readonly title?: string\n readonly subject?: string\n readonly creator?: string\n readonly lastModifiedBy?: string\n readonly created?: Date\n readonly modified?: Date\n}\n\n/**\n * A wrapper around ExcelJS Workbook with navigation and query capabilities.\n *\n * XlsxWorkbook provides access to sheets, workbook properties, and\n * supports predicate-based queries for finding sheets.\n */\nexport class XlsxWorkbook {\n private readonly sheetsCache: Map<string, XlsxSheet> = new Map()\n\n private constructor(\n private readonly workbook: Workbook,\n private readonly _path: XlsxPath\n ) {}\n\n /**\n * Creates an XlsxWorkbook from an ExcelJS workbook.\n * @internal\n */\n static fromExcelJS(workbook: Workbook, file?: string): XlsxWorkbook {\n const path: XlsxPath = { file }\n return new XlsxWorkbook(workbook, path)\n }\n\n // ---------------------------------------------------------------------------\n // IDENTITY\n // ---------------------------------------------------------------------------\n\n /**\n * Returns the path for lineage tracking.\n */\n get path(): XlsxPath {\n return this._path\n }\n\n /**\n * Returns the file name if known.\n */\n get file(): string | undefined {\n return this._path.file\n }\n\n // ---------------------------------------------------------------------------\n // SHEET ACCESS\n // ---------------------------------------------------------------------------\n\n /**\n * Get a sheet by name.\n */\n sheet(name: string): XlsxResult<XlsxSheet> {\n // Check cache first\n const cached = this.sheetsCache.get(name)\n if (cached) {\n return ok(cached, { ...this._path, sheet: name })\n }\n\n const worksheet = this.workbook.getWorksheet(name)\n if (!worksheet) {\n return fail(\n 'missing',\n `Sheet \"${name}\" not found`,\n this._path\n )\n }\n\n const sheet = XlsxSheet.fromExcelJS(worksheet, this._path.file)\n this.sheetsCache.set(name, sheet)\n return ok(sheet, sheet.path)\n }\n\n /**\n * Get a sheet by index (1-based, as per Excel convention).\n */\n sheetAt(index: number): XlsxResult<XlsxSheet> {\n if (index < 1) {\n return fail(\n 'bounds',\n `Sheet index must be >= 1, got ${index}`,\n this._path\n )\n }\n\n const worksheet = this.workbook.getWorksheet(index)\n if (!worksheet) {\n return fail(\n 'missing',\n `Sheet at index ${index} not found`,\n this._path\n )\n }\n\n // Check cache by name\n const cached = this.sheetsCache.get(worksheet.name)\n if (cached) {\n return ok(cached, cached.path)\n }\n\n const sheet = XlsxSheet.fromExcelJS(worksheet, this._path.file)\n this.sheetsCache.set(worksheet.name, sheet)\n return ok(sheet, sheet.path)\n }\n\n /**\n * Get all sheets.\n */\n sheets(): XlsxSheet[] {\n const sheets: XlsxSheet[] = []\n this.workbook.eachSheet((worksheet) => {\n const cached = this.sheetsCache.get(worksheet.name)\n if (cached) {\n sheets.push(cached)\n } else {\n const sheet = XlsxSheet.fromExcelJS(worksheet, this._path.file)\n this.sheetsCache.set(worksheet.name, sheet)\n sheets.push(sheet)\n }\n })\n return sheets\n }\n\n /**\n * Get all sheet names.\n */\n sheetNames(): string[] {\n const names: string[] = []\n this.workbook.eachSheet((worksheet) => {\n names.push(worksheet.name)\n })\n return names\n }\n\n /**\n * Get the number of sheets.\n */\n sheetCount(): number {\n return this.workbook.worksheets.length\n }\n\n /**\n * Get the first sheet.\n */\n firstSheet(): XlsxResult<XlsxSheet> {\n return this.sheetAt(1)\n }\n\n /**\n * Get the last sheet.\n */\n lastSheet(): XlsxResult<XlsxSheet> {\n const count = this.sheetCount()\n if (count === 0) {\n return fail('missing', 'Workbook has no sheets', this._path)\n }\n return this.sheetAt(count)\n }\n\n // ---------------------------------------------------------------------------\n // PREDICATES\n // ---------------------------------------------------------------------------\n\n /**\n * Check if a sheet with the given name exists.\n */\n hasSheet(name: string): boolean {\n return this.workbook.getWorksheet(name) !== undefined\n }\n\n /**\n * Find the first sheet matching the predicate.\n */\n findSheet(predicate: SheetPredicate): XlsxResult<XlsxSheet> {\n for (const sheet of this.sheets()) {\n if (predicate(sheet)) {\n return ok(sheet, sheet.path)\n }\n }\n return fail(\n 'missing',\n 'No sheet matching predicate found',\n this._path\n )\n }\n\n /**\n * Find all sheets matching the predicate.\n */\n filterSheets(predicate: SheetPredicate): XlsxSheet[] {\n return this.sheets().filter(predicate)\n }\n\n /**\n * Find a sheet by name pattern (regex).\n */\n findSheetByPattern(pattern: RegExp): XlsxResult<XlsxSheet> {\n return this.findSheet(sheet => pattern.test(sheet.name))\n }\n\n /**\n * Find all sheets by name pattern (regex).\n */\n filterSheetsByPattern(pattern: RegExp): XlsxSheet[] {\n return this.filterSheets(sheet => pattern.test(sheet.name))\n }\n\n // ---------------------------------------------------------------------------\n // WORKBOOK PROPERTIES\n // ---------------------------------------------------------------------------\n\n /**\n * Get workbook properties.\n */\n properties(): WorkbookProperties {\n return {\n title: this.workbook.title,\n subject: this.workbook.subject,\n creator: this.workbook.creator,\n lastModifiedBy: this.workbook.lastModifiedBy,\n created: this.workbook.created,\n modified: this.workbook.modified,\n }\n }\n\n /**\n * Get the workbook creator.\n */\n creator(): string | undefined {\n return this.workbook.creator\n }\n\n /**\n * Get the workbook creation date.\n */\n created(): Date | undefined {\n return this.workbook.created\n }\n\n /**\n * Get the workbook modification date.\n */\n modified(): Date | undefined {\n return this.workbook.modified\n }\n\n // ---------------------------------------------------------------------------\n // DEFINED NAMES\n // ---------------------------------------------------------------------------\n\n /**\n * Get all defined names in the workbook.\n */\n definedNames(): string[] {\n const names: string[] = []\n // ExcelJS stores defined names differently\n // This is a simplified implementation\n return names\n }\n\n // ---------------------------------------------------------------------------\n // ITERATION\n // ---------------------------------------------------------------------------\n\n /**\n * Iterate over all sheets.\n */\n *[Symbol.iterator](): Iterator<XlsxSheet> {\n for (const sheet of this.sheets()) {\n yield sheet\n }\n }\n\n /**\n * Execute a function for each sheet.\n */\n forEach(fn: (sheet: XlsxSheet, index: number) => void): void {\n this.sheets().forEach(fn)\n }\n\n /**\n * Map over all sheets.\n */\n map<T>(fn: (sheet: XlsxSheet, index: number) => T): T[] {\n return this.sheets().map(fn)\n }\n\n // ---------------------------------------------------------------------------\n // INTERNAL\n // ---------------------------------------------------------------------------\n\n /**\n * Get the underlying ExcelJS workbook.\n * @internal\n */\n getWorkbook(): Workbook {\n return this.workbook\n }\n}\n","/**\n * Query predicates for XLSX cell matching.\n *\n * @module xlsx/xlsx-query\n */\n\nimport type { XlsxCell } from './xlsx-cell'\nimport type { CellValue } from './xlsx-result'\n\n/**\n * A predicate function for matching cells.\n */\nexport type CellPredicate = (cell: XlsxCell) => boolean\n\n/**\n * Built-in predicates for common cell matching scenarios.\n */\nexport const predicates = {\n // ---------------------------------------------------------------------------\n // VALUE PREDICATES\n // ---------------------------------------------------------------------------\n\n /**\n * Match cells with the exact value.\n */\n equals: (value: CellValue): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.value()\n if (!val.ok) return false\n if (value === null) return val.value === null\n if (val.value === null) return false\n // Handle date comparison\n if (value instanceof Date && val.value instanceof Date) {\n return value.getTime() === val.value.getTime()\n }\n return val.value === value\n }\n },\n\n /**\n * Match cells containing the specified text (case-insensitive by default).\n */\n contains: (text: string, caseSensitive: boolean = false): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.string()\n if (!val.ok) return false\n if (caseSensitive) {\n return val.value.includes(text)\n }\n return val.value.toLowerCase().includes(text.toLowerCase())\n }\n },\n\n /**\n * Match cells whose value matches the regex pattern.\n */\n matches: (pattern: RegExp): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.string()\n if (!val.ok) return false\n return pattern.test(val.value)\n }\n },\n\n /**\n * Match cells whose string value starts with the prefix.\n */\n startsWith: (prefix: string, caseSensitive: boolean = false): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.string()\n if (!val.ok) return false\n if (caseSensitive) {\n return val.value.startsWith(prefix)\n }\n return val.value.toLowerCase().startsWith(prefix.toLowerCase())\n }\n },\n\n /**\n * Match cells whose string value ends with the suffix.\n */\n endsWith: (suffix: string, caseSensitive: boolean = false): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.string()\n if (!val.ok) return false\n if (caseSensitive) {\n return val.value.endsWith(suffix)\n }\n return val.value.toLowerCase().endsWith(suffix.toLowerCase())\n }\n },\n\n // ---------------------------------------------------------------------------\n // TYPE PREDICATES\n // ---------------------------------------------------------------------------\n\n /**\n * Match cells containing a string value.\n */\n isString: (): CellPredicate => {\n return (cell: XlsxCell) => cell.isString()\n },\n\n /**\n * Match cells containing a numeric value.\n */\n isNumber: (): CellPredicate => {\n return (cell: XlsxCell) => cell.isNumber()\n },\n\n /**\n * Match cells containing a boolean value.\n */\n isBoolean: (): CellPredicate => {\n return (cell: XlsxCell) => cell.isBoolean()\n },\n\n /**\n * Match cells containing a date value.\n */\n isDate: (): CellPredicate => {\n return (cell: XlsxCell) => cell.isDate()\n },\n\n /**\n * Match empty cells.\n */\n isEmpty: (): CellPredicate => {\n return (cell: XlsxCell) => cell.isEmpty()\n },\n\n /**\n * Match non-empty cells.\n */\n isNotEmpty: (): CellPredicate => {\n return (cell: XlsxCell) => !cell.isEmpty()\n },\n\n /**\n * Match cells containing a formula.\n */\n isFormula: (): CellPredicate => {\n return (cell: XlsxCell) => cell.isFormula()\n },\n\n /**\n * Match cells containing an error.\n */\n isError: (): CellPredicate => {\n return (cell: XlsxCell) => cell.isError()\n },\n\n /**\n * Match merged cells.\n */\n isMerged: (): CellPredicate => {\n return (cell: XlsxCell) => cell.isMerged()\n },\n\n // ---------------------------------------------------------------------------\n // NUMERIC PREDICATES\n // ---------------------------------------------------------------------------\n\n /**\n * Match cells with numeric value greater than n.\n */\n greaterThan: (n: number): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.number()\n return val.ok && val.value > n\n }\n },\n\n /**\n * Match cells with numeric value greater than or equal to n.\n */\n greaterThanOrEqual: (n: number): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.number()\n return val.ok && val.value >= n\n }\n },\n\n /**\n * Match cells with numeric value less than n.\n */\n lessThan: (n: number): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.number()\n return val.ok && val.value < n\n }\n },\n\n /**\n * Match cells with numeric value less than or equal to n.\n */\n lessThanOrEqual: (n: number): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.number()\n return val.ok && val.value <= n\n }\n },\n\n /**\n * Match cells with numeric value between min and max (inclusive).\n */\n between: (min: number, max: number): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.number()\n return val.ok && val.value >= min && val.value <= max\n }\n },\n\n // ---------------------------------------------------------------------------\n // DATE PREDICATES\n // ---------------------------------------------------------------------------\n\n /**\n * Match cells with date before the specified date.\n */\n dateBefore: (date: Date): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.date()\n return val.ok && val.value.getTime() < date.getTime()\n }\n },\n\n /**\n * Match cells with date after the specified date.\n */\n dateAfter: (date: Date): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.date()\n return val.ok && val.value.getTime() > date.getTime()\n }\n },\n\n /**\n * Match cells with date between start and end (inclusive).\n */\n dateBetween: (start: Date, end: Date): CellPredicate => {\n return (cell: XlsxCell) => {\n const val = cell.date()\n if (!val.ok) return false\n const time = val.value.getTime()\n return time >= start.getTime() && time <= end.getTime()\n }\n },\n\n // ---------------------------------------------------------------------------\n // LOCATION PREDICATES\n // ---------------------------------------------------------------------------\n\n /**\n * Match cells in the specified row.\n */\n inRow: (rowNum: number): CellPredicate => {\n return (cell: XlsxCell) => cell.row === rowNum\n },\n\n /**\n * Match cells in the specified column.\n */\n inCol: (colNum: number): CellPredicate => {\n return (cell: XlsxCell) => cell.col === colNum\n },\n\n /**\n * Match cells in the specified column (by letter).\n */\n inColLetter: (colLetter: string): CellPredicate => {\n return (cell: XlsxCell) =>\n cell.colLetter.toUpperCase() === colLetter.toUpperCase()\n },\n\n // ---------------------------------------------------------------------------\n // COMPOSITION\n // ---------------------------------------------------------------------------\n\n /**\n * Match cells that satisfy all predicates.\n */\n and: (...preds: CellPredicate[]): CellPredicate => {\n return (cell: XlsxCell) => preds.every(pred => pred(cell))\n },\n\n /**\n * Match cells that satisfy at least one predicate.\n */\n or: (...preds: CellPredicate[]): CellPredicate => {\n return (cell: XlsxCell) => preds.some(pred => pred(cell))\n },\n\n /**\n * Match cells that do not satisfy the predicate.\n */\n not: (pred: CellPredicate): CellPredicate => {\n return (cell: XlsxCell) => !pred(cell)\n },\n\n // ---------------------------------------------------------------------------\n // STYLE PREDICATES\n // ---------------------------------------------------------------------------\n\n /**\n * Match cells with bold font.\n */\n isBold: (): CellPredicate => {\n return (cell: XlsxCell) => {\n const style = cell.style()\n return style.font?.bold === true\n }\n },\n\n /**\n * Match cells with italic font.\n */\n isItalic: (): CellPredicate => {\n return (cell: XlsxCell) => {\n const style = cell.style()\n return style.font?.italic === true\n }\n },\n\n /**\n * Match cells with a hyperlink.\n */\n hasHyperlink: (): CellPredicate => {\n return (cell: XlsxCell) => {\n const link = cell.hyperlink()\n return link.ok\n }\n },\n\n /**\n * Match cells with a comment.\n */\n hasComment: (): CellPredicate => {\n return (cell: XlsxCell) => {\n const comment = cell.comment()\n return comment.ok\n }\n },\n\n // ---------------------------------------------------------------------------\n // UTILITY\n // ---------------------------------------------------------------------------\n\n /**\n * Always match.\n */\n always: (): CellPredicate => {\n return () => true\n },\n\n /**\n * Never match.\n */\n never: (): CellPredicate => {\n return () => false\n },\n\n /**\n * Create a custom predicate from a function.\n */\n custom: (fn: (cell: XlsxCell) => boolean): CellPredicate => {\n return fn\n },\n}\n\n/**\n * Type for the predicates object.\n */\nexport type Predicates = typeof predicates\n","/**\n * XLSX parsing transform for Origins.\n *\n * @module xlsx/parse\n */\n\nimport ExcelJS from 'exceljs'\nimport { XlsxWorkbook } from './xlsx-workbook'\nimport { streamToBuffer } from './util'\n\n/**\n * Transform AST specification.\n * Compatible with @origints/core TransformAst.\n */\nexport interface TransformAst {\n readonly kind: 'transform'\n readonly namespace: string\n readonly name: string\n readonly args?: unknown\n}\n\n/**\n * Transform implementation.\n * Compatible with @origints/core TransformImpl.\n */\nexport interface TransformImpl<In = unknown, Out = unknown> {\n readonly namespace: string\n readonly name: string\n execute(input: In, args?: unknown): Out | Promise<Out>\n}\n\n/**\n * Options for parsing XLSX.\n */\nexport interface XlsxParseOptions {\n /**\n * Which sheets to parse.\n * - 'all': Parse all sheets (default)\n * - string[]: Only parse sheets with these names\n * - number[]: Only parse sheets at these indices (1-based)\n */\n sheets?: 'all' | string[] | number[]\n\n /**\n * Whether to use formula results instead of formulas.\n * Default: true (use calculated results)\n */\n formulaResults?: boolean\n\n /**\n * Whether to include hidden sheets.\n * Default: true\n */\n includeHidden?: boolean\n\n /**\n * Date format for parsing dates.\n * This affects how date values are interpreted.\n */\n dateFormat?: string\n\n /**\n * File name to associate with the parsed workbook.\n * Used for lineage tracking.\n */\n fileName?: string\n}\n\n/**\n * Creates a TransformAst for parsing XLSX.\n *\n * @example\n * ```ts\n * const plan = new Planner()\n * .in(loadFile('data.xlsx'))\n * .mapIn(parseXlsx())\n * .emit((out, $) => out\n * .add('revenue', $.sheet('Sales').cell('B2').number())\n * )\n * .compile()\n * ```\n */\nexport function parseXlsx(options?: XlsxParseOptions): TransformAst {\n return {\n kind: 'transform',\n namespace: '@origints/xlsx',\n name: 'parseXlsx',\n args: options,\n }\n}\n\n/**\n * Sync transform implementation for parseXlsx.\n * Note: XLSX parsing requires async due to file reading.\n */\nexport const parseXlsxImpl: TransformImpl = {\n namespace: '@origints/xlsx',\n name: 'parseXlsx',\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n execute(input: unknown, args?: unknown): never {\n throw new Error(\n 'parseXlsx requires async execution. Use parseXlsxAsyncImpl instead.'\n )\n },\n}\n\n/**\n * Convert a buffer-like input to ArrayBuffer.\n */\nfunction toArrayBuffer(input: Buffer | Uint8Array): ArrayBuffer {\n // Create a new ArrayBuffer and copy data to avoid SharedArrayBuffer issues\n const copy = new Uint8Array(input)\n return copy.buffer\n}\n\n/**\n * Async transform implementation for parseXlsx (handles streams and buffers).\n */\nexport const parseXlsxAsyncImpl: TransformImpl = {\n namespace: '@origints/xlsx',\n name: 'parseXlsx',\n\n async execute(input: unknown, args?: unknown): Promise<XlsxWorkbook> {\n const options = (args as XlsxParseOptions) ?? {}\n\n let data: ArrayBuffer\n\n if (input instanceof ReadableStream) {\n const buffer = await streamToBuffer(input)\n data = toArrayBuffer(buffer)\n } else if (Buffer.isBuffer(input)) {\n data = toArrayBuffer(input)\n } else if (input instanceof ArrayBuffer) {\n data = input\n } else if (input instanceof Uint8Array) {\n data = toArrayBuffer(input)\n } else {\n throw new Error(\n `parseXlsx expects stream or buffer input, got ${typeof input}`\n )\n }\n\n const workbook = new ExcelJS.Workbook()\n await workbook.xlsx.load(data)\n\n return XlsxWorkbook.fromExcelJS(workbook, options.fileName)\n },\n}\n\n/**\n * Parse XLSX from a buffer directly.\n */\nexport async function parseXlsxBuffer(\n buffer: Buffer | ArrayBuffer | Uint8Array,\n options?: XlsxParseOptions\n): Promise<XlsxWorkbook> {\n const workbook = new ExcelJS.Workbook()\n let data: ArrayBuffer\n if (buffer instanceof ArrayBuffer) {\n data = buffer\n } else {\n data = toArrayBuffer(buffer)\n }\n await workbook.xlsx.load(data)\n return XlsxWorkbook.fromExcelJS(workbook, options?.fileName)\n}\n\n/**\n * Parse XLSX from a file path directly.\n * Useful for testing and standalone usage.\n */\nexport async function parseXlsxFile(\n filePath: string,\n options?: XlsxParseOptions\n): Promise<XlsxWorkbook> {\n const workbook = new ExcelJS.Workbook()\n await workbook.xlsx.readFile(filePath)\n return XlsxWorkbook.fromExcelJS(workbook, options?.fileName ?? filePath)\n}\n","/**\n * Conversion utilities for XLSX data.\n *\n * @module xlsx/convert\n */\n\nimport type { XlsxWorkbook } from './xlsx-workbook'\nimport type { XlsxSheet } from './xlsx-sheet'\nimport type { XlsxRange } from './xlsx-range'\nimport type { XlsxCell } from './xlsx-cell'\nimport type { CellValue } from './xlsx-result'\n\n/**\n * JSON-compatible value types.\n */\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue }\n\n/**\n * Options for converting to JSON.\n */\nexport interface ToJsonOptions {\n /**\n * Include sheet names as keys.\n * Default: true\n */\n includeSheetNames?: boolean\n\n /**\n * Include cell addresses in output.\n * Default: false\n */\n includeCellAddresses?: boolean\n\n /**\n * Convert dates to ISO strings.\n * Default: true\n */\n dateAsIsoString?: boolean\n\n /**\n * Include empty cells.\n * Default: false\n */\n includeEmpty?: boolean\n\n /**\n * Use first row as headers for object conversion.\n * Default: false\n */\n firstRowAsHeaders?: boolean\n}\n\n/**\n * Convert a cell value to a JSON-compatible value.\n */\nexport function cellValueToJson(\n value: CellValue,\n options?: ToJsonOptions\n): JsonValue {\n if (value === null || value === undefined) {\n return null\n }\n if (value instanceof Date) {\n if (options?.dateAsIsoString !== false) {\n return value.toISOString()\n }\n return value.getTime()\n }\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return value\n }\n return null\n}\n\n/**\n * Convert a cell to a JSON representation.\n */\nexport function cellToJson(\n cell: XlsxCell,\n options?: ToJsonOptions\n): JsonValue {\n const val = cell.value()\n const value = val.ok ? cellValueToJson(val.value, options) : null\n\n if (options?.includeCellAddresses) {\n return {\n address: cell.address,\n value,\n }\n }\n return value\n}\n\n/**\n * Convert a range to a JSON representation.\n */\nexport function rangeToJson(\n range: XlsxRange,\n options?: ToJsonOptions\n): JsonValue {\n if (options?.firstRowAsHeaders) {\n return rangeToObjects(range, options)\n }\n return rangeToArray(range, options)\n}\n\n/**\n * Convert a range to a 2D array.\n */\nexport function rangeToArray(\n range: XlsxRange,\n options?: ToJsonOptions\n): JsonValue[][] {\n const result: JsonValue[][] = []\n for (const rowCells of range.rows()) {\n const row: JsonValue[] = []\n for (const cell of rowCells) {\n const value = cellToJson(cell, options)\n if (value !== null || options?.includeEmpty) {\n row.push(value)\n } else if (row.length > 0 || options?.includeEmpty) {\n // Keep nulls for consistent column count\n row.push(null)\n }\n }\n if (row.length > 0 || options?.includeEmpty) {\n result.push(row)\n }\n }\n return result\n}\n\n/**\n * Convert a range to an array of objects using the first row as headers.\n */\nexport function rangeToObjects(\n range: XlsxRange,\n options?: ToJsonOptions\n): JsonValue {\n const rows = [...range.rows()]\n if (rows.length === 0) return []\n\n // Get headers from first row\n const headerRow = rows[0]\n const headers: string[] = headerRow.map(cell => {\n const val = cell.value()\n if (val.ok && val.value !== null) {\n return String(val.value)\n }\n return `col_${cell.col}`\n })\n\n // Convert data rows to objects\n const result: JsonValue[] = []\n for (let i = 1; i < rows.length; i++) {\n const row = rows[i]\n const obj: { [key: string]: JsonValue } = {}\n let hasData = false\n\n for (let j = 0; j < headers.length; j++) {\n const header = headers[j]\n const cell = row[j]\n if (cell) {\n const value = cellToJson(cell, options)\n if (value !== null) {\n hasData = true\n }\n obj[header] = value\n } else {\n obj[header] = null\n }\n }\n\n if (hasData || options?.includeEmpty) {\n result.push(obj)\n }\n }\n\n return result\n}\n\n/**\n * Convert a sheet to a JSON representation.\n */\nexport function sheetToJson(\n sheet: XlsxSheet,\n options?: ToJsonOptions\n): JsonValue {\n const rangeResult = sheet.usedRange()\n if (!rangeResult.ok) {\n return options?.firstRowAsHeaders ? [] : [[]]\n }\n return rangeToJson(rangeResult.value, options)\n}\n\n/**\n * Convert a workbook to a JSON representation.\n */\nexport function workbookToJson(\n workbook: XlsxWorkbook,\n options?: ToJsonOptions\n): JsonValue {\n const sheets = workbook.sheets()\n\n if (options?.includeSheetNames !== false) {\n const result: { [key: string]: JsonValue } = {}\n for (const sheet of sheets) {\n result[sheet.name] = sheetToJson(sheet, options)\n }\n return result\n }\n\n // Just return array of sheet data\n return sheets.map(sheet => sheetToJson(sheet, options))\n}\n\n/**\n * Convert a range to CSV format.\n */\nexport function rangeToCsv(\n range: XlsxRange,\n options?: {\n delimiter?: string\n lineEnding?: string\n quoteStrings?: boolean\n }\n): string {\n const delimiter = options?.delimiter ?? ','\n const lineEnding = options?.lineEnding ?? '\\n'\n const quoteStrings = options?.quoteStrings ?? true\n\n const lines: string[] = []\n\n for (const rowCells of range.rows()) {\n const values: string[] = []\n for (const cell of rowCells) {\n const val = cell.value()\n let str: string\n\n if (!val.ok || val.value === null) {\n str = ''\n } else if (val.value instanceof Date) {\n str = val.value.toISOString()\n } else {\n str = String(val.value)\n }\n\n // Quote if contains delimiter, newline, or quotes\n if (quoteStrings && (\n str.includes(delimiter) ||\n str.includes('\\n') ||\n str.includes('\\r') ||\n str.includes('\"')\n )) {\n str = '\"' + str.replace(/\"/g, '\"\"') + '\"'\n }\n\n values.push(str)\n }\n lines.push(values.join(delimiter))\n }\n\n return lines.join(lineEnding)\n}\n\n/**\n * Convert a sheet to CSV format.\n */\nexport function sheetToCsv(\n sheet: XlsxSheet,\n options?: {\n delimiter?: string\n lineEnding?: string\n quoteStrings?: boolean\n }\n): string {\n const rangeResult = sheet.usedRange()\n if (!rangeResult.ok) {\n return ''\n }\n return rangeToCsv(rangeResult.value, options)\n}\n","/**\n * @origints/xlsx - XLSX parsing for Origins with full traceability.\n *\n * This package provides a rich API for parsing and navigating XLSX files\n * with complete traceability to sheets, ranges, and cells.\n *\n * @packageDocumentation\n */\n\n// Re-export result types\nexport type {\n ExcelLocation,\n XlsxPath,\n XlsxFailure,\n XlsxFailureKind,\n XlsxResult,\n CellValue,\n ExtendedCellValue,\n} from './xlsx-result'\nexport {\n ok,\n fail,\n formatXlsxPath,\n toExcelLocation,\n isFormula,\n isError,\n} from './xlsx-result'\n\n// Re-export cell\nexport type { CellStyle, RichTextSegment, RichTextContent } from './xlsx-cell'\nexport { XlsxCell } from './xlsx-cell'\n\n// Re-export range\nexport { XlsxRange } from './xlsx-range'\n\n// Re-export sheet\nexport type { SheetDimensions } from './xlsx-sheet'\nexport { XlsxSheet } from './xlsx-sheet'\n\n// Re-export workbook\nexport type { SheetPredicate, WorkbookProperties } from './xlsx-workbook'\nexport { XlsxWorkbook } from './xlsx-workbook'\n\n// Re-export cursor\nexport type {\n CursorDirection,\n GrabResult,\n GrabOneResult,\n} from './xlsx-cursor'\nexport { XlsxCursor } from './xlsx-cursor'\n\n// Re-export query predicates\nexport type { CellPredicate, Predicates } from './xlsx-query'\nexport { predicates } from './xlsx-query'\n\n// Re-export parse functions and implementations\nexport type { XlsxParseOptions, TransformAst, TransformImpl } from './parse'\nexport {\n parseXlsx,\n parseXlsxImpl,\n parseXlsxAsyncImpl,\n parseXlsxBuffer,\n parseXlsxFile,\n} from './parse'\n\n// Re-export conversion utilities\nexport type { JsonValue, ToJsonOptions } from './convert'\nexport {\n cellValueToJson,\n cellToJson,\n rangeToJson,\n rangeToArray,\n rangeToObjects,\n sheetToJson,\n workbookToJson,\n rangeToCsv,\n sheetToCsv,\n} from './convert'\n\n// Re-export utilities\nexport {\n streamToBuffer,\n columnLetterToNumber,\n columnNumberToLetter,\n parseAddress,\n formatAddress,\n parseRange,\n formatRange,\n isInRange,\n} from './util'\n\n// ---------------------------------------------------------------------------\n// Auto-registration of transforms\n// ---------------------------------------------------------------------------\n\nimport { parseXlsxAsyncImpl } from './parse'\n\n/**\n * Register the XLSX transforms with a registry.\n * Call this to enable parseXlsx() in your plans.\n *\n * @example\n * ```ts\n * import { globalRegistry } from '@origints/core'\n * import { registerXlsxTransforms } from '@origints/xlsx'\n *\n * registerXlsxTransforms(globalRegistry)\n * ```\n */\nexport function registerXlsxTransforms(registry: {\n register(impl: {\n namespace: string\n name: string\n execute: (...args: unknown[]) => unknown\n }): void\n}): void {\n registry.register(parseXlsxAsyncImpl)\n}\n"],"names":["ok","value","path","fail","kind","message","sourceLocation","formatXlsxPath","parts","toExcelLocation","isFormula","isError","streamToBuffer","stream","reader","chunks","done","columnLetterToNumber","col","result","i","columnNumberToLetter","num","remainder","parseAddress","address","match","colLetter","formatAddress","row","parseRange","range","addr","start","end","formatRange","startRow","startCol","endRow","endCol","isInRange","XlsxCell","cell","_path","_sheetName","sheetName","file","val","typeOf","date","rawVal","hyperlink","segments","segment","linkVal","style","plainValue","text","rtResult","font","fill","border","alignment","link","note","t","rowDelta","colDelta","getCell","newRow","newCol","formulaVal","sharedVal","excelDate","offset","days","excelEpoch","XlsxRange","worksheet","_startRow","_startCol","_endRow","_endCol","_file","rangeAddr","rowOffset","colOffset","rowCells","colCells","rowValues","predicate","results","cellVal","count","headerRowOffset","dataStartOffset","allRows","headerRow","headers","obj","j","header","XlsxCursor","sheet","_row","_col","_direction","colNum","direction","cursor","dims","maxIterations","cellResult","cells","XlsxSheet","rowNum","colId","r","c","startAddress","rangeResult","rangeAddress","rowCount","columnCount","parsed","merges","XlsxWorkbook","workbook","name","cached","index","sheets","names","pattern","fn","predicates","caseSensitive","prefix","suffix","n","min","max","time","preds","pred","parseXlsx","options","parseXlsxImpl","input","args","toArrayBuffer","parseXlsxAsyncImpl","data","buffer","ExcelJS","parseXlsxBuffer","parseXlsxFile","filePath","cellValueToJson","cellToJson","rangeToJson","rangeToObjects","rangeToArray","rows","hasData","sheetToJson","workbookToJson","rangeToCsv","delimiter","lineEnding","quoteStrings","lines","values","str","sheetToCsv","registerXlsxTransforms","registry"],"mappings":"2GAgEO,SAASA,EAAMC,EAAUC,EAA+B,CAC7D,MAAO,CAAE,GAAI,GAAM,MAAAD,EAAO,KAAAC,CAAA,CAC5B,CAKO,SAASC,EACdC,EACAC,EACAH,EACAI,EACmB,CACnB,MAAO,CACL,GAAI,GACJ,QAAS,CAAE,KAAAF,EAAM,QAAAC,EAAS,KAAAH,EAAM,eAAAI,CAAA,CAAe,CAEnD,CAKO,SAASC,EAAeL,EAAwB,CACrD,MAAMM,EAAkB,CAAA,EACxB,OAAIN,EAAK,MAAMM,EAAM,KAAKN,EAAK,IAAI,EAC/BA,EAAK,OAAOM,EAAM,KAAK,IAAIN,EAAK,KAAK,GAAG,EACxCA,EAAK,MAAOM,EAAM,KAAK,IAAIN,EAAK,KAAK,EAAE,EAClCA,EAAK,MAAMM,EAAM,KAAK,IAAIN,EAAK,IAAI,EAAE,EACvCM,EAAM,KAAK,EAAE,GAAK,UAC3B,CAKO,SAASC,EACdP,EAC2B,CAC3B,GAAKA,EAAK,MACV,MAAO,CACL,KAAM,QACN,KAAMA,EAAK,MAAQ,GACnB,MAAOA,EAAK,MACZ,MAAOA,EAAK,OAASA,EAAK,MAAQ,EAAA,CAEtC,CAkBO,SAASQ,EACdT,EACkD,CAClD,OACE,OAAOA,GAAU,UACjBA,IAAU,MACV,EAAEA,aAAiB,OACnB,YAAaA,CAEjB,CAKO,SAASU,EACdV,EAC4B,CAC5B,OACE,OAAOA,GAAU,UACjBA,IAAU,MACV,EAAEA,aAAiB,OACnB,UAAWA,CAEf,CC5IA,eAAsBW,EACpBC,EACiB,CACjB,MAAMC,EAASD,EAAO,UAAA,EAChBE,EAAuB,CAAA,EAE7B,GAAI,CACF,OAAa,CACX,KAAM,CAAE,KAAAC,EAAM,MAAAf,CAAA,EAAU,MAAMa,EAAO,KAAA,EACrC,GAAIE,EAAM,MACVD,EAAO,KAAKd,CAAK,CACnB,CACA,OAAO,OAAO,OAAOc,CAAM,CAC7B,QAAA,CACED,EAAO,YAAA,CACT,CACF,CAMO,SAASG,EAAqBC,EAAqB,CACxD,IAAIC,EAAS,EACb,QAASC,EAAI,EAAGA,EAAIF,EAAI,OAAQE,IAC9BD,EAASA,EAAS,IAAMD,EAAI,WAAWE,CAAC,EAAI,IAE9C,OAAOD,CACT,CAMO,SAASE,EAAqBC,EAAqB,CACxD,IAAIH,EAAS,GACb,KAAOG,EAAM,GAAG,CACd,MAAMC,GAAaD,EAAM,GAAK,GAC9BH,EAAS,OAAO,aAAa,GAAKI,CAAS,EAAIJ,EAC/CG,EAAM,KAAK,OAAOA,EAAM,GAAK,EAAE,CACjC,CACA,OAAOH,CACT,CAMO,SAASK,EAAaC,EAI3B,CACA,MAAMC,EAAQD,EAAQ,MAAM,kBAAkB,EAC9C,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,yBAAyBD,CAAO,EAAE,EAEpD,MAAME,EAAYD,EAAM,CAAC,EAAE,YAAA,EAC3B,MAAO,CACL,IAAK,SAASA,EAAM,CAAC,EAAG,EAAE,EAC1B,IAAKT,EAAqBU,CAAS,EACnC,UAAAA,CAAA,CAEJ,CAMO,SAASC,EAAcC,EAAaX,EAAqB,CAC9D,MAAO,GAAGG,EAAqBH,CAAG,CAAC,GAAGW,CAAG,EAC3C,CAMO,SAASC,EAAWC,EAGzB,CACA,MAAMvB,EAAQuB,EAAM,MAAM,GAAG,EAC7B,GAAIvB,EAAM,SAAW,EAAG,CAEtB,MAAMwB,EAAOR,EAAahB,EAAM,CAAC,CAAC,EAClC,MAAO,CACL,MAAO,CAAE,IAAKwB,EAAK,IAAK,IAAKA,EAAK,GAAA,EAClC,IAAK,CAAE,IAAKA,EAAK,IAAK,IAAKA,EAAK,GAAA,CAAI,CAExC,CACA,GAAIxB,EAAM,SAAW,EACnB,MAAM,IAAI,MAAM,kBAAkBuB,CAAK,EAAE,EAE3C,MAAME,EAAQT,EAAahB,EAAM,CAAC,CAAC,EAC7B0B,EAAMV,EAAahB,EAAM,CAAC,CAAC,EACjC,MAAO,CACL,MAAO,CAAE,IAAKyB,EAAM,IAAK,IAAKA,EAAM,GAAA,EACpC,IAAK,CAAE,IAAKC,EAAI,IAAK,IAAKA,EAAI,GAAA,CAAI,CAEtC,CAKO,SAASC,EACdC,EACAC,EACAC,EACAC,EACQ,CACR,MAAMN,EAAQL,EAAcQ,EAAUC,CAAQ,EACxCH,EAAMN,EAAcU,EAAQC,CAAM,EACxC,OAAON,IAAUC,EAAMD,EAAQ,GAAGA,CAAK,IAAIC,CAAG,EAChD,CAKO,SAASM,EACdX,EACAX,EACAa,EACS,CACT,OACEF,GAAOE,EAAM,MAAM,KACnBF,GAAOE,EAAM,IAAI,KACjBb,GAAOa,EAAM,MAAM,KACnBb,GAAOa,EAAM,IAAI,GAErB,CC3DO,MAAMU,CAAS,CACZ,YACWC,EACAC,EACAC,EACjB,CAHiB,KAAA,KAAAF,EACA,KAAA,MAAAC,EACA,KAAA,WAAAC,CAChB,CAMH,OAAO,YACLF,EACAG,EACAC,EACU,CACV,MAAM5C,EAAiB,CACrB,KAAA4C,EACA,MAAOD,EACP,KAAMH,EAAK,OAAA,EAEb,OAAO,IAAID,EAASC,EAAMxC,EAAM2C,CAAS,CAC3C,CASA,IAAI,SAAkB,CACpB,OAAO,KAAK,KAAK,OACnB,CAKA,IAAI,KAAc,CAChB,OAAO,OAAO,KAAK,KAAK,KAAQ,SAAW,KAAK,KAAK,IAAM,SAAS,OAAO,KAAK,KAAK,GAAG,EAAG,EAAE,CAC/F,CAKA,IAAI,KAAc,CAChB,OAAO,OAAO,KAAK,KAAK,KAAQ,SAAW,KAAK,KAAK,IAAM,SAAS,OAAO,KAAK,KAAK,GAAG,EAAG,EAAE,CAC/F,CAKA,IAAI,WAAoB,CACtB,OAAO,KAAK,QAAQ,QAAQ,OAAQ,EAAE,CACxC,CAKA,IAAI,MAAiB,CACnB,OAAO,KAAK,KACd,CAKA,IAAI,WAAoB,CACtB,OAAO,KAAK,UACd,CASA,OAA+B,CAC7B,MAAME,EAAM,KAAK,YAAA,EACjB,OAAIrC,EAAUqC,CAAG,EACR/C,EAAG+C,EAAI,QAAU,KAAM,KAAK,KAAK,EAEtCpC,EAAQoC,CAAG,EACN5C,EAAK,UAAW,wBAAwB4C,EAAI,KAAK,GAAI,KAAK,KAAK,EAGjE/C,EAAG+C,EAAkB,KAAK,KAAK,CACxC,CAKA,eAA+C,CAC7C,OAAO/C,EAAG,KAAK,YAAA,EAAe,KAAK,KAAK,CAC1C,CAKA,QAA6B,CAC3B,MAAM+C,EAAM,KAAK,iBAAA,EACjB,OAAIA,GAAQ,KACH5C,EAAK,OAAQ,4BAA6B,KAAK,KAAK,EAEzD,OAAO4C,GAAQ,SACV/C,EAAG+C,EAAK,KAAK,KAAK,EAGvB,OAAOA,GAAQ,UAAY,OAAOA,GAAQ,UACrC/C,EAAG,OAAO+C,CAAG,EAAG,KAAK,KAAK,EAE/BA,aAAe,KACV/C,EAAG+C,EAAI,YAAA,EAAe,KAAK,KAAK,EAElC5C,EAAK,OAAQ,wBAAwB,OAAO4C,CAAG,GAAI,KAAK,KAAK,CACtE,CAKA,QAA6B,CAC3B,MAAMA,EAAM,KAAK,iBAAA,EACjB,GAAI,OAAOA,GAAQ,SACjB,OAAO/C,EAAG+C,EAAK,KAAK,KAAK,EAE3B,GAAI,OAAOA,GAAQ,SAAU,CAC3B,MAAMzB,EAAM,WAAWyB,CAAG,EAC1B,GAAI,CAAC,MAAMzB,CAAG,EACZ,OAAOtB,EAAGsB,EAAK,KAAK,KAAK,CAE7B,CACA,OAAOnB,EAAK,OAAQ,wBAAwB6C,EAAOD,CAAG,CAAC,GAAI,KAAK,KAAK,CACvE,CAKA,SAA+B,CAC7B,MAAMA,EAAM,KAAK,iBAAA,EACjB,OAAI,OAAOA,GAAQ,UACV/C,EAAG+C,EAAK,KAAK,KAAK,EAEpB5C,EAAK,OAAQ,yBAAyB6C,EAAOD,CAAG,CAAC,GAAI,KAAK,KAAK,CACxE,CAKA,MAAyB,CACvB,MAAMA,EAAM,KAAK,iBAAA,EACjB,GAAIA,aAAe,KACjB,OAAO/C,EAAG+C,EAAK,KAAK,KAAK,EAE3B,GAAI,OAAOA,GAAQ,SAAU,CAE3B,MAAME,EAAO,KAAK,cAAcF,CAAG,EACnC,OAAO/C,EAAGiD,EAAM,KAAK,KAAK,CAC5B,CACA,GAAI,OAAOF,GAAQ,SAAU,CAC3B,MAAME,EAAO,IAAI,KAAKF,CAAG,EACzB,GAAI,CAAC,MAAME,EAAK,QAAA,CAAS,EACvB,OAAOjD,EAAGiD,EAAM,KAAK,KAAK,CAE9B,CACA,OAAO9C,EAAK,OAAQ,sBAAsB6C,EAAOD,CAAG,CAAC,GAAI,KAAK,KAAK,CACrE,CAKA,SAA8B,CAC5B,MAAMA,EAAM,KAAK,YAAA,EACjB,OAAIrC,EAAUqC,CAAG,EACR/C,EAAG+C,EAAI,QAAS,KAAK,KAAK,EAE5B5C,EAAK,OAAQ,kCAAmC,KAAK,KAAK,CACnE,CAUA,UAAwC,CACtC,MAAM+C,EAAS,KAAK,KAAK,MACnBC,EAAY,KAAK,KAAK,UAG5B,GAAID,GAAU,OAAOA,GAAW,UAAY,aAAcA,EAAQ,CAgBhE,MAAME,EAfKF,EAe4B,SAAS,IAAIG,IAAY,CAC9D,KAAMA,EAAQ,KACd,KAAMA,EAAQ,MAAM,KACpB,OAAQA,EAAQ,MAAM,OACtB,UAAWA,EAAQ,MAAM,YAAc,IAAQA,EAAQ,MAAM,YAAc,SAC3E,cAAeA,EAAQ,MAAM,OAC7B,MAAOA,EAAQ,MAAM,OAAO,KAC5B,KAAMA,EAAQ,MAAM,KACpB,KAAMA,EAAQ,MAAM,IAAA,EACpB,EAEF,OAAOrD,EAAG,CAAE,SAAAoD,EAAU,UAAAD,CAAA,EAAa,KAAK,KAAK,CAC/C,CAGA,GAAID,GAAU,OAAOA,GAAW,UAAY,SAAUA,GAAU,cAAeA,EAAQ,CACrF,MAAMI,EAAUJ,EACVK,EAAQ,KAAK,MAAA,EACbF,EAA2B,CAC/B,KAAMC,EAAQ,KACd,KAAMC,EAAM,MAAM,KAClB,OAAQA,EAAM,MAAM,OACpB,UAAWA,EAAM,MAAM,UACvB,cAAeA,EAAM,MAAM,cAC3B,MAAOA,EAAM,MAAM,MACnB,KAAMA,EAAM,MAAM,KAClB,KAAMA,EAAM,MAAM,IAAA,EAEpB,OAAOvD,EACL,CACE,SAAU,CAACqD,CAAO,EAClB,UAAWC,EAAQ,SAAA,EAErB,KAAK,KAAA,CAET,CAGA,MAAME,EAAa,KAAK,iBAAA,EAClBC,EAAOD,IAAe,KAAO,OAAOA,CAAU,EAAI,GAClDD,EAAQ,KAAK,MAAA,EAEbF,EAA2B,CAC/B,KAAAI,EACA,KAAMF,EAAM,MAAM,KAClB,OAAQA,EAAM,MAAM,OACpB,UAAWA,EAAM,MAAM,UACvB,cAAeA,EAAM,MAAM,cAC3B,MAAOA,EAAM,MAAM,MACnB,KAAMA,EAAM,MAAM,KAClB,KAAMA,EAAM,MAAM,IAAA,EAGpB,OAAOvD,EAAG,CAAE,SAAU,CAACqD,CAAO,EAAG,UAAAF,CAAA,EAAa,KAAK,KAAK,CAC1D,CAYA,UAA+B,CAC7B,MAAMO,EAAW,KAAK,SAAA,EACtB,GAAI,CAACA,EAAS,GACZ,OAAOA,EAGT,KAAM,CAAE,SAAAN,EAAU,UAAAD,CAAA,EAAcO,EAAS,MACzC,IAAIvC,EAAS,GAEb,UAAWkC,KAAWD,EAAU,CAC9B,IAAIK,EAAOJ,EAAQ,KAGfA,EAAQ,gBACVI,EAAO,KAAKA,CAAI,MAEdJ,EAAQ,OACVI,EAAO,KAAKA,CAAI,MAEdJ,EAAQ,SACVI,EAAO,IAAIA,CAAI,KAGjBtC,GAAUsC,CACZ,CAGA,OAAIN,IACFhC,EAAS,IAAIA,CAAM,KAAKgC,CAAS,KAG5BnD,EAAGmB,EAAQ,KAAK,KAAK,CAC9B,CAKA,YAAsB,CACpB,MAAM+B,EAAS,KAAK,KAAK,MACzB,OAAOA,IAAW,MAAQ,OAAOA,GAAW,UAAY,aAAcA,CACxE,CASA,SAAmB,CACjB,MAAMH,EAAM,KAAK,KAAK,MACtB,OAAOA,GAAQ,MAA6BA,IAAQ,EACtD,CAKA,WAAqB,CACnB,OAAOrC,EAAU,KAAK,aAAa,CACrC,CAKA,UAAoB,CAClB,OAAO,KAAK,KAAK,QACnB,CAKA,gBAA0B,CACxB,OAAK,KAAK,KAAK,SACA,KAAK,KAAK,OACX,UAAY,KAAK,KAAK,QAFJ,EAGlC,CAKA,UAAoB,CAClB,OAAO,OAAO,KAAK,iBAAA,GAAuB,QAC5C,CAKA,UAAoB,CAClB,OAAO,OAAO,KAAK,iBAAA,GAAuB,QAC5C,CAKA,WAAqB,CACnB,OAAO,OAAO,KAAK,iBAAA,GAAuB,SAC5C,CAKA,QAAkB,CAEhB,OADY,KAAK,iBAAA,YACK,IACxB,CAKA,SAAmB,CACjB,OAAOC,EAAQ,KAAK,aAAa,CACnC,CASA,OAAmB,CACjB,MAAMgD,EAAO,KAAK,KAAK,KACjBC,EAAO,KAAK,KAAK,KACjBC,EAAS,KAAK,KAAK,OACnBC,EAAY,KAAK,KAAK,UAE5B,MAAO,CACL,KAAMH,EACF,CACE,KAAMA,EAAK,KACX,KAAMA,EAAK,KACX,KAAMA,EAAK,KACX,OAAQA,EAAK,OACb,UAAWA,EAAK,YAAc,IAAQA,EAAK,YAAc,SACzD,cAAeA,EAAK,OACpB,MACEA,EAAK,OAAO,OACXA,EAAK,OAAO,QAAU,OACnB,SAASA,EAAK,MAAM,KAAK,GACzB,OAAA,EAER,OACJ,KACEC,GAAQA,EAAK,OAAS,UAClB,CACE,KAAOA,EAA8B,QACrC,MAAQA,EAAyC,SAAS,IAAA,EAE5D,OACN,OAAQC,EACJ,CACE,IAAK,CAAC,CAACA,EAAO,IACd,OAAQ,CAAC,CAACA,EAAO,OACjB,KAAM,CAAC,CAACA,EAAO,KACf,MAAO,CAAC,CAACA,EAAO,KAAA,EAElB,OACJ,UAAWC,EACP,CACE,WAAYA,EAAU,WACtB,SAAUA,EAAU,SACpB,SAAUA,EAAU,QAAA,EAEtB,OACJ,OAAQ,KAAK,KAAK,MAAA,CAEtB,CAKA,WAAgC,CAC9B,MAAMC,EAAO,KAAK,KAAK,UACvB,OAAKA,EAGE/D,EAAG+D,EAAM,KAAK,KAAK,EAFjB5D,EAAK,UAAW,oCAAqC,KAAK,KAAK,CAG1E,CAKA,SAA8B,CAC5B,MAAM6D,EAAO,KAAK,KAAK,KACvB,OAAKA,EAGD,OAAOA,GAAS,SACXhE,EAAGgE,EAAM,KAAK,KAAK,EAGxBA,EAAK,MACAhE,EACLgE,EAAK,MAAM,IAAKC,GAAwBA,EAAE,IAAI,EAAE,KAAK,EAAE,EACvD,KAAK,KAAA,EAGF9D,EAAK,SAAU,iCAAkC,KAAK,KAAK,EAZzDA,EAAK,UAAW,kCAAmC,KAAK,KAAK,CAaxE,CAUA,cACE+D,EACAC,EACAC,EACsB,CACtB,MAAMC,EAAS,KAAK,IAAMH,EACpBI,EAAS,KAAK,IAAMH,EAC1B,GAAIE,EAAS,GAAKC,EAAS,EACzB,OAAOnE,EACL,SACA,gBAAgB+D,CAAQ,KAAKC,CAAQ,UAAU,KAAK,OAAO,oBAC3D,KAAK,KAAA,EAGT,MAAMzB,EAAO0B,EAAQC,EAAQC,CAAM,EACnC,OAAK5B,EAOE1C,EAAG0C,EAAMA,EAAK,IAAI,EANhBvC,EACL,UACA,WAAWyB,EAAcyC,EAAQC,CAAM,CAAC,aACxC,KAAK,KAAA,CAIX,CASQ,aAAiC,CACvC,MAAMvB,EAAM,KAAK,KAAK,MACtB,GAAIA,GAAQ,KACV,OAAO,KAIT,GAAI,OAAOA,GAAQ,SAAU,CAE3B,GAAI,UAAWA,EACb,MAAO,CAAE,MAAO,OAAQA,EAA2B,KAAK,CAAA,EAG1D,GAAI,YAAaA,EAAK,CACpB,MAAMwB,EAAaxB,EAInB,MAAO,CACL,QAASwB,EAAW,QACpB,OAAQ,KAAK,gBAAgBA,EAAW,MAAM,CAAA,CAElD,CAEA,GAAI,kBAAmBxB,EAAK,CAC1B,MAAMyB,EAAYzB,EAIlB,MAAO,CACL,QAASyB,EAAU,cACnB,OAAQ,KAAK,gBAAgBA,EAAU,MAAM,CAAA,CAEjD,CAEA,GAAI,aAAczB,EAIhB,OAHiBA,EAGD,SAAS,IAAI,GAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAGnD,GAAIA,aAAe,KACjB,OAAOA,CAEX,CAGA,OACE,OAAOA,GAAQ,UACf,OAAOA,GAAQ,UACf,OAAOA,GAAQ,UAERA,EAGF,IACT,CAKQ,kBAA8B,CACpC,MAAMA,EAAM,KAAK,YAAA,EACjB,OAAIrC,EAAUqC,CAAG,EACRA,EAAI,QAAU,KAEnBpC,EAAQoC,CAAG,EACN,KAGFA,CACT,CAKQ,gBAAgB5B,EAA4B,CAClD,OAAIA,GAAW,KAAqC,KAElD,OAAOA,GAAW,UAClB,OAAOA,GAAW,UAClB,OAAOA,GAAW,WAIhBA,aAAkB,KACbA,EAEF,IACT,CAMQ,cAAcsD,EAAyB,CAG7C,MAAMC,EAASD,EAAY,GAAK,GAAK,EAC/BE,EAAOF,EAAYC,EAAS,EAG5BE,EAAa,IAAI,KAAK,KAAM,EAAG,CAAC,EAGtC,OAFe,IAAI,KAAKA,EAAW,QAAA,EAAYD,EAAO,GAAK,GAAK,GAAK,GAAI,CAG3E,CACF,CAKA,SAAS3B,EAAO/C,EAAwB,CACtC,OAAIA,IAAU,KAAa,OACvBA,IAAU,OAAkB,YAC5BA,aAAiB,KAAa,OAC9B,MAAM,QAAQA,CAAK,EAAU,QAC1B,OAAOA,CAChB,CC9qBO,MAAM4E,CAAU,CACb,YACWC,EACAC,EACAC,EACAC,EACAC,EACAvC,EACAC,EACAuC,EACjB,CARiB,KAAA,UAAAL,EACA,KAAA,UAAAC,EACA,KAAA,UAAAC,EACA,KAAA,QAAAC,EACA,KAAA,QAAAC,EACA,KAAA,MAAAvC,EACA,KAAA,WAAAC,EACA,KAAA,MAAAuC,CAChB,CAMH,OAAO,WACLL,EACA1C,EACAC,EACAC,EACAC,EACAM,EACAC,EACW,CACX,MAAMsC,EAAYjD,EAAYC,EAAUC,EAAUC,EAAQC,CAAM,EAC1DrC,EAAiB,CACrB,KAAA4C,EACA,MAAOD,EACP,MAAOuC,CAAA,EAET,OAAO,IAAIP,EACTC,EACA1C,EACAC,EACAC,EACAC,EACArC,EACA2C,EACAC,CAAA,CAEJ,CAMA,OAAO,YACLgC,EACArD,EACAoB,EACAC,EACuB,CACvB,GAAI,CACF,KAAM,CAAE,MAAAb,EAAO,IAAAC,GAAQJ,EAAWL,CAAO,EACzC,OAAOzB,EACL6E,EAAU,WACRC,EACA7C,EAAM,IACNA,EAAM,IACNC,EAAI,IACJA,EAAI,IACJW,EACAC,CAAA,EAEF,CAAE,KAAAA,EAAM,MAAOD,EAAW,MAAOpB,CAAA,CAAQ,CAE7C,MAAQ,CACN,OAAOtB,EACL,QACA,0BAA0BsB,CAAO,GACjC,CAAE,KAAAqB,EAAM,MAAOD,CAAA,CAAU,CAE7B,CACF,CASA,IAAI,SAAkB,CACpB,OAAOV,EACL,KAAK,UACL,KAAK,UACL,KAAK,QACL,KAAK,OAAA,CAET,CAKA,IAAI,UAAmB,CACrB,OAAO,KAAK,SACd,CAKA,IAAI,UAAmB,CACrB,OAAO,KAAK,SACd,CAKA,IAAI,QAAiB,CACnB,OAAO,KAAK,OACd,CAKA,IAAI,QAAiB,CACnB,OAAO,KAAK,OACd,CAKA,IAAI,MAAiB,CACnB,OAAO,KAAK,KACd,CAKA,IAAI,UAAmB,CACrB,OAAO,KAAK,QAAU,KAAK,UAAY,CACzC,CAKA,IAAI,UAAmB,CACrB,OAAO,KAAK,QAAU,KAAK,UAAY,CACzC,CAKA,IAAI,WAAoB,CACtB,OAAO,KAAK,SAAW,KAAK,QAC9B,CAUA,OAAOkD,EAAmBC,EAAyC,CACjE,MAAMzD,EAAM,KAAK,UAAYwD,EACvBnE,EAAM,KAAK,UAAYoE,EAC7B,GACEzD,EAAM,KAAK,WACXA,EAAM,KAAK,SACXX,EAAM,KAAK,WACXA,EAAM,KAAK,QAEX,OAAOf,EACL,SACA,WAAWkF,CAAS,KAAKC,CAAS,sBAAsB,KAAK,OAAO,GACpE,KAAK,KAAA,EAGT,MAAM5C,EAAO,KAAK,UAAU,QAAQb,EAAKX,CAAG,EAC5C,OAAOlB,EAAGyC,EAAS,YAAYC,EAAM,KAAK,WAAY,KAAK,KAAK,EAAG,CACjE,GAAG,KAAK,MACR,KAAMA,EAAK,QACX,MAAO,MAAA,CACR,CACH,CAKA,KAAKjB,EAAuC,CAC1C,GAAI,CACF,KAAM,CAAE,MAAAQ,CAAA,EAAUH,EAAWL,CAAO,EACpC,GACEQ,EAAM,IAAM,KAAK,WACjBA,EAAM,IAAM,KAAK,SACjBA,EAAM,IAAM,KAAK,WACjBA,EAAM,IAAM,KAAK,QAEjB,OAAO9B,EACL,SACA,QAAQsB,CAAO,qBAAqB,KAAK,OAAO,GAChD,KAAK,KAAA,EAGT,MAAMiB,EAAO,KAAK,UAAU,QAAQjB,CAAO,EAC3C,OAAOzB,EAAGyC,EAAS,YAAYC,EAAM,KAAK,WAAY,KAAK,KAAK,EAAG,CACjE,GAAG,KAAK,MACR,KAAMjB,EACN,MAAO,MAAA,CACR,CACH,MAAQ,CACN,OAAOtB,EAAK,QAAS,yBAAyBsB,CAAO,GAAI,KAAK,KAAK,CACrE,CACF,CASA,CAAC,OAA4B,CAC3B,QAASI,EAAM,KAAK,UAAWA,GAAO,KAAK,QAASA,IAClD,QAASX,EAAM,KAAK,UAAWA,GAAO,KAAK,QAASA,IAAO,CACzD,MAAMwB,EAAO,KAAK,UAAU,QAAQb,EAAKX,CAAG,EAC5C,MAAMuB,EAAS,YAAYC,EAAM,KAAK,WAAY,KAAK,KAAK,CAC9D,CAEJ,CAKA,CAAC,MAA6B,CAC5B,QAASb,EAAM,KAAK,UAAWA,GAAO,KAAK,QAASA,IAAO,CACzD,MAAM0D,EAAuB,CAAA,EAC7B,QAASrE,EAAM,KAAK,UAAWA,GAAO,KAAK,QAASA,IAAO,CACzD,MAAMwB,EAAO,KAAK,UAAU,QAAQb,EAAKX,CAAG,EAC5CqE,EAAS,KAAK9C,EAAS,YAAYC,EAAM,KAAK,WAAY,KAAK,KAAK,CAAC,CACvE,CACA,MAAM6C,CACR,CACF,CAKA,CAAC,MAA6B,CAC5B,QAASrE,EAAM,KAAK,UAAWA,GAAO,KAAK,QAASA,IAAO,CACzD,MAAMsE,EAAuB,CAAA,EAC7B,QAAS3D,EAAM,KAAK,UAAWA,GAAO,KAAK,QAASA,IAAO,CACzD,MAAMa,EAAO,KAAK,UAAU,QAAQb,EAAKX,CAAG,EAC5CsE,EAAS,KAAK/C,EAAS,YAAYC,EAAM,KAAK,WAAY,KAAK,KAAK,CAAC,CACvE,CACA,MAAM8C,CACR,CACF,CAKA,QAAwB,CACtB,MAAMrE,EAAwB,CAAA,EAC9B,UAAWoE,KAAY,KAAK,OAAQ,CAClC,MAAME,EAAyB,CAAA,EAC/B,UAAW/C,KAAQ6C,EAAU,CAC3B,MAAMxC,EAAML,EAAK,MAAA,EACjB+C,EAAU,KAAK1C,EAAI,GAAKA,EAAI,MAAQ,IAAI,CAC1C,CACA5B,EAAO,KAAKsE,CAAS,CACvB,CACA,OAAOtE,CACT,CAKA,YAAyB,CACvB,MAAO,CAAC,GAAG,KAAK,OAAO,CACzB,CASA,SAASM,EAAwC,CAC/C,GAAI,CACF,KAAM,CAAE,MAAAQ,EAAO,IAAAC,GAAQJ,EAAWL,CAAO,EACzC,OACEQ,EAAM,IAAM,KAAK,WACjBC,EAAI,IAAM,KAAK,SACfD,EAAM,IAAM,KAAK,WACjBC,EAAI,IAAM,KAAK,QAER/B,EACL,SACA,YAAYsB,CAAO,0BAA0B,KAAK,OAAO,GACzD,KAAK,KAAA,EAGFzB,EACL6E,EAAU,WACR,KAAK,UACL5C,EAAM,IACNA,EAAM,IACNC,EAAI,IACJA,EAAI,IACJ,KAAK,WACL,KAAK,KAAA,EAEP,CAAE,GAAG,KAAK,MAAO,MAAOT,CAAA,CAAQ,CAEpC,MAAQ,CACN,OAAOtB,EAAK,QAAS,0BAA0BsB,CAAO,GAAI,KAAK,KAAK,CACtE,CACF,CAKA,UAAsB,CACpB,OAAOoD,EAAU,WACf,KAAK,UACL,KAAK,UACL,KAAK,UACL,KAAK,UACL,KAAK,QACL,KAAK,WACL,KAAK,KAAA,CAET,CAKA,SAAqB,CACnB,OAAOA,EAAU,WACf,KAAK,UACL,KAAK,QACL,KAAK,UACL,KAAK,QACL,KAAK,QACL,KAAK,WACL,KAAK,KAAA,CAET,CAKA,UAAsB,CACpB,OAAOA,EAAU,WACf,KAAK,UACL,KAAK,UACL,KAAK,UACL,KAAK,QACL,KAAK,UACL,KAAK,WACL,KAAK,KAAA,CAET,CAKA,SAAqB,CACnB,OAAOA,EAAU,WACf,KAAK,UACL,KAAK,UACL,KAAK,QACL,KAAK,QACL,KAAK,QACL,KAAK,WACL,KAAK,KAAA,CAET,CAKA,MAAMH,EAAuC,CAC3C,MAAM7C,EAAM,KAAK,UAAY6C,EAC7B,OAAI7C,EAAM,KAAK,WAAaA,EAAM,KAAK,QAC9B1B,EACL,SACA,cAAcuE,CAAM,qBAAqB,KAAK,OAAO,GACrD,KAAK,KAAA,EAGF1E,EACL6E,EAAU,WACR,KAAK,UACLhD,EACA,KAAK,UACLA,EACA,KAAK,QACL,KAAK,WACL,KAAK,KAAA,EAEP,KAAK,KAAA,CAET,CAKA,MAAM6C,EAAuC,CAC3C,MAAMxD,EAAM,KAAK,UAAYwD,EAC7B,OAAIxD,EAAM,KAAK,WAAaA,EAAM,KAAK,QAC9Bf,EACL,SACA,iBAAiBuE,CAAM,qBAAqB,KAAK,OAAO,GACxD,KAAK,KAAA,EAGF1E,EACL6E,EAAU,WACR,KAAK,UACL,KAAK,UACL3D,EACA,KAAK,QACLA,EACA,KAAK,WACL,KAAK,KAAA,EAEP,KAAK,KAAA,CAET,CASA,KAAKwE,EAAgD,CACnD,UAAWhD,KAAQ,KAAK,QACtB,GAAIgD,EAAUhD,CAAI,EAChB,OAAO1C,EAAG0C,EAAMA,EAAK,IAAI,EAG7B,OAAOvC,EACL,UACA,6CAA6C,KAAK,OAAO,GACzD,KAAK,KAAA,CAET,CAKA,QAAQuF,EAAsC,CAC5C,MAAMC,EAAsB,CAAA,EAC5B,UAAWjD,KAAQ,KAAK,QAClBgD,EAAUhD,CAAI,GAChBiD,EAAQ,KAAKjD,CAAI,EAGrB,OAAOiD,CACT,CAKA,UAAU1F,EAAwC,CAChD,UAAWyC,KAAQ,KAAK,QAAS,CAC/B,MAAMkD,EAAUlD,EAAK,MAAA,EACrB,GAAIkD,EAAQ,IAAMA,EAAQ,QAAU3F,EAClC,OAAOD,EAAG0C,EAAMA,EAAK,IAAI,CAE7B,CACA,OAAOvC,EACL,UACA,UAAUF,CAAK,wBAAwB,KAAK,OAAO,GACnD,KAAK,KAAA,CAET,CAKA,KAAKyF,EAAmC,CACtC,UAAWhD,KAAQ,KAAK,QACtB,GAAIgD,EAAUhD,CAAI,EAChB,MAAO,GAGX,MAAO,EACT,CAKA,MAAMgD,EAAmC,CACvC,UAAWhD,KAAQ,KAAK,QACtB,GAAI,CAACgD,EAAUhD,CAAI,EACjB,MAAO,GAGX,MAAO,EACT,CAKA,MAAMgD,EAAkC,CACtC,IAAIG,EAAQ,EACZ,UAAWnD,KAAQ,KAAK,QAClBgD,EAAUhD,CAAI,GAChBmD,IAGJ,OAAOA,CACT,CASA,SAAyB,CACvB,OAAO,KAAK,OAAA,CACd,CAOA,UACEC,EAA0B,EAC1BC,EAA0B,EACG,CAC7B,MAAMC,EAAU,CAAC,GAAG,KAAK,MAAM,EAC/B,GAAIA,EAAQ,SAAW,EAAG,MAAO,CAAA,EAGjC,MAAMC,EAAYD,EAAQF,CAAe,EACzC,GAAI,CAACG,EAAW,MAAO,CAAA,EAEvB,MAAMC,EAAoBD,EAAU,IAAIvD,GAAQ,CAC9C,MAAMK,EAAML,EAAK,MAAA,EACjB,OAAOK,EAAI,IAAMA,EAAI,QAAU,KAAO,OAAOA,EAAI,KAAK,EAAI,EAC5D,CAAC,EAGK5B,EAAsC,CAAA,EAC5C,QAASC,EAAI2E,EAAiB3E,EAAI4E,EAAQ,OAAQ5E,IAAK,CACrD,MAAMS,EAAMmE,EAAQ5E,CAAC,EACf+E,EAAiC,CAAA,EACvC,QAASC,EAAI,EAAGA,EAAIF,EAAQ,OAAQE,IAAK,CACvC,MAAMC,EAASH,EAAQE,CAAC,EACxB,GAAIC,EAAQ,CAEV,MAAMtD,EADOlB,EAAIuE,CAAC,GACA,MAAA,EAClBD,EAAIE,CAAM,EAAItD,GAAK,GAAKA,EAAI,MAAQ,IACtC,CACF,CACA5B,EAAO,KAAKgF,CAAG,CACjB,CACA,OAAOhF,CACT,CAKA,QAGE,CACA,MAAO,CACL,QAAS,KAAK,QACd,KAAM,KAAK,OAAA,CAAO,CAEtB,CACF,CCriBO,MAAMmF,CAAW,CACd,YACWC,EACAC,EACAC,EACAC,EAA8B,QAC/C,CAJiB,KAAA,MAAAH,EACA,KAAA,KAAAC,EACA,KAAA,KAAAC,EACA,KAAA,WAAAC,CAChB,CAMH,OAAO,OAAOH,EAAkB9E,EAA6B,CAC3D,KAAM,CAAE,IAAAI,EAAK,IAAAX,GAAQM,EAAaC,CAAO,EACzC,OAAO,IAAI6E,EAAWC,EAAO1E,EAAKX,CAAG,CACvC,CAMA,OAAO,SAASqF,EAAkB1E,EAAaX,EAAyB,CACtE,OAAO,IAAIoF,EAAWC,EAAO,KAAK,IAAI,EAAG1E,CAAG,EAAG,KAAK,IAAI,EAAGX,CAAG,CAAC,CACjE,CASA,IAAI,KAAc,CAChB,OAAO,KAAK,IACd,CAKA,IAAI,KAAc,CAChB,OAAO,KAAK,IACd,CAKA,IAAI,SAAkB,CACpB,OAAOU,EAAc,KAAK,KAAM,KAAK,IAAI,CAC3C,CAKA,IAAI,WAAoB,CACtB,OAAOP,EAAqB,KAAK,IAAI,CACvC,CAKA,IAAI,WAA6B,CAC/B,OAAO,KAAK,UACd,CAKA,IAAI,MAAiB,CACnB,MAAO,CACL,GAAG,KAAK,MAAM,KACd,KAAM,KAAK,OAAA,CAEf,CASA,KAAK6C,EAAkBC,EAA8B,CACnD,OAAO,IAAImC,EACT,KAAK,MACL,KAAK,IAAI,EAAG,KAAK,KAAOpC,CAAQ,EAChC,KAAK,IAAI,EAAG,KAAK,KAAOC,CAAQ,EAChC,KAAK,UAAA,CAET,CAKA,OAAO1C,EAA6B,CAClC,KAAM,CAAE,IAAAI,EAAK,IAAAX,GAAQM,EAAaC,CAAO,EACzC,OAAO,IAAI6E,EAAW,KAAK,MAAOzE,EAAKX,EAAK,KAAK,UAAU,CAC7D,CAKA,UAAUW,EAAyB,CACjC,OAAO,IAAIyE,EAAW,KAAK,MAAO,KAAK,IAAI,EAAGzE,CAAG,EAAG,KAAK,KAAM,KAAK,UAAU,CAChF,CAKA,UAAUX,EAAkC,CAC1C,MAAMyF,EACJ,OAAOzF,GAAQ,SAAWD,EAAqBC,EAAI,YAAA,CAAa,EAAIA,EACtE,OAAO,IAAIoF,EAAW,KAAK,MAAO,KAAK,KAAM,KAAK,IAAI,EAAGK,CAAM,EAAG,KAAK,UAAU,CACnF,CAKA,KAAKd,EAAgB,EAAe,CAClC,OAAO,IAAIS,EACT,KAAK,MACL,KAAK,KACL,KAAK,IAAI,EAAG,KAAK,KAAOT,CAAK,EAC7B,MAAA,CAEJ,CAKA,MAAMA,EAAgB,EAAe,CACnC,OAAO,IAAIS,EAAW,KAAK,MAAO,KAAK,KAAM,KAAK,KAAOT,EAAO,OAAO,CACzE,CAKA,GAAGA,EAAgB,EAAe,CAChC,OAAO,IAAIS,EACT,KAAK,MACL,KAAK,IAAI,EAAG,KAAK,KAAOT,CAAK,EAC7B,KAAK,KACL,IAAA,CAEJ,CAKA,KAAKA,EAAgB,EAAe,CAClC,OAAO,IAAIS,EAAW,KAAK,MAAO,KAAK,KAAOT,EAAO,KAAK,KAAM,MAAM,CACxE,CAKA,aAAae,EAAwC,CACnD,OAAO,IAAIN,EAAW,KAAK,MAAO,KAAK,KAAM,KAAK,KAAMM,CAAS,CACnE,CAKA,QAAQf,EAAgB,EAAe,CACrC,OAAQ,KAAK,WAAA,CACX,IAAK,QACH,OAAO,KAAK,MAAMA,CAAK,EACzB,IAAK,OACH,OAAO,KAAK,KAAKA,CAAK,EACxB,IAAK,OACH,OAAO,KAAK,KAAKA,CAAK,EACxB,IAAK,KACH,OAAO,KAAK,GAAGA,CAAK,CAAA,CAE1B,CAKA,YAAyB,CACvB,OAAO,IAAIS,EAAW,KAAK,MAAO,KAAK,KAAM,EAAG,KAAK,UAAU,CACjE,CAKA,YAAyB,CACvB,OAAO,IAAIA,EAAW,KAAK,MAAO,EAAG,KAAK,KAAM,KAAK,UAAU,CACjE,CASA,WAAwB,CACtB,OAAO,KAAK,UAAU5D,GAAQA,EAAK,SAAS,CAC9C,CAKA,UAAUgD,EAAsC,CAE9C,IAAImB,EAAqB,KACzB,MAAMC,EAAO,KAAK,MAAM,WAAA,EAClBC,EAAgB,KAAK,IAAID,EAAK,SAAUA,EAAK,QAAQ,EAAI,EAE/D,QAAS1F,EAAI,EAAGA,EAAI2F,EAAe3F,IAAK,CACtC,MAAM4F,EAAaH,EAAO,KAAA,EAE1B,GADI,CAACG,EAAW,IACZ,CAACtB,EAAUsB,EAAW,KAAK,EAAG,MAClCH,EAASA,EAAO,QAAA,CAClB,CACA,OAAOA,CACT,CAKA,UAAUnB,EAAsC,CAC9C,OAAO,KAAK,UAAUhD,GAAQ,CAACgD,EAAUhD,CAAI,CAAC,CAChD,CAKA,YAAYzC,EAA4B,CACtC,OAAO,KAAK,UAAUyC,GAAQ,CAC5B,MAAMK,EAAML,EAAK,MAAA,EACjB,OAAOK,EAAI,IAAMA,EAAI,QAAU9C,CACjC,CAAC,CACH,CAKA,KAAK4F,EAA2B,CAC9B,OAAO,KAAK,QAAQA,CAAK,CAC3B,CASA,MAAkC,CAChC,MAAMmB,EAAa,KAAK,KAAA,EACxB,OAAKA,EAAW,GACThH,EACL,CACE,KAAMgH,EAAW,MACjB,OAAQ,KAAK,QAAA,CAAQ,EAEvB,KAAK,IAAA,EANoBA,CAQ7B,CAKA,MAAMnB,EAAuC,CAC3C,MAAMoB,EAAoB,CAAA,EAE1B,IAAIJ,EAAqB,KAEzB,QAASzF,EAAI,EAAGA,EAAIyE,EAAOzE,IAAK,CAC9B,MAAM4F,EAAaH,EAAO,KAAA,EAC1B,GAAI,CAACG,EAAW,GAEd,MAEFC,EAAM,KAAKD,EAAW,KAAK,EAC3BH,EAASA,EAAO,QAAA,CAClB,CAEA,OAAII,EAAM,SAAW,EACZ9G,EAAK,SAAU,mBAAoB,KAAK,IAAI,EAG9CH,EAAG,CAAE,MAAAiH,EAAO,OAAAJ,CAAA,EAAU,KAAK,IAAI,CACxC,CAKA,UAAUnB,EAAkD,CAC1D,MAAMuB,EAAoB,CAAA,EAE1B,IAAIJ,EAAqB,KACzB,MAAMC,EAAO,KAAK,MAAM,WAAA,EAClBC,EAAgB,KAAK,IAAID,EAAK,SAAUA,EAAK,QAAQ,EAAI,EAE/D,QAAS1F,EAAI,EAAGA,EAAI2F,EAAe3F,IAAK,CACtC,MAAM4F,EAAaH,EAAO,KAAA,EAE1B,GADI,CAACG,EAAW,IACZ,CAACtB,EAAUsB,EAAW,KAAK,EAAG,MAClCC,EAAM,KAAKD,EAAW,KAAK,EAC3BH,EAASA,EAAO,QAAA,CAClB,CAEA,OAAO7G,EAAG,CAAE,MAAAiH,EAAO,OAAAJ,CAAA,EAAU,KAAK,IAAI,CACxC,CAKA,UAAUnB,EAAkD,CAC1D,OAAO,KAAK,UAAUhD,GAAQ,CAACgD,EAAUhD,CAAI,CAAC,CAChD,CAKA,SAAkC,CAChC,MAAMuE,EAAoB,CAAA,EACpBH,EAAO,KAAK,MAAM,WAAA,EACxB,IAAID,EAAS,KAAK,aAAa,OAAO,EAEtC,QAAS3F,EAAM,KAAK,KAAMA,GAAO4F,EAAK,OAAQ5F,IAAO,CACnD,MAAM8F,EAAaH,EAAO,KAAA,EAC1B,GAAI,CAACG,EAAW,GAAI,MACpBC,EAAM,KAAKD,EAAW,KAAK,EAC3BH,EAASA,EAAO,QAAA,CAClB,CAEA,OAAO7G,EAAG,CAAE,MAAAiH,EAAO,OAAAJ,CAAA,EAAU,KAAK,IAAI,CACxC,CAKA,SAAkC,CAChC,MAAMI,EAAoB,CAAA,EACpBH,EAAO,KAAK,MAAM,WAAA,EACxB,IAAID,EAAS,KAAK,aAAa,MAAM,EAErC,QAAShF,EAAM,KAAK,KAAMA,GAAOiF,EAAK,OAAQjF,IAAO,CACnD,MAAMmF,EAAaH,EAAO,KAAA,EAC1B,GAAI,CAACG,EAAW,GAAI,MACpBC,EAAM,KAAKD,EAAW,KAAK,EAC3BH,EAASA,EAAO,QAAA,CAClB,CAEA,OAAO7G,EAAG,CAAE,MAAAiH,EAAO,OAAAJ,CAAA,EAAU,KAAK,IAAI,CACxC,CAKA,cAAuC,CACrC,OAAO,KAAK,UAAUnE,GAAQ,CAACA,EAAK,SAAS,CAC/C,CASA,MAA6B,CAC3B,OAAO,KAAK,KAAA,CACd,CAKA,UAAUmD,EAAuC,CAC/C,MAAMoB,EAAoB,CAAA,EAE1B,IAAIJ,EAAqB,KAEzB,QAASzF,EAAI,EAAGA,EAAIyE,EAAOzE,IAAK,CAC9B,MAAM4F,EAAaH,EAAO,KAAA,EAC1B,GAAI,CAACG,EAAW,GAAI,MACpBC,EAAM,KAAKD,EAAW,KAAK,EAC3BH,EAASA,EAAO,QAAA,CAClB,CAEA,OAAO7G,EAAGiH,EAAO,KAAK,IAAI,CAC5B,CAKA,OAAO/C,EAAkBC,EAAwC,CAC/D,OAAO,KAAK,KAAKD,EAAUC,CAAQ,EAAE,KAAA,CACvC,CASA,MAA6B,CAC3B,OAAO,KAAK,MAAM,OAAO,KAAK,KAAM,KAAK,IAAI,CAC/C,CAKA,OAA6B,CAC3B,MAAM6C,EAAa,KAAK,KAAA,EACxB,OAAKA,EAAW,GACTA,EAAW,MAAM,MAAA,EADGA,CAE7B,CASA,SAAmB,CAEjB,OADmB,KAAK,KAAA,EACN,EACpB,CAKA,SAAmB,CACjB,MAAMA,EAAa,KAAK,KAAA,EACxB,OAAOA,EAAW,IAAMA,EAAW,MAAM,QAAA,CAC3C,CAKA,YAAsB,CACpB,MAAMA,EAAa,KAAK,KAAA,EACxB,OAAOA,EAAW,IAAM,CAACA,EAAW,MAAM,QAAA,CAC5C,CAKA,OAAoB,CAClB,OAAO,IAAIV,EAAW,KAAK,MAAO,KAAK,KAAM,KAAK,KAAM,KAAK,UAAU,CACzE,CACF,CCvcO,MAAMY,CAAU,CACb,YACWpC,EACAnC,EACAwC,EACjB,CAHiB,KAAA,UAAAL,EACA,KAAA,MAAAnC,EACA,KAAA,MAAAwC,CAChB,CAMH,OAAO,YAAYL,EAAsBhC,EAA0B,CACjE,MAAM5C,EAAiB,CACrB,KAAA4C,EACA,MAAOgC,EAAU,IAAA,EAEnB,OAAO,IAAIoC,EAAUpC,EAAW5E,EAAM4C,CAAI,CAC5C,CASA,IAAI,MAAe,CACjB,OAAO,KAAK,UAAU,IACxB,CAKA,IAAI,OAAgB,CAClB,OAAO,KAAK,UAAU,EACxB,CAKA,IAAI,MAAiB,CACnB,OAAO,KAAK,KACd,CASA,KAAKrB,EAAuC,CAC1C,GAAI,CACFD,EAAaC,CAAO,EACpB,MAAMiB,EAAO,KAAK,UAAU,QAAQjB,CAAO,EAC3C,OAAOzB,EAAGyC,EAAS,YAAYC,EAAM,KAAK,KAAM,KAAK,KAAK,EAAG,CAC3D,GAAG,KAAK,MACR,KAAMjB,CAAA,CACP,CACH,MAAQ,CACN,OAAOtB,EAAK,QAAS,yBAAyBsB,CAAO,GAAI,KAAK,KAAK,CACrE,CACF,CAKA,OAAOI,EAAaX,EAAmC,CACrD,GAAIW,EAAM,GAAKX,EAAM,EACnB,OAAOf,EACL,SACA,iCAAiC0B,CAAG,SAASX,CAAG,GAChD,KAAK,KAAA,EAGT,MAAMwB,EAAO,KAAK,UAAU,QAAQb,EAAKX,CAAG,EAC5C,OAAOlB,EAAGyC,EAAS,YAAYC,EAAM,KAAK,KAAM,KAAK,KAAK,EAAG,CAC3D,GAAG,KAAK,MACR,KAAMA,EAAK,OAAA,CACZ,CACH,CAKA,SAASjB,EAAwC,CAC/C,MAAMuF,EAAa,KAAK,KAAKvF,CAAO,EACpC,OAAKuF,EAAW,GACTA,EAAW,MAAM,MAAA,EADGA,CAE7B,CASA,MAAMvF,EAAwC,CAC5C,OAAOoD,EAAU,YAAY,KAAK,UAAWpD,EAAS,KAAK,KAAM,KAAK,KAAK,CAC7E,CAKA,UAAUQ,EAAeC,EAAoC,CAC3D,OAAO,KAAK,MAAM,GAAGD,CAAK,IAAIC,CAAG,EAAE,CACrC,CAKA,QACEE,EACAC,EACAC,EACAC,EACuB,CACvB,OAAIH,EAAW,GAAKC,EAAW,GAAKC,EAAS,GAAKC,EAAS,EAClDpC,EAAK,SAAU,4BAA6B,KAAK,KAAK,EAExDH,EACL6E,EAAU,WACR,KAAK,UACLzC,EACAC,EACAC,EACAC,EACA,KAAK,KACL,KAAK,KAAA,EAEP,KAAK,KAAA,CAET,CAKA,WAAmC,CACjC,MAAMuE,EAAO,KAAK,WAAA,EAClB,OAAIA,EAAK,WAAa,GAAKA,EAAK,WAAa,EACpC3G,EAAK,UAAW,0BAA2B,KAAK,KAAK,EAEvDH,EACL6E,EAAU,WACR,KAAK,UACLiC,EAAK,SACLA,EAAK,SACLA,EAAK,OACLA,EAAK,OACL,KAAK,KACL,KAAK,KAAA,EAEP,KAAK,KAAA,CAET,CASA,IAAIK,EAAuC,CACzC,MAAML,EAAO,KAAK,WAAA,EAClB,GAAIK,EAAS,EACX,OAAOhH,EAAK,SAAU,uBAAuBgH,CAAM,GAAI,KAAK,KAAK,EAEnE,MAAM5E,EAAS,KAAK,IAAIuE,EAAK,OAAQ,CAAC,EACtC,OAAO9G,EACL6E,EAAU,WACR,KAAK,UACLsC,EACA,EACAA,EACA5E,EACA,KAAK,KACL,KAAK,KAAA,EAEP,KAAK,KAAA,CAET,CAKA,IAAI6E,EAA+C,CACjD,MAAMT,EACJ,OAAOS,GAAU,SAAWnG,EAAqBmG,EAAM,YAAA,CAAa,EAAIA,EAC1E,GAAIT,EAAS,EACX,OAAOxG,EAAK,SAAU,mBAAmBiH,CAAK,GAAI,KAAK,KAAK,EAE9D,MAAMN,EAAO,KAAK,WAAA,EACZxE,EAAS,KAAK,IAAIwE,EAAK,OAAQ,CAAC,EACtC,OAAO9G,EACL6E,EAAU,WACR,KAAK,UACL,EACA8B,EACArE,EACAqE,EACA,KAAK,KACL,KAAK,KAAA,EAEP,KAAK,KAAA,CAET,CAKA,CAAC,MAA4B,CAC3B,MAAMG,EAAO,KAAK,WAAA,EAClB,QAASO,EAAIP,EAAK,SAAUO,GAAKP,EAAK,OAAQO,IAC5C,MAAMxC,EAAU,WACd,KAAK,UACLwC,EACAP,EAAK,SACLO,EACAP,EAAK,OACL,KAAK,KACL,KAAK,KAAA,CAGX,CAKA,CAAC,MAA4B,CAC3B,MAAMA,EAAO,KAAK,WAAA,EAClB,QAASQ,EAAIR,EAAK,SAAUQ,GAAKR,EAAK,OAAQQ,IAC5C,MAAMzC,EAAU,WACd,KAAK,UACLiC,EAAK,SACLQ,EACAR,EAAK,OACLQ,EACA,KAAK,KACL,KAAK,KAAA,CAGX,CASA,OAAOC,EAAmC,CACxC,MAAM9F,EAAU8F,GAAgB,KAChC,OAAOjB,EAAW,OAAO,KAAM7E,CAAO,CACxC,CAKA,SAASI,EAAaX,EAAyB,CAC7C,OAAOoF,EAAW,SAAS,KAAMzE,EAAKX,CAAG,CAC3C,CASA,KAAKwE,EAAgD,CACnD,MAAM8B,EAAc,KAAK,UAAA,EACzB,OAAKA,EAAY,GACVA,EAAY,MAAM,KAAK9B,CAAS,EADX8B,CAE9B,CAKA,QAAQ9B,EAAsC,CAC5C,MAAM8B,EAAc,KAAK,UAAA,EACzB,OAAKA,EAAY,GACVA,EAAY,MAAM,QAAQ9B,CAAS,EADd,CAAA,CAE9B,CAKA,UAAUzF,EAAwC,CAChD,MAAMuH,EAAc,KAAK,UAAA,EACzB,OAAKA,EAAY,GACVA,EAAY,MAAM,UAAUvH,CAAK,EADZuH,CAE9B,CAKA,YACEC,EACA/B,EACsB,CACtB,MAAM8B,EAAc,KAAK,MAAMC,CAAY,EAC3C,OAAKD,EAAY,GACVA,EAAY,MAAM,KAAK9B,CAAS,EADX8B,CAE9B,CAKA,eAAeC,EAAsB/B,EAAsC,CACzE,MAAM8B,EAAc,KAAK,MAAMC,CAAY,EAC3C,OAAKD,EAAY,GACVA,EAAY,MAAM,QAAQ9B,CAAS,EADd,CAAA,CAE9B,CASA,YAA8B,CAE5B,MAAMgC,EAAW,KAAK,UAAU,SAC1BC,EAAc,KAAK,UAAU,YAGnC,IAAIvF,EAAW,EACXE,EAASoF,EACTrF,EAAW,EACXE,EAASoF,EAGb,GAAI,KAAK,UAAU,WAAY,CAC7B,MAAMb,EAAO,KAAK,UAAU,WAE5B,GAAI,OAAOA,GAAS,SAClB,GAAI,CACF,MAAMc,EAAS9F,EAAWgF,CAAI,EAC9B1E,EAAWwF,EAAO,MAAM,IACxBvF,EAAWuF,EAAO,MAAM,IACxBtF,EAASsF,EAAO,IAAI,IACpBrF,EAASqF,EAAO,IAAI,GACtB,MAAQ,CAER,CAEJ,CAEA,MAAO,CACL,SAAAxF,EACA,OAAAE,EACA,SAAAD,EACA,OAAAE,EACA,SAAUD,EAASF,EAAW,EAC9B,SAAUG,EAASF,EAAW,CAAA,CAElC,CAKA,UAAmB,CACjB,OAAO,KAAK,aAAa,QAC3B,CAKA,UAAmB,CACjB,OAAO,KAAK,aAAa,QAC3B,CASA,cAAyB,CAEvB,MAAMwF,EAAU,KAAK,UAA+D,QACpF,OAAKA,EACE,OAAO,KAAKA,CAAM,EADL,CAAA,CAEtB,CAKA,SAASpG,EAA0B,CACjC,MAAMuF,EAAa,KAAK,KAAKvF,CAAO,EACpC,OAAKuF,EAAW,GACTA,EAAW,MAAM,SAAA,EADG,EAE7B,CAUA,cAA0B,CACxB,OAAO,KAAK,SACd,CAMA,gBAAgBnF,EAAaX,EAAmC,CAC9D,GAAIW,EAAM,GAAKX,EAAM,EAAG,OACxB,MAAMwB,EAAO,KAAK,UAAU,QAAQb,EAAKX,CAAG,EAC5C,OAAOuB,EAAS,YAAYC,EAAM,KAAK,KAAM,KAAK,KAAK,CACzD,CACF,CCxaO,MAAMoF,CAAa,CAGhB,YACWC,EACApF,EACjB,CAFiB,KAAA,SAAAoF,EACA,KAAA,MAAApF,EAJnB,KAAiB,gBAA0C,GAKxD,CAMH,OAAO,YAAYoF,EAAoBjF,EAA6B,CAClE,MAAM5C,EAAiB,CAAE,KAAA4C,CAAA,EACzB,OAAO,IAAIgF,EAAaC,EAAU7H,CAAI,CACxC,CASA,IAAI,MAAiB,CACnB,OAAO,KAAK,KACd,CAKA,IAAI,MAA2B,CAC7B,OAAO,KAAK,MAAM,IACpB,CASA,MAAM8H,EAAqC,CAEzC,MAAMC,EAAS,KAAK,YAAY,IAAID,CAAI,EACxC,GAAIC,EACF,OAAOjI,EAAGiI,EAAQ,CAAE,GAAG,KAAK,MAAO,MAAOD,EAAM,EAGlD,MAAMlD,EAAY,KAAK,SAAS,aAAakD,CAAI,EACjD,GAAI,CAAClD,EACH,OAAO3E,EACL,UACA,UAAU6H,CAAI,cACd,KAAK,KAAA,EAIT,MAAMzB,EAAQW,EAAU,YAAYpC,EAAW,KAAK,MAAM,IAAI,EAC9D,YAAK,YAAY,IAAIkD,EAAMzB,CAAK,EACzBvG,EAAGuG,EAAOA,EAAM,IAAI,CAC7B,CAKA,QAAQ2B,EAAsC,CAC5C,GAAIA,EAAQ,EACV,OAAO/H,EACL,SACA,iCAAiC+H,CAAK,GACtC,KAAK,KAAA,EAIT,MAAMpD,EAAY,KAAK,SAAS,aAAaoD,CAAK,EAClD,GAAI,CAACpD,EACH,OAAO3E,EACL,UACA,kBAAkB+H,CAAK,aACvB,KAAK,KAAA,EAKT,MAAMD,EAAS,KAAK,YAAY,IAAInD,EAAU,IAAI,EAClD,GAAImD,EACF,OAAOjI,EAAGiI,EAAQA,EAAO,IAAI,EAG/B,MAAM1B,EAAQW,EAAU,YAAYpC,EAAW,KAAK,MAAM,IAAI,EAC9D,YAAK,YAAY,IAAIA,EAAU,KAAMyB,CAAK,EACnCvG,EAAGuG,EAAOA,EAAM,IAAI,CAC7B,CAKA,QAAsB,CACpB,MAAM4B,EAAsB,CAAA,EAC5B,YAAK,SAAS,UAAWrD,GAAc,CACrC,MAAMmD,EAAS,KAAK,YAAY,IAAInD,EAAU,IAAI,EAClD,GAAImD,EACFE,EAAO,KAAKF,CAAM,MACb,CACL,MAAM1B,EAAQW,EAAU,YAAYpC,EAAW,KAAK,MAAM,IAAI,EAC9D,KAAK,YAAY,IAAIA,EAAU,KAAMyB,CAAK,EAC1C4B,EAAO,KAAK5B,CAAK,CACnB,CACF,CAAC,EACM4B,CACT,CAKA,YAAuB,CACrB,MAAMC,EAAkB,CAAA,EACxB,YAAK,SAAS,UAAWtD,GAAc,CACrCsD,EAAM,KAAKtD,EAAU,IAAI,CAC3B,CAAC,EACMsD,CACT,CAKA,YAAqB,CACnB,OAAO,KAAK,SAAS,WAAW,MAClC,CAKA,YAAoC,CAClC,OAAO,KAAK,QAAQ,CAAC,CACvB,CAKA,WAAmC,CACjC,MAAMvC,EAAQ,KAAK,WAAA,EACnB,OAAIA,IAAU,EACL1F,EAAK,UAAW,yBAA0B,KAAK,KAAK,EAEtD,KAAK,QAAQ0F,CAAK,CAC3B,CASA,SAASmC,EAAuB,CAC9B,OAAO,KAAK,SAAS,aAAaA,CAAI,IAAM,MAC9C,CAKA,UAAUtC,EAAkD,CAC1D,UAAWa,KAAS,KAAK,SACvB,GAAIb,EAAUa,CAAK,EACjB,OAAOvG,EAAGuG,EAAOA,EAAM,IAAI,EAG/B,OAAOpG,EACL,UACA,oCACA,KAAK,KAAA,CAET,CAKA,aAAauF,EAAwC,CACnD,OAAO,KAAK,SAAS,OAAOA,CAAS,CACvC,CAKA,mBAAmB2C,EAAwC,CACzD,OAAO,KAAK,UAAU9B,GAAS8B,EAAQ,KAAK9B,EAAM,IAAI,CAAC,CACzD,CAKA,sBAAsB8B,EAA8B,CAClD,OAAO,KAAK,aAAa9B,GAAS8B,EAAQ,KAAK9B,EAAM,IAAI,CAAC,CAC5D,CASA,YAAiC,CAC/B,MAAO,CACL,MAAO,KAAK,SAAS,MACrB,QAAS,KAAK,SAAS,QACvB,QAAS,KAAK,SAAS,QACvB,eAAgB,KAAK,SAAS,eAC9B,QAAS,KAAK,SAAS,QACvB,SAAU,KAAK,SAAS,QAAA,CAE5B,CAKA,SAA8B,CAC5B,OAAO,KAAK,SAAS,OACvB,CAKA,SAA4B,CAC1B,OAAO,KAAK,SAAS,OACvB,CAKA,UAA6B,CAC3B,OAAO,KAAK,SAAS,QACvB,CASA,cAAyB,CAIvB,MAHwB,CAAA,CAI1B,CASA,EAAE,OAAO,QAAQ,GAAyB,CACxC,UAAWA,KAAS,KAAK,SACvB,MAAMA,CAEV,CAKA,QAAQ+B,EAAqD,CAC3D,KAAK,OAAA,EAAS,QAAQA,CAAE,CAC1B,CAKA,IAAOA,EAAiD,CACtD,OAAO,KAAK,SAAS,IAAIA,CAAE,CAC7B,CAUA,aAAwB,CACtB,OAAO,KAAK,QACd,CACF,CCrTO,MAAMC,EAAa,CAQxB,OAAStI,GACCyC,GAAmB,CACzB,MAAMK,EAAML,EAAK,MAAA,EACjB,OAAKK,EAAI,GACL9C,IAAU,KAAa8C,EAAI,QAAU,KACrCA,EAAI,QAAU,KAAa,GAE3B9C,aAAiB,MAAQ8C,EAAI,iBAAiB,KACzC9C,EAAM,QAAA,IAAc8C,EAAI,MAAM,QAAA,EAEhCA,EAAI,QAAU9C,EAPD,EAQtB,EAMF,SAAU,CAACwD,EAAc+E,EAAyB,KACxC9F,GAAmB,CACzB,MAAMK,EAAML,EAAK,OAAA,EACjB,OAAKK,EAAI,GACLyF,EACKzF,EAAI,MAAM,SAASU,CAAI,EAEzBV,EAAI,MAAM,YAAA,EAAc,SAASU,EAAK,aAAa,EAJtC,EAKtB,EAMF,QAAU4E,GACA3F,GAAmB,CACzB,MAAMK,EAAML,EAAK,OAAA,EACjB,OAAKK,EAAI,GACFsF,EAAQ,KAAKtF,EAAI,KAAK,EADT,EAEtB,EAMF,WAAY,CAAC0F,EAAgBD,EAAyB,KAC5C9F,GAAmB,CACzB,MAAMK,EAAML,EAAK,OAAA,EACjB,OAAKK,EAAI,GACLyF,EACKzF,EAAI,MAAM,WAAW0F,CAAM,EAE7B1F,EAAI,MAAM,YAAA,EAAc,WAAW0F,EAAO,aAAa,EAJ1C,EAKtB,EAMF,SAAU,CAACC,EAAgBF,EAAyB,KAC1C9F,GAAmB,CACzB,MAAMK,EAAML,EAAK,OAAA,EACjB,OAAKK,EAAI,GACLyF,EACKzF,EAAI,MAAM,SAAS2F,CAAM,EAE3B3F,EAAI,MAAM,YAAA,EAAc,SAAS2F,EAAO,aAAa,EAJxC,EAKtB,EAUF,SAAU,IACAhG,GAAmBA,EAAK,SAAA,EAMlC,SAAU,IACAA,GAAmBA,EAAK,SAAA,EAMlC,UAAW,IACDA,GAAmBA,EAAK,UAAA,EAMlC,OAAQ,IACEA,GAAmBA,EAAK,OAAA,EAMlC,QAAS,IACCA,GAAmBA,EAAK,QAAA,EAMlC,WAAY,IACFA,GAAmB,CAACA,EAAK,QAAA,EAMnC,UAAW,IACDA,GAAmBA,EAAK,UAAA,EAMlC,QAAS,IACCA,GAAmBA,EAAK,QAAA,EAMlC,SAAU,IACAA,GAAmBA,EAAK,SAAA,EAUlC,YAAciG,GACJjG,GAAmB,CACzB,MAAMK,EAAML,EAAK,OAAA,EACjB,OAAOK,EAAI,IAAMA,EAAI,MAAQ4F,CAC/B,EAMF,mBAAqBA,GACXjG,GAAmB,CACzB,MAAMK,EAAML,EAAK,OAAA,EACjB,OAAOK,EAAI,IAAMA,EAAI,OAAS4F,CAChC,EAMF,SAAWA,GACDjG,GAAmB,CACzB,MAAMK,EAAML,EAAK,OAAA,EACjB,OAAOK,EAAI,IAAMA,EAAI,MAAQ4F,CAC/B,EAMF,gBAAkBA,GACRjG,GAAmB,CACzB,MAAMK,EAAML,EAAK,OAAA,EACjB,OAAOK,EAAI,IAAMA,EAAI,OAAS4F,CAChC,EAMF,QAAS,CAACC,EAAaC,IACbnG,GAAmB,CACzB,MAAMK,EAAML,EAAK,OAAA,EACjB,OAAOK,EAAI,IAAMA,EAAI,OAAS6F,GAAO7F,EAAI,OAAS8F,CACpD,EAUF,WAAa5F,GACHP,GAAmB,CACzB,MAAMK,EAAML,EAAK,KAAA,EACjB,OAAOK,EAAI,IAAMA,EAAI,MAAM,QAAA,EAAYE,EAAK,QAAA,CAC9C,EAMF,UAAYA,GACFP,GAAmB,CACzB,MAAMK,EAAML,EAAK,KAAA,EACjB,OAAOK,EAAI,IAAMA,EAAI,MAAM,QAAA,EAAYE,EAAK,QAAA,CAC9C,EAMF,YAAa,CAAChB,EAAaC,IACjBQ,GAAmB,CACzB,MAAMK,EAAML,EAAK,KAAA,EACjB,GAAI,CAACK,EAAI,GAAI,MAAO,GACpB,MAAM+F,EAAO/F,EAAI,MAAM,QAAA,EACvB,OAAO+F,GAAQ7G,EAAM,QAAA,GAAa6G,GAAQ5G,EAAI,QAAA,CAChD,EAUF,MAAQiF,GACEzE,GAAmBA,EAAK,MAAQyE,EAM1C,MAAQR,GACEjE,GAAmBA,EAAK,MAAQiE,EAM1C,YAAchF,GACJe,GACNA,EAAK,UAAU,YAAA,IAAkBf,EAAU,YAAA,EAU/C,IAAK,IAAIoH,IACCrG,GAAmBqG,EAAM,MAAMC,GAAQA,EAAKtG,CAAI,CAAC,EAM3D,GAAI,IAAIqG,IACErG,GAAmBqG,EAAM,KAAKC,GAAQA,EAAKtG,CAAI,CAAC,EAM1D,IAAMsG,GACItG,GAAmB,CAACsG,EAAKtG,CAAI,EAUvC,OAAQ,IACEA,GACQA,EAAK,MAAA,EACN,MAAM,OAAS,GAOhC,SAAU,IACAA,GACQA,EAAK,MAAA,EACN,MAAM,SAAW,GAOlC,aAAc,IACJA,GACOA,EAAK,UAAA,EACN,GAOhB,WAAY,IACFA,GACUA,EAAK,QAAA,EACN,GAWnB,OAAQ,IACC,IAAM,GAMf,MAAO,IACE,IAAM,GAMf,OAAS4F,GACAA,CAEX,EC9RO,SAASW,EAAUC,EAA0C,CAClE,MAAO,CACL,KAAM,YACN,UAAW,iBACX,KAAM,YACN,KAAMA,CAAA,CAEV,CAMO,MAAMC,EAA+B,CAC1C,UAAW,iBACX,KAAM,YAGN,QAAQC,EAAgBC,EAAuB,CAC7C,MAAM,IAAI,MACR,qEAAA,CAEJ,CACF,EAKA,SAASC,EAAcF,EAAyC,CAG9D,OADa,IAAI,WAAWA,CAAK,EACrB,MACd,CAKO,MAAMG,EAAoC,CAC/C,UAAW,iBACX,KAAM,YAEN,MAAM,QAAQH,EAAgBC,EAAuC,CACnE,MAAMH,EAAWG,GAA6B,CAAA,EAE9C,IAAIG,EAEJ,GAAIJ,aAAiB,eAAgB,CACnC,MAAMK,EAAS,MAAM7I,EAAewI,CAAK,EACzCI,EAAOF,EAAcG,CAAM,CAC7B,SAAW,OAAO,SAASL,CAAK,EAC9BI,EAAOF,EAAcF,CAAK,UACjBA,aAAiB,YAC1BI,EAAOJ,UACEA,aAAiB,WAC1BI,EAAOF,EAAcF,CAAK,MAE1B,OAAM,IAAI,MACR,iDAAiD,OAAOA,CAAK,EAAA,EAIjE,MAAMrB,EAAW,IAAI2B,EAAQ,SAC7B,aAAM3B,EAAS,KAAK,KAAKyB,CAAI,EAEtB1B,EAAa,YAAYC,EAAUmB,EAAQ,QAAQ,CAC5D,CACF,EAKA,eAAsBS,EACpBF,EACAP,EACuB,CACvB,MAAMnB,EAAW,IAAI2B,EAAQ,SAC7B,IAAIF,EACJ,OAAIC,aAAkB,YACpBD,EAAOC,EAEPD,EAAOF,EAAcG,CAAM,EAE7B,MAAM1B,EAAS,KAAK,KAAKyB,CAAI,EACtB1B,EAAa,YAAYC,EAAUmB,GAAS,QAAQ,CAC7D,CAMA,eAAsBU,EACpBC,EACAX,EACuB,CACvB,MAAMnB,EAAW,IAAI2B,EAAQ,SAC7B,aAAM3B,EAAS,KAAK,SAAS8B,CAAQ,EAC9B/B,EAAa,YAAYC,EAAUmB,GAAS,UAAYW,CAAQ,CACzE,CCtHO,SAASC,EACd7J,EACAiJ,EACW,CACX,OAAIjJ,GAAU,KACL,KAELA,aAAiB,KACfiJ,GAAS,kBAAoB,GACxBjJ,EAAM,YAAA,EAERA,EAAM,QAAA,EAEX,OAAOA,GAAU,UAAY,OAAOA,GAAU,UAAY,OAAOA,GAAU,UACtEA,EAEF,IACT,CAKO,SAAS8J,EACdrH,EACAwG,EACW,CACX,MAAMnG,EAAML,EAAK,MAAA,EACXzC,EAAQ8C,EAAI,GAAK+G,EAAgB/G,EAAI,MAAOmG,CAAO,EAAI,KAE7D,OAAIA,GAAS,qBACJ,CACL,QAASxG,EAAK,QACd,MAAAzC,CAAA,EAGGA,CACT,CAKO,SAAS+J,EACdjI,EACAmH,EACW,CACX,OAAIA,GAAS,kBACJe,EAAelI,EAAOmH,CAAO,EAE/BgB,EAAanI,EAAOmH,CAAO,CACpC,CAKO,SAASgB,EACdnI,EACAmH,EACe,CACf,MAAM/H,EAAwB,CAAA,EAC9B,UAAWoE,KAAYxD,EAAM,OAAQ,CACnC,MAAMF,EAAmB,CAAA,EACzB,UAAWa,KAAQ6C,EAAU,CAC3B,MAAMtF,EAAQ8J,EAAWrH,EAAMwG,CAAO,EAClCjJ,IAAU,MAAQiJ,GAAS,aAC7BrH,EAAI,KAAK5B,CAAK,GACL4B,EAAI,OAAS,GAAKqH,GAAS,eAEpCrH,EAAI,KAAK,IAAI,CAEjB,EACIA,EAAI,OAAS,GAAKqH,GAAS,eAC7B/H,EAAO,KAAKU,CAAG,CAEnB,CACA,OAAOV,CACT,CAKO,SAAS8I,EACdlI,EACAmH,EACW,CACX,MAAMiB,EAAO,CAAC,GAAGpI,EAAM,MAAM,EAC7B,GAAIoI,EAAK,SAAW,EAAG,MAAO,CAAA,EAI9B,MAAMjE,EADYiE,EAAK,CAAC,EACY,IAAIzH,GAAQ,CAC9C,MAAMK,EAAML,EAAK,MAAA,EACjB,OAAIK,EAAI,IAAMA,EAAI,QAAU,KACnB,OAAOA,EAAI,KAAK,EAElB,OAAOL,EAAK,GAAG,EACxB,CAAC,EAGKvB,EAAsB,CAAA,EAC5B,QAASC,EAAI,EAAGA,EAAI+I,EAAK,OAAQ/I,IAAK,CACpC,MAAMS,EAAMsI,EAAK/I,CAAC,EACZ+E,EAAoC,CAAA,EAC1C,IAAIiE,EAAU,GAEd,QAAShE,EAAI,EAAGA,EAAIF,EAAQ,OAAQE,IAAK,CACvC,MAAMC,EAASH,EAAQE,CAAC,EAClB1D,EAAOb,EAAIuE,CAAC,EAClB,GAAI1D,EAAM,CACR,MAAMzC,EAAQ8J,EAAWrH,EAAMwG,CAAO,EAClCjJ,IAAU,OACZmK,EAAU,IAEZjE,EAAIE,CAAM,EAAIpG,CAChB,MACEkG,EAAIE,CAAM,EAAI,IAElB,EAEI+D,GAAWlB,GAAS,eACtB/H,EAAO,KAAKgF,CAAG,CAEnB,CAEA,OAAOhF,CACT,CAKO,SAASkJ,EACd9D,EACA2C,EACW,CACX,MAAM1B,EAAcjB,EAAM,UAAA,EAC1B,OAAKiB,EAAY,GAGVwC,EAAYxC,EAAY,MAAO0B,CAAO,EAFpCA,GAAS,kBAAoB,CAAA,EAAK,CAAC,CAAA,CAAE,CAGhD,CAKO,SAASoB,EACdvC,EACAmB,EACW,CACX,MAAMf,EAASJ,EAAS,OAAA,EAExB,GAAImB,GAAS,oBAAsB,GAAO,CACxC,MAAM/H,EAAuC,CAAA,EAC7C,UAAWoF,KAAS4B,EAClBhH,EAAOoF,EAAM,IAAI,EAAI8D,EAAY9D,EAAO2C,CAAO,EAEjD,OAAO/H,CACT,CAGA,OAAOgH,EAAO,IAAI5B,GAAS8D,EAAY9D,EAAO2C,CAAO,CAAC,CACxD,CAKO,SAASqB,EACdxI,EACAmH,EAKQ,CACR,MAAMsB,EAAYtB,GAAS,WAAa,IAClCuB,EAAavB,GAAS,YAAc;AAAA,EACpCwB,EAAexB,GAAS,cAAgB,GAExCyB,EAAkB,CAAA,EAExB,UAAWpF,KAAYxD,EAAM,OAAQ,CACnC,MAAM6I,EAAmB,CAAA,EACzB,UAAWlI,KAAQ6C,EAAU,CAC3B,MAAMxC,EAAML,EAAK,MAAA,EACjB,IAAImI,EAEA,CAAC9H,EAAI,IAAMA,EAAI,QAAU,KAC3B8H,EAAM,GACG9H,EAAI,iBAAiB,KAC9B8H,EAAM9H,EAAI,MAAM,YAAA,EAEhB8H,EAAM,OAAO9H,EAAI,KAAK,EAIpB2H,IACFG,EAAI,SAASL,CAAS,GACtBK,EAAI,SAAS;AAAA,CAAI,GACjBA,EAAI,SAAS,IAAI,GACjBA,EAAI,SAAS,GAAG,KAEhBA,EAAM,IAAMA,EAAI,QAAQ,KAAM,IAAI,EAAI,KAGxCD,EAAO,KAAKC,CAAG,CACjB,CACAF,EAAM,KAAKC,EAAO,KAAKJ,CAAS,CAAC,CACnC,CAEA,OAAOG,EAAM,KAAKF,CAAU,CAC9B,CAKO,SAASK,EACdvE,EACA2C,EAKQ,CACR,MAAM1B,EAAcjB,EAAM,UAAA,EAC1B,OAAKiB,EAAY,GAGV+C,EAAW/C,EAAY,MAAO0B,CAAO,EAFnC,EAGX,CClLO,SAAS6B,EAAuBC,EAM9B,CACPA,EAAS,SAASzB,CAAkB,CACtC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @origints/xlsx - XLSX parsing for Origins with full traceability.
|
|
3
|
+
*
|
|
4
|
+
* This package provides a rich API for parsing and navigating XLSX files
|
|
5
|
+
* with complete traceability to sheets, ranges, and cells.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
export type { ExcelLocation, XlsxPath, XlsxFailure, XlsxFailureKind, XlsxResult, CellValue, ExtendedCellValue, } from './xlsx-result';
|
|
10
|
+
export { ok, fail, formatXlsxPath, toExcelLocation, isFormula, isError, } from './xlsx-result';
|
|
11
|
+
export type { CellStyle, RichTextSegment, RichTextContent } from './xlsx-cell';
|
|
12
|
+
export { XlsxCell } from './xlsx-cell';
|
|
13
|
+
export { XlsxRange } from './xlsx-range';
|
|
14
|
+
export type { SheetDimensions } from './xlsx-sheet';
|
|
15
|
+
export { XlsxSheet } from './xlsx-sheet';
|
|
16
|
+
export type { SheetPredicate, WorkbookProperties } from './xlsx-workbook';
|
|
17
|
+
export { XlsxWorkbook } from './xlsx-workbook';
|
|
18
|
+
export type { CursorDirection, GrabResult, GrabOneResult, } from './xlsx-cursor';
|
|
19
|
+
export { XlsxCursor } from './xlsx-cursor';
|
|
20
|
+
export type { CellPredicate, Predicates } from './xlsx-query';
|
|
21
|
+
export { predicates } from './xlsx-query';
|
|
22
|
+
export type { XlsxParseOptions, TransformAst, TransformImpl } from './parse';
|
|
23
|
+
export { parseXlsx, parseXlsxImpl, parseXlsxAsyncImpl, parseXlsxBuffer, parseXlsxFile, } from './parse';
|
|
24
|
+
export type { JsonValue, ToJsonOptions } from './convert';
|
|
25
|
+
export { cellValueToJson, cellToJson, rangeToJson, rangeToArray, rangeToObjects, sheetToJson, workbookToJson, rangeToCsv, sheetToCsv, } from './convert';
|
|
26
|
+
export { streamToBuffer, columnLetterToNumber, columnNumberToLetter, parseAddress, formatAddress, parseRange, formatRange, isInRange, } from './util';
|
|
27
|
+
/**
|
|
28
|
+
* Register the XLSX transforms with a registry.
|
|
29
|
+
* Call this to enable parseXlsx() in your plans.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { globalRegistry } from '@origints/core'
|
|
34
|
+
* import { registerXlsxTransforms } from '@origints/xlsx'
|
|
35
|
+
*
|
|
36
|
+
* registerXlsxTransforms(globalRegistry)
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function registerXlsxTransforms(registry: {
|
|
40
|
+
register(impl: {
|
|
41
|
+
namespace: string;
|
|
42
|
+
name: string;
|
|
43
|
+
execute: (...args: unknown[]) => unknown;
|
|
44
|
+
}): void;
|
|
45
|
+
}): void;
|