allyhub 0.5.0 → 0.6.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/commands/render.js +1 -1
- package/dist/commands/sheet.js +7 -7
- package/dist/commands/slides.js +1 -1
- package/dist/node_modules/@allyhub-next/audio/package.json +1 -1
- package/dist/node_modules/@allyhub-next/browser/package.json +1 -1
- package/dist/node_modules/@allyhub-next/build/package.json +1 -1
- package/dist/node_modules/@allyhub-next/chart/package.json +1 -1
- package/dist/node_modules/@allyhub-next/check/package.json +1 -1
- package/dist/node_modules/@allyhub-next/cloud/package.json +1 -1
- package/dist/node_modules/@allyhub-next/components/package.json +1 -1
- package/dist/node_modules/@allyhub-next/dev-server/dist/exports.js +1 -1
- package/dist/node_modules/@allyhub-next/dev-server/package.json +1 -1
- package/dist/node_modules/@allyhub-next/doc/package.json +1 -1
- package/dist/node_modules/@allyhub-next/export/dist/export.d.ts +2 -2
- package/dist/node_modules/@allyhub-next/export/dist/export.js +4 -4
- package/dist/node_modules/@allyhub-next/export/dist/names.d.ts +1 -1
- package/dist/node_modules/@allyhub-next/export/package.json +1 -1
- package/dist/node_modules/@allyhub-next/formats/dist/data/sheet.d.ts +179 -0
- package/dist/node_modules/@allyhub-next/formats/dist/data/sheet.js +1 -1
- package/dist/node_modules/@allyhub-next/formats/dist/data/slides.d.ts +303 -11
- package/dist/node_modules/@allyhub-next/formats/dist/data/slides.js +1 -1
- package/dist/node_modules/@allyhub-next/formats/dist/index.d.ts +1 -0
- package/dist/node_modules/@allyhub-next/formats/dist/index.js +1 -1
- package/dist/node_modules/@allyhub-next/formats/dist/items.js +1 -1
- package/dist/node_modules/@allyhub-next/formats/dist/schemas.d.ts +135 -3
- package/dist/node_modules/@allyhub-next/formats/dist/zip.d.ts +17 -0
- package/dist/node_modules/@allyhub-next/formats/dist/zip.js +2 -0
- package/dist/node_modules/@allyhub-next/formats/package.json +1 -1
- package/dist/node_modules/@allyhub-next/measure/package.json +1 -1
- package/dist/node_modules/@allyhub-next/media/package.json +1 -1
- package/dist/node_modules/@allyhub-next/model/package.json +1 -1
- package/dist/node_modules/@allyhub-next/project/package.json +1 -1
- package/dist/node_modules/@allyhub-next/protocol/dist/editor.d.ts +10 -0
- package/dist/node_modules/@allyhub-next/protocol/dist/editor.js +1 -1
- package/dist/node_modules/@allyhub-next/protocol/dist/notes.d.ts +2 -0
- package/dist/node_modules/@allyhub-next/protocol/dist/notes.js +1 -1
- package/dist/node_modules/@allyhub-next/protocol/package.json +1 -1
- package/dist/node_modules/@allyhub-next/registry/package.json +1 -1
- package/dist/node_modules/@allyhub-next/render/dist/exports.d.ts +2 -11
- package/dist/node_modules/@allyhub-next/render/dist/exports.js +2 -2
- package/dist/node_modules/@allyhub-next/render/dist/page.d.ts +1 -9
- package/dist/node_modules/@allyhub-next/render/package.json +1 -1
- package/dist/node_modules/@allyhub-next/runtime/package.json +1 -1
- package/dist/node_modules/@allyhub-next/runtimes/package.json +1 -1
- package/dist/node_modules/@allyhub-next/scaffold/package.json +1 -1
- package/dist/node_modules/@allyhub-next/scenery/package.json +1 -1
- package/dist/node_modules/@allyhub-next/scenery-host/package.json +1 -1
- package/dist/node_modules/@allyhub-next/sheet/dist/api/capabilities.js +1 -1
- package/dist/node_modules/@allyhub-next/sheet/dist/api/index.d.ts +1 -0
- package/dist/node_modules/@allyhub-next/sheet/dist/api/index.js +1 -1
- package/dist/node_modules/@allyhub-next/sheet/dist/api/page.d.ts +83 -0
- package/dist/node_modules/@allyhub-next/sheet/dist/api/page.js +2 -0
- package/dist/node_modules/@allyhub-next/sheet/dist/api/workbook.d.ts +40 -1
- package/dist/node_modules/@allyhub-next/sheet/dist/api/workbook.js +1 -1
- package/dist/node_modules/@allyhub-next/sheet/dist/check.js +1 -1
- package/dist/node_modules/@allyhub-next/sheet/dist/structure.js +1 -1
- package/dist/node_modules/@allyhub-next/sheet/dist/xlsx/charts.d.ts +2 -0
- package/dist/node_modules/@allyhub-next/sheet/dist/xlsx/charts.js +1 -1
- package/dist/node_modules/@allyhub-next/sheet/dist/xlsx/import.d.ts +3 -0
- package/dist/node_modules/@allyhub-next/sheet/dist/xlsx/import.js +1 -1
- package/dist/node_modules/@allyhub-next/sheet/dist/xlsx/read.d.ts +2 -1
- package/dist/node_modules/@allyhub-next/sheet/dist/xlsx/read.js +1 -1
- package/dist/node_modules/@allyhub-next/sheet/dist/xlsx/write.js +1 -1
- package/dist/node_modules/@allyhub-next/sheet/package.json +1 -1
- package/dist/node_modules/@allyhub-next/site/package.json +1 -1
- package/dist/node_modules/@allyhub-next/slides-core/dist/api.d.ts +64 -7
- package/dist/node_modules/@allyhub-next/slides-core/dist/api.js +2 -2
- package/dist/node_modules/@allyhub-next/slides-core/dist/capabilities.js +1 -1
- package/dist/node_modules/@allyhub-next/slides-core/dist/chart-api.d.ts +23 -0
- package/dist/node_modules/@allyhub-next/slides-core/dist/chart-api.js +1 -1
- package/dist/node_modules/@allyhub-next/slides-core/dist/chart-file.js +1 -1
- package/dist/node_modules/@allyhub-next/slides-core/dist/enums.d.ts +20 -0
- package/dist/node_modules/@allyhub-next/slides-core/dist/enums.js +1 -1
- package/dist/node_modules/@allyhub-next/slides-core/dist/index.d.ts +1 -0
- package/dist/node_modules/@allyhub-next/slides-core/dist/index.js +1 -1
- package/dist/node_modules/@allyhub-next/slides-core/dist/model.d.ts +37 -1
- package/dist/node_modules/@allyhub-next/slides-core/dist/office.d.ts +10 -0
- package/dist/node_modules/@allyhub-next/slides-core/dist/office.js +1 -1
- package/dist/node_modules/@allyhub-next/slides-core/dist/preset.d.ts +5 -0
- package/dist/node_modules/@allyhub-next/slides-core/dist/preset.js +2 -0
- package/dist/node_modules/@allyhub-next/slides-core/dist/resolve.d.ts +7 -2
- package/dist/node_modules/@allyhub-next/slides-core/dist/resolve.js +1 -1
- package/dist/node_modules/@allyhub-next/slides-core/package.json +1 -1
- package/dist/node_modules/@allyhub-next/slides-pptx/dist/charts.js +1 -1
- package/dist/node_modules/@allyhub-next/slides-pptx/dist/import.js +1 -1
- package/dist/node_modules/@allyhub-next/slides-pptx/dist/read.d.ts +2 -1
- package/dist/node_modules/@allyhub-next/slides-pptx/dist/read.js +2 -2
- package/dist/node_modules/@allyhub-next/slides-pptx/dist/shapes.d.ts +6 -1
- package/dist/node_modules/@allyhub-next/slides-pptx/dist/shapes.js +1 -1
- package/dist/node_modules/@allyhub-next/slides-pptx/dist/text.d.ts +11 -0
- package/dist/node_modules/@allyhub-next/slides-pptx/dist/text.js +1 -1
- package/dist/node_modules/@allyhub-next/slides-pptx/dist/write.js +2 -2
- package/dist/node_modules/@allyhub-next/slides-pptx/dist/xml.d.ts +10 -4
- package/dist/node_modules/@allyhub-next/slides-pptx/dist/xml.js +2 -2
- package/dist/node_modules/@allyhub-next/slides-pptx/package.json +1 -1
- package/dist/node_modules/@allyhub-next/slides-runtime/dist/draw.d.ts +3 -0
- package/dist/node_modules/@allyhub-next/slides-runtime/dist/draw.js +2 -2
- package/dist/node_modules/@allyhub-next/slides-runtime/dist/edit.js +1 -1
- package/dist/node_modules/@allyhub-next/slides-runtime/package.json +1 -1
- package/dist/node_modules/@allyhub-next/stage/dist/graphics.js +1 -1
- package/dist/node_modules/@allyhub-next/stage/package.json +1 -1
- package/dist/node_modules/@allyhub-next/stage-page/dist/page.js +19 -19
- package/dist/node_modules/@allyhub-next/stage-page/package.json +1 -1
- package/dist/node_modules/@allyhub-next/video-core/package.json +1 -1
- package/editor-web/assets/dist-BW2s9FMO.js +4 -0
- package/editor-web/assets/{dist-CuW84oPe.js → dist-C-6JmebI.js} +22 -22
- package/editor-web/assets/dist-CCYMLMKN.js +6 -0
- package/editor-web/assets/dist-CHzurjMx.js +33 -0
- package/editor-web/assets/{dist-Yi3sy7Ea.js → dist-DF7H1dxw.js} +1 -1
- package/editor-web/assets/dist-Da5AUSKX.js +2 -0
- package/editor-web/assets/index-CovQYWvD.js +69 -0
- package/editor-web/assets/minus-BrvjaJyO.js +1 -0
- package/editor-web/assets/react-DV5fPdiH.js +101 -0
- package/editor-web/assets/{textarea-CvxipnGW.js → textarea-B0vCGdZI.js} +2 -2
- package/editor-web/assets/{trash-2-Bq1Dt8XG.js → trash-2-B0dvc1cZ.js} +1 -1
- package/editor-web/assets/{undo-2-Djhvu4xt.js → undo-2-A1EPubPO.js} +1 -1
- package/editor-web/index.html +2 -2
- package/package.json +2 -2
- package/editor-web/assets/dist-Cg2PdedY.js +0 -6
- package/editor-web/assets/dist-CxAS_vp7.js +0 -2
- package/editor-web/assets/dist-DCVaj9i1.js +0 -4
- package/editor-web/assets/dist-DGVUuVPB.js +0 -33
- package/editor-web/assets/index-pwRfZ2Jv.js +0 -69
- package/editor-web/assets/minus-BizJdinJ.js +0 -1
- package/editor-web/assets/react-D54s6gwK.js +0 -101
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { type SheetHeaderFooter, type SheetNote, type SheetPrint } from "@allyhub-next/formats";
|
|
2
|
+
/** What a page object changes: the sheet's `print`, and that it changed. */
|
|
3
|
+
export interface PageHost {
|
|
4
|
+
_print: SheetPrint;
|
|
5
|
+
_changed(): void;
|
|
6
|
+
}
|
|
7
|
+
/** openpyxl's `PrintPageSetup`. */
|
|
8
|
+
export declare class PageSetup {
|
|
9
|
+
private readonly ws;
|
|
10
|
+
constructor(ws: PageHost);
|
|
11
|
+
get orientation(): SheetPrint["orientation"];
|
|
12
|
+
set orientation(v: SheetPrint["orientation"]);
|
|
13
|
+
/** Excel's number (9 is A4), or a name: letter, legal, a3, a4, a5. */
|
|
14
|
+
get paperSize(): number | undefined;
|
|
15
|
+
set paperSize(v: number | string | undefined);
|
|
16
|
+
get fitToWidth(): number | undefined;
|
|
17
|
+
/** Pages wide. Setting it fits the sheet: openpyxl's pageSetUpPr.fitToPage is not asked for. */
|
|
18
|
+
set fitToWidth(v: number | undefined);
|
|
19
|
+
get fitToHeight(): number | undefined;
|
|
20
|
+
/** Pages tall; 0 as many as it takes. */
|
|
21
|
+
set fitToHeight(v: number | undefined);
|
|
22
|
+
private _fit;
|
|
23
|
+
}
|
|
24
|
+
/** openpyxl's `PageMargins`, in inches. */
|
|
25
|
+
export declare class PageMargins {
|
|
26
|
+
private readonly ws;
|
|
27
|
+
constructor(ws: PageHost);
|
|
28
|
+
private _set;
|
|
29
|
+
get left(): number | undefined;
|
|
30
|
+
set left(v: number | undefined);
|
|
31
|
+
get right(): number | undefined;
|
|
32
|
+
set right(v: number | undefined);
|
|
33
|
+
get top(): number | undefined;
|
|
34
|
+
set top(v: number | undefined);
|
|
35
|
+
get bottom(): number | undefined;
|
|
36
|
+
set bottom(v: number | undefined);
|
|
37
|
+
get header(): number | undefined;
|
|
38
|
+
set header(v: number | undefined);
|
|
39
|
+
get footer(): number | undefined;
|
|
40
|
+
set footer(v: number | undefined);
|
|
41
|
+
}
|
|
42
|
+
/** openpyxl's `_HeaderFooterPart`: its `text`, Excel's codes holding. */
|
|
43
|
+
export declare class HeaderFooterPart {
|
|
44
|
+
private readonly ws;
|
|
45
|
+
private readonly kind;
|
|
46
|
+
private readonly side;
|
|
47
|
+
constructor(ws: PageHost, kind: "header" | "footer", side: keyof SheetHeaderFooter);
|
|
48
|
+
get text(): string | undefined;
|
|
49
|
+
set text(v: string | undefined);
|
|
50
|
+
}
|
|
51
|
+
/** openpyxl's `_HeaderFooterItem`: a header's or a footer's three parts. */
|
|
52
|
+
export declare class HeaderFooter {
|
|
53
|
+
readonly left: HeaderFooterPart;
|
|
54
|
+
readonly center: HeaderFooterPart;
|
|
55
|
+
readonly right: HeaderFooterPart;
|
|
56
|
+
constructor(ws: PageHost, kind: "header" | "footer");
|
|
57
|
+
}
|
|
58
|
+
/** openpyxl's `SheetProtection`, with no password. */
|
|
59
|
+
export declare class SheetProtection {
|
|
60
|
+
private readonly read;
|
|
61
|
+
private readonly write;
|
|
62
|
+
constructor(read: () => boolean, write: (on: boolean) => void);
|
|
63
|
+
get sheet(): boolean;
|
|
64
|
+
set sheet(on: boolean);
|
|
65
|
+
enable(): void;
|
|
66
|
+
disable(): void;
|
|
67
|
+
}
|
|
68
|
+
/** openpyxl's `Comment`: Excel's Note. */
|
|
69
|
+
export declare class Comment {
|
|
70
|
+
readonly text: string;
|
|
71
|
+
readonly author: string | undefined;
|
|
72
|
+
constructor(text: string, author?: string);
|
|
73
|
+
_file(): SheetNote;
|
|
74
|
+
}
|
|
75
|
+
/** openpyxl's `Image`: a picture over the cells, a path from the sheet's folder. */
|
|
76
|
+
export declare class Image {
|
|
77
|
+
readonly path: string;
|
|
78
|
+
width: number | undefined;
|
|
79
|
+
height: number | undefined;
|
|
80
|
+
anchor: string | undefined;
|
|
81
|
+
constructor(path: string);
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=page.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
+
import{SHEET_PAPERS as h,strict as s}from"@allyhub-next/formats";import{HINT as r}from"./hint.js";export class PageSetup{ws;constructor(t){return this.ws=t,s(this,"PageSetup",r)}get orientation(){return this.ws._print.orientation}set orientation(t){t===void 0?delete this.ws._print.orientation:this.ws._print.orientation=t,this.ws._changed()}get paperSize(){const{paper:t}=this.ws._print;return t===void 0?void 0:h[t]}set paperSize(t){const e=Object.keys(h).find(i=>i===t||String(h[i])===String(t));if(t===void 0)delete this.ws._print.paper;else if(e)this.ws._print.paper=e;else throw new RangeError(`Paper is one of ${Object.keys(h).join(", ")}, not ${String(t)}.`);this.ws._changed()}get fitToWidth(){return this.ws._print.fit?.width}set fitToWidth(t){this._fit("width",t)}get fitToHeight(){return this.ws._print.fit?.height}set fitToHeight(t){this._fit("height",t)}_fit(t,e){const i={...this.ws._print.fit};e===void 0?Reflect.deleteProperty(i,t):i[t]=e,Object.keys(i).length===0?delete this.ws._print.fit:this.ws._print.fit=i,this.ws._changed()}}export class PageMargins{ws;constructor(t){return this.ws=t,s(this,"PageMargins",r)}_set(t,e){const i={...this.ws._print.margins};e===void 0?Reflect.deleteProperty(i,t):i[t]=e,this.ws._print.margins=i,this.ws._changed()}get left(){return this.ws._print.margins?.left}set left(t){this._set("left",t)}get right(){return this.ws._print.margins?.right}set right(t){this._set("right",t)}get top(){return this.ws._print.margins?.top}set top(t){this._set("top",t)}get bottom(){return this.ws._print.margins?.bottom}set bottom(t){this._set("bottom",t)}get header(){return this.ws._print.margins?.header}set header(t){this._set("header",t)}get footer(){return this.ws._print.margins?.footer}set footer(t){this._set("footer",t)}}export class HeaderFooterPart{ws;kind;side;constructor(t,e,i){return this.ws=t,this.kind=e,this.side=i,s(this,"_HeaderFooterPart",r)}get text(){return this.ws._print[this.kind]?.[this.side]}set text(t){const e={...this.ws._print[this.kind]};t===void 0?Reflect.deleteProperty(e,this.side):e[this.side]=t,this.ws._print[this.kind]=e,this.ws._changed()}}export class HeaderFooter{left;center;right;constructor(t,e){return this.left=new HeaderFooterPart(t,e,"left"),this.center=new HeaderFooterPart(t,e,"center"),this.right=new HeaderFooterPart(t,e,"right"),s(this,"_HeaderFooterItem",r)}}export class SheetProtection{read;write;constructor(t,e){return this.read=t,this.write=e,s(this,"SheetProtection",r)}get sheet(){return this.read()}set sheet(t){this.write(t)}enable(){this.write(!0)}disable(){this.write(!1)}}export class Comment{text;author;constructor(t,e){return this.text=t,this.author=e,s(this,"Comment",r)}_file(){return this.author===void 0?this.text:{text:this.text,author:this.author}}}export class Image{path;width;height;anchor;constructor(t){return this.path=t,this.width=void 0,this.height=void 0,this.anchor=void 0,s(this,"Image",r)}}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type SheetConditional, type SheetFile, type SheetFilesColumn, type SheetTable, type SheetWorksheet } from "@allyhub-next/formats";
|
|
1
|
+
import { type SheetNote, type SheetPicture, type SheetPrint, type SheetConditional, type SheetFile, type SheetFilesColumn, type SheetTable, type SheetWorksheet } from "@allyhub-next/formats";
|
|
2
|
+
import { Comment, HeaderFooter, PageMargins, PageSetup, SheetProtection, type Image } from "./page.js";
|
|
2
3
|
import { Calc } from "../calc/engine.js";
|
|
3
4
|
import { type ParsedCsv } from "../csv.js";
|
|
4
5
|
import type { SheetProblem } from "../file.js";
|
|
@@ -36,6 +37,12 @@ export declare class Cell {
|
|
|
36
37
|
get computed(): CellValue;
|
|
37
38
|
get data_type(): string;
|
|
38
39
|
get is_date(): boolean;
|
|
40
|
+
/** What it opens: an address on the web, or `#Sheet!A1`. */
|
|
41
|
+
get hyperlink(): string | undefined;
|
|
42
|
+
set hyperlink(to: string | undefined);
|
|
43
|
+
/** Its note: Excel's Note, openpyxl's Comment. */
|
|
44
|
+
get comment(): Comment | undefined;
|
|
45
|
+
set comment(note: Comment | undefined);
|
|
39
46
|
get number_format(): string;
|
|
40
47
|
set number_format(code: string);
|
|
41
48
|
private _setLook;
|
|
@@ -55,8 +62,12 @@ export declare class ColumnDimension {
|
|
|
55
62
|
_width: number | undefined;
|
|
56
63
|
_hidden: boolean | undefined;
|
|
57
64
|
_files: SheetFilesColumn | undefined;
|
|
65
|
+
_level: number | undefined;
|
|
58
66
|
_ws: Worksheet;
|
|
59
67
|
constructor(ws: Worksheet, letter: string);
|
|
68
|
+
/** How deep it is grouped, Excel's outline, 1 to 7. */
|
|
69
|
+
get outlineLevel(): number | undefined;
|
|
70
|
+
set outlineLevel(level: number | undefined);
|
|
60
71
|
/** Its cells name files, not an openpyxl field: true, or how they join and how tall a picture is. */
|
|
61
72
|
get files(): SheetFilesColumn | undefined;
|
|
62
73
|
set files(files: SheetFilesColumn | undefined);
|
|
@@ -70,8 +81,12 @@ export declare class RowDimension {
|
|
|
70
81
|
readonly index: number;
|
|
71
82
|
_height: number | undefined;
|
|
72
83
|
_hidden: boolean | undefined;
|
|
84
|
+
_level: number | undefined;
|
|
73
85
|
_ws: Worksheet;
|
|
74
86
|
constructor(ws: Worksheet, row: number);
|
|
87
|
+
/** How deep it is grouped, Excel's outline, 1 to 7. */
|
|
88
|
+
get outlineLevel(): number | undefined;
|
|
89
|
+
set outlineLevel(level: number | undefined);
|
|
75
90
|
/** In points, as openpyxl's; the file holds pixels. */
|
|
76
91
|
get height(): number | undefined;
|
|
77
92
|
set height(points: number | undefined);
|
|
@@ -149,6 +164,11 @@ export declare class Worksheet {
|
|
|
149
164
|
_filter: AutoFilter;
|
|
150
165
|
/** Its charts, openpyxl's private list. */
|
|
151
166
|
_charts: ChartBase[];
|
|
167
|
+
_print: SheetPrint;
|
|
168
|
+
_links: Record<string, string>;
|
|
169
|
+
_notes: Record<string, SheetNote>;
|
|
170
|
+
_pictures: SheetPicture[];
|
|
171
|
+
_protect: boolean;
|
|
152
172
|
constructor(parent: Workbook, title: string, model?: ModelSheet);
|
|
153
173
|
_spec(): SheetWorksheet | undefined;
|
|
154
174
|
/** What sheet.yaml says of its rules and filter. */
|
|
@@ -210,6 +230,25 @@ export declare class Worksheet {
|
|
|
210
230
|
add_data_validation(data_validation: DataValidation): void;
|
|
211
231
|
/** The sheet's AutoFilter: set its ref to have one. A table has its own. */
|
|
212
232
|
get auto_filter(): AutoFilter;
|
|
233
|
+
_changed(): void;
|
|
234
|
+
/** `print`, `links`, `notes`, `pictures` and `protect` as sheet.yaml holds them. */
|
|
235
|
+
_heldPage(spec: SheetWorksheet | undefined): void;
|
|
236
|
+
get page_setup(): PageSetup;
|
|
237
|
+
get page_margins(): PageMargins;
|
|
238
|
+
get oddHeader(): HeaderFooter;
|
|
239
|
+
get oddFooter(): HeaderFooter;
|
|
240
|
+
get protection(): SheetProtection;
|
|
241
|
+
/** The range that prints. */
|
|
242
|
+
get print_area(): string | undefined;
|
|
243
|
+
set print_area(area: string | undefined);
|
|
244
|
+
/** Rows repeated on every page, as `1:2`. */
|
|
245
|
+
get print_title_rows(): string | undefined;
|
|
246
|
+
set print_title_rows(rows: string | undefined);
|
|
247
|
+
/** Columns repeated on every page, as `A:B`. */
|
|
248
|
+
get print_title_cols(): string | undefined;
|
|
249
|
+
set print_title_cols(columns: string | undefined);
|
|
250
|
+
/** A picture over the cells, at a cell: its anchor unless it says. */
|
|
251
|
+
add_image(image: Image, anchor?: string): void;
|
|
213
252
|
/** A chart at a cell: its anchor unless it says. */
|
|
214
253
|
add_chart(chart: ChartBase, anchor?: string): void;
|
|
215
254
|
add_table(table: Table): void;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{SHEET_DATA as H,SHEET_FILE as z,strict as g}from"@allyhub-next/formats";import{columnIndex as E,columnLetter as N,cellName as C,contains as L,rangeName as x,readAddress as b,readArea as k}from"../address.js";import{Calc as U}from"../calc/engine.js";import{checkWorkbook as G}from"../check.js";import{readCsv as V,writeCsv as Y}from"../csv.js";import{GENERATED as q}from"../generated.js";import{moveFormula as Q,relativeKey as X}from"../formula/move.js";import{parseFormula as F}from"../formula/parse.js";import{printFormula as A}from"../formula/print.js";import{rewriteFormula as Z}from"../formula/rewrite.js";import{isDateCode as S}from"../format.js";import{patchCsv as ee}from"../patch.js";import{CellError as P,dateOfSerial as te,isoOfSerial as se,readTyped as M,serialOfDate as oe,writeTyped as ne}from"../values.js";import{FormulaCell as re,readWorkbook as B,validName as W}from"../workbook.js";import{restructure as ie,tableShape as le}from"../structure.js";import{patchYaml as ae}from"../write.js";import{anchorOf as he,chartOfSpec as fe}from"./charts.js";import{HINT as w}from"./hint.js";import{rectangles as T}from"./rectangles.js";import{AutoFilter as I,ConditionalFormattingList as ce,DataValidationList as ue,validationOf as _e,validationSpec as de}from"./rules.js";import{alignmentLook as me,alignmentOf as pe,borderLook as we,borderOf as ge,fillLook as ke,fillOf as ye,fontLook as be,fontOf as ve}from"./styles.js";const K=()=>process.getBuiltinModule("node:fs"),$=(...l)=>process.getBuiltinModule("node:path").join(...l);export const BLOCK_CELLS=100;const xe=l=>Math.round(l*7+5),Ee=l=>(l-5)/7,Se=l=>l*4/3,$e=l=>l*3/4;function Ce(l,e){const t={},s=l,o=e;for(const n of new Set([...Object.keys(s),...Object.keys(o)])){const r=o[n];JSON.stringify(r??!1)!==JSON.stringify(s[n]??!1)&&(t[n]=r??!1)}return t}const p=l=>Object.keys(l).length===0,y=(l,e)=>{if(!Number.isInteger(l)||l<1)throw new RangeError(`A ${e} is a whole number from 1: ${String(l)}.`);return l},j=(l,e)=>Object.fromEntries(Object.entries(l).filter(([t])=>t!==e));export class Cell{row;column;_ws;_value;_formula=void 0;_look;_changed=!1;_styled=!1;_fresh=!1;constructor(e,t,s){this._ws=e,this.row=t,this.column=s;const o=t-1,n=s-1,r=e._model?.at(o,n);return this._value=null,r instanceof re?this._formula=r.text:r!==void 0&&(this._value=r),this._look=e._model?.lookAt(o,n)??{},this._fresh=r===void 0,g(this,"Cell",w)}get parent(){return this._ws}get coordinate(){return C({row:this.row-1,col:this.column-1})}get column_letter(){return N(this.column-1)}get col_idx(){return this.column}get value(){return this._ws.parent.data_only?this.computed:this._formula!==void 0?this._formula:this._shown(this._value)}set value(e){if(e===void 0)throw new TypeError(`${this.coordinate}: a value is not undefined.`);if(this._formula=void 0,this._changed=!0,this._ws.parent._pending=!0,e instanceof Date){if(Number.isNaN(e.getTime()))throw new TypeError(`${this.coordinate}: the date is not valid.`);this._value=oe(e),S(this._look.format)||(this._look={...this._look,format:Number.isInteger(this._value)?"yyyy-mm-dd":"yyyy-mm-dd hh:mm"});return}if(typeof e=="string"&&e.length>1&&e.startsWith("=")){this._formula=e,this._value=null;return}this._value=e}_shown(e){return typeof e=="number"&&S(this._look.format)?te(e)??e:e instanceof P?e.code:e}get computed(){const{calc:e,model:t}=this._ws.parent._computed(),s=t.sheet(this._ws.title);return s?this._shown(e.value(s,this.row-1,this.column-1)):null}get data_type(){if(this._formula!==void 0)return"f";const e=this._value;return e===null?"n":typeof e=="number"?S(this._look.format)?"d":"n":typeof e=="boolean"?"b":e instanceof P?"e":"s"}get is_date(){return this.data_type==="d"}get number_format(){return this._look.format??"General"}set number_format(e){this._setLook({format:e})}_setLook(e){this._look={...this._look,...e},this._styled=!0,this._ws.parent._pending=!0}get font(){return ve(this._look)}set font(e){this._setLook(be(e))}get fill(){return ye(this._look)}set fill(e){this._setLook(ke(e))}get border(){return ge(this._look)}set border(e){this._setLook(we(e))}get alignment(){return pe(this._look)}set alignment(e){this._setLook(me(e))}get has_style(){return!p(this._look)}offset(e=0,t=0){return this._ws.cell(this.row+e,this.column+t)}}export class ColumnDimension{index;_width;_hidden;_files;_ws;constructor(e,t){this._ws=e,this.index=t;const s=e._spec()?.columns?.[t];return this._width=s?.width,this._hidden=s?.hidden,this._files=s?.files,g(this,"ColumnDimension",w)}get files(){return this._files}set files(e){this._files=e,this._ws._dimensions=!0}get width(){return this._width===void 0?void 0:Ee(this._width)}set width(e){this._width=e===void 0?void 0:xe(e),this._ws._dimensions=!0}get hidden(){return this._hidden??!1}set hidden(e){this._hidden=e,this._ws._dimensions=!0}}export class RowDimension{index;_height;_hidden;_ws;constructor(e,t){this._ws=e,this.index=t;const s=e._spec()?.rows?.[String(t)];return this._height=s?.height,this._hidden=s?.hidden,g(this,"RowDimension",w)}get height(){return this._height===void 0?void 0:$e(this._height)}set height(e){this._height=e===void 0?void 0:Se(e),this._ws._dimensions=!0}get hidden(){return this._hidden??!1}set hidden(e){this._hidden=e,this._ws._dimensions=!0}}export class Table{displayName;ref;key;_spec;autoFilter;constructor(e){for(const t of Object.keys(e))if(!["displayName","ref","key"].includes(t))throw new TypeError(`Table takes displayName, ref and key; it has no ${t}. ${w}`);if(!W(e.displayName))throw new TypeError(`${e.displayName} cannot be a table's name.`);if(!k(e.ref))throw new TypeError(`${e.ref} is not a range.`);return this.displayName=e.displayName,this.ref=e.ref,this.key=e.key,this.autoFilter=new I(e.ref,()=>{}),g(this,"Table",w)}get name(){return this.displayName}}export class TableList{_items=new Map;constructor(){return g(this,"TableList",w,{key:e=>this._items.get(e)})}add(e){this._items.set(e.name,e)}get(e){return this._items.get(e)}keys(){return[...this._items.keys()]}values(){return[...this._items.values()]}items(){return[...this._items.entries()]}pop(e){const t=this._items.get(e);return this._items.delete(e),t}}export class DefinedName{name;attr_text;constructor(e,t){if(!W(e))throw new TypeError(`${e} cannot be a name.`);return this.name=e,this.attr_text=t.attr_text.replace(/^=/u,""),g(this,"DefinedName",w)}get value(){return this.attr_text}set value(e){this.attr_text=e.replace(/^=/u,"")}}export class DefinedNameDict{_items=new Map;constructor(){return g(this,"DefinedNameDict",w,{key:e=>this._items.get(e),setKey:(e,t)=>t instanceof DefinedName?(this._items.set(e,t),!0):!1})}add(e){this._items.set(e.name,e)}get(e){return this._items.get(e)}keys(){return[...this._items.keys()]}values(){return[...this._items.values()]}items(){return[...this._items.entries()]}pop(e){const t=this._items.get(e);return this._items.delete(e),t}}const v=l=>{if(l._formula!==void 0)return l._formula;const e=l._value;return typeof e=="number"&&S(l._look.format)?se(e):ne(e)};function J(l){if(l._formula!==void 0)return l._formula;const e=l._value;return e===null?null:typeof e=="number"&&!S(l._look.format)||typeof e=="boolean"?e:v(l)}const Te=l=>l.toLowerCase().replace(/[^\p{L}\p{N}]+/gu,"-").replace(/^-+|-+$/gu,"")||"rows";export class Worksheet{_parent;_title;_was;_model;_cells=new Map;_columns=new Map;_rows=new Map;_tables=new TableList;_freeze;_merges=[];_state="visible";_dimensions=!1;_lastRow=0;_rules=[];_validations=[];_filter;_charts=[];constructor(e,t,s){if(this._parent=e,this._title=t,this._filter=new I(void 0,()=>{this._parent._pending=!0}),s){this._model=s,this._was=t,this._freeze=s.spec.freeze,this._merges=[...s.spec.merges??[]],this._state=s.spec.hidden===!0?"hidden":"visible",this._lastRow=(s.used?.bottom??-1)+1,this._heldRules(s.spec);for(const o of s.tables){const n=new Table({displayName:o.name,ref:x(o.area),...o.spec.key===void 0?{}:{key:o.spec.key}});n._spec=o.spec;const{filter:r}=o.spec;if(r)for(const[a,f]of Object.entries(r.columns)){const u=o.column(a);u&&n.autoFilter._columns.set(u.index,f)}this._tables.add(n)}}return g(this,"Worksheet",w,{index:o=>this._rowCells(o),key:o=>this._at(o),setKey:(o,n)=>{const r=b(o);return r?(this.cell(r.row+1,r.col+1).value=n,!0):!1}})}_spec(){return this._parent._file.sheets.find(e=>e.name===(this._was??this._title))}_heldRules(e){this._rules=[...e?.conditional??[]],this._validations=(e?.validations??[]).map(_e),this._charts=(e?.charts??[]).map(fe),this._filter.ref=e?.filter?.range,this._filter._columns.clear();const t=e?.filter?k(e.filter.range):void 0;for(const[s,o]of Object.entries(e?.filter?.columns??{})){const n=E(s);t&&n!==void 0&&this._filter._columns.set(n-t.left,o)}}_at(e){const t=b(e);if(t)return this.cell(t.row+1,t.col+1);const s=k(e);if(s)return this._area(s);const o=E(e);if(o!==void 0){const n=[];for(let r=1;r<=this.max_row;r++)n.push(this.cell(r,o+1));return n}}_rowCells(e){const t=[];for(let s=1;s<=this.max_column;s++)t.push(this.cell(e,s));return t}_area(e){const t=[];for(let s=e.top;s<=e.bottom;s++){const o=[];for(let n=e.left;n<=e.right;n++)o.push(this.cell(s+1,n+1));t.push(o)}return t}get parent(){return this._parent}get title(){return this._title}set title(e){const t=this._title;e!==t&&this._parent._renameSheet(this,t,e)}get sheet_state(){return this._state}set sheet_state(e){this._state=e}cell(e,t,s){if(e<1||t<1)throw new RangeError(`Row and column values must be at least 1: ${String(e)}, ${String(t)}.`);const o=(e-1)*16384+t-1;let n=this._cells.get(o);return n||(n=new Cell(this,e,t),this._cells.set(o,n)),s!==void 0&&(n.value=s),e>this._lastRow&&(this._lastRow=e),n}append(e){const t=this._lastRow+1,s=(o,n)=>{n!=null&&this.cell(t,o,n)};if(Array.isArray(e))e.forEach((o,n)=>{s(n+1,o)});else for(const[o,n]of Object.entries(e)){const r=/^\d+$/u.test(o)?Number(o)-1:E(o);if(r===void 0)throw new TypeError(`${o} is not a column.`);s(r+1,n)}this._lastRow=t}get max_row(){return Math.max(1,this._lastRow)}get max_column(){let e=this._model?.columnsUsed??0;for(const t of this._cells.values())(t._value!==null||t._formula!==void 0)&&t.column>e&&(e=t.column);return Math.max(1,e)}min_row=1;min_column=1;get dimensions(){return x({top:0,left:0,bottom:this.max_row-1,right:this.max_column-1})}iter_rows(e={}){const t=this._area({top:(e.min_row??1)-1,left:(e.min_col??1)-1,bottom:(e.max_row??this.max_row)-1,right:(e.max_col??this.max_column)-1});return e.values_only===!0?t.map(s=>s.map(o=>o.value)):t}iter_cols(e={}){const t=this.iter_rows(e);return(t[0]??[]).map((o,n)=>t.map(r=>r[n]))}get rows(){return this.iter_rows()}get columns(){return this.iter_cols()}get values(){return this.iter_rows({values_only:!0})}insert_rows(e,t=1){this._parent._restructure({op:"insert-rows",sheet:this._title,at:y(e,"row")-1,count:y(t,"amount")})}delete_rows(e,t=1){this._parent._restructure({op:"delete-rows",sheet:this._title,at:y(e,"row")-1,count:y(t,"amount")})}insert_cols(e,t=1){this._parent._restructure({op:"insert-columns",sheet:this._title,at:y(e,"column")-1,count:y(t,"amount")})}delete_cols(e,t=1){this._parent._restructure({op:"delete-columns",sheet:this._title,at:y(e,"column")-1,count:y(t,"amount")})}merge_cells(e){if(!k(e))throw new TypeError(`${e} is not a range.`);this._merges.includes(e)||this._merges.push(e),this._parent._pending=!0}unmerge_cells(e){this._merges=this._merges.filter(t=>t!==e),this._parent._pending=!0}get merged_cells(){return[...this._merges]}get freeze_panes(){return this._freeze}set freeze_panes(e){const t=e instanceof Cell?e.coordinate:e;if(t!==void 0&&!b(t))throw new TypeError(`${t} is not a cell.`);this._freeze=t,this._parent._pending=!0}get column_dimensions(){return new Proxy({},{get:(e,t)=>{if(typeof t!="string")return;const s=t.toUpperCase();if(E(s)===void 0)throw new TypeError(`${t} is not a column.`);let o=this._columns.get(s);return o||(o=new ColumnDimension(this,s),this._columns.set(s,o)),o}})}get row_dimensions(){return new Proxy({},{get:(e,t)=>{if(typeof t!="string"||!/^[1-9]\d*$/u.test(t))throw new TypeError(`${String(t)} is not a row.`);const s=Number(t);let o=this._rows.get(s);return o||(o=new RowDimension(this,s),this._rows.set(s,o)),o}})}get tables(){return this._tables}get conditional_formatting(){return new ce(this._rules,()=>{this._parent._pending=!0})}get data_validations(){return new ue(this._validations,()=>{this._parent._pending=!0})}add_data_validation(e){this._validations.push(e),this._parent._pending=!0}get auto_filter(){return this._filter}add_chart(e,t){e.anchor=he(t)??e.anchor,this._charts.push(e),this._parent._pending=!0}add_table(e){if(this._parent._tableNamed(e.name))throw new Error(`There is already a table named ${e.name}.`);this._tables.add(e),this._parent._pending=!0}}export class Workbook{worksheets=[];defined_names=new DefinedNameDict;data_only;title;path;block_cells=BLOCK_CELLS;_file={sheets:[]};_text="";_disk={text:"",csv:new Map};_csv=new Map;_model;_names=new Map;_active=0;_pending=!1;_making=!1;_calc=void 0;constructor(e={}){this.data_only=e.data_only??!1;const t=g(this,"Workbook",w,{key:s=>this.worksheets.find(o=>o.title===s),index:s=>this.worksheets[s]});return t.worksheets=[new Worksheet(t,"Sheet")],t}static open(e,t={}){const s=new Workbook(t);return s.path=e,s._read(e),s}_read(e){const{readFileSync:t}=K(),s=t($(e,z),"utf8"),o=new Map,n=r=>{try{const a=t($(e,r),"utf8");return o.set(r,a),a}catch{return}};this._load(s,n);for(const[r,a]of o)this._keepCsv(r,a);this._disk={text:s,csv:o}}_keepCsv(e,t){const s=V(t);this._csv.set(e,{parsed:s,rows:s.records.map(o=>o.end===o.start?[]:[...o.fields])})}_load(e,t){const{workbook:s,problems:o}=B({text:e,read:t});if(!s)throw new Error(`sheet.yaml cannot be opened: ${o.map(n=>n.message).join("; ")}`);this._text=e,this._file=structuredClone(s.file),this._model=s,this.title=s.title,this.worksheets=s.sheets.map(n=>new Worksheet(this,n.name,n));for(const n of s.names.values()){if(n.source.path?.[0]!=="names")continue;const r=n.formula?n.formula.text:n.value??null;this._names.set(n.name,r),this.defined_names.add(new DefinedName(n.name,{attr_text:String(r)}))}}get active(){const e=this.worksheets[this._active]??this.worksheets[0];if(!e)throw new Error("The workbook has no sheets.");return e}set active(e){this._active=this.worksheets.indexOf(e)}get sheetnames(){return this.worksheets.map(e=>e.title)}get_sheet_by_name(e){return this.worksheets.find(t=>t.title===e)}index(e){return this.worksheets.indexOf(e)}create_sheet(e,t){let s=e??"Sheet";for(let n=1;this.worksheets.some(r=>r.title===s);n++)s=`${e??"Sheet"}${String(n)}`;const o=new Worksheet(this,s);return this.worksheets.splice(t??this.worksheets.length,0,o),this._pending=!0,o}remove(e){this.worksheets=this.worksheets.filter(t=>t!==e),this._pending=!0}move_sheet(e,t=0){const s=this.worksheets.indexOf(e);this.worksheets.splice(s,1),this.worksheets.splice(s+t,0,e),this._pending=!0}_tableNamed(e){for(const t of this.worksheets){const s=t._tables.get(e);if(s)return s}}_renameSheet(e,t,s){if(this.worksheets.some(n=>n!==e&&n.title===s))throw new Error(`There is already a sheet named ${s}.`);this._apply(),this._rewrite({op:"rename-sheet",from:t,to:s}),e._title=s,e._was=s;const o=this._file.sheets.find(n=>n.name===t);o&&(o.name=s),this._apply()}_restructure(e){this._apply();const t=ie({file:this._file,rows:new Map([...this._csv].map(([o,n])=>[o,n.rows]))},e);if(t.refused!==void 0)throw new Error(t.refused==="table-header"?"A table's header row is not deleted: delete the table's rows, or all of it.":"That sheet is not there.");this._file=t.file;for(const[o,n]of t.rows){const r=this._csv.get(o);r&&(r.rows=n.map(a=>[...a]))}for(const o of this.worksheets){const n=this._file.sheets.find(r=>r.name===o._title);o._cells.clear(),o._columns.clear(),o._rows.clear(),o._merges=[...n?.merges??[]],o._freeze=n?.freeze,o._heldRules(n)}const s=this._build();this._rebase(s.text,s.files);for(const o of this.worksheets){const n=this._model?.sheet(o._title);if(n){o._lastRow=(n.used?.bottom??-1)+1;for(const r of n.tables){const a=o._tables.get(r.name);a&&(a.ref=x(r.area))}}}}_rewrite(e){const t=(o,n)=>{const r=F(o);if(!r.ok)return o;const a=Z(r.node,e,n);return a===r.node?o:A(a)},{_file:s}=this;if(s.names){for(const[o,n]of Object.entries(s.names))if(typeof n=="string"&&n.startsWith("=")){const r=t(n,s.sheets[0]?.name??"");s.names[o]=r,this._names.set(o,r);const a=this.defined_names.get(o);a&&(a.attr_text=r.slice(1))}}for(const o of s.checks??[])o.formula=t(o.formula,s.sheets[0]?.name??"");for(const o of s.sheets){for(const[n,r]of Object.entries(o.cells??{}))typeof r=="string"&&r.startsWith("=")?o.cells[n]=t(r,o.name):r!==null&&typeof r=="object"&&r.formula!==void 0&&(r.formula=t(r.formula,o.name));for(const n of o.tables??[]){for(const r of Object.values(n.columns??{}))r.formula!==void 0&&(r.formula=t(r.formula,o.name));this._rewriteCsv(n.rows,o.name,t)}for(const n of o.blocks??[])this._rewriteCsv(n.rows,o.name,t)}}_rewriteCsv(e,t,s){const o=this._csv.get(e);o&&(o.rows=o.rows.map(n=>n.map(r=>M(r).formula!==void 0?s(r,t):r)))}_sheetEntry(e){const t=e._was??e._title;let s=this._file.sheets.find(o=>o.name===t);return s||(s={name:e._title},this._file.sheets.push(s)),s.name=e._title,s}_dataPath(e){const t=`${H}/${Te(e)}`;let s=`${t}.csv`;const o=n=>this._csv.has(n)||this._file.sheets.some(r=>r.tables?.some(a=>a.rows===n)??r.blocks?.some(a=>a.rows===n));for(let n=2;o(s);n++)s=`${t}-${String(n)}.csv`;return s}_writeNewTable(e,t,s){const o=k(s.ref);if(!o)throw new Error(`${s.ref} is not a range.`);const n=[];for(let i=o.left;i<=o.right;i++){const h=e.cell(o.top+1,i+1).value;if(h===null||h==="")throw new Error(`Table ${s.name}'s header has no name at ${C({row:o.top,col:i})}.`);n.push(String(h))}const r={},a=[];n.forEach((i,h)=>{const c=o.left+h,d=this._columnFormula(e,o,c);d===void 0?a.push(h):r[i]={formula:d};const m=this._columnFormat(e,o,c);m!==void 0&&(r[i]={...r[i],format:m})}),this._columnsStyled(e,o);const f=[a.map(i=>n[i]??"")];for(let i=o.top+1;i<=o.bottom;i++)f.push(a.map(h=>v(e.cell(i+1,o.left+h+1))));t.cells&&(t.cells=Object.fromEntries(Object.entries(t.cells).filter(([i])=>{const h=b(i);return!h||!L(o,h.row,h.col)})));const u=this._dataPath(s.name);this._csv.set(u,{parsed:void 0,rows:f});const _={name:s.name,at:C({row:o.top,col:o.left}),rows:u,...s.key===void 0?{}:{key:s.key},...p(r)?{}:{columns:r}};(t.tables??=[]).push(_),s._spec=_}_columnsStyled(e,t){for(let s=t.left;s<=t.right;s++)for(let o=t.top+1;o<=t.bottom;o++){const n=e.cell(o+1,s+1),{format:r,...a}=this._ownLook(n);r!==void 0&&p(a)&&(n._styled=!1)}}_columnFormula(e,t,s){if(t.bottom<=t.top)return;const o=e.cell(t.top+2,s+1),n=D(o);if(n!==void 0){for(let r=t.top+2;r<=t.bottom;r++)if(D(e.cell(r+1,s+1))!==n)return;return o._formula}}_columnFormat(e,t,s){if(t.bottom<=t.top)return;const o=r=>this._ownLook(e.cell(r+1,s+1)).format,n=o(t.top+1);for(let r=t.top+2;r<=t.bottom;r++)if(o(r)!==n)return;return n}_held(e){const t=this._csv.get(e);if(!t)throw new Error(`${e} was not read.`);return t}_setCsvCell(e,t,s,o){const{rows:n}=this._held(e);for(;n.length<=t;)n.push([]);const r=n[t];if(r){for(;r.length<=s;)r.push("");r[s]=o}}_recordOf(e,t){let s=0;for(let o=0;o<t;){if(s+=1,s>=e.length)return s+t-o-1;e[s]?.length!==0&&(o+=1)}return s}_writeTableCell(e,t,s){const o=this._held(e.rows),n=o.rows[0]??[],r=s.column-1-t.left,a=this._recordOf(o.rows,s.row-1-t.top),f=Object.keys(e.columns??{}).filter(c=>!n.some(d=>d.trim().toLowerCase()===c.toLowerCase())),_=[...n.map(c=>c.trim()),...f][r];if(_===void 0)return;if(a===0){r<n.length&&(n[r]=v(s));return}const i=e.columns?.[_]?.formula;if(i!==void 0){const c=this._movedColumn(i,t,s);if(s._formula===c){const d=n.findIndex(m=>m.trim()===_);d>=0&&this._setCsvCell(e.rows,a,d,"");return}}let h=n.findIndex(c=>c.trim()===_);h<0&&(h=n.length,this._setCsvCell(e.rows,0,h,_)),this._setCsvCell(e.rows,a,h,v(s))}_movedColumn(e,t,s){const o=F(e);if(!o.ok)return e;const n=s.row-1-(t.top+1);return n===0?e:A(Q(o.node,n,0))}_apply(){this.title===void 0?delete this._file.title:this._file.title=this.title;const e=new Set(this.worksheets.map(s=>s._was??s._title));this._file.sheets=this._file.sheets.filter(s=>e.has(s.name));for(const s of this.worksheets)this._applySheet(s);this._file.sheets=this.worksheets.map(s=>this._sheetEntry(s)),this._applyNames();const t=this._build();this._rebase(t.text,t.files)}_applyNames(){const e={};for(const t of this.defined_names.values()){const s=M(t.attr_text),o=this._names.get(t.name);e[t.name]=o!==void 0&&String(o).replace(/^=/u,"")===t.attr_text?o:typeof s.value=="number"||typeof s.value=="boolean"?s.value:/^"[^"]*"$/u.test(t.attr_text)?t.attr_text.slice(1,-1):`=${t.attr_text}`}p(e)?delete this._file.names:this._file.names=e}_applySheet(e){const t=this._sheetEntry(e);e._freeze===void 0?delete t.freeze:t.freeze=e._freeze,e._merges.length===0?delete t.merges:t.merges=[...e._merges],e._state==="hidden"?t.hidden=!0:delete t.hidden,e._rules.length===0?delete t.conditional:t.conditional=[...e._rules],e._validations.length===0?delete t.validations:t.validations=e._validations.map(de),e._charts.length===0?delete t.charts:t.charts=e._charts.map(o=>o._spec(e._title)),this._applyFilter(e,t);const s=new Set(t.tables?.map(o=>o.name.toLowerCase()));for(const o of e._tables.values())s.has(o.name.toLowerCase())||this._writeNewTable(e,t,o);this._applyTableFilters(e,t),this._applyCells(e,t),this._applyDimensions(e,t),t.cells&&p(t.cells)&&delete t.cells,t.columns&&p(t.columns)&&delete t.columns,t.rows&&p(t.rows)&&delete t.rows,t.format?.length===0&&delete t.format,t.tables?.length===0&&delete t.tables,t.blocks?.length===0&&delete t.blocks}_applyFilter(e,t){const{ref:s,_columns:o}=e._filter;if(s===void 0){delete t.filter;return}const n=k(s);if(!n)throw new TypeError(`${s} is not a range.`);const r={};for(const[a,f]of o)r[N(n.left+a)]=f;t.filter={range:s,...p(r)?{}:{columns:r}}}_applyTableFilters(e,t){for(const s of t.tables??[]){const o=e._tables.get(s.name);if(!o||o.autoFilter._columns.size===0)continue;const n=this._csv.get(s.rows)?.rows??[],r=le(s,n)?.names??[],a={};for(const[f,u]of o.autoFilter._columns){const _=r[f];if(_===void 0)throw new RangeError(`Table ${s.name} has no column at ${String(f)}.`);a[_]=u}s.filter={columns:a}}}_applyDimensions(e,t){if(e._dimensions){for(const[s,o]of e._columns){const n={...t.columns?.[s]};o._width===void 0?delete n.width:n.width=o._width,o._hidden===void 0?delete n.hidden:n.hidden=o._hidden,o._files===void 0?delete n.files:n.files=o._files;const r=j(t.columns??{},s);t.columns=p(n)?r:{...r,[s]:n}}for(const[s,o]of e._rows){const n={...t.rows?.[String(s)]};o._height===void 0?delete n.height:n.height=o._height,o._hidden===void 0?delete n.hidden:n.hidden=o._hidden;const r=j(t.rows??{},String(s));t.rows=p(n)?r:{...r,[String(s)]:n}}e._dimensions=!1}}_applyCells(e,t){const s=(t.tables??[]).flatMap(r=>{const a=b(r.at),f=e._tables.get(r.name),u=f?k(f.ref):void 0;return a&&u?[{entry:r,area:u}]:[]}),o=(t.blocks??[]).flatMap(r=>{const a=e._model?.blocks.find(f=>f.file===r.rows);return a?[{entry:r,area:a.area}]:[]}),n=[];for(const r of e._cells.values()){if(!r._changed&&!r._styled)continue;const a=r.row-1,f=r.column-1,u=s.find(i=>L(i.area,a,f)),_=o.find(i=>L(i.area,a,f));u?(r._changed&&this._writeTableCell(u.entry,u.area,r),r._styled&&this._styleByFormat(t,r)):_?(r._changed&&this._setCsvCell(_.entry.rows,a-_.area.top,f-_.area.left,v(r)),r._styled&&this._styleByFormat(t,r)):r._fresh&&!e._model?.keys.has(a*16384+f)?n.push(r):this._writeLoose(e,t,r),r._changed=!1,r._styled=!1}this._consolidate(e,t,n),Oe(t)}_styleByFormat(e,t){(e.format??=[]).push({range:t.coordinate,...this._ownLook(t)})}_ownLook(e){const t=e._ws._model?.lookAt(e.row-1,e.column-1)??{},s=Ce(t,e._look);return s.format!==void 0&&e._formula===void 0&&M(v(e)).format===s.format&&delete s.format,s}_writeLoose(e,t,s){const o=s.coordinate,n=t.cells??={},r=J(s),a=this._ownLook(s),f=n[o],_={...f!==null&&typeof f=="object"?Object.fromEntries(Object.entries(f).filter(([c])=>c!=="value"&&c!=="formula"&&c!=="name")):{},...a},i=f!==null&&typeof f=="object"&&f.name!==void 0?{name:f.name}:{},h=e._model?.at(s.row-1,s.column-1)!==void 0;if(r===null&&p(_)&&!h){t.cells=j(n,o);return}n[o]=p(_)&&p(i)?r:{...typeof r=="string"&&r.startsWith("=")?{formula:r}:r===null?{}:{value:r},...i,..._}}_consolidate(e,t,s){const o=s.filter(i=>i._value!==null||i._formula!==void 0),n=new Map;for(const i of s){const h=this._ownLook(i);if(p(h))continue;const c=JSON.stringify(h),d=n.get(c);d?d.push(i):n.set(c,[i])}const r=new Map(o.map(i=>[`${String(i.row)}:${String(i.column)}`,i])),a=i=>r.get(`${String(i.row+1)}:${String(i.col+1)}`)??e.cell(i.row+1,i.col+1),f=new Map,u=[];for(const i of o){const h={row:i.row-1,col:i.column-1},c=i._formula===void 0?void 0:D(i);if(c===void 0){u.push(h);continue}const d=f.get(c);d?d.push(h):f.set(c,[h])}const _=t.cells??={};for(const i of f.values())for(const h of T(i))_[x(h)]=a({row:h.top,col:h.left})._formula??null;for(const i of T(u))if((i.bottom-i.top+1)*(i.right-i.left+1)>=this.block_cells){const c=[];for(let m=i.top;m<=i.bottom;m++){const R=[];for(let O=i.left;O<=i.right;O++)R.push(v(a({row:m,col:O})));c.push(R)}const d=this._dataPath(e._title);this._csv.set(d,{parsed:void 0,rows:c}),(t.blocks??=[]).push({at:C({row:i.top,col:i.left}),rows:d})}else for(let c=i.top;c<=i.bottom;c++)for(let d=i.left;d<=i.right;d++){const m=a({row:c,col:d});_[m.coordinate]=J(m)}for(const i of n.values()){const[h]=i;if(!h)continue;const c=this._ownLook(h),d=i.map(m=>({row:m.row-1,col:m.column-1}));for(const m of T(d))(t.format??=[]).push({range:x(m),...c})}}_build(){const e=new Map;for(const[t,s]of this._csv)e.set(t,s.parsed?ee(s.parsed,s.rows):Y(s.rows));return{text:ae(this._text,this._file),files:e}}_rebase(e,t){const{workbook:s,problems:o}=B({text:e,read:n=>t.get(n)});if(!s)throw new Error(`The workbook is not one: ${o.map(n=>n.message).join("; ")}`);this._text=e,this._file=structuredClone(s.file),this._model=s;for(const[n,r]of t)this._keepCsv(n,r);this._calc=void 0,this._pending=!1;for(const n of this.worksheets){n._was=n._title;const r=s.sheet(n._title);r&&(n._model=r);for(const a of n._cells.values())a._fresh=r?.at(a.row-1,a.column-1)===void 0}this._names=new Map;for(const n of s.names.values())n.source.path?.[0]==="names"&&this._names.set(n.name,n.formula?n.formula.text:n.value??null)}_computed(){const e=[...this.defined_names.values()];if((this._pending||e.length!==this._names.size||e.some(t=>String(this._names.get(t.name)).replace(/^=/u,"")!==t.attr_text))&&this._apply(),!this._calc){const t=this._model;if(!t)throw new Error("The workbook has no sheets.");this._calc={calc:new U(t).calculate(),model:t}}return this._calc}check(){this._apply();const{text:e,files:t}=this._build();return G({text:e,read:s=>t.get(s)}).problems}_generated(){if(this.worksheets.length===0)return this._applyNames(),{sheets:[],csv:{},...this._file.names?{names:this._file.names}:{}};this._apply();const e=structuredClone(this._file.sheets),t=o=>`${q}${o}`;for(const o of e){for(const n of o.tables??[])n.rows=t(n.rows);for(const n of o.blocks??[])n.rows=t(n.rows)}const s={};for(const[o,n]of this._build().files)s[t(o)]=n;return{sheets:e,csv:s,...this._file.names?{names:this._file.names}:{}}}save(e){if(this._making)throw new Error("sheet.ts makes sheets and saves nothing: what it adds to wb is what it makes.");const t=e??this.path;if(t===void 0)throw new TypeError("A new workbook is saved to a folder: wb.save('content/budget').");if(this.worksheets.length===0)throw new Error("A workbook has at least one sheet.");const{text:s,csv:o}=this._disk;this._apply();const n=new Set(this._file.sheets.flatMap(i=>[...(i.tables??[]).map(h=>h.rows),...(i.blocks??[]).map(h=>h.rows)])),r=[...this._csv.keys()].filter(i=>!n.has(i));for(const i of r)this._csv.delete(i);const{mkdirSync:a,rmSync:f,writeFileSync:u}=K(),_=process.getBuiltinModule("node:path");a(t,{recursive:!0}),(this._text!==s||e!==void 0)&&u($(t,z),this._text);for(const[i,h]of this._csv){const c=h.parsed?.source??"";if(e===void 0&&o.get(i)===c)continue;const d=$(t,i);a(_.dirname(d),{recursive:!0}),u(d,c)}if(e===void 0||t===this.path)for(const i of r)f($(t,i),{force:!0});this._disk={text:this._text,csv:new Map([...this._csv].map(([i,h])=>[i,h.parsed?.source??""]))},this.path=t}}function D(l){if(l._formula===void 0)return;const e=F(l._formula);if(e.ok)return X(e.node,l.row-1,l.column-1)}function Oe(l){const e=l.format;if(!e||e.length<2)return;const t=[],s=new Map;for(const o of e){const{range:n,...r}=o,a=b(n);if(!a){t.push(o);continue}const f=JSON.stringify(r),u=s.get(f);u?u.places.push(a):s.set(f,{look:r,places:[a]})}for(const{look:o,places:n}of s.values())for(const r of T(n))t.push({range:x(r),...o});l.format=t}export function load_workbook(l,e={}){return Workbook.open(l,e)}export const get_column_letter=l=>N(l-1);export function column_index_from_string(l){const e=E(l);if(e===void 0)throw new TypeError(`${l} is not a column.`);return e+1}export function coordinate_to_tuple(l){const e=b(l);if(!e)throw new TypeError(`${l} is not a cell.`);return[e.row+1,e.col+1]}export function range_boundaries(l){const e=k(l);if(!e)throw new TypeError(`${l} is not a range.`);return[e.left+1,e.top+1,e.right+1,e.bottom+1]}
|
|
2
|
+
import{SHEET_DATA as G,SHEET_FILE as P,strict as g}from"@allyhub-next/formats";import{Comment as z,HeaderFooter as A,PageMargins as V,PageSetup as Y,SheetProtection as q}from"./page.js";import{columnIndex as E,columnLetter as L,cellName as C,contains as N,rangeName as x,readAddress as y,readArea as k}from"../address.js";import{Calc as Q}from"../calc/engine.js";import{checkWorkbook as X}from"../check.js";import{readCsv as Z,writeCsv as ee}from"../csv.js";import{GENERATED as te}from"../generated.js";import{moveFormula as se,relativeKey as ne}from"../formula/move.js";import{parseFormula as F}from"../formula/parse.js";import{printFormula as B}from"../formula/print.js";import{rewriteFormula as oe}from"../formula/rewrite.js";import{isDateCode as S}from"../format.js";import{patchCsv as re}from"../patch.js";import{CellError as W,dateOfSerial as ie,isoOfSerial as le,readTyped as M,serialOfDate as ae,writeTyped as he}from"../values.js";import{FormulaCell as fe,readWorkbook as I,validName as H}from"../workbook.js";import{restructure as _e,tableShape as ce}from"../structure.js";import{patchYaml as ue}from"../write.js";import{anchorOf as de,chartOfSpec as me}from"./charts.js";import{HINT as w}from"./hint.js";import{rectangles as T}from"./rectangles.js";import{AutoFilter as K,ConditionalFormattingList as pe,DataValidationList as we,validationOf as ge,validationSpec as ke}from"./rules.js";import{alignmentLook as ye,alignmentOf as be,borderLook as ve,borderOf as xe,fillLook as Ee,fillOf as Se,fontLook as $e,fontOf as Ce}from"./styles.js";const J=()=>process.getBuiltinModule("node:fs"),$=(...l)=>process.getBuiltinModule("node:path").join(...l);export const BLOCK_CELLS=100;const Te=l=>Math.round(l*7+5),Oe=l=>(l-5)/7,Le=l=>l*4/3,Ne=l=>l*3/4;function Fe(l,e){const t={},s=l,n=e;for(const o of new Set([...Object.keys(s),...Object.keys(n)])){const r=n[o];JSON.stringify(r??!1)!==JSON.stringify(s[o]??!1)&&(t[o]=r??!1)}return t}const m=l=>Object.keys(l).length===0,b=(l,e)=>{if(!Number.isInteger(l)||l<1)throw new RangeError(`A ${e} is a whole number from 1: ${String(l)}.`);return l},j=(l,e)=>Object.fromEntries(Object.entries(l).filter(([t])=>t!==e));export class Cell{row;column;_ws;_value;_formula=void 0;_look;_changed=!1;_styled=!1;_fresh=!1;constructor(e,t,s){this._ws=e,this.row=t,this.column=s;const n=t-1,o=s-1,r=e._model?.at(n,o);return this._value=null,r instanceof fe?this._formula=r.text:r!==void 0&&(this._value=r),this._look=e._model?.lookAt(n,o)??{},this._fresh=r===void 0,g(this,"Cell",w)}get parent(){return this._ws}get coordinate(){return C({row:this.row-1,col:this.column-1})}get column_letter(){return L(this.column-1)}get col_idx(){return this.column}get value(){return this._ws.parent.data_only?this.computed:this._formula!==void 0?this._formula:this._shown(this._value)}set value(e){if(e===void 0)throw new TypeError(`${this.coordinate}: a value is not undefined.`);if(this._formula=void 0,this._changed=!0,this._ws.parent._pending=!0,e instanceof Date){if(Number.isNaN(e.getTime()))throw new TypeError(`${this.coordinate}: the date is not valid.`);this._value=ae(e),S(this._look.format)||(this._look={...this._look,format:Number.isInteger(this._value)?"yyyy-mm-dd":"yyyy-mm-dd hh:mm"});return}if(typeof e=="string"&&e.length>1&&e.startsWith("=")){this._formula=e,this._value=null;return}this._value=e}_shown(e){return typeof e=="number"&&S(this._look.format)?ie(e)??e:e instanceof W?e.code:e}get computed(){const{calc:e,model:t}=this._ws.parent._computed(),s=t.sheet(this._ws.title);return s?this._shown(e.value(s,this.row-1,this.column-1)):null}get data_type(){if(this._formula!==void 0)return"f";const e=this._value;return e===null?"n":typeof e=="number"?S(this._look.format)?"d":"n":typeof e=="boolean"?"b":e instanceof W?"e":"s"}get is_date(){return this.data_type==="d"}get hyperlink(){return this._ws._links[this.coordinate]}set hyperlink(e){e===void 0?Reflect.deleteProperty(this._ws._links,this.coordinate):this._ws._links[this.coordinate]=e,this._ws._changed()}get comment(){const e=this._ws._notes[this.coordinate];if(e!==void 0)return typeof e=="string"?new z(e):new z(e.text,e.author)}set comment(e){e===void 0?Reflect.deleteProperty(this._ws._notes,this.coordinate):this._ws._notes[this.coordinate]=e._file(),this._ws._changed()}get number_format(){return this._look.format??"General"}set number_format(e){this._setLook({format:e})}_setLook(e){this._look={...this._look,...e},this._styled=!0,this._ws.parent._pending=!0}get font(){return Ce(this._look)}set font(e){this._setLook($e(e))}get fill(){return Se(this._look)}set fill(e){this._setLook(Ee(e))}get border(){return xe(this._look)}set border(e){this._setLook(ve(e))}get alignment(){return be(this._look)}set alignment(e){this._setLook(ye(e))}get has_style(){return!m(this._look)}offset(e=0,t=0){return this._ws.cell(this.row+e,this.column+t)}}export class ColumnDimension{index;_width;_hidden;_files;_level;_ws;constructor(e,t){this._ws=e,this.index=t;const s=e._spec()?.columns?.[t];return this._level=s?.level,this._width=s?.width,this._hidden=s?.hidden,this._files=s?.files,g(this,"ColumnDimension",w)}get outlineLevel(){return this._level}set outlineLevel(e){this._level=e,this._ws._dimensions=!0}get files(){return this._files}set files(e){this._files=e,this._ws._dimensions=!0}get width(){return this._width===void 0?void 0:Oe(this._width)}set width(e){this._width=e===void 0?void 0:Te(e),this._ws._dimensions=!0}get hidden(){return this._hidden??!1}set hidden(e){this._hidden=e,this._ws._dimensions=!0}}export class RowDimension{index;_height;_hidden;_level;_ws;constructor(e,t){this._ws=e,this.index=t;const s=e._spec()?.rows?.[String(t)];return this._level=s?.level,this._height=s?.height,this._hidden=s?.hidden,g(this,"RowDimension",w)}get outlineLevel(){return this._level}set outlineLevel(e){this._level=e,this._ws._dimensions=!0}get height(){return this._height===void 0?void 0:Ne(this._height)}set height(e){this._height=e===void 0?void 0:Le(e),this._ws._dimensions=!0}get hidden(){return this._hidden??!1}set hidden(e){this._hidden=e,this._ws._dimensions=!0}}export class Table{displayName;ref;key;_spec;autoFilter;constructor(e){for(const t of Object.keys(e))if(!["displayName","ref","key"].includes(t))throw new TypeError(`Table takes displayName, ref and key; it has no ${t}. ${w}`);if(!H(e.displayName))throw new TypeError(`${e.displayName} cannot be a table's name.`);if(!k(e.ref))throw new TypeError(`${e.ref} is not a range.`);return this.displayName=e.displayName,this.ref=e.ref,this.key=e.key,this.autoFilter=new K(e.ref,()=>{}),g(this,"Table",w)}get name(){return this.displayName}}export class TableList{_items=new Map;constructor(){return g(this,"TableList",w,{key:e=>this._items.get(e)})}add(e){this._items.set(e.name,e)}get(e){return this._items.get(e)}keys(){return[...this._items.keys()]}values(){return[...this._items.values()]}items(){return[...this._items.entries()]}pop(e){const t=this._items.get(e);return this._items.delete(e),t}}export class DefinedName{name;attr_text;constructor(e,t){if(!H(e))throw new TypeError(`${e} cannot be a name.`);return this.name=e,this.attr_text=t.attr_text.replace(/^=/u,""),g(this,"DefinedName",w)}get value(){return this.attr_text}set value(e){this.attr_text=e.replace(/^=/u,"")}}export class DefinedNameDict{_items=new Map;constructor(){return g(this,"DefinedNameDict",w,{key:e=>this._items.get(e),setKey:(e,t)=>t instanceof DefinedName?(this._items.set(e,t),!0):!1})}add(e){this._items.set(e.name,e)}get(e){return this._items.get(e)}keys(){return[...this._items.keys()]}values(){return[...this._items.values()]}items(){return[...this._items.entries()]}pop(e){const t=this._items.get(e);return this._items.delete(e),t}}const v=l=>{if(l._formula!==void 0)return l._formula;const e=l._value;return typeof e=="number"&&S(l._look.format)?le(e):he(e)};function U(l){if(l._formula!==void 0)return l._formula;const e=l._value;return e===null?null:typeof e=="number"&&!S(l._look.format)||typeof e=="boolean"?e:v(l)}const Me=l=>l.toLowerCase().replace(/[^\p{L}\p{N}]+/gu,"-").replace(/^-+|-+$/gu,"")||"rows";export class Worksheet{_parent;_title;_was;_model;_cells=new Map;_columns=new Map;_rows=new Map;_tables=new TableList;_freeze;_merges=[];_state="visible";_dimensions=!1;_lastRow=0;_rules=[];_validations=[];_filter;_charts=[];_print={};_links={};_notes={};_pictures=[];_protect=!1;constructor(e,t,s){if(this._parent=e,this._title=t,this._filter=new K(void 0,()=>{this._parent._pending=!0}),s){this._model=s,this._was=t,this._freeze=s.spec.freeze,this._heldPage(s.spec),this._merges=[...s.spec.merges??[]],this._state=s.spec.hidden===!0?"hidden":"visible",this._lastRow=(s.used?.bottom??-1)+1,this._heldRules(s.spec);for(const n of s.tables){const o=new Table({displayName:n.name,ref:x(n.area),...n.spec.key===void 0?{}:{key:n.spec.key}});o._spec=n.spec;const{filter:r}=n.spec;if(r)for(const[a,f]of Object.entries(r.columns)){const c=n.column(a);c&&o.autoFilter._columns.set(c.index,f)}this._tables.add(o)}}return g(this,"Worksheet",w,{index:n=>this._rowCells(n),key:n=>this._at(n),setKey:(n,o)=>{const r=y(n);return r?(this.cell(r.row+1,r.col+1).value=o,!0):!1}})}_spec(){return this._parent._file.sheets.find(e=>e.name===(this._was??this._title))}_heldRules(e){this._rules=[...e?.conditional??[]],this._validations=(e?.validations??[]).map(ge),this._charts=(e?.charts??[]).map(me),this._filter.ref=e?.filter?.range,this._filter._columns.clear();const t=e?.filter?k(e.filter.range):void 0;for(const[s,n]of Object.entries(e?.filter?.columns??{})){const o=E(s);t&&o!==void 0&&this._filter._columns.set(o-t.left,n)}}_at(e){const t=y(e);if(t)return this.cell(t.row+1,t.col+1);const s=k(e);if(s)return this._area(s);const n=E(e);if(n!==void 0){const o=[];for(let r=1;r<=this.max_row;r++)o.push(this.cell(r,n+1));return o}}_rowCells(e){const t=[];for(let s=1;s<=this.max_column;s++)t.push(this.cell(e,s));return t}_area(e){const t=[];for(let s=e.top;s<=e.bottom;s++){const n=[];for(let o=e.left;o<=e.right;o++)n.push(this.cell(s+1,o+1));t.push(n)}return t}get parent(){return this._parent}get title(){return this._title}set title(e){const t=this._title;e!==t&&this._parent._renameSheet(this,t,e)}get sheet_state(){return this._state}set sheet_state(e){this._state=e}cell(e,t,s){if(e<1||t<1)throw new RangeError(`Row and column values must be at least 1: ${String(e)}, ${String(t)}.`);const n=(e-1)*16384+t-1;let o=this._cells.get(n);return o||(o=new Cell(this,e,t),this._cells.set(n,o)),s!==void 0&&(o.value=s),e>this._lastRow&&(this._lastRow=e),o}append(e){const t=this._lastRow+1,s=(n,o)=>{o!=null&&this.cell(t,n,o)};if(Array.isArray(e))e.forEach((n,o)=>{s(o+1,n)});else for(const[n,o]of Object.entries(e)){const r=/^\d+$/u.test(n)?Number(n)-1:E(n);if(r===void 0)throw new TypeError(`${n} is not a column.`);s(r+1,o)}this._lastRow=t}get max_row(){return Math.max(1,this._lastRow)}get max_column(){let e=this._model?.columnsUsed??0;for(const t of this._cells.values())(t._value!==null||t._formula!==void 0)&&t.column>e&&(e=t.column);return Math.max(1,e)}min_row=1;min_column=1;get dimensions(){return x({top:0,left:0,bottom:this.max_row-1,right:this.max_column-1})}iter_rows(e={}){const t=this._area({top:(e.min_row??1)-1,left:(e.min_col??1)-1,bottom:(e.max_row??this.max_row)-1,right:(e.max_col??this.max_column)-1});return e.values_only===!0?t.map(s=>s.map(n=>n.value)):t}iter_cols(e={}){const t=this.iter_rows(e);return(t[0]??[]).map((n,o)=>t.map(r=>r[o]))}get rows(){return this.iter_rows()}get columns(){return this.iter_cols()}get values(){return this.iter_rows({values_only:!0})}insert_rows(e,t=1){this._parent._restructure({op:"insert-rows",sheet:this._title,at:b(e,"row")-1,count:b(t,"amount")})}delete_rows(e,t=1){this._parent._restructure({op:"delete-rows",sheet:this._title,at:b(e,"row")-1,count:b(t,"amount")})}insert_cols(e,t=1){this._parent._restructure({op:"insert-columns",sheet:this._title,at:b(e,"column")-1,count:b(t,"amount")})}delete_cols(e,t=1){this._parent._restructure({op:"delete-columns",sheet:this._title,at:b(e,"column")-1,count:b(t,"amount")})}merge_cells(e){if(!k(e))throw new TypeError(`${e} is not a range.`);this._merges.includes(e)||this._merges.push(e),this._parent._pending=!0}unmerge_cells(e){this._merges=this._merges.filter(t=>t!==e),this._parent._pending=!0}get merged_cells(){return[...this._merges]}get freeze_panes(){return this._freeze}set freeze_panes(e){const t=e instanceof Cell?e.coordinate:e;if(t!==void 0&&!y(t))throw new TypeError(`${t} is not a cell.`);this._freeze=t,this._parent._pending=!0}get column_dimensions(){return new Proxy({},{get:(e,t)=>{if(typeof t!="string")return;const s=t.toUpperCase();if(E(s)===void 0)throw new TypeError(`${t} is not a column.`);let n=this._columns.get(s);return n||(n=new ColumnDimension(this,s),this._columns.set(s,n)),n}})}get row_dimensions(){return new Proxy({},{get:(e,t)=>{if(typeof t!="string"||!/^[1-9]\d*$/u.test(t))throw new TypeError(`${String(t)} is not a row.`);const s=Number(t);let n=this._rows.get(s);return n||(n=new RowDimension(this,s),this._rows.set(s,n)),n}})}get tables(){return this._tables}get conditional_formatting(){return new pe(this._rules,()=>{this._parent._pending=!0})}get data_validations(){return new we(this._validations,()=>{this._parent._pending=!0})}add_data_validation(e){this._validations.push(e),this._parent._pending=!0}get auto_filter(){return this._filter}_changed(){this._parent._pending=!0}_heldPage(e){this._print=structuredClone(e?.print??{}),this._links={...e?.links},this._notes={...e?.notes},this._pictures=[...e?.pictures??[]],this._protect=e?.protect===!0}get page_setup(){return new Y(this)}get page_margins(){return new V(this)}get oddHeader(){return new A(this,"header")}get oddFooter(){return new A(this,"footer")}get protection(){return new q(()=>this._protect,e=>{this._protect=e,this._changed()})}get print_area(){return this._print.area}set print_area(e){if(e===void 0)delete this._print.area;else if(k(e))this._print.area=e;else throw new TypeError(`${e} is not a range.`);this._changed()}get print_title_rows(){return this._print.title_rows}set print_title_rows(e){e===void 0?delete this._print.title_rows:this._print.title_rows=e,this._changed()}get print_title_cols(){return this._print.title_cols}set print_title_cols(e){e===void 0?delete this._print.title_cols:this._print.title_cols=e,this._changed()}add_image(e,t){const s=t??e.anchor??"A1";if(!y(s))throw new TypeError(`${s} is not a cell.`);this._pictures.push({file:e.path,at:s,...e.width===void 0?{}:{width:e.width},...e.height===void 0?{}:{height:e.height}}),this._changed()}add_chart(e,t){e.anchor=de(t)??e.anchor,this._charts.push(e),this._parent._pending=!0}add_table(e){if(this._parent._tableNamed(e.name))throw new Error(`There is already a table named ${e.name}.`);this._tables.add(e),this._parent._pending=!0}}export class Workbook{worksheets=[];defined_names=new DefinedNameDict;data_only;title;path;block_cells=BLOCK_CELLS;_file={sheets:[]};_text="";_disk={text:"",csv:new Map};_csv=new Map;_model;_names=new Map;_active=0;_pending=!1;_making=!1;_calc=void 0;constructor(e={}){this.data_only=e.data_only??!1;const t=g(this,"Workbook",w,{key:s=>this.worksheets.find(n=>n.title===s),index:s=>this.worksheets[s]});return t.worksheets=[new Worksheet(t,"Sheet")],t}static open(e,t={}){const s=new Workbook(t);return s.path=e,s._read(e),s}_read(e){const{readFileSync:t}=J(),s=t($(e,P),"utf8"),n=new Map,o=r=>{try{const a=t($(e,r),"utf8");return n.set(r,a),a}catch{return}};this._load(s,o);for(const[r,a]of n)this._keepCsv(r,a);this._disk={text:s,csv:n}}_keepCsv(e,t){const s=Z(t);this._csv.set(e,{parsed:s,rows:s.records.map(n=>n.end===n.start?[]:[...n.fields])})}_load(e,t){const{workbook:s,problems:n}=I({text:e,read:t});if(!s)throw new Error(`sheet.yaml cannot be opened: ${n.map(o=>o.message).join("; ")}`);this._text=e,this._file=structuredClone(s.file),this._model=s,this.title=s.title,this.worksheets=s.sheets.map(o=>new Worksheet(this,o.name,o));for(const o of s.names.values()){if(o.source.path?.[0]!=="names")continue;const r=o.formula?o.formula.text:o.value??null;this._names.set(o.name,r),this.defined_names.add(new DefinedName(o.name,{attr_text:String(r)}))}}get active(){const e=this.worksheets[this._active]??this.worksheets[0];if(!e)throw new Error("The workbook has no sheets.");return e}set active(e){this._active=this.worksheets.indexOf(e)}get sheetnames(){return this.worksheets.map(e=>e.title)}get_sheet_by_name(e){return this.worksheets.find(t=>t.title===e)}index(e){return this.worksheets.indexOf(e)}create_sheet(e,t){let s=e??"Sheet";for(let o=1;this.worksheets.some(r=>r.title===s);o++)s=`${e??"Sheet"}${String(o)}`;const n=new Worksheet(this,s);return this.worksheets.splice(t??this.worksheets.length,0,n),this._pending=!0,n}remove(e){this.worksheets=this.worksheets.filter(t=>t!==e),this._pending=!0}move_sheet(e,t=0){const s=this.worksheets.indexOf(e);this.worksheets.splice(s,1),this.worksheets.splice(s+t,0,e),this._pending=!0}_tableNamed(e){for(const t of this.worksheets){const s=t._tables.get(e);if(s)return s}}_renameSheet(e,t,s){if(this.worksheets.some(o=>o!==e&&o.title===s))throw new Error(`There is already a sheet named ${s}.`);this._apply(),this._rewrite({op:"rename-sheet",from:t,to:s}),e._title=s,e._was=s;const n=this._file.sheets.find(o=>o.name===t);n&&(n.name=s),this._apply()}_restructure(e){this._apply();const t=_e({file:this._file,rows:new Map([...this._csv].map(([n,o])=>[n,o.rows]))},e);if(t.refused!==void 0)throw new Error(t.refused==="table-header"?"A table's header row is not deleted: delete the table's rows, or all of it.":"That sheet is not there.");this._file=t.file;for(const[n,o]of t.rows){const r=this._csv.get(n);r&&(r.rows=o.map(a=>[...a]))}for(const n of this.worksheets){const o=this._file.sheets.find(r=>r.name===n._title);n._cells.clear(),n._columns.clear(),n._rows.clear(),n._merges=[...o?.merges??[]],n._freeze=o?.freeze,n._heldPage(o),n._heldRules(o)}const s=this._build();this._rebase(s.text,s.files);for(const n of this.worksheets){const o=this._model?.sheet(n._title);if(o){n._lastRow=(o.used?.bottom??-1)+1;for(const r of o.tables){const a=n._tables.get(r.name);a&&(a.ref=x(r.area))}}}}_rewrite(e){const t=(n,o)=>{const r=F(n);if(!r.ok)return n;const a=oe(r.node,e,o);return a===r.node?n:B(a)},{_file:s}=this;if(s.names){for(const[n,o]of Object.entries(s.names))if(typeof o=="string"&&o.startsWith("=")){const r=t(o,s.sheets[0]?.name??"");s.names[n]=r,this._names.set(n,r);const a=this.defined_names.get(n);a&&(a.attr_text=r.slice(1))}}for(const n of s.checks??[])n.formula=t(n.formula,s.sheets[0]?.name??"");for(const n of s.sheets){for(const[o,r]of Object.entries(n.cells??{}))typeof r=="string"&&r.startsWith("=")?n.cells[o]=t(r,n.name):r!==null&&typeof r=="object"&&r.formula!==void 0&&(r.formula=t(r.formula,n.name));for(const o of n.tables??[]){for(const r of Object.values(o.columns??{}))r.formula!==void 0&&(r.formula=t(r.formula,n.name));this._rewriteCsv(o.rows,n.name,t)}for(const o of n.blocks??[])this._rewriteCsv(o.rows,n.name,t)}}_rewriteCsv(e,t,s){const n=this._csv.get(e);n&&(n.rows=n.rows.map(o=>o.map(r=>M(r).formula!==void 0?s(r,t):r)))}_sheetEntry(e){const t=e._was??e._title;let s=this._file.sheets.find(n=>n.name===t);return s||(s={name:e._title},this._file.sheets.push(s)),s.name=e._title,s}_dataPath(e){const t=`${G}/${Me(e)}`;let s=`${t}.csv`;const n=o=>this._csv.has(o)||this._file.sheets.some(r=>r.tables?.some(a=>a.rows===o)??r.blocks?.some(a=>a.rows===o));for(let o=2;n(s);o++)s=`${t}-${String(o)}.csv`;return s}_writeNewTable(e,t,s){const n=k(s.ref);if(!n)throw new Error(`${s.ref} is not a range.`);const o=[];for(let i=n.left;i<=n.right;i++){const h=e.cell(n.top+1,i+1).value;if(h===null||h==="")throw new Error(`Table ${s.name}'s header has no name at ${C({row:n.top,col:i})}.`);o.push(String(h))}const r={},a=[];o.forEach((i,h)=>{const _=n.left+h,d=this._columnFormula(e,n,_);d===void 0?a.push(h):r[i]={formula:d};const p=this._columnFormat(e,n,_);p!==void 0&&(r[i]={...r[i],format:p})}),this._columnsStyled(e,n);const f=[a.map(i=>o[i]??"")];for(let i=n.top+1;i<=n.bottom;i++)f.push(a.map(h=>v(e.cell(i+1,n.left+h+1))));t.cells&&(t.cells=Object.fromEntries(Object.entries(t.cells).filter(([i])=>{const h=y(i);return!h||!N(n,h.row,h.col)})));const c=this._dataPath(s.name);this._csv.set(c,{parsed:void 0,rows:f});const u={name:s.name,at:C({row:n.top,col:n.left}),rows:c,...s.key===void 0?{}:{key:s.key},...m(r)?{}:{columns:r}};(t.tables??=[]).push(u),s._spec=u}_columnsStyled(e,t){for(let s=t.left;s<=t.right;s++)for(let n=t.top+1;n<=t.bottom;n++){const o=e.cell(n+1,s+1),{format:r,...a}=this._ownLook(o);r!==void 0&&m(a)&&(o._styled=!1)}}_columnFormula(e,t,s){if(t.bottom<=t.top)return;const n=e.cell(t.top+2,s+1),o=R(n);if(o!==void 0){for(let r=t.top+2;r<=t.bottom;r++)if(R(e.cell(r+1,s+1))!==o)return;return n._formula}}_columnFormat(e,t,s){if(t.bottom<=t.top)return;const n=r=>this._ownLook(e.cell(r+1,s+1)).format,o=n(t.top+1);for(let r=t.top+2;r<=t.bottom;r++)if(n(r)!==o)return;return o}_held(e){const t=this._csv.get(e);if(!t)throw new Error(`${e} was not read.`);return t}_setCsvCell(e,t,s,n){const{rows:o}=this._held(e);for(;o.length<=t;)o.push([]);const r=o[t];if(r){for(;r.length<=s;)r.push("");r[s]=n}}_recordOf(e,t){let s=0;for(let n=0;n<t;){if(s+=1,s>=e.length)return s+t-n-1;e[s]?.length!==0&&(n+=1)}return s}_writeTableCell(e,t,s){const n=this._held(e.rows),o=n.rows[0]??[],r=s.column-1-t.left,a=this._recordOf(n.rows,s.row-1-t.top),f=Object.keys(e.columns??{}).filter(_=>!o.some(d=>d.trim().toLowerCase()===_.toLowerCase())),u=[...o.map(_=>_.trim()),...f][r];if(u===void 0)return;if(a===0){r<o.length&&(o[r]=v(s));return}const i=e.columns?.[u]?.formula;if(i!==void 0){const _=this._movedColumn(i,t,s);if(s._formula===_){const d=o.findIndex(p=>p.trim()===u);d>=0&&this._setCsvCell(e.rows,a,d,"");return}}let h=o.findIndex(_=>_.trim()===u);h<0&&(h=o.length,this._setCsvCell(e.rows,0,h,u)),this._setCsvCell(e.rows,a,h,v(s))}_movedColumn(e,t,s){const n=F(e);if(!n.ok)return e;const o=s.row-1-(t.top+1);return o===0?e:B(se(n.node,o,0))}_apply(){this.title===void 0?delete this._file.title:this._file.title=this.title;const e=new Set(this.worksheets.map(s=>s._was??s._title));this._file.sheets=this._file.sheets.filter(s=>e.has(s.name));for(const s of this.worksheets)this._applySheet(s);this._file.sheets=this.worksheets.map(s=>this._sheetEntry(s)),this._applyNames();const t=this._build();this._rebase(t.text,t.files)}_applyNames(){const e={};for(const t of this.defined_names.values()){const s=M(t.attr_text),n=this._names.get(t.name);e[t.name]=n!==void 0&&String(n).replace(/^=/u,"")===t.attr_text?n:typeof s.value=="number"||typeof s.value=="boolean"?s.value:/^"[^"]*"$/u.test(t.attr_text)?t.attr_text.slice(1,-1):`=${t.attr_text}`}m(e)?delete this._file.names:this._file.names=e}_applySheet(e){const t=this._sheetEntry(e);e._freeze===void 0?delete t.freeze:t.freeze=e._freeze,m(e._print)?delete t.print:t.print=e._print,m(e._links)?delete t.links:t.links=e._links,m(e._notes)?delete t.notes:t.notes=e._notes,e._pictures.length===0?delete t.pictures:t.pictures=e._pictures,e._protect?t.protect=!0:delete t.protect,e._merges.length===0?delete t.merges:t.merges=[...e._merges],e._state==="hidden"?t.hidden=!0:delete t.hidden,e._rules.length===0?delete t.conditional:t.conditional=[...e._rules],e._validations.length===0?delete t.validations:t.validations=e._validations.map(ke),e._charts.length===0?delete t.charts:t.charts=e._charts.map(n=>n._spec(e._title)),this._applyFilter(e,t);const s=new Set(t.tables?.map(n=>n.name.toLowerCase()));for(const n of e._tables.values())s.has(n.name.toLowerCase())||this._writeNewTable(e,t,n);this._applyTableFilters(e,t),this._applyCells(e,t),this._applyDimensions(e,t),t.cells&&m(t.cells)&&delete t.cells,t.columns&&m(t.columns)&&delete t.columns,t.rows&&m(t.rows)&&delete t.rows,t.format?.length===0&&delete t.format,t.tables?.length===0&&delete t.tables,t.blocks?.length===0&&delete t.blocks}_applyFilter(e,t){const{ref:s,_columns:n}=e._filter;if(s===void 0){delete t.filter;return}const o=k(s);if(!o)throw new TypeError(`${s} is not a range.`);const r={};for(const[a,f]of n)r[L(o.left+a)]=f;t.filter={range:s,...m(r)?{}:{columns:r}}}_applyTableFilters(e,t){for(const s of t.tables??[]){const n=e._tables.get(s.name);if(!n||n.autoFilter._columns.size===0)continue;const o=this._csv.get(s.rows)?.rows??[],r=ce(s,o)?.names??[],a={};for(const[f,c]of n.autoFilter._columns){const u=r[f];if(u===void 0)throw new RangeError(`Table ${s.name} has no column at ${String(f)}.`);a[u]=c}s.filter={columns:a}}}_applyDimensions(e,t){if(e._dimensions){for(const[s,n]of e._columns){const o={...t.columns?.[s]};n._width===void 0?delete o.width:o.width=n._width,n._hidden===void 0?delete o.hidden:o.hidden=n._hidden,n._files===void 0?delete o.files:o.files=n._files,n._level===void 0?delete o.level:o.level=n._level;const r=j(t.columns??{},s);t.columns=m(o)?r:{...r,[s]:o}}for(const[s,n]of e._rows){const o={...t.rows?.[String(s)]};n._height===void 0?delete o.height:o.height=n._height,n._hidden===void 0?delete o.hidden:o.hidden=n._hidden,n._level===void 0?delete o.level:o.level=n._level;const r=j(t.rows??{},String(s));t.rows=m(o)?r:{...r,[String(s)]:o}}e._dimensions=!1}}_applyCells(e,t){const s=(t.tables??[]).flatMap(r=>{const a=y(r.at),f=e._tables.get(r.name),c=f?k(f.ref):void 0;return a&&c?[{entry:r,area:c}]:[]}),n=(t.blocks??[]).flatMap(r=>{const a=e._model?.blocks.find(f=>f.file===r.rows);return a?[{entry:r,area:a.area}]:[]}),o=[];for(const r of e._cells.values()){if(!r._changed&&!r._styled)continue;const a=r.row-1,f=r.column-1,c=s.find(i=>N(i.area,a,f)),u=n.find(i=>N(i.area,a,f));c?(r._changed&&this._writeTableCell(c.entry,c.area,r),r._styled&&this._styleByFormat(t,r)):u?(r._changed&&this._setCsvCell(u.entry.rows,a-u.area.top,f-u.area.left,v(r)),r._styled&&this._styleByFormat(t,r)):r._fresh&&!e._model?.keys.has(a*16384+f)?o.push(r):this._writeLoose(e,t,r),r._changed=!1,r._styled=!1}this._consolidate(e,t,o),je(t)}_styleByFormat(e,t){(e.format??=[]).push({range:t.coordinate,...this._ownLook(t)})}_ownLook(e){const t=e._ws._model?.lookAt(e.row-1,e.column-1)??{},s=Fe(t,e._look);return s.format!==void 0&&e._formula===void 0&&M(v(e)).format===s.format&&delete s.format,s}_writeLoose(e,t,s){const n=s.coordinate,o=t.cells??={},r=U(s),a=this._ownLook(s),f=o[n],u={...f!==null&&typeof f=="object"?Object.fromEntries(Object.entries(f).filter(([_])=>_!=="value"&&_!=="formula"&&_!=="name")):{},...a},i=f!==null&&typeof f=="object"&&f.name!==void 0?{name:f.name}:{},h=e._model?.at(s.row-1,s.column-1)!==void 0;if(r===null&&m(u)&&!h){t.cells=j(o,n);return}o[n]=m(u)&&m(i)?r:{...typeof r=="string"&&r.startsWith("=")?{formula:r}:r===null?{}:{value:r},...i,...u}}_consolidate(e,t,s){const n=s.filter(i=>i._value!==null||i._formula!==void 0),o=new Map;for(const i of s){const h=this._ownLook(i);if(m(h))continue;const _=JSON.stringify(h),d=o.get(_);d?d.push(i):o.set(_,[i])}const r=new Map(n.map(i=>[`${String(i.row)}:${String(i.column)}`,i])),a=i=>r.get(`${String(i.row+1)}:${String(i.col+1)}`)??e.cell(i.row+1,i.col+1),f=new Map,c=[];for(const i of n){const h={row:i.row-1,col:i.column-1},_=i._formula===void 0?void 0:R(i);if(_===void 0){c.push(h);continue}const d=f.get(_);d?d.push(h):f.set(_,[h])}const u=t.cells??={};for(const i of f.values())for(const h of T(i))u[x(h)]=a({row:h.top,col:h.left})._formula??null;for(const i of T(c))if((i.bottom-i.top+1)*(i.right-i.left+1)>=this.block_cells){const _=[];for(let p=i.top;p<=i.bottom;p++){const D=[];for(let O=i.left;O<=i.right;O++)D.push(v(a({row:p,col:O})));_.push(D)}const d=this._dataPath(e._title);this._csv.set(d,{parsed:void 0,rows:_}),(t.blocks??=[]).push({at:C({row:i.top,col:i.left}),rows:d})}else for(let _=i.top;_<=i.bottom;_++)for(let d=i.left;d<=i.right;d++){const p=a({row:_,col:d});u[p.coordinate]=U(p)}for(const i of o.values()){const[h]=i;if(!h)continue;const _=this._ownLook(h),d=i.map(p=>({row:p.row-1,col:p.column-1}));for(const p of T(d))(t.format??=[]).push({range:x(p),..._})}}_build(){const e=new Map;for(const[t,s]of this._csv)e.set(t,s.parsed?re(s.parsed,s.rows):ee(s.rows));return{text:ue(this._text,this._file),files:e}}_rebase(e,t){const{workbook:s,problems:n}=I({text:e,read:o=>t.get(o)});if(!s)throw new Error(`The workbook is not one: ${n.map(o=>o.message).join("; ")}`);this._text=e,this._file=structuredClone(s.file),this._model=s;for(const[o,r]of t)this._keepCsv(o,r);this._calc=void 0,this._pending=!1;for(const o of this.worksheets){o._was=o._title;const r=s.sheet(o._title);r&&(o._model=r);for(const a of o._cells.values())a._fresh=r?.at(a.row-1,a.column-1)===void 0}this._names=new Map;for(const o of s.names.values())o.source.path?.[0]==="names"&&this._names.set(o.name,o.formula?o.formula.text:o.value??null)}_computed(){const e=[...this.defined_names.values()];if((this._pending||e.length!==this._names.size||e.some(t=>String(this._names.get(t.name)).replace(/^=/u,"")!==t.attr_text))&&this._apply(),!this._calc){const t=this._model;if(!t)throw new Error("The workbook has no sheets.");this._calc={calc:new Q(t).calculate(),model:t}}return this._calc}check(){this._apply();const{text:e,files:t}=this._build();return X({text:e,read:s=>t.get(s)}).problems}_generated(){if(this.worksheets.length===0)return this._applyNames(),{sheets:[],csv:{},...this._file.names?{names:this._file.names}:{}};this._apply();const e=structuredClone(this._file.sheets),t=n=>`${te}${n}`;for(const n of e){for(const o of n.tables??[])o.rows=t(o.rows);for(const o of n.blocks??[])o.rows=t(o.rows)}const s={};for(const[n,o]of this._build().files)s[t(n)]=o;return{sheets:e,csv:s,...this._file.names?{names:this._file.names}:{}}}save(e){if(this._making)throw new Error("sheet.ts makes sheets and saves nothing: what it adds to wb is what it makes.");const t=e??this.path;if(t===void 0)throw new TypeError("A new workbook is saved to a folder: wb.save('content/budget').");if(this.worksheets.length===0)throw new Error("A workbook has at least one sheet.");const{text:s,csv:n}=this._disk;this._apply();const o=new Set(this._file.sheets.flatMap(i=>[...(i.tables??[]).map(h=>h.rows),...(i.blocks??[]).map(h=>h.rows)])),r=[...this._csv.keys()].filter(i=>!o.has(i));for(const i of r)this._csv.delete(i);const{mkdirSync:a,rmSync:f,writeFileSync:c}=J(),u=process.getBuiltinModule("node:path");a(t,{recursive:!0}),(this._text!==s||e!==void 0)&&c($(t,P),this._text);for(const[i,h]of this._csv){const _=h.parsed?.source??"";if(e===void 0&&n.get(i)===_)continue;const d=$(t,i);a(u.dirname(d),{recursive:!0}),c(d,_)}if(e===void 0||t===this.path)for(const i of r)f($(t,i),{force:!0});this._disk={text:this._text,csv:new Map([...this._csv].map(([i,h])=>[i,h.parsed?.source??""]))},this.path=t}}function R(l){if(l._formula===void 0)return;const e=F(l._formula);if(e.ok)return ne(e.node,l.row-1,l.column-1)}function je(l){const e=l.format;if(!e||e.length<2)return;const t=[],s=new Map;for(const n of e){const{range:o,...r}=n,a=y(o);if(!a){t.push(n);continue}const f=JSON.stringify(r),c=s.get(f);c?c.places.push(a):s.set(f,{look:r,places:[a]})}for(const{look:n,places:o}of s.values())for(const r of T(o))t.push({range:x(r),...n});l.format=t}export function load_workbook(l,e={}){return Workbook.open(l,e)}export const get_column_letter=l=>L(l-1);export function column_index_from_string(l){const e=E(l);if(e===void 0)throw new TypeError(`${l} is not a column.`);return e+1}export function coordinate_to_tuple(l){const e=y(l);if(!e)throw new TypeError(`${l} is not a cell.`);return[e.row+1,e.col+1]}export function range_boundaries(l){const e=k(l);if(!e)throw new TypeError(`${l} is not a range.`);return[e.left+1,e.top+1,e.right+1,e.bottom+1]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{cellName as d,rangeName as b}from"./address.js";import{ERR as p,Matrix as w,CellError as m}from"./values.js";import{analyse as $}from"./calc/analyse.js";import{Calc as k}from"./calc/engine.js";import{toBool as g}from"./calc/coerce.js";import{ENTRY as l}from"./file.js";import{fileCells as x}from"./files.js";import{applyScenario as y}from"./scenario.js";import{readWorkbook as S}from"./workbook.js";class O{problems;wb;lineOf;constructor(t,
|
|
2
|
+
import{cellName as d,rangeName as b}from"./address.js";import{ERR as p,Matrix as w,CellError as m}from"./values.js";import{analyse as $}from"./calc/analyse.js";import{Calc as k}from"./calc/engine.js";import{toBool as g}from"./calc/coerce.js";import{ENTRY as l}from"./file.js";import{fileCells as x}from"./files.js";import{applyScenario as y}from"./scenario.js";import{readWorkbook as S}from"./workbook.js";class O{problems;wb;lineOf;constructor(t,o){this.wb=t,this.problems=[...o.problems],this.lineOf=o.lineOf}at(t,o){const e=t.line??(t.path===void 0?void 0:this.lineOf(t.path));this.problems.push({file:t.file===""?l:t.file,...e===void 0?{}:{line:e},message:o})}formulas(){const t=new Map;for(const o of this.wb.sheets){for(const e of o.formulas)t.set(e.shared,o);for(const e of o.tables)for(const s of e.columns)s.formula&&t.set(s.formula,o);for(const e of o.conditions)for(const s of e.formulas)t.set(s,o);for(const e of o.validations)for(const s of e.formulas)s&&t.set(s,o);for(const e of o.charts){e.title&&t.set(e.title,o),e.categories&&t.set(e.categories,o);for(const s of e.series)t.set(s.values,o),s.x&&t.set(s.x,o),s.name&&t.set(s.name,o)}}for(const o of this.wb.names.values())o.formula&&t.set(o.formula,void 0);for(const o of this.wb.checks)t.set(o.formula,void 0);return t}formulaProblems(){for(const[t,o]of this.formulas()){const e=n=>{this.at(t.source,`${t.text}: ${n}`)};if(t.error){e(`does not parse: ${t.error.message}`);continue}const s=$(this.wb,t);t.analysis=s;for(const n of new Set(s.unknownNames))e(`there is no name ${n}`);for(const n of new Set(s.unknownFunctions))e(`there is no function ${n}`);for(const n of s.arguments)e(`${n.name} takes ${n.min===n.max?String(n.min):`${String(n.min)} to ${String(n.max)}`} arguments and is given ${String(n.given)}`);for(const n of s.reads){if(n.kind==="ref"){for(const r of[n.sheet,n.lastSheet])r!==void 0&&!this.wb.sheet(r)&&e(`there is no sheet ${r}`);continue}const f=n.table===void 0?o?.tableAt(t.row,t.col):this.wb.table(n.table);if(!f){e(n.table===void 0?"a column named with no table, outside a table":`there is no table ${n.table}`);continue}for(const r of n.columns)f.column(r)||e(`table ${f.name} has no column ${r}; it has ${f.columns.map(c=>c.name).join(", ")}`)}}}cycles(t){for(const o of t.cycles){const e=o.reduce((r,c,u)=>{const a=o[r];return a&&(c.row<a.row||c.row===a.row&&c.col<a.col)?u:r},0),s=[...o.slice(e),...o.slice(0,e)],n=s[0];if(!n)continue;const f=[...s,n].map(r=>`${r.sheet.name}!${d(r)}`).join(" → ");this.at(n.shared.source,`a circular reference: ${f}`)}}scenarios(){const{scenarios:t}=this.wb.file;for(const[o,e]of Object.entries(t??{}))for(const s of Object.keys(e))this.wb.name(s)||this.at({file:l,path:["scenarios",o,s]},`scenario ${o} sets ${s}, and there is no name ${s}`)}files(t,o){for(const e of this.wb.sheets)for(const{row:s,col:n,paths:f}of x(e,t))for(const r of f)o(r)||this.at(this.wb.sourceOf(e,s,n)??{file:l},`${placeName(e,s,n)} names ${r}, which is not there`);for(const e of this.wb.sheets)for(const s of e.spec.pictures??[])o(s.file)||this.at({file:l},`${e.name} has a picture ${s.file}, which is not there`)}checks(t){const o=this.wb.sheets[0];if(o)for(const e of this.wb.checks){if(!e.formula.node)continue;const s=t.evaluate(e.formula,o),n=h(s);n!==void 0&&this.at(e.source,`check "${e.name}" does not hold: ${e.formula.text} is ${n}`)}}}function h(i){if(i instanceof w){for(const o of i.data){const e=h(o);if(e!==void 0)return e}return}if(i instanceof m)return i.code;const t=g(i);return t instanceof m?p.VALUE.code:t?void 0:"FALSE"}export function checkWorkbook(i,t={}){const o=S(i),{workbook:e}=o;if(!e)return{problems:o.problems};const s=new O(e,o);s.scenarios(),t.scenario!==void 0&&y(e,t.scenario);const n=new k(e,t);return s.formulaProblems(),n.calculate(),s.cycles(n),s.checks(n),i.exists&&s.files(n,i.exists),{workbook:e,calc:n,problems:s.problems}}export const placeName=(i,t,o)=>`${i.name}!${b({top:t,left:o,bottom:t,right:o})}`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{MAX_COLUMNS as q,MAX_ROWS as D,cellName as S,columnIndex as R,columnLetter as _,rangeName as x,readAddress as y,readArea as A,readAreas as G}from"./address.js";import{chartAfter as H}from"./chart.js";import{moveFormula as J,relativeKey as Q}from"./formula/move.js";import{parseFormula as z}from"./formula/parse.js";import{printFormula as N}from"./formula/print.js";import{rewriteFormula as B}from"./formula/rewrite.js";import{walk as V}from"./formula/walk.js";import{readTyped as Y}from"./values.js";import{chartFormula as Z}from"./workbook.js";const E=r=>r.op==="insert-rows"||r.op==="delete-rows"||r.op==="insert-columns"||r.op==="delete-columns",k=r=>r.op==="insert-rows"||r.op==="insert-columns",b=r=>r.op==="insert-rows"||r.op==="delete-rows";function v(r,t){return k(t)?r>=t.at?r+t.count:r:r<t.at?r:r>=t.at+t.count?r-t.count:void 0}const tt=r=>b(r)?D:q;function $(r,t,n){const s=tt(n);if(k(n)){const e=r>=n.at?r+n.count:r,c=t>=n.at?t+n.count:t;return e>=s?void 0:[e,Math.min(c,s-1)]}const i=n.at+n.count-1;if(r>=n.at&&t<=i)return;const a=r<n.at?r:r>i?r-n.count:n.at,o=t<n.at?t:t>i?t-n.count:n.at-1;return[a,o]}function L(r,t){const n=b(t)?$(r.top,r.bottom,t):$(r.left,r.right,t);if(n)return b(t)?{...r,top:n[0],bottom:n[1]}:{...r,left:n[0],right:n[1]}}function nt(r,t,n,s){let i=0;const a=(o,e)=>{o&&!o.abs&&(i=Math.max(i,Math.abs(o.index-e)))};return V(r,o=>{o.kind==="ref"&&(t?(a(o.row,n),a(o.row2,n)):(a(o.col,s),a(o.col2,s)))}),i}function et(r,t,n,s){const i=new Set,a=l=>{for(let f=l-s-1;f<=l+s+1;f++)f>=r&&f<=t&&i.add(f)};a(n.at),a(n.at+n.count);const o=[...i].sort((l,f)=>l-f),e=[];let c=r;for(const l of o)l>c&&e.push([c,l-1]),e.push([l,l]),c=l+1;return c<=t&&e.push([c,t]),e}function ot(r,t,n,s,i){const a=z(t);if(!a.ok){const m=i?L(r,s):r;return m?[{area:m,text:t}]:[]}const o=b(s),[e,c]=o?[r.top,r.bottom]:[r.left,r.right],l=nt(a.node,o,r.top,r.left),f=[];let u=!0;for(const[m,d]of et(e,c,s,l)){const w=o?m:r.top,p=o?r.left:m,h=i?v(m,s):m;if(h===void 0)continue;const g=i?v(d,s):d;if(g===void 0)continue;const C=J(a.node,w-r.top,p-r.left),j=B(C,s,n);j!==C&&(u=!1);const U=o?h:r.top,X=o?r.left:h,F=Q(j,U,X),I=f[f.length-1];I?.key===F&&I.to+1===h?I.to=g:f.push({from:h,to:g,key:F,text:N(j)})}return f.map(m=>({area:o?{...r,top:m.from,bottom:m.to}:{...r,left:m.from,right:m.to},text:u&&f.length===1?t:m.text}))}function W(r,t){return r!==null&&typeof r=="object"?{...r,formula:t}:t}const st=r=>{if(typeof r=="string")return r.startsWith("=")?r:void 0;if(!(r===null||typeof r!="object"))return r.formula!==void 0?r.formula.startsWith("=")?r.formula:`=${r.formula}`:typeof r.value=="string"&&r.value.startsWith("=")?r.value:void 0};function O(r,t,n,s){const i=z(r);if(!i.ok)return r;const a=B(i.node,t,n,s);return a===i.node?r:N(a)}function rt(r,t,n,s){const i={},a=E(n)?n:void 0;for(const[o,e]of Object.entries(r)){const c=st(e),l=A(o);if(!l){i[o]=e;continue}const f=s&&a!==void 0;if(o.includes(":")){if(!a){i[o]=c===void 0?e:W(e,O(c,n,t));continue}if(c!==void 0){for(const h of ot(l,c,t,a,f))i[x(h.area)]=W(e,h.text);continue}if(!f){i[o]=e;continue}if(!k(a)){const h=L(l,a);h&&(i[x(h)]=e);continue}const d=b(a),[w,p]=d?[l.top,l.bottom]:[l.left,l.right];for(const[h,g]of[[w,Math.min(p,a.at-1)],[Math.max(w,a.at),p]]){if(h>g)continue;const C=h>=a.at?a.count:0,j=d?{...l,top:h+C,bottom:g+C}:{...l,left:h+C,right:g+C};i[x(j)]=e}continue}const u={row:l.top,col:l.left};let m=u;if(f){const d=v(b(a)?u.row:u.col,a);m=d===void 0?void 0:b(a)?{...u,row:d}:{...u,col:d}}m&&(i[S(m)]=c===void 0?e:W(e,O(c,n,t)))}return i}export function tableShape(r,t){const n=y(r.at);if(!n)return;const s=t[0]??[],i=s.map(e=>e.trim()),a=new Set(i.map(e=>e.toLowerCase()));for(const e of Object.keys(r.columns??{}))a.has(e.toLowerCase())||i.push(e);const o=[];return t.forEach((e,c)=>{c>0&&e.length>0&&o.push(c)}),{at:n,header:s,names:i,places:o}}const P=r=>r.reduce((t,n)=>Math.max(t,n.length),0);function K(r,t,n){const s=Math.max(P(r),1),i=Array.from({length:n},()=>new Array(s).fill(""));return[...r.slice(0,t),...i,...r.slice(t)]}export function freeColumn(r,t="Column"){const n=new Set(r.map(s=>s.toLowerCase()));for(let s=1;;s++){const i=`${t}${String(s)}`;if(!n.has(i.toLowerCase()))return i}}export function uniqueColumn(r,t){const n=new Set(r.map(s=>s.toLowerCase()));if(!n.has(t.toLowerCase()))return t;for(let s=2;;s++){const i=`${t}${String(s)}`;if(!n.has(i.toLowerCase()))return i}}export function withColumnsUpTo(r,t,n){const s=r.map(o=>[...o]),i=s[0]??[];for(s.length===0&&s.push(i);i.length<=n;)i.push(t[i.length]??"");const a=i.length;for(let o=1;o<s.length;o++){const e=s[o];if(e&&e.length>0)for(;e.length<a;)e.push("")}return s}class T{file;rows;edit;after=[];refused;constructor(t,n){this.file=structuredClone(t.file),this.rows=new Map(t.rows),this.edit=n}sheets(){return this.file.sheets}rewrite(t){const n=this.file.sheets[0]?.name??"";if(this.file.names)for(const[s,i]of Object.entries(this.file.names))typeof i=="string"&&i.startsWith("=")&&(this.file.names[s]=O(i,t,n));for(const s of this.file.checks??[])s.formula=O(s.formula,t,n);for(const s of this.sheets())this.rewriteSheet(s,t)}rewriteSheet(t,n){const s=E(n)&&M(t.name,n.sheet);t.cells&&(t.cells=rt(t.cells,t.name,n,s));for(const i of t.tables??[]){for(const a of Object.values(i.columns??{}))a.formula!==void 0&&(a.formula=O(a.formula,n,t.name,i.name));this.rewriteCsv(i.rows,n,t.name,i.name)}for(const i of t.blocks??[])this.rewriteCsv(i.rows,n,t.name);this.rewriteRules(t,n)}freePath(t,n){const s=t.slice(0,t.lastIndexOf("/")+1),i=o=>[...this.rows.keys()].some(e=>M(e,o));let a=`${s}${n}.csv`;for(let o=2;i(a);o++)a=`${s}${n}-${String(o)}.csv`;return a}duplicate(t,n){const s=this.sheets(),i=s.findIndex(f=>M(f.name,t)),a=s[i];if(!a){this.refused="no-sheet";return}const o=structuredClone(a);o.name=n,delete o.hidden;for(const f of Object.values(o.cells??{}))f!==null&&typeof f=="object"&&delete f.name;const e=new Set(s.flatMap(f=>f.tables??[]).map(f=>f.name.toLowerCase())),c=new Set(Object.keys(this.file.names??{}).map(f=>f.toLowerCase())),l=[];for(const f of o.tables??[]){let u=f.name;for(let d=2;;d++){u=`${f.name}${String(d)}`;const w=u.toLowerCase();if(!e.has(w)&&!c.has(w))break}e.add(u.toLowerCase());const m=this.freePath(f.rows,u);this.rows.set(m,this.rows.get(f.rows)??[]),l.push({op:"rename-table",from:f.name,to:u}),f.rows=m,f.name=u}for(const f of o.blocks??[]){const u=f.rows.slice(f.rows.lastIndexOf("/")+1,-4),m=this.freePath(f.rows,u);this.rows.set(m,this.rows.get(f.rows)??[]),f.rows=m}this.file.sheets=[...s.slice(0,i+1),o,...s.slice(i+1)],this.rewriteSheet(o,{op:"rename-sheet",from:t,to:n});for(const f of l)this.rewriteSheet(o,f)}rewriteRules(t,n){const s=e=>typeof e=="string"&&e.startsWith("=")?O(e,n,t.name):e,i=e=>e.value===void 0?e:{...e,value:s(e.value)},a=t.conditional?.map(e=>{switch(e.type){case"cellIs":return{...e,formula:e.formula.map(s)};case"expression":return{...e,formula:O(e.formula.startsWith("=")?e.formula:`=${e.formula}`,n,t.name)};case"dataBar":return{...e,...e.min?{min:i(e.min)}:{},...e.max?{max:i(e.max)}:{}};case"colorScale":return{...e,stops:e.stops.map(i)};case"iconSet":return e.stops?{...e,stops:e.stops.map(i)}:e;default:return e}});a&&(t.conditional=a);const o=t.validations?.map(e=>e.formula?{...e,formula:e.formula.map(s)}:e);o&&(t.validations=o),t.charts&&(t.charts=t.charts.map(e=>H(e,c=>{const l=c.startsWith("="),f=O(Z(c),n,t.name);return l?f:f.slice(1)})))}rewriteCsv(t,n,s,i){const a=this.rows.get(t);if(!a)return;let o;a.forEach((e,c)=>{if(!e.some(f=>f.charCodeAt(0)===61))return;const l=e.map(f=>Y(f).formula===void 0?f:O(f,n,s,i));l.every((f,u)=>f===e[u])||(o??=[...a],o[c]=l)}),o&&this.rows.set(t,o)}tableOn(t,n){const s=b(n),i=[];for(const a of t.tables??[]){const o=this.rows.get(a.rows),e=o&&tableShape(a,o);if(!o||!e){i.push(a);continue}const c=e.at.row,l=e.at.col,f=c+e.places.length,u=l+Math.max(e.names.length,1)-1,[m,d]=s?[c,f]:[l,u];if(!k(n)&&n.at<=m&&n.at+n.count-1>=d){this.after.push({op:"delete-table",name:a.name});continue}const w={...e.at};if(s)if(k(n)){if(n.at<=c)w.row+=n.count;else if(n.at<=f){const p=e.places[n.at-c-1]??o.length;this.rows.set(a.rows,K(o,p,n.count))}}else{const p=n.at+n.count-1;if(p<c)w.row-=n.count;else if(n.at<=c){this.refused="table-header";return}else if(n.at<=f){const h=new Set(e.places.slice(n.at-c-1,p-c));this.rows.set(a.rows,o.filter((g,C)=>!h.has(C)))}}else if(k(n))n.at<=l?w.col+=n.count:n.at<=u&&this.columnsIn(a,e,n.at-l,n.count);else{const p=n.at+n.count-1;if(p<l)w.col-=n.count;else if(n.at<=u){w.col=Math.min(l,n.at);const h=Math.max(0,n.at-l),g=Math.min(e.names.length-1,p-l);this.columnsOut(a,e,h,g)}}a.at=S(w),i.push(a)}t.tables=i,i.length===0&&delete t.tables}columnsIn(t,n,s,i){const a=this.rows.get(t.rows)??[],o=s>0?withColumnsUpTo(a,n.names,s-1):a.map(c=>[...c]),e=[...n.names];o.forEach((c,l)=>{if(l>0&&c.length===0)return;const f=[];for(let u=0;u<i;u++)if(l===0){const m=freeColumn(e);e.push(m),f.push(m)}else f.push("");for(;c.length<s;)c.push("");c.splice(s,0,...f)}),this.rows.set(t.rows,o)}columnsOut(t,n,s,i){const a=n.names.slice(s,i+1),o=this.rows.get(t.rows)??[],e=n.header.length,c=new Set;for(let l=s;l<=i&&l<e;l++)c.add(l);if(c.size>0&&this.rows.set(t.rows,o.map(l=>l.length===0?l:l.filter((f,u)=>!c.has(u)))),t.columns){const l=new Set(a.map(f=>f.toLowerCase()));t.columns=Object.fromEntries(Object.entries(t.columns).filter(([f])=>!l.has(f.toLowerCase()))),Object.keys(t.columns).length===0&&delete t.columns}if(t.key!==void 0&&a.some(l=>l.toLowerCase()===t.key?.toLowerCase())&&delete t.key,t.filter){const l=new Set(a.map(u=>u.toLowerCase())),f=Object.fromEntries(Object.entries(t.filter.columns).filter(([u])=>!l.has(u.toLowerCase())));Object.keys(f).length>0?t.filter={columns:f}:delete t.filter}for(const l of a)this.after.push({op:"delete-column",table:t.name,name:l})}blocksOn(t,n){const s=b(n),i=(t.blocks??[]).flatMap(a=>{const o=y(a.at),e=this.rows.get(a.rows);if(!o||!e)return[a];const c=s?o.row:o.col,l=s?e.length:Math.max(P(e),1),f=c+l-1,u=$(c,f,n);if(!u)return[];const m=s?{...o,row:u[0]}:{...o,col:u[0]};if(k(n)&&n.at>c&&n.at<=f){const d=n.at-c;this.rows.set(a.rows,s?K(e,d,n.count):e.map(w=>{if(w.length===0)return w;const p=[...w];for(;p.length<d;)p.push("");return p.splice(d,0,...new Array(n.count).fill("")),p}))}else if(!k(n)&&n.at<=f){const d=Math.max(n.at,c)-c,w=Math.min(n.at+n.count-1,f)-c;this.rows.set(a.rows,s?e.filter((p,h)=>h<d||h>w):e.map(p=>p.filter((h,g)=>g<d||g>w)))}return[{...a,at:S(m)}]});t.blocks=i,i.length===0&&delete t.blocks}looksOn(t,n){const s=b(n);t.format&&(t.format=t.format.flatMap(o=>{const e=A(o.range);if(!e)return[o];const c=L(e,n);return c?[{...o,range:x(c)}]:[]})),t.format?.length===0&&delete t.format,t.merges&&(t.merges=t.merges.flatMap(o=>{const e=A(o);if(!e)return[o];const c=L(e,n);return c?[x(c)]:[]})),t.merges?.length===0&&delete t.merges;const i=o=>{const e=G(o);if(!e)return o;const c=e.flatMap(l=>{const f=L(l,n);return f?[x(f)]:[]});return c.length===0?void 0:c.join(" ")};if(t.conditional&&(t.conditional=t.conditional.flatMap(o=>{const e=i(o.range);return e===void 0?[]:[{...o,range:e}]})),t.conditional?.length===0&&delete t.conditional,t.validations&&(t.validations=t.validations.flatMap(o=>{const e=i(o.range);return e===void 0?[]:[{...o,range:e}]})),t.validations?.length===0&&delete t.validations,t.charts&&(t.charts=t.charts.map(o=>{const e=y(o.at);if(!e)return o;const c=s?e.row:e.col,l=v(c,n)??n.at;return{...o,at:S(s?{...e,row:l}:{...e,col:l})}})),t.filter){const o=A(t.filter.range),e=o&&L(o,n);if(o&&!e)delete t.filter;else if(e){const c=s?t.filter.columns:Object.fromEntries(Object.entries(t.filter.columns??{}).flatMap(([l,f])=>{const u=R(l),m=u===void 0?void 0:v(u,n);return m===void 0?[]:[[_(m),f]]}));t.filter={range:x(e),...c&&Object.keys(c).length>0?{columns:c}:{}}}}if(t.freeze!==void 0){const o=y(t.freeze);if(o){const e=s?o.row:o.col,c=$(0,e-1,n),l=e===0?0:c?c[1]+1:0;t.freeze=S(s?{...o,row:l}:{...o,col:l})}}const a=(o,e,c)=>{if(!o)return;const l={};for(const[f,u]of Object.entries(o)){const m=e(f),d=m===void 0?void 0:v(m,n);m===void 0?l[f]=u:d!==void 0&&(l[c(d)]=u)}return l};if(s){const o=a(t.rows,e=>/^[1-9]\d*$/u.test(e)?Number(e)-1:void 0,e=>String(e+1));o&&(t.rows=o)}else{const o=a(t.columns,R,_);o&&(t.columns=o)}}run(){const t=this.edit;if(E(t)){const n=this.sheets().find(s=>M(s.name,t.sheet));if(!n){this.refused="no-sheet";return}if(this.rewrite(t),this.tableOn(n,t),this.refused)return;this.blocksOn(n,t),this.looksOn(n,t);for(const s of this.after)this.rewrite(s);return}switch(t.op){case"rename-sheet":{this.rewrite(t);const n=this.sheets().find(s=>M(s.name,t.from));n&&(n.name=t.to);return}case"rename-column":{this.renameColumn(t.table,t.from,t.to),this.rewrite(t);return}case"delete-sheet":{const n=this.sheets(),s=n.find(i=>M(i.name,t.name));if(!s){this.refused="no-sheet";return}if(n.filter(i=>i.hidden!==!0).length<=1){this.refused="last-sheet";return}this.rewrite(t);for(const i of s.tables??[])this.rewrite({op:"delete-table",name:i.name});this.file.sheets=n.filter(i=>i!==s);return}default:this.rewrite(t)}}renameColumn(t,n,s){const i=this.sheets().flatMap(c=>c.tables??[]).find(c=>M(c.name,t));if(!i)return;const a=n.toLowerCase(),o=this.rows.get(i.rows),e=o?.[0]?.findIndex(c=>c.trim().toLowerCase()===a)??-1;if(o&&e>=0){const c=[...o[0]??[]];c[e]=s,this.rows.set(i.rows,[c,...o.slice(1)])}if(i.columns){const c=Object.keys(i.columns).find(l=>l.toLowerCase()===a);c!==void 0&&(i.columns=Object.fromEntries(Object.entries(i.columns).map(([l,f])=>[l===c?s:l,f])))}i.key?.toLowerCase()===a&&(i.key=s),i.filter&&(i.filter={columns:Object.fromEntries(Object.entries(i.filter.columns).map(([c,l])=>[c.toLowerCase()===a?s:c,l]))})}}const M=(r,t)=>r.toLowerCase()===t.toLowerCase();export function restructure(r,t){const n=new T(r,t);return n.run(),n.refused?{file:r.file,rows:new Map(r.rows),refused:n.refused}:{file:n.file,rows:n.rows}}export function duplicated(r,t,n){const s=new T(r,{op:"rename-sheet",from:t,to:n});return s.duplicate(t,n),s.refused?{file:r.file,rows:new Map(r.rows),refused:s.refused}:{file:s.file,rows:s.rows}}
|
|
2
|
+
import{MAX_COLUMNS as G,MAX_ROWS as H,cellName as v,columnIndex as R,columnLetter as _,rangeName as M,readAddress as y,readArea as A,readAreas as J}from"./address.js";import{chartAfter as Q}from"./chart.js";import{moveFormula as V,relativeKey as Y}from"./formula/move.js";import{parseFormula as z}from"./formula/parse.js";import{printFormula as N}from"./formula/print.js";import{rewriteFormula as B}from"./formula/rewrite.js";import{walk as Z}from"./formula/walk.js";import{readTyped as tt}from"./values.js";import{chartFormula as nt}from"./workbook.js";const $=r=>r.op==="insert-rows"||r.op==="delete-rows"||r.op==="insert-columns"||r.op==="delete-columns",k=r=>r.op==="insert-rows"||r.op==="insert-columns",b=r=>r.op==="insert-rows"||r.op==="delete-rows";function x(r,t){return k(t)?r>=t.at?r+t.count:r:r<t.at?r:r>=t.at+t.count?r-t.count:void 0}function P(r,t){const n=y(r);if(!n)return r;const s=x(b(t)?n.row:n.col,t);if(s!==void 0)return v(b(t)?{...n,row:s}:{...n,col:s})}function K(r,t){return Object.fromEntries(Object.entries(r).flatMap(([n,s])=>{const i=P(n,t);return i===void 0?[]:[[i,s]]}))}const et=r=>b(r)?H:G;function E(r,t,n){const s=et(n);if(k(n)){const e=r>=n.at?r+n.count:r,c=t>=n.at?t+n.count:t;return e>=s?void 0:[e,Math.min(c,s-1)]}const i=n.at+n.count-1;if(r>=n.at&&t<=i)return;const a=r<n.at?r:r>i?r-n.count:n.at,o=t<n.at?t:t>i?t-n.count:n.at-1;return[a,o]}function L(r,t){const n=b(t)?E(r.top,r.bottom,t):E(r.left,r.right,t);if(n)return b(t)?{...r,top:n[0],bottom:n[1]}:{...r,left:n[0],right:n[1]}}function ot(r,t,n,s){let i=0;const a=(o,e)=>{o&&!o.abs&&(i=Math.max(i,Math.abs(o.index-e)))};return Z(r,o=>{o.kind==="ref"&&(t?(a(o.row,n),a(o.row2,n)):(a(o.col,s),a(o.col2,s)))}),i}function st(r,t,n,s){const i=new Set,a=l=>{for(let f=l-s-1;f<=l+s+1;f++)f>=r&&f<=t&&i.add(f)};a(n.at),a(n.at+n.count);const o=[...i].sort((l,f)=>l-f),e=[];let c=r;for(const l of o)l>c&&e.push([c,l-1]),e.push([l,l]),c=l+1;return c<=t&&e.push([c,t]),e}function rt(r,t,n,s,i){const a=z(t);if(!a.ok){const m=i?L(r,s):r;return m?[{area:m,text:t}]:[]}const o=b(s),[e,c]=o?[r.top,r.bottom]:[r.left,r.right],l=ot(a.node,o,r.top,r.left),f=[];let u=!0;for(const[m,d]of st(e,c,s,l)){const w=o?m:r.top,p=o?r.left:m,h=i?x(m,s):m;if(h===void 0)continue;const g=i?x(d,s):d;if(g===void 0)continue;const C=V(a.node,w-r.top,p-r.left),S=B(C,s,n);S!==C&&(u=!1);const q=o?h:r.top,D=o?r.left:h,F=Y(S,q,D),I=f[f.length-1];I?.key===F&&I.to+1===h?I.to=g:f.push({from:h,to:g,key:F,text:N(S)})}return f.map(m=>({area:o?{...r,top:m.from,bottom:m.to}:{...r,left:m.from,right:m.to},text:u&&f.length===1?t:m.text}))}function W(r,t){return r!==null&&typeof r=="object"?{...r,formula:t}:t}const it=r=>{if(typeof r=="string")return r.startsWith("=")?r:void 0;if(!(r===null||typeof r!="object"))return r.formula!==void 0?r.formula.startsWith("=")?r.formula:`=${r.formula}`:typeof r.value=="string"&&r.value.startsWith("=")?r.value:void 0};function O(r,t,n,s){const i=z(r);if(!i.ok)return r;const a=B(i.node,t,n,s);return a===i.node?r:N(a)}function ct(r,t,n,s){const i={},a=$(n)?n:void 0;for(const[o,e]of Object.entries(r)){const c=it(e),l=A(o);if(!l){i[o]=e;continue}const f=s&&a!==void 0;if(o.includes(":")){if(!a){i[o]=c===void 0?e:W(e,O(c,n,t));continue}if(c!==void 0){for(const h of rt(l,c,t,a,f))i[M(h.area)]=W(e,h.text);continue}if(!f){i[o]=e;continue}if(!k(a)){const h=L(l,a);h&&(i[M(h)]=e);continue}const d=b(a),[w,p]=d?[l.top,l.bottom]:[l.left,l.right];for(const[h,g]of[[w,Math.min(p,a.at-1)],[Math.max(w,a.at),p]]){if(h>g)continue;const C=h>=a.at?a.count:0,S=d?{...l,top:h+C,bottom:g+C}:{...l,left:h+C,right:g+C};i[M(S)]=e}continue}const u={row:l.top,col:l.left};let m=u;if(f){const d=x(b(a)?u.row:u.col,a);m=d===void 0?void 0:b(a)?{...u,row:d}:{...u,col:d}}m&&(i[v(m)]=c===void 0?e:W(e,O(c,n,t)))}return i}export function tableShape(r,t){const n=y(r.at);if(!n)return;const s=t[0]??[],i=s.map(e=>e.trim()),a=new Set(i.map(e=>e.toLowerCase()));for(const e of Object.keys(r.columns??{}))a.has(e.toLowerCase())||i.push(e);const o=[];return t.forEach((e,c)=>{c>0&&e.length>0&&o.push(c)}),{at:n,header:s,names:i,places:o}}const T=r=>r.reduce((t,n)=>Math.max(t,n.length),0);function U(r,t,n){const s=Math.max(T(r),1),i=Array.from({length:n},()=>new Array(s).fill(""));return[...r.slice(0,t),...i,...r.slice(t)]}export function freeColumn(r,t="Column"){const n=new Set(r.map(s=>s.toLowerCase()));for(let s=1;;s++){const i=`${t}${String(s)}`;if(!n.has(i.toLowerCase()))return i}}export function uniqueColumn(r,t){const n=new Set(r.map(s=>s.toLowerCase()));if(!n.has(t.toLowerCase()))return t;for(let s=2;;s++){const i=`${t}${String(s)}`;if(!n.has(i.toLowerCase()))return i}}export function withColumnsUpTo(r,t,n){const s=r.map(o=>[...o]),i=s[0]??[];for(s.length===0&&s.push(i);i.length<=n;)i.push(t[i.length]??"");const a=i.length;for(let o=1;o<s.length;o++){const e=s[o];if(e&&e.length>0)for(;e.length<a;)e.push("")}return s}class X{file;rows;edit;after=[];refused;constructor(t,n){this.file=structuredClone(t.file),this.rows=new Map(t.rows),this.edit=n}sheets(){return this.file.sheets}rewrite(t){const n=this.file.sheets[0]?.name??"";if(this.file.names)for(const[s,i]of Object.entries(this.file.names))typeof i=="string"&&i.startsWith("=")&&(this.file.names[s]=O(i,t,n));for(const s of this.file.checks??[])s.formula=O(s.formula,t,n);for(const s of this.sheets())this.rewriteSheet(s,t)}rewriteSheet(t,n){const s=$(n)&&j(t.name,n.sheet);t.cells&&(t.cells=ct(t.cells,t.name,n,s));for(const i of t.tables??[]){for(const a of Object.values(i.columns??{}))a.formula!==void 0&&(a.formula=O(a.formula,n,t.name,i.name));this.rewriteCsv(i.rows,n,t.name,i.name)}for(const i of t.blocks??[])this.rewriteCsv(i.rows,n,t.name);this.rewriteRules(t,n)}freePath(t,n){const s=t.slice(0,t.lastIndexOf("/")+1),i=o=>[...this.rows.keys()].some(e=>j(e,o));let a=`${s}${n}.csv`;for(let o=2;i(a);o++)a=`${s}${n}-${String(o)}.csv`;return a}duplicate(t,n){const s=this.sheets(),i=s.findIndex(f=>j(f.name,t)),a=s[i];if(!a){this.refused="no-sheet";return}const o=structuredClone(a);o.name=n,delete o.hidden;for(const f of Object.values(o.cells??{}))f!==null&&typeof f=="object"&&delete f.name;const e=new Set(s.flatMap(f=>f.tables??[]).map(f=>f.name.toLowerCase())),c=new Set(Object.keys(this.file.names??{}).map(f=>f.toLowerCase())),l=[];for(const f of o.tables??[]){let u=f.name;for(let d=2;;d++){u=`${f.name}${String(d)}`;const w=u.toLowerCase();if(!e.has(w)&&!c.has(w))break}e.add(u.toLowerCase());const m=this.freePath(f.rows,u);this.rows.set(m,this.rows.get(f.rows)??[]),l.push({op:"rename-table",from:f.name,to:u}),f.rows=m,f.name=u}for(const f of o.blocks??[]){const u=f.rows.slice(f.rows.lastIndexOf("/")+1,-4),m=this.freePath(f.rows,u);this.rows.set(m,this.rows.get(f.rows)??[]),f.rows=m}this.file.sheets=[...s.slice(0,i+1),o,...s.slice(i+1)],this.rewriteSheet(o,{op:"rename-sheet",from:t,to:n});for(const f of l)this.rewriteSheet(o,f)}rewriteRules(t,n){const s=e=>typeof e=="string"&&e.startsWith("=")?O(e,n,t.name):e,i=e=>e.value===void 0?e:{...e,value:s(e.value)},a=t.conditional?.map(e=>{switch(e.type){case"cellIs":return{...e,formula:e.formula.map(s)};case"expression":return{...e,formula:O(e.formula.startsWith("=")?e.formula:`=${e.formula}`,n,t.name)};case"dataBar":return{...e,...e.min?{min:i(e.min)}:{},...e.max?{max:i(e.max)}:{}};case"colorScale":return{...e,stops:e.stops.map(i)};case"iconSet":return e.stops?{...e,stops:e.stops.map(i)}:e;default:return e}});a&&(t.conditional=a);const o=t.validations?.map(e=>e.formula?{...e,formula:e.formula.map(s)}:e);o&&(t.validations=o),$(n)&&n.sheet===t.name&&(t.links&&(t.links=K(t.links,n)),t.notes&&(t.notes=K(t.notes,n)),t.pictures&&(t.pictures=t.pictures.flatMap(e=>{const c=P(e.at,n);return c===void 0?[]:[{...e,at:c}]}))),t.charts&&(t.charts=t.charts.map(e=>Q(e,c=>{const l=c.startsWith("="),f=O(nt(c),n,t.name);return l?f:f.slice(1)})))}rewriteCsv(t,n,s,i){const a=this.rows.get(t);if(!a)return;let o;a.forEach((e,c)=>{if(!e.some(f=>f.charCodeAt(0)===61))return;const l=e.map(f=>tt(f).formula===void 0?f:O(f,n,s,i));l.every((f,u)=>f===e[u])||(o??=[...a],o[c]=l)}),o&&this.rows.set(t,o)}tableOn(t,n){const s=b(n),i=[];for(const a of t.tables??[]){const o=this.rows.get(a.rows),e=o&&tableShape(a,o);if(!o||!e){i.push(a);continue}const c=e.at.row,l=e.at.col,f=c+e.places.length,u=l+Math.max(e.names.length,1)-1,[m,d]=s?[c,f]:[l,u];if(!k(n)&&n.at<=m&&n.at+n.count-1>=d){this.after.push({op:"delete-table",name:a.name});continue}const w={...e.at};if(s)if(k(n)){if(n.at<=c)w.row+=n.count;else if(n.at<=f){const p=e.places[n.at-c-1]??o.length;this.rows.set(a.rows,U(o,p,n.count))}}else{const p=n.at+n.count-1;if(p<c)w.row-=n.count;else if(n.at<=c){this.refused="table-header";return}else if(n.at<=f){const h=new Set(e.places.slice(n.at-c-1,p-c));this.rows.set(a.rows,o.filter((g,C)=>!h.has(C)))}}else if(k(n))n.at<=l?w.col+=n.count:n.at<=u&&this.columnsIn(a,e,n.at-l,n.count);else{const p=n.at+n.count-1;if(p<l)w.col-=n.count;else if(n.at<=u){w.col=Math.min(l,n.at);const h=Math.max(0,n.at-l),g=Math.min(e.names.length-1,p-l);this.columnsOut(a,e,h,g)}}a.at=v(w),i.push(a)}t.tables=i,i.length===0&&delete t.tables}columnsIn(t,n,s,i){const a=this.rows.get(t.rows)??[],o=s>0?withColumnsUpTo(a,n.names,s-1):a.map(c=>[...c]),e=[...n.names];o.forEach((c,l)=>{if(l>0&&c.length===0)return;const f=[];for(let u=0;u<i;u++)if(l===0){const m=freeColumn(e);e.push(m),f.push(m)}else f.push("");for(;c.length<s;)c.push("");c.splice(s,0,...f)}),this.rows.set(t.rows,o)}columnsOut(t,n,s,i){const a=n.names.slice(s,i+1),o=this.rows.get(t.rows)??[],e=n.header.length,c=new Set;for(let l=s;l<=i&&l<e;l++)c.add(l);if(c.size>0&&this.rows.set(t.rows,o.map(l=>l.length===0?l:l.filter((f,u)=>!c.has(u)))),t.columns){const l=new Set(a.map(f=>f.toLowerCase()));t.columns=Object.fromEntries(Object.entries(t.columns).filter(([f])=>!l.has(f.toLowerCase()))),Object.keys(t.columns).length===0&&delete t.columns}if(t.key!==void 0&&a.some(l=>l.toLowerCase()===t.key?.toLowerCase())&&delete t.key,t.filter){const l=new Set(a.map(u=>u.toLowerCase())),f=Object.fromEntries(Object.entries(t.filter.columns).filter(([u])=>!l.has(u.toLowerCase())));Object.keys(f).length>0?t.filter={columns:f}:delete t.filter}for(const l of a)this.after.push({op:"delete-column",table:t.name,name:l})}blocksOn(t,n){const s=b(n),i=(t.blocks??[]).flatMap(a=>{const o=y(a.at),e=this.rows.get(a.rows);if(!o||!e)return[a];const c=s?o.row:o.col,l=s?e.length:Math.max(T(e),1),f=c+l-1,u=E(c,f,n);if(!u)return[];const m=s?{...o,row:u[0]}:{...o,col:u[0]};if(k(n)&&n.at>c&&n.at<=f){const d=n.at-c;this.rows.set(a.rows,s?U(e,d,n.count):e.map(w=>{if(w.length===0)return w;const p=[...w];for(;p.length<d;)p.push("");return p.splice(d,0,...new Array(n.count).fill("")),p}))}else if(!k(n)&&n.at<=f){const d=Math.max(n.at,c)-c,w=Math.min(n.at+n.count-1,f)-c;this.rows.set(a.rows,s?e.filter((p,h)=>h<d||h>w):e.map(p=>p.filter((h,g)=>g<d||g>w)))}return[{...a,at:v(m)}]});t.blocks=i,i.length===0&&delete t.blocks}looksOn(t,n){const s=b(n);t.format&&(t.format=t.format.flatMap(o=>{const e=A(o.range);if(!e)return[o];const c=L(e,n);return c?[{...o,range:M(c)}]:[]})),t.format?.length===0&&delete t.format,t.merges&&(t.merges=t.merges.flatMap(o=>{const e=A(o);if(!e)return[o];const c=L(e,n);return c?[M(c)]:[]})),t.merges?.length===0&&delete t.merges;const i=o=>{const e=J(o);if(!e)return o;const c=e.flatMap(l=>{const f=L(l,n);return f?[M(f)]:[]});return c.length===0?void 0:c.join(" ")};if(t.conditional&&(t.conditional=t.conditional.flatMap(o=>{const e=i(o.range);return e===void 0?[]:[{...o,range:e}]})),t.conditional?.length===0&&delete t.conditional,t.validations&&(t.validations=t.validations.flatMap(o=>{const e=i(o.range);return e===void 0?[]:[{...o,range:e}]})),t.validations?.length===0&&delete t.validations,t.charts&&(t.charts=t.charts.map(o=>{const e=y(o.at);if(!e)return o;const c=s?e.row:e.col,l=x(c,n)??n.at;return{...o,at:v(s?{...e,row:l}:{...e,col:l})}})),t.filter){const o=A(t.filter.range),e=o&&L(o,n);if(o&&!e)delete t.filter;else if(e){const c=s?t.filter.columns:Object.fromEntries(Object.entries(t.filter.columns??{}).flatMap(([l,f])=>{const u=R(l),m=u===void 0?void 0:x(u,n);return m===void 0?[]:[[_(m),f]]}));t.filter={range:M(e),...c&&Object.keys(c).length>0?{columns:c}:{}}}}if(t.freeze!==void 0){const o=y(t.freeze);if(o){const e=s?o.row:o.col,c=E(0,e-1,n),l=e===0?0:c?c[1]+1:0;t.freeze=v(s?{...o,row:l}:{...o,col:l})}}const a=(o,e,c)=>{if(!o)return;const l={};for(const[f,u]of Object.entries(o)){const m=e(f),d=m===void 0?void 0:x(m,n);m===void 0?l[f]=u:d!==void 0&&(l[c(d)]=u)}return l};if(s){const o=a(t.rows,e=>/^[1-9]\d*$/u.test(e)?Number(e)-1:void 0,e=>String(e+1));o&&(t.rows=o)}else{const o=a(t.columns,R,_);o&&(t.columns=o)}}run(){const t=this.edit;if($(t)){const n=this.sheets().find(s=>j(s.name,t.sheet));if(!n){this.refused="no-sheet";return}if(this.rewrite(t),this.tableOn(n,t),this.refused)return;this.blocksOn(n,t),this.looksOn(n,t);for(const s of this.after)this.rewrite(s);return}switch(t.op){case"rename-sheet":{this.rewrite(t);const n=this.sheets().find(s=>j(s.name,t.from));n&&(n.name=t.to);return}case"rename-column":{this.renameColumn(t.table,t.from,t.to),this.rewrite(t);return}case"delete-sheet":{const n=this.sheets(),s=n.find(i=>j(i.name,t.name));if(!s){this.refused="no-sheet";return}if(n.filter(i=>i.hidden!==!0).length<=1){this.refused="last-sheet";return}this.rewrite(t);for(const i of s.tables??[])this.rewrite({op:"delete-table",name:i.name});this.file.sheets=n.filter(i=>i!==s);return}default:this.rewrite(t)}}renameColumn(t,n,s){const i=this.sheets().flatMap(c=>c.tables??[]).find(c=>j(c.name,t));if(!i)return;const a=n.toLowerCase(),o=this.rows.get(i.rows),e=o?.[0]?.findIndex(c=>c.trim().toLowerCase()===a)??-1;if(o&&e>=0){const c=[...o[0]??[]];c[e]=s,this.rows.set(i.rows,[c,...o.slice(1)])}if(i.columns){const c=Object.keys(i.columns).find(l=>l.toLowerCase()===a);c!==void 0&&(i.columns=Object.fromEntries(Object.entries(i.columns).map(([l,f])=>[l===c?s:l,f])))}i.key?.toLowerCase()===a&&(i.key=s),i.filter&&(i.filter={columns:Object.fromEntries(Object.entries(i.filter.columns).map(([c,l])=>[c.toLowerCase()===a?s:c,l]))})}}const j=(r,t)=>r.toLowerCase()===t.toLowerCase();export function restructure(r,t){const n=new X(r,t);return n.run(),n.refused?{file:r.file,rows:new Map(r.rows),refused:n.refused}:{file:n.file,rows:n.rows}}export function duplicated(r,t,n){const s=new X(r,{op:"rename-sheet",from:t,to:n});return s.duplicate(t,n),s.refused?{file:r.file,rows:new Map(r.rows),refused:s.refused}:{file:s.file,rows:s.rows}}
|
|
@@ -10,6 +10,8 @@ export interface DrawnPicture {
|
|
|
10
10
|
col: number;
|
|
11
11
|
/** How far into its cell, px. */
|
|
12
12
|
x: number;
|
|
13
|
+
/** Down it: a picture over the cells; one in a cell has none, and its row grows to hold it. */
|
|
14
|
+
y?: number;
|
|
13
15
|
width: number;
|
|
14
16
|
height: number;
|
|
15
17
|
name: string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{CHART_DEFAULTS as Q,chartSpaceXml as ce}from"@allyhub-next/chart";import{columnLetter as Y}from"../address.js";import{Reference as Z,Union as ae}from"../calc/types.js";import{chartDef as fe,chartSize as de}from"../chart.js";import{sheetPrefix as le}from"../formula/print.js";import{HEAD as ue,attr as
|
|
2
|
+
import{CHART_DEFAULTS as Q,chartSpaceXml as ce}from"@allyhub-next/chart";import{columnLetter as Y}from"../address.js";import{Reference as Z,Union as ae}from"../calc/types.js";import{chartDef as fe,chartSize as de}from"../chart.js";import{sheetPrefix as le}from"../formula/print.js";import{HEAD as ue,attr as C,el as s,flag as ee,numberAttr as P,tag as o,tags as S,textOf as y}from"./xml.js";const he="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing",me="http://schemas.openxmlformats.org/drawingml/2006/main",te="http://schemas.openxmlformats.org/drawingml/2006/chart",re="http://schemas.openxmlformats.org/officeDocument/2006/relationships",p=9525,xe=(e,t)=>`${le(e.sheet.name)}$${Y(e.left)}$${String(e.top+1)}${e.single?"":`:$${Y(e.right)}$${String(t+1)}`}`;function k(e,t,r){if(!r?.node)return;const n=e.eval(r.node,{sheet:t,row:0,col:0,dr:0,dc:0}),i=a=>xe(a,Math.min(a.bottom,Math.max(a.top,a.sheet.lastRow)));if(n instanceof Z)return i(n);if(n instanceof ae)return`(${n.parts.map(i).join(",")})`}function ge(e,t,r){if(!r?.node)return!1;const n=e.eval(r.node,{sheet:t,row:0,col:0,dr:0,dc:0});return n instanceof Z&&typeof e.value(n.sheet,n.top,n.left)=="number"}export function chartPart(e,t,r){const n=fe(e,t,r),i={name:f=>k(e,t,r.series[f]?.name),categories:k(e,t,r.categories),numeric:ge(e,t,r.categories),values:f=>k(e,t,r.series[f]?.values)??"",x:f=>k(e,t,r.series[f]?.x??r.categories)},a=k(e,t,r.title);return ce(n,{refs:i,...a===void 0?{}:{titleRef:a}})}const pe=(e,t,r)=>s("xdr:oneCellAnchor",{},s("xdr:from",{},`<xdr:col>${String(e.col)}</xdr:col>`,`<xdr:colOff>${String(Math.round(e.x*p))}</xdr:colOff>`,`<xdr:row>${String(e.row)}</xdr:row>`,`<xdr:rowOff>${String(Math.round((e.y??0)*p))}</xdr:rowOff>`),s("xdr:ext",{cx:Math.round(e.width*p),cy:Math.round(e.height*p)}),s("xdr:pic",{},s("xdr:nvPicPr",{},s("xdr:cNvPr",{id:t,name:e.name}),s("xdr:cNvPicPr",{},s("a:picLocks",{noChangeAspect:!0}))),s("xdr:blipFill",{},s("a:blip",{"xmlns:r":re,"r:embed":`rId${String(r)}`}),s("a:stretch",{},s("a:fillRect"))),s("xdr:spPr",{},s("a:xfrm",{},s("a:off",{x:0,y:0}),s("a:ext",{cx:Math.round(e.width*p),cy:Math.round(e.height*p)})),s("a:prstGeom",{prst:"rect"},s("a:avLst")))),s("xdr:clientData"));export function drawingPart(e,t=[]){const r=(n,i)=>{const{width:a,height:f}=de(n.spec);return s("xdr:oneCellAnchor",{},s("xdr:from",{},`<xdr:col>${String(n.at.col)}</xdr:col>`,`<xdr:colOff>${String(Math.round((n.spec.x??0)*p))}</xdr:colOff>`,`<xdr:row>${String(n.at.row)}</xdr:row>`,`<xdr:rowOff>${String(Math.round((n.spec.y??0)*p))}</xdr:rowOff>`),s("xdr:ext",{cx:Math.round(a*p),cy:Math.round(f*p)}),s("xdr:graphicFrame",{macro:""},s("xdr:nvGraphicFramePr",{},s("xdr:cNvPr",{id:i+2,name:`Chart ${String(i+1)}`}),s("xdr:cNvGraphicFramePr")),s("xdr:xfrm",{},s("a:off",{x:0,y:0}),s("a:ext",{cx:0,cy:0})),s("a:graphic",{},s("a:graphicData",{uri:te},s("c:chart",{"xmlns:c":te,"xmlns:r":re,"r:id":`rId${String(i+1)}`})))),s("xdr:clientData"))};return ue+s("xdr:wsDr",{"xmlns:xdr":he,"xmlns:a":me},...e.map(r),...t.map((n,i)=>pe(n,e.length+i+2,e.length+i+1)))}function G(e){if(Array.isArray(e))return e.map(G).join("");if(typeof e!="object"||e===null)return"";const t=e,r=[];for(const[n,i]of Object.entries(t))n==="t"?r.push(y(i)):typeof i=="object"&&r.push(G(i));return r.join("")}const T=e=>{const t=o(e?.solidFill),r=C(o(t?.srgbClr),"val");return r!==void 0?`#${r.toUpperCase()}`:we[C(o(t?.schemeClr),"val")??""]},we={accent1:"#4472C4",accent2:"#ED7D31",accent3:"#A5A5A5",accent4:"#FFC000",accent5:"#5B9BD5",accent6:"#70AD47"},O=(e,t)=>C(o(e?.[t]),"val"),$=(e,t)=>P(o(e?.[t]),"val"),D=(e,t)=>ee(o(e?.[t]),"val");function ne(e){if(!e)return;const t=o(e.tx),r=o(t?.strRef);if(r)return`=${y(r.f)}`;const n=G(t?.rich);return n===""?void 0:n}function oe(e){if(!e)return;const t=o(e.scaling),r=o(e.numFmt),n=C(r,"formatCode"),i={},a=ne(o(e.title));a!==void 0&&(i.title=a);const f=$(t,"min"),w=$(t,"max"),l=$(e,"majorUnit");return f!==void 0&&(i.min=f),w!==void 0&&(i.max=w),l!==void 0&&l>0&&(i.major=l),D(e,"delete")===!0&&(i.visible=!1),O(t,"orientation")==="maxMin"&&(i.reverse=!0),n!==void 0&&n!=="General"&&ee(r,"sourceLinked")!==!0&&(i.format=n),i}const R=e=>{const t=o(e?.numRef)??o(e?.strRef),r=t?y(t.f):"";return r===""?void 0:r};function be(e,t){const r=R(o(e[t?"yVal":"val"]));if(r===void 0)return"its numbers are written in the chart";const n={values:r},i=o(e.tx),a=R(i);if(a!==void 0)n.name=`=${a}`;else{const g=y(i?.v);g!==""&&(n.name=g)}const f=o(e.spPr),w=o(f?.ln),l=o(e.marker),c=t||l!==void 0,d=T(f)??(c?T(w)??T(o(l?.spPr)):void 0);d!==void 0&&(n.color=d);const h=P(w,"w");if(c&&h!==void 0&&w?.noFill===void 0){const g=Number((h/12700).toFixed(2));g!==Q.lineWidth&&(n.line_width=g)}D(e,"smooth")===!0&&(n.smooth=!0);const m=$(l,"size");m!==void 0&&m!==Q.marker&&(n.marker_size=m);const b=t?R(o(e.xVal)):void 0;b!==void 0&&(n.x=b);const x=t?void 0:R(o(e.cat));return{series:n,...x===void 0?{}:{categories:x}}}function ve(e){const t=O(e,"barDir")==="bar"?"bar":"column",r=O(e,"grouping");return r==="stacked"?`${t}-stacked`:r==="percentStacked"?`${t}-stacked-100`:`${t}-clustered`}function ye(e){const t=O(e,"grouping");return t==="stacked"?"area-stacked":t==="percentStacked"?"area-stacked-100":"area"}export function readChart(e){const t=o(e?.chartSpace),r=o(t?.chart),n=o(r?.plotArea);if(!r||!n)return"it has no plot";const i=Object.entries(n).filter(([u])=>u.endsWith("Chart")),[a]=i;if(!a)return"it has no plot";if(i.length>1||Array.isArray(a[1])&&a[1].length>1)return"it combines several kinds of chart";const[f,w]=a,l=o(w);if(!l)return"it has no plot";const c=S(l.ser),d=f==="scatterChart",h=[];let m;for(const u of c){const A=be(u,d);if(typeof A=="string")return A;h.push(A.series),m??=A.categories}if(h.length===0)return"it has no series";const b=u=>o(o(u.spPr)?.ln)?.noFill!==void 0,x=u=>O(o(u.marker),"symbol")==="none",g=(()=>{switch(f){case"barChart":return ve(l);case"lineChart":return c.every(x)?"line":"line-markers";case"areaChart":return ye(l);case"pieChart":return"pie";case"doughnutChart":return"doughnut";case"scatterChart":return c.every(b)?"scatter":c.some(u=>D(u,"smooth")===!0)?"scatter-smooth":"scatter-lines";default:return}})();if(!g)return`a sheet has no ${f.replace(/Chart$/u,"")} chart`;const U=ne(o(r.title)),I=o(r.legend),j=O(I,"legendPos"),V=o(l.dLbls),v=u=>D(V,u)===!0,se=v("showVal")||v("showPercent")||v("showCatName")||v("showSerName"),H=O(V,"dLblPos"),F=$(l,"gapWidth"),W=$(l,"overlap"),N=$(l,"holeSize"),X=D(l,"varyColors"),B=g==="pie"||g==="doughnut",M={value:S(n.valAx).find((u,A,ie)=>d?A===ie.length-1:!0),category:d?S(n.valAx)[0]:o(n.catAx)??o(n.dateAx)},L=oe(M.value),z=oe(M.category);L&&M.value?.majorGridlines===void 0&&(L.gridlines=!1),z&&M.category?.majorGridlines!==void 0&&(z.gridlines=!0);const E=P(o(o(o(o(t?.txPr)?.p)?.pPr)?.defRPr),"sz"),q=u=>u&&Object.keys(u).length>0?u:void 0,J=q(L),K=q(z);return{type:g,at:"A1",...U===void 0?{}:{title:U},...m===void 0?{}:{categories:m},series:B?h.slice(0,1):h,...I?{legend:j==="b"?"bottom":j==="t"?"top":j==="l"?"left":"right"}:{},...se?{labels:{...v("showVal")?{value:!0}:{},...v("showPercent")?{percentage:!0}:{},...v("showCatName")?{category:!0}:{},...v("showSerName")?{series:!0}:{},...H===void 0?{}:{position:H}}}:{},...F===void 0||F===150?{}:{gap_width:F},...W===void 0||g.includes("stacked")?{}:{overlap:W},...N===void 0||N===50?{}:{hole_size:N},...X===!0&&f==="barChart"?{vary_by_categories:!0}:{},...X===!1&&B?{vary_by_categories:!1}:{},...J?{value_axis:J}:{},...K?{category_axis:K}:{},...E===void 0||E===900?{}:{size:E/100}}}const _=e=>Math.round(e/p);export function chartAnchors(e,t,r){const n=o(e?.wsDr),i=[];let a=0;const f=c=>({col:Number(y(c?.col)),row:Number(y(c?.row)),colOff:_(Number(y(c?.colOff))),rowOff:_(Number(y(c?.rowOff)))}),w=c=>C(o(o(o(o(c.graphicFrame)?.graphic)?.graphicData)?.chart),"id"),l=(c,d,h,m)=>{const b=w(c);if(b===void 0){a+=1;return}i.push({id:b,at:{row:d.row,col:d.col},...d.colOff>0?{x:d.colOff}:{},...d.rowOff>0?{y:d.rowOff}:{},width:h,height:m})};for(const c of S(n?.oneCellAnchor)){const d=o(c.ext);l(c,f(o(c.from)),_(P(d,"cx")??0),_(P(d,"cy")??0))}for(const c of S(n?.twoCellAnchor)){const d=f(o(c.from)),h=f(o(c.to));let m=h.colOff-d.colOff;for(let x=d.col;x<h.col;x++)m+=t(x);let b=h.rowOff-d.rowOff;for(let x=d.row;x<h.row;x++)b+=r(x);l(c,d,m,b)}return{anchors:i,others:a}}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ZipLimits } from "@allyhub-next/formats";
|
|
1
2
|
import type { SheetProblem } from "../file.js";
|
|
2
3
|
import { type Scalar } from "../values.js";
|
|
3
4
|
/** How far apart two numbers may be, as a share of the larger, and be the same. */
|
|
@@ -36,6 +37,8 @@ export interface ImportOptions {
|
|
|
36
37
|
name: string;
|
|
37
38
|
/** See COMPARE_TOLERANCE. */
|
|
38
39
|
tolerance?: number;
|
|
40
|
+
/** What the file may unzip to; ZIP_LIMITS unless it says. */
|
|
41
|
+
zip?: Partial<ZipLimits>;
|
|
39
42
|
}
|
|
40
43
|
/** Whether a value the engine gives is what a file cached. */
|
|
41
44
|
export declare function sameValue(a: Scalar, b: Scalar, tolerance: number): boolean;
|