@cj-tech-master/excelts 9.3.1 → 9.4.0-canary.20260421000114.3ec32dd
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/browser/index.browser.d.ts +1 -0
- package/dist/browser/index.browser.js +1 -0
- package/dist/browser/index.d.ts +2 -0
- package/dist/browser/index.js +3 -0
- package/dist/browser/modules/excel/cell.d.ts +19 -0
- package/dist/browser/modules/excel/cell.js +21 -0
- package/dist/browser/modules/excel/note.d.ts +3 -23
- package/dist/browser/modules/excel/note.js +8 -2
- package/dist/browser/modules/excel/utils/cell-format.js +85 -13
- package/dist/browser/modules/excel/utils/ooxml-paths.d.ts +17 -5
- package/dist/browser/modules/excel/utils/ooxml-paths.js +46 -19
- package/dist/browser/modules/excel/workbook.browser.d.ts +57 -0
- package/dist/browser/modules/excel/workbook.browser.js +49 -0
- package/dist/browser/modules/excel/xlsx/defaultnumformats.js +3 -3
- package/dist/browser/modules/excel/xlsx/xform/comment/comment-xform.js +3 -2
- package/dist/browser/modules/excel/xlsx/xform/comment/comments-xform.d.ts +8 -0
- package/dist/browser/modules/excel/xlsx/xform/comment/comments-xform.js +52 -5
- package/dist/browser/modules/excel/xlsx/xform/comment/vml-client-data-xform.d.ts +6 -0
- package/dist/browser/modules/excel/xlsx/xform/comment/vml-client-data-xform.js +27 -1
- package/dist/browser/modules/excel/xlsx/xform/comment/vml-shape-xform.js +4 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +54 -14
- package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +3 -3
- package/dist/browser/modules/excel/xlsx/xlsx.browser.js +16 -15
- package/dist/browser/modules/formula/compile/binder.js +48 -6
- package/dist/browser/modules/formula/compile/bound-ast.d.ts +16 -2
- package/dist/browser/modules/formula/compile/bound-ast.js +1 -0
- package/dist/browser/modules/formula/compile/compiled-formula.js +41 -8
- package/dist/browser/modules/formula/functions/_shared.d.ts +19 -0
- package/dist/browser/modules/formula/functions/_shared.js +47 -0
- package/dist/browser/modules/formula/functions/conditional.js +103 -22
- package/dist/browser/modules/formula/functions/date.js +105 -23
- package/dist/browser/modules/formula/functions/dynamic-array.js +173 -69
- package/dist/browser/modules/formula/functions/engineering.d.ts +2 -2
- package/dist/browser/modules/formula/functions/engineering.js +103 -151
- package/dist/browser/modules/formula/functions/financial.js +210 -184
- package/dist/browser/modules/formula/functions/lookup.js +224 -157
- package/dist/browser/modules/formula/functions/math.d.ts +26 -0
- package/dist/browser/modules/formula/functions/math.js +249 -69
- package/dist/browser/modules/formula/functions/statistical.js +221 -171
- package/dist/browser/modules/formula/functions/text.js +112 -52
- package/dist/browser/modules/formula/integration/calculate-formulas-impl.js +20 -1
- package/dist/browser/modules/formula/materialize/build-writeback-plan.js +10 -6
- package/dist/browser/modules/formula/materialize/types.d.ts +15 -0
- package/dist/browser/modules/formula/runtime/evaluator.d.ts +8 -0
- package/dist/browser/modules/formula/runtime/evaluator.js +582 -162
- package/dist/browser/modules/formula/runtime/function-registry.d.ts +5 -0
- package/dist/browser/modules/formula/runtime/function-registry.js +59 -13
- package/dist/browser/modules/formula/runtime/values.d.ts +13 -0
- package/dist/browser/modules/formula/runtime/values.js +20 -2
- package/dist/browser/modules/formula/syntax/ast.d.ts +14 -2
- package/dist/browser/modules/formula/syntax/ast.js +1 -0
- package/dist/browser/modules/formula/syntax/parser.js +29 -7
- package/dist/browser/modules/formula/syntax/token-types.d.ts +4 -0
- package/dist/browser/modules/formula/syntax/token-types.js +9 -0
- package/dist/browser/modules/formula/syntax/tokenizer.js +76 -19
- package/dist/cjs/index.js +9 -2
- package/dist/cjs/modules/excel/cell.js +21 -0
- package/dist/cjs/modules/excel/note.js +8 -2
- package/dist/cjs/modules/excel/utils/cell-format.js +85 -13
- package/dist/cjs/modules/excel/utils/ooxml-paths.js +49 -24
- package/dist/cjs/modules/excel/workbook.browser.js +49 -0
- package/dist/cjs/modules/excel/xlsx/defaultnumformats.js +3 -3
- package/dist/cjs/modules/excel/xlsx/xform/comment/comment-xform.js +3 -2
- package/dist/cjs/modules/excel/xlsx/xform/comment/comments-xform.js +52 -5
- package/dist/cjs/modules/excel/xlsx/xform/comment/vml-client-data-xform.js +27 -1
- package/dist/cjs/modules/excel/xlsx/xform/comment/vml-shape-xform.js +4 -0
- package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +53 -13
- package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +15 -14
- package/dist/cjs/modules/formula/compile/binder.js +48 -6
- package/dist/cjs/modules/formula/compile/compiled-formula.js +41 -8
- package/dist/cjs/modules/formula/functions/_shared.js +48 -0
- package/dist/cjs/modules/formula/functions/conditional.js +103 -22
- package/dist/cjs/modules/formula/functions/date.js +104 -22
- package/dist/cjs/modules/formula/functions/dynamic-array.js +173 -69
- package/dist/cjs/modules/formula/functions/engineering.js +109 -157
- package/dist/cjs/modules/formula/functions/financial.js +209 -183
- package/dist/cjs/modules/formula/functions/lookup.js +224 -157
- package/dist/cjs/modules/formula/functions/math.js +254 -70
- package/dist/cjs/modules/formula/functions/statistical.js +222 -172
- package/dist/cjs/modules/formula/functions/text.js +112 -52
- package/dist/cjs/modules/formula/integration/calculate-formulas-impl.js +20 -1
- package/dist/cjs/modules/formula/materialize/build-writeback-plan.js +10 -6
- package/dist/cjs/modules/formula/runtime/evaluator.js +581 -161
- package/dist/cjs/modules/formula/runtime/function-registry.js +57 -11
- package/dist/cjs/modules/formula/runtime/values.js +21 -2
- package/dist/cjs/modules/formula/syntax/parser.js +29 -7
- package/dist/cjs/modules/formula/syntax/token-types.js +9 -0
- package/dist/cjs/modules/formula/syntax/tokenizer.js +76 -19
- package/dist/esm/index.browser.js +1 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/modules/excel/cell.js +21 -0
- package/dist/esm/modules/excel/note.js +8 -2
- package/dist/esm/modules/excel/utils/cell-format.js +85 -13
- package/dist/esm/modules/excel/utils/ooxml-paths.js +46 -19
- package/dist/esm/modules/excel/workbook.browser.js +49 -0
- package/dist/esm/modules/excel/xlsx/defaultnumformats.js +3 -3
- package/dist/esm/modules/excel/xlsx/xform/comment/comment-xform.js +3 -2
- package/dist/esm/modules/excel/xlsx/xform/comment/comments-xform.js +52 -5
- package/dist/esm/modules/excel/xlsx/xform/comment/vml-client-data-xform.js +27 -1
- package/dist/esm/modules/excel/xlsx/xform/comment/vml-shape-xform.js +4 -0
- package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +54 -14
- package/dist/esm/modules/excel/xlsx/xlsx.browser.js +16 -15
- package/dist/esm/modules/formula/compile/binder.js +48 -6
- package/dist/esm/modules/formula/compile/bound-ast.js +1 -0
- package/dist/esm/modules/formula/compile/compiled-formula.js +41 -8
- package/dist/esm/modules/formula/functions/_shared.js +47 -0
- package/dist/esm/modules/formula/functions/conditional.js +103 -22
- package/dist/esm/modules/formula/functions/date.js +105 -23
- package/dist/esm/modules/formula/functions/dynamic-array.js +173 -69
- package/dist/esm/modules/formula/functions/engineering.js +103 -151
- package/dist/esm/modules/formula/functions/financial.js +210 -184
- package/dist/esm/modules/formula/functions/lookup.js +224 -157
- package/dist/esm/modules/formula/functions/math.js +249 -69
- package/dist/esm/modules/formula/functions/statistical.js +221 -171
- package/dist/esm/modules/formula/functions/text.js +112 -52
- package/dist/esm/modules/formula/integration/calculate-formulas-impl.js +20 -1
- package/dist/esm/modules/formula/materialize/build-writeback-plan.js +10 -6
- package/dist/esm/modules/formula/runtime/evaluator.js +582 -162
- package/dist/esm/modules/formula/runtime/function-registry.js +59 -13
- package/dist/esm/modules/formula/runtime/values.js +20 -2
- package/dist/esm/modules/formula/syntax/ast.js +1 -0
- package/dist/esm/modules/formula/syntax/parser.js +29 -7
- package/dist/esm/modules/formula/syntax/token-types.js +9 -0
- package/dist/esm/modules/formula/syntax/tokenizer.js +76 -19
- package/dist/iife/excelts.iife.js +3576 -3360
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +34 -34
- package/dist/types/index.browser.d.ts +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/modules/excel/cell.d.ts +19 -0
- package/dist/types/modules/excel/note.d.ts +3 -23
- package/dist/types/modules/excel/utils/ooxml-paths.d.ts +17 -5
- package/dist/types/modules/excel/workbook.browser.d.ts +57 -0
- package/dist/types/modules/excel/xlsx/xform/comment/comments-xform.d.ts +8 -0
- package/dist/types/modules/excel/xlsx/xform/comment/vml-client-data-xform.d.ts +6 -0
- package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +3 -3
- package/dist/types/modules/formula/compile/bound-ast.d.ts +16 -2
- package/dist/types/modules/formula/functions/_shared.d.ts +19 -0
- package/dist/types/modules/formula/functions/engineering.d.ts +2 -2
- package/dist/types/modules/formula/functions/math.d.ts +26 -0
- package/dist/types/modules/formula/materialize/types.d.ts +15 -0
- package/dist/types/modules/formula/runtime/evaluator.d.ts +8 -0
- package/dist/types/modules/formula/runtime/function-registry.d.ts +5 -0
- package/dist/types/modules/formula/runtime/values.d.ts +13 -0
- package/dist/types/modules/formula/syntax/ast.d.ts +14 -2
- package/dist/types/modules/formula/syntax/token-types.d.ts +4 -0
- package/package.json +4 -4
|
@@ -11,6 +11,7 @@ export { Range } from "./modules/excel/range.js";
|
|
|
11
11
|
export { Image } from "./modules/excel/image.js";
|
|
12
12
|
export * from "./modules/excel/anchor.js";
|
|
13
13
|
export { Table } from "./modules/excel/table.js";
|
|
14
|
+
export { Note } from "./modules/excel/note.js";
|
|
14
15
|
export { DataValidations } from "./modules/excel/data-validations.js";
|
|
15
16
|
export { FormCheckbox } from "./modules/excel/form-control.js";
|
|
16
17
|
export * from "./modules/excel/enums.js";
|
|
@@ -14,6 +14,7 @@ export { Range } from "./modules/excel/range.js";
|
|
|
14
14
|
export { Image } from "./modules/excel/image.js";
|
|
15
15
|
export * from "./modules/excel/anchor.js";
|
|
16
16
|
export { Table } from "./modules/excel/table.js";
|
|
17
|
+
export { Note } from "./modules/excel/note.js";
|
|
17
18
|
export { DataValidations } from "./modules/excel/data-validations.js";
|
|
18
19
|
export { FormCheckbox } from "./modules/excel/form-control.js";
|
|
19
20
|
// Note: the formula engine lives at the `./formula` subpath so it stays
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { Range } from "./modules/excel/range.js";
|
|
|
7
7
|
export { Image } from "./modules/excel/image.js";
|
|
8
8
|
export * from "./modules/excel/anchor.js";
|
|
9
9
|
export { Table } from "./modules/excel/table.js";
|
|
10
|
+
export { Note } from "./modules/excel/note.js";
|
|
10
11
|
export { DataValidations } from "./modules/excel/data-validations.js";
|
|
11
12
|
export { FormCheckbox } from "./modules/excel/form-control.js";
|
|
12
13
|
export { WorkbookWriter } from "./modules/excel/stream/workbook-writer.js";
|
|
@@ -35,6 +36,7 @@ export type { NodeInput } from "./modules/excel/stream/workbook-reader.js";
|
|
|
35
36
|
export { decodeCol, encodeCol, decodeRow, encodeRow, decodeCell, encodeCell, decodeRange, encodeRange } from "./modules/excel/utils/address.js";
|
|
36
37
|
export type { CellAddress, SheetRange, Origin } from "./modules/excel/utils/address.js";
|
|
37
38
|
export type { SheetToJSONOptions, AddJSONOptions, AddAOAOptions } from "./modules/excel/worksheet.js";
|
|
39
|
+
export { getCellDisplayText, formatCellValue, isDateDisplayFormat } from "./modules/excel/utils/cell-format.js";
|
|
38
40
|
export { dateToExcel, excelToDate } from "./utils/utils.base.js";
|
|
39
41
|
export { base64ToUint8Array, uint8ArrayToBase64 } from "./utils/utils.base.js";
|
|
40
42
|
export { xmlEncode, xmlDecode } from "./modules/xml/encode.js";
|
package/dist/browser/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export { Range } from "./modules/excel/range.js";
|
|
|
10
10
|
export { Image } from "./modules/excel/image.js";
|
|
11
11
|
export * from "./modules/excel/anchor.js";
|
|
12
12
|
export { Table } from "./modules/excel/table.js";
|
|
13
|
+
export { Note } from "./modules/excel/note.js";
|
|
13
14
|
export { DataValidations } from "./modules/excel/data-validations.js";
|
|
14
15
|
export { FormCheckbox } from "./modules/excel/form-control.js";
|
|
15
16
|
// Note: the formula engine lives at the `./formula` subpath so it stays
|
|
@@ -45,6 +46,8 @@ export { DefinedNames } from "./modules/excel/defined-names.js";
|
|
|
45
46
|
// =============================================================================
|
|
46
47
|
// Cell address encoding/decoding (0-indexed)
|
|
47
48
|
export { decodeCol, encodeCol, decodeRow, encodeRow, decodeCell, encodeCell, decodeRange, encodeRange } from "./modules/excel/utils/address.js";
|
|
49
|
+
// Cell display-text helpers (apply numFmt to produce an Excel-style string)
|
|
50
|
+
export { getCellDisplayText, formatCellValue, isDateDisplayFormat } from "./modules/excel/utils/cell-format.js";
|
|
48
51
|
// Date conversion (Excel serial dates <-> JS Date)
|
|
49
52
|
export { dateToExcel, excelToDate } from "./utils/utils.base.js";
|
|
50
53
|
// Base64 utilities (cross-platform)
|
|
@@ -47,6 +47,7 @@ export interface NoteConfig {
|
|
|
47
47
|
export interface NoteModel {
|
|
48
48
|
type: string;
|
|
49
49
|
note: NoteConfig;
|
|
50
|
+
author?: string;
|
|
50
51
|
}
|
|
51
52
|
export interface CellModel {
|
|
52
53
|
address: string;
|
|
@@ -130,6 +131,24 @@ declare class Cell {
|
|
|
130
131
|
get comment(): Note | undefined;
|
|
131
132
|
set comment(comment: Note | NoteConfig | undefined);
|
|
132
133
|
get text(): string;
|
|
134
|
+
/**
|
|
135
|
+
* The cell's display text — the value formatted the way Excel would render
|
|
136
|
+
* it, applying the cell's `numFmt`. For a Date cell with `numFmt` `"mm-dd-yy"`,
|
|
137
|
+
* this returns e.g. `"04-12-19"` rather than the JS `Date.prototype.toString()`
|
|
138
|
+
* output you'd get from `cell.text`.
|
|
139
|
+
*
|
|
140
|
+
* Handles primitive values, dates, and formula results. For rich text,
|
|
141
|
+
* hyperlinks, errors, and other complex types, falls back to `cell.text`.
|
|
142
|
+
*
|
|
143
|
+
* Note: numFmt codes that are locale-dependent in Excel (e.g. built-in
|
|
144
|
+
* numFmtId 14 renders as `dd.mm.yyyy` under German locale but is stored
|
|
145
|
+
* as `mm-dd-yy`) are applied literally — excelts does not perform
|
|
146
|
+
* Excel's locale-based format substitution. If you need a specific date
|
|
147
|
+
* style across cells regardless of per-cell numFmts, call the exported
|
|
148
|
+
* {@link getCellDisplayText} helper with a `dateFormat` argument, or use
|
|
149
|
+
* `worksheet.toJSON({ dateFormat })`.
|
|
150
|
+
*/
|
|
151
|
+
get displayText(): string;
|
|
133
152
|
get html(): string;
|
|
134
153
|
toString(): string;
|
|
135
154
|
get formula(): string | undefined;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Enums } from "./enums.js";
|
|
2
2
|
import { ExcelError, InvalidValueTypeError } from "./errors.js";
|
|
3
3
|
import { Note } from "./note.js";
|
|
4
|
+
import { getCellDisplayText } from "./utils/cell-format.js";
|
|
4
5
|
import { colCache } from "./utils/col-cache.js";
|
|
5
6
|
import { copyStyle } from "./utils/copy-style.js";
|
|
6
7
|
import { slideFormula } from "./utils/shared-formula.js";
|
|
@@ -271,6 +272,26 @@ class Cell {
|
|
|
271
272
|
get text() {
|
|
272
273
|
return this._value.toString();
|
|
273
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* The cell's display text — the value formatted the way Excel would render
|
|
277
|
+
* it, applying the cell's `numFmt`. For a Date cell with `numFmt` `"mm-dd-yy"`,
|
|
278
|
+
* this returns e.g. `"04-12-19"` rather than the JS `Date.prototype.toString()`
|
|
279
|
+
* output you'd get from `cell.text`.
|
|
280
|
+
*
|
|
281
|
+
* Handles primitive values, dates, and formula results. For rich text,
|
|
282
|
+
* hyperlinks, errors, and other complex types, falls back to `cell.text`.
|
|
283
|
+
*
|
|
284
|
+
* Note: numFmt codes that are locale-dependent in Excel (e.g. built-in
|
|
285
|
+
* numFmtId 14 renders as `dd.mm.yyyy` under German locale but is stored
|
|
286
|
+
* as `mm-dd-yy`) are applied literally — excelts does not perform
|
|
287
|
+
* Excel's locale-based format substitution. If you need a specific date
|
|
288
|
+
* style across cells regardless of per-cell numFmts, call the exported
|
|
289
|
+
* {@link getCellDisplayText} helper with a `dateFormat` argument, or use
|
|
290
|
+
* `worksheet.toJSON({ dateFormat })`.
|
|
291
|
+
*/
|
|
292
|
+
get displayText() {
|
|
293
|
+
return getCellDisplayText(this);
|
|
294
|
+
}
|
|
274
295
|
get html() {
|
|
275
296
|
return escapeHtml(this.text);
|
|
276
297
|
}
|
|
@@ -1,29 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
interface NoteText {
|
|
3
|
-
text: string;
|
|
4
|
-
font?: Partial<Font>;
|
|
5
|
-
}
|
|
6
|
-
interface NoteConfig {
|
|
7
|
-
margins?: {
|
|
8
|
-
insetmode?: string;
|
|
9
|
-
inset?: number[];
|
|
10
|
-
};
|
|
11
|
-
protection?: {
|
|
12
|
-
locked?: string;
|
|
13
|
-
lockText?: string;
|
|
14
|
-
};
|
|
15
|
-
editAs?: string;
|
|
16
|
-
texts?: NoteText[];
|
|
17
|
-
anchor?: string;
|
|
18
|
-
}
|
|
19
|
-
interface NoteModel {
|
|
20
|
-
type: string;
|
|
21
|
-
note: NoteConfig;
|
|
22
|
-
}
|
|
1
|
+
import type { NoteConfig, NoteModel } from "./cell.js";
|
|
23
2
|
declare class Note {
|
|
24
3
|
note: string | NoteConfig | undefined;
|
|
4
|
+
author: string | undefined;
|
|
25
5
|
static readonly DEFAULT_CONFIGS: NoteModel;
|
|
26
|
-
constructor(note?: string | NoteConfig);
|
|
6
|
+
constructor(note?: string | NoteConfig, author?: string);
|
|
27
7
|
get model(): NoteModel;
|
|
28
8
|
set model(value: NoteModel);
|
|
29
9
|
static fromModel(model: NoteModel): Note;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { deepMerge } from "./utils/under-dash.js";
|
|
2
2
|
class Note {
|
|
3
|
-
constructor(note) {
|
|
3
|
+
constructor(note, author) {
|
|
4
4
|
this.note = note;
|
|
5
|
+
this.author = author;
|
|
5
6
|
}
|
|
6
7
|
get model() {
|
|
7
8
|
let value;
|
|
@@ -26,7 +27,11 @@ class Note {
|
|
|
26
27
|
break;
|
|
27
28
|
}
|
|
28
29
|
// Suitable for all cell comments
|
|
29
|
-
|
|
30
|
+
const result = deepMerge({}, Note.DEFAULT_CONFIGS, value);
|
|
31
|
+
if (this.author !== undefined) {
|
|
32
|
+
result.author = this.author;
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
30
35
|
}
|
|
31
36
|
set model(value) {
|
|
32
37
|
const { note } = value;
|
|
@@ -37,6 +42,7 @@ class Note {
|
|
|
37
42
|
else {
|
|
38
43
|
this.note = note;
|
|
39
44
|
}
|
|
45
|
+
this.author = value.author;
|
|
40
46
|
}
|
|
41
47
|
static fromModel(model) {
|
|
42
48
|
const note = new Note();
|
|
@@ -20,7 +20,7 @@ const TABLE_FMT = {
|
|
|
20
20
|
11: "0.00E+00",
|
|
21
21
|
12: "# ?/?",
|
|
22
22
|
13: "# ??/??",
|
|
23
|
-
14: "
|
|
23
|
+
14: "mm-dd-yy",
|
|
24
24
|
15: "d-mmm-yy",
|
|
25
25
|
16: "d-mmm",
|
|
26
26
|
17: "mmm-yy",
|
|
@@ -210,6 +210,56 @@ const MONTHS_LONG = [
|
|
|
210
210
|
const MONTHS_LETTER = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"];
|
|
211
211
|
const DAYS_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
212
212
|
const DAYS_LONG = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
213
|
+
/**
|
|
214
|
+
* Disambiguate each `mm` occurrence in a format string that has already been
|
|
215
|
+
* placeholder-substituted for the other date/time tokens.
|
|
216
|
+
*
|
|
217
|
+
* Excel's rule: `mm` is minutes when it's adjacent to an hour or seconds
|
|
218
|
+
* token (with no intervening date tokens); otherwise it's a zero-padded
|
|
219
|
+
* month. This must be decided per occurrence — a single format string can
|
|
220
|
+
* contain both roles (e.g. `"yyyy-mm-dd hh:mm:ss"`).
|
|
221
|
+
*
|
|
222
|
+
* The caller has already replaced `yyyy`/`yy` → `Y4/Y2`, month-name tokens
|
|
223
|
+
* `mmmmm/mmmm/mmm` → `MN5/MN4/MN3`, `dd`/`d` → `D2/D1`, `hh`/`h` → `H2/H1`,
|
|
224
|
+
* `ss`/`s` → `S2/S1`. So any remaining literal `mm` substrings here are
|
|
225
|
+
* ambiguous between minute and month.
|
|
226
|
+
*
|
|
227
|
+
* Returns the input with each `mm` replaced by either `\x00MI2\x00` (minutes)
|
|
228
|
+
* or `\x00M2\x00` (month, zero-padded).
|
|
229
|
+
*/
|
|
230
|
+
function resolveMonthOrMinute(s) {
|
|
231
|
+
// Tokens that, when present between an `mm` and a time anchor, break the
|
|
232
|
+
// "adjacent time context" chain and push the `mm` back into month-land.
|
|
233
|
+
const DATE_TOKEN = /\x00(?:Y[24]|D[12]|MN[345])\x00/;
|
|
234
|
+
const HOUR_TOKEN = /\x00H[12]\x00/g;
|
|
235
|
+
const SEC_TOKEN = /\x00S[12]\x00/g;
|
|
236
|
+
let out = "";
|
|
237
|
+
let work = s;
|
|
238
|
+
let idx = work.search(/mm/i);
|
|
239
|
+
while (idx !== -1) {
|
|
240
|
+
const before = work.slice(0, idx);
|
|
241
|
+
const after = work.slice(idx + 2);
|
|
242
|
+
// Find the *nearest* hour token preceding this `mm` (scan from the right).
|
|
243
|
+
let nearestHourIdx = -1;
|
|
244
|
+
let m;
|
|
245
|
+
HOUR_TOKEN.lastIndex = 0;
|
|
246
|
+
while ((m = HOUR_TOKEN.exec(before)) !== null) {
|
|
247
|
+
nearestHourIdx = m.index;
|
|
248
|
+
}
|
|
249
|
+
// Find the *nearest* seconds token following this `mm`.
|
|
250
|
+
SEC_TOKEN.lastIndex = 0;
|
|
251
|
+
const secMatch = SEC_TOKEN.exec(after);
|
|
252
|
+
const nearestSecIdx = secMatch ? secMatch.index : -1;
|
|
253
|
+
const hourInRange = nearestHourIdx !== -1 && !DATE_TOKEN.test(before.slice(nearestHourIdx));
|
|
254
|
+
const secInRange = nearestSecIdx !== -1 && !DATE_TOKEN.test(after.slice(0, nearestSecIdx));
|
|
255
|
+
const isMinutes = hourInRange || secInRange;
|
|
256
|
+
out += before + (isMinutes ? "\x00MI2\x00" : "\x00M2\x00");
|
|
257
|
+
work = after;
|
|
258
|
+
idx = work.search(/mm/i);
|
|
259
|
+
}
|
|
260
|
+
out += work;
|
|
261
|
+
return out;
|
|
262
|
+
}
|
|
213
263
|
/**
|
|
214
264
|
* Format a date value using Excel date format
|
|
215
265
|
* @param serial Excel serial number (days since 1900-01-01)
|
|
@@ -270,16 +320,14 @@ function formatDate(serial, fmt) {
|
|
|
270
320
|
// Seconds (before mm to avoid confusion)
|
|
271
321
|
result = result.replace(/ss/gi, "\x00S2\x00");
|
|
272
322
|
result = result.replace(/\bs\b/gi, "\x00S1\x00");
|
|
273
|
-
// Minutes/Month mm -
|
|
274
|
-
//
|
|
275
|
-
//
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
result = result.replace(/mm/gi, "\x00M2\x00");
|
|
282
|
-
}
|
|
323
|
+
// Minutes/Month `mm` — position-dependent. Excel treats `mm` as minutes
|
|
324
|
+
// when the nearest neighboring time-token is an hour (before) or a
|
|
325
|
+
// seconds token (after); otherwise it's month. This must be decided **per
|
|
326
|
+
// occurrence**, because a single format string can contain both roles —
|
|
327
|
+
// e.g. in `"yyyy-mm-dd hh:mm:ss"` the first `mm` is month and the second
|
|
328
|
+
// is minutes. A single global `hasTimeContext` flag would miscategorise
|
|
329
|
+
// all `mm` as minutes in such mixed formats.
|
|
330
|
+
result = resolveMonthOrMinute(result);
|
|
283
331
|
result = result.replace(/\bm\b/gi, "\x00M1\x00");
|
|
284
332
|
// AM/PM
|
|
285
333
|
result = result.replace(/AM\/PM/gi, "\x00AMPM\x00");
|
|
@@ -887,6 +935,16 @@ export function isDateDisplayFormat(fmt) {
|
|
|
887
935
|
}
|
|
888
936
|
return false;
|
|
889
937
|
}
|
|
938
|
+
/**
|
|
939
|
+
* Default format applied to Date values whose numFmt is `General` or empty.
|
|
940
|
+
*
|
|
941
|
+
* Excel itself substitutes a locale-dependent short date in this case (US:
|
|
942
|
+
* `m/d/yyyy`). We pick an ISO-like `yyyy-mm-dd` so consumers who never set a
|
|
943
|
+
* `numFmt` still get a sensible, unambiguous rendering instead of the raw
|
|
944
|
+
* Excel serial number.
|
|
945
|
+
*/
|
|
946
|
+
const DEFAULT_DATE_FORMAT = "yyyy-mm-dd";
|
|
947
|
+
const DEFAULT_DATETIME_FORMAT = "yyyy-mm-dd hh:mm:ss";
|
|
890
948
|
/**
|
|
891
949
|
* Format a value according to the given format string.
|
|
892
950
|
* Handles Date objects with timezone-independent Excel serial conversion.
|
|
@@ -901,8 +959,22 @@ export function formatCellValue(value, fmt, dateFormat) {
|
|
|
901
959
|
}
|
|
902
960
|
return format(fmt, serial);
|
|
903
961
|
}
|
|
904
|
-
|
|
905
|
-
|
|
962
|
+
// For Date values whose numFmt is missing or General, Excel substitutes a
|
|
963
|
+
// default short-date format. Without this, `format("General", serial)`
|
|
964
|
+
// would emit the raw Excel serial (e.g. "43567") — almost never what the
|
|
965
|
+
// caller wants. Pick a datetime-aware default based on whether the value
|
|
966
|
+
// carries a non-midnight time component.
|
|
967
|
+
let effectiveFmt;
|
|
968
|
+
if (dateFormat && isDateDisplayFormat(fmt)) {
|
|
969
|
+
effectiveFmt = dateFormat;
|
|
970
|
+
}
|
|
971
|
+
else if (!fmt || isGeneral(fmt)) {
|
|
972
|
+
effectiveFmt = serial % 1 === 0 ? DEFAULT_DATE_FORMAT : DEFAULT_DATETIME_FORMAT;
|
|
973
|
+
}
|
|
974
|
+
else {
|
|
975
|
+
effectiveFmt = fmt;
|
|
976
|
+
}
|
|
977
|
+
return format(effectiveFmt, serial);
|
|
906
978
|
}
|
|
907
979
|
return format(fmt, value);
|
|
908
980
|
}
|
|
@@ -23,7 +23,11 @@ export declare function getDrawingNameFromPath(path: string): string | undefined
|
|
|
23
23
|
export declare function getDrawingNameFromRelsPath(path: string): string | undefined;
|
|
24
24
|
export declare function getVmlDrawingNameFromPath(path: string): string | undefined;
|
|
25
25
|
export declare function getVmlDrawingHFNameFromPath(path: string): string | undefined;
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Check if a zip entry path is a comments XML file.
|
|
28
|
+
* Works for both `xl/comments1.xml` and `xl/comments/comment1.xml`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isCommentsPath(path: string): boolean;
|
|
27
31
|
export declare function getTableNameFromPath(path: string): string | undefined;
|
|
28
32
|
export declare function getPivotTableNameFromPath(path: string): string | undefined;
|
|
29
33
|
export declare function getPivotTableNameFromRelsPath(path: string): string | undefined;
|
|
@@ -59,6 +63,7 @@ export declare function pivotCacheDefinitionRelsPath(n: number | string): string
|
|
|
59
63
|
export declare function pivotCacheRecordsPath(n: number | string): string;
|
|
60
64
|
export declare function pivotCacheRecordsRelTarget(n: number | string): string;
|
|
61
65
|
export declare function pivotTablePath(n: number | string): string;
|
|
66
|
+
export declare function pivotTablePathFromName(name: string): string;
|
|
62
67
|
export declare function pivotTableRelsPath(n: number | string): string;
|
|
63
68
|
export declare function externalLinkPath(n: number | string): string;
|
|
64
69
|
export declare function externalLinkRelsPath(n: number | string): string;
|
|
@@ -80,12 +85,19 @@ export declare function commentsRelTargetFromWorksheet(sheetId: number | string)
|
|
|
80
85
|
export declare function vmlDrawingRelTargetFromWorksheet(sheetId: number | string): string;
|
|
81
86
|
export declare function vmlDrawingHFRelTargetFromWorksheet(sheetId: number | string): string;
|
|
82
87
|
export declare function drawingRelTargetFromWorksheet(drawingName: string): string;
|
|
83
|
-
export declare function vmlDrawingRelTargetFromWorksheetName(vmlName: string): string;
|
|
84
|
-
export declare function commentsRelTargetFromWorksheetName(commentName: string): string;
|
|
85
88
|
export declare function pivotTableRelTargetFromWorksheet(n: number | string): string;
|
|
86
|
-
export declare function pivotTableRelTargetFromWorksheetName(pivotName: string): string;
|
|
87
89
|
export declare function tableRelTargetFromWorksheet(target: string): string;
|
|
88
|
-
export declare function tableRelTargetFromWorksheetName(name: string): string;
|
|
89
90
|
export declare function mediaRelTargetFromRels(filename: string): string;
|
|
90
91
|
export declare function ctrlPropPath(id: number | string): string;
|
|
91
92
|
export declare function ctrlPropRelTargetFromWorksheet(id: number | string): string;
|
|
93
|
+
/**
|
|
94
|
+
* Resolve a relationship Target (relative or absolute) to a normalized zip path.
|
|
95
|
+
*
|
|
96
|
+
* OOXML relationship targets may be:
|
|
97
|
+
* - Relative: `../comments1.xml` (resolved against `baseDir`)
|
|
98
|
+
* - Absolute: `/xl/comments/comment1.xml` (leading slash stripped)
|
|
99
|
+
*
|
|
100
|
+
* @param baseDir The directory containing the source part (e.g. `xl/worksheets/`)
|
|
101
|
+
* @param target The raw Target value from the .rels file
|
|
102
|
+
*/
|
|
103
|
+
export declare function resolveRelTarget(baseDir: string, target: string): string;
|
|
@@ -19,7 +19,9 @@ const drawingXmlRegex = /^xl\/drawings\/(drawing\d+)[.]xml$/;
|
|
|
19
19
|
const drawingRelsXmlRegex = /^xl\/drawings\/_rels\/(drawing\d+)[.]xml[.]rels$/;
|
|
20
20
|
const vmlDrawingRegex = /^xl\/drawings\/(vmlDrawing\d+)[.]vml$/;
|
|
21
21
|
const vmlDrawingHFRegex = /^xl\/drawings\/(vmlDrawingHF\d+)[.]vml$/;
|
|
22
|
-
|
|
22
|
+
// Matches both flat layout (xl/comments1.xml) and subdirectory layout (xl/comments/comment1.xml).
|
|
23
|
+
// Both are valid OOXML — the actual path is determined by .rels, not by convention.
|
|
24
|
+
const commentsXmlRegex = /^xl\/(?:comments(\d+)|comments\/comment(\d+))[.]xml$/;
|
|
23
25
|
const tableXmlRegex = /^xl\/tables\/(table\d+)[.]xml$/;
|
|
24
26
|
const pivotTableXmlRegex = /^xl\/pivotTables\/(pivotTable\d+)[.]xml$/;
|
|
25
27
|
const pivotTableRelsXmlRegex = /^xl\/pivotTables\/_rels\/(pivotTable\d+)[.]xml[.]rels$/;
|
|
@@ -81,9 +83,12 @@ export function getVmlDrawingHFNameFromPath(path) {
|
|
|
81
83
|
const match = vmlDrawingHFRegex.exec(path);
|
|
82
84
|
return match ? match[1] : undefined;
|
|
83
85
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Check if a zip entry path is a comments XML file.
|
|
88
|
+
* Works for both `xl/comments1.xml` and `xl/comments/comment1.xml`.
|
|
89
|
+
*/
|
|
90
|
+
export function isCommentsPath(path) {
|
|
91
|
+
return commentsXmlRegex.test(path);
|
|
87
92
|
}
|
|
88
93
|
export function getTableNameFromPath(path) {
|
|
89
94
|
const match = tableXmlRegex.exec(path);
|
|
@@ -184,6 +189,9 @@ export function pivotCacheRecordsRelTarget(n) {
|
|
|
184
189
|
export function pivotTablePath(n) {
|
|
185
190
|
return `xl/pivotTables/pivotTable${n}.xml`;
|
|
186
191
|
}
|
|
192
|
+
export function pivotTablePathFromName(name) {
|
|
193
|
+
return `xl/pivotTables/${name}.xml`;
|
|
194
|
+
}
|
|
187
195
|
export function pivotTableRelsPath(n) {
|
|
188
196
|
return `xl/pivotTables/_rels/pivotTable${n}.xml.rels`;
|
|
189
197
|
}
|
|
@@ -232,29 +240,14 @@ export function drawingRelTargetFromWorksheet(drawingName) {
|
|
|
232
240
|
// Target inside xl/worksheets/_rels/sheetN.xml.rels (base: xl/worksheets/)
|
|
233
241
|
return `../drawings/${drawingName}.xml`;
|
|
234
242
|
}
|
|
235
|
-
export function vmlDrawingRelTargetFromWorksheetName(vmlName) {
|
|
236
|
-
// For VML drawings when the caller already has the logical name (e.g. "vmlDrawing1").
|
|
237
|
-
return `../drawings/${vmlName}.vml`;
|
|
238
|
-
}
|
|
239
|
-
export function commentsRelTargetFromWorksheetName(commentName) {
|
|
240
|
-
// For comments when the caller already has the logical name (e.g. "comments1").
|
|
241
|
-
return `../${commentName}.xml`;
|
|
242
|
-
}
|
|
243
243
|
export function pivotTableRelTargetFromWorksheet(n) {
|
|
244
244
|
// Target inside xl/worksheets/_rels/sheetN.xml.rels (base: xl/worksheets/)
|
|
245
245
|
return `../pivotTables/pivotTable${n}.xml`;
|
|
246
246
|
}
|
|
247
|
-
export function pivotTableRelTargetFromWorksheetName(pivotName) {
|
|
248
|
-
// For pivot tables when the caller already has the logical name (e.g. "pivotTable1").
|
|
249
|
-
return `../pivotTables/${pivotName}.xml`;
|
|
250
|
-
}
|
|
251
247
|
export function tableRelTargetFromWorksheet(target) {
|
|
252
248
|
// Target inside xl/worksheets/_rels/sheetN.xml.rels (base: xl/worksheets/)
|
|
253
249
|
return `../tables/${target}`;
|
|
254
250
|
}
|
|
255
|
-
export function tableRelTargetFromWorksheetName(name) {
|
|
256
|
-
return `../tables/${name}.xml`;
|
|
257
|
-
}
|
|
258
251
|
export function mediaRelTargetFromRels(filename) {
|
|
259
252
|
// Target from a rels file located under xl/*/_rels (base is one level deeper than xl/)
|
|
260
253
|
return `../media/${filename}`;
|
|
@@ -267,3 +260,37 @@ export function ctrlPropRelTargetFromWorksheet(id) {
|
|
|
267
260
|
// Target inside xl/worksheets/_rels/sheetN.xml.rels (base: xl/worksheets/)
|
|
268
261
|
return `../ctrlProps/ctrlProp${id}.xml`;
|
|
269
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Resolve a relationship Target (relative or absolute) to a normalized zip path.
|
|
265
|
+
*
|
|
266
|
+
* OOXML relationship targets may be:
|
|
267
|
+
* - Relative: `../comments1.xml` (resolved against `baseDir`)
|
|
268
|
+
* - Absolute: `/xl/comments/comment1.xml` (leading slash stripped)
|
|
269
|
+
*
|
|
270
|
+
* @param baseDir The directory containing the source part (e.g. `xl/worksheets/`)
|
|
271
|
+
* @param target The raw Target value from the .rels file
|
|
272
|
+
*/
|
|
273
|
+
export function resolveRelTarget(baseDir, target) {
|
|
274
|
+
// Absolute target — strip leading slash to get the zip path.
|
|
275
|
+
if (target.startsWith("/")) {
|
|
276
|
+
return target.slice(1);
|
|
277
|
+
}
|
|
278
|
+
// Ensure baseDir ends with "/" so the join works correctly.
|
|
279
|
+
const base = baseDir.endsWith("/") ? baseDir : baseDir + "/";
|
|
280
|
+
// Relative target — resolve against baseDir.
|
|
281
|
+
// Simple resolution: join base + target, then resolve `.` and `..` segments.
|
|
282
|
+
const parts = (base + target).split("/");
|
|
283
|
+
const resolved = [];
|
|
284
|
+
for (const part of parts) {
|
|
285
|
+
if (part === "." || part === "") {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
else if (part === "..") {
|
|
289
|
+
resolved.pop();
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
resolved.push(part);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return resolved.join("/");
|
|
296
|
+
}
|
|
@@ -603,6 +603,63 @@ declare class Workbook {
|
|
|
603
603
|
* ```
|
|
604
604
|
*/
|
|
605
605
|
calculateFormulas(): void;
|
|
606
|
+
/**
|
|
607
|
+
* Per-workbook registry of user-defined functions. The formula engine
|
|
608
|
+
* consults this map before the built-in 433-function registry, so a
|
|
609
|
+
* registered name either adds a new function (`MYFN`) or shadows a
|
|
610
|
+
* built-in (`IRR` → project-specific variant).
|
|
611
|
+
*
|
|
612
|
+
* Populated by {@link registerFunction}; read by the formula engine
|
|
613
|
+
* when the host calls `calculateFormulas()` — see
|
|
614
|
+
* `@formula/runtime/evaluator.ts::evaluateCall`.
|
|
615
|
+
*/
|
|
616
|
+
userFunctions?: Map<string, {
|
|
617
|
+
minArity: number;
|
|
618
|
+
maxArity: number;
|
|
619
|
+
invoke: (args: unknown[]) => unknown;
|
|
620
|
+
volatile?: boolean;
|
|
621
|
+
}>;
|
|
622
|
+
/**
|
|
623
|
+
* Register (or replace) a custom formula function on this workbook.
|
|
624
|
+
*
|
|
625
|
+
* The function becomes visible to `calculateFormulas()` on this
|
|
626
|
+
* workbook only — the built-in registry stays untouched. Names are
|
|
627
|
+
* case-insensitive (normalised to uppercase) and must not include
|
|
628
|
+
* the `_XLFN.` prefix — the engine strips that automatically.
|
|
629
|
+
*
|
|
630
|
+
* @param name Function name (case-insensitive).
|
|
631
|
+
* @param fn Implementation. Receives already-evaluated RuntimeValue
|
|
632
|
+
* arguments; return a RuntimeValue. Wrap failures with
|
|
633
|
+
* `rvError("#VALUE!")` rather than throwing — throws are
|
|
634
|
+
* caught at the evaluator boundary and surface as
|
|
635
|
+
* `#VALUE!` so a buggy custom function doesn't tear
|
|
636
|
+
* down the whole calculation pass.
|
|
637
|
+
* @param options Optional arity bounds. Defaults to `minArity=0`,
|
|
638
|
+
* `maxArity=255` (Excel's universal argument cap), so
|
|
639
|
+
* simple variadic functions work without extra config.
|
|
640
|
+
* Set `volatile: true` when the function should be
|
|
641
|
+
* re-evaluated on every calc cycle (analogous to
|
|
642
|
+
* built-in `RAND`, `NOW`). Currently reserved for
|
|
643
|
+
* future use; the engine recomputes every formula on
|
|
644
|
+
* each `calculateFormulas()` call regardless.
|
|
645
|
+
*
|
|
646
|
+
* ```ts
|
|
647
|
+
* import { rvNumber } from "@cj-tech-master/excelts/formula";
|
|
648
|
+
* workbook.registerFunction("DOUBLE", ([x]) => {
|
|
649
|
+
* return rvNumber((x as any).value * 2);
|
|
650
|
+
* }, { minArity: 1, maxArity: 1 });
|
|
651
|
+
* ```
|
|
652
|
+
*/
|
|
653
|
+
registerFunction(name: string, fn: (args: unknown[]) => unknown, options?: {
|
|
654
|
+
minArity?: number;
|
|
655
|
+
maxArity?: number;
|
|
656
|
+
volatile?: boolean;
|
|
657
|
+
}): void;
|
|
658
|
+
/**
|
|
659
|
+
* Remove a user-registered function. No-op when the name isn't
|
|
660
|
+
* registered; returns `true` when an entry was removed.
|
|
661
|
+
*/
|
|
662
|
+
unregisterFunction(name: string): boolean;
|
|
606
663
|
clearThemes(): void;
|
|
607
664
|
/**
|
|
608
665
|
* Add Image to Workbook and return the id
|
|
@@ -1060,6 +1060,55 @@ class Workbook {
|
|
|
1060
1060
|
calculateFormulas() {
|
|
1061
1061
|
invokeFormulaEngine(this);
|
|
1062
1062
|
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Register (or replace) a custom formula function on this workbook.
|
|
1065
|
+
*
|
|
1066
|
+
* The function becomes visible to `calculateFormulas()` on this
|
|
1067
|
+
* workbook only — the built-in registry stays untouched. Names are
|
|
1068
|
+
* case-insensitive (normalised to uppercase) and must not include
|
|
1069
|
+
* the `_XLFN.` prefix — the engine strips that automatically.
|
|
1070
|
+
*
|
|
1071
|
+
* @param name Function name (case-insensitive).
|
|
1072
|
+
* @param fn Implementation. Receives already-evaluated RuntimeValue
|
|
1073
|
+
* arguments; return a RuntimeValue. Wrap failures with
|
|
1074
|
+
* `rvError("#VALUE!")` rather than throwing — throws are
|
|
1075
|
+
* caught at the evaluator boundary and surface as
|
|
1076
|
+
* `#VALUE!` so a buggy custom function doesn't tear
|
|
1077
|
+
* down the whole calculation pass.
|
|
1078
|
+
* @param options Optional arity bounds. Defaults to `minArity=0`,
|
|
1079
|
+
* `maxArity=255` (Excel's universal argument cap), so
|
|
1080
|
+
* simple variadic functions work without extra config.
|
|
1081
|
+
* Set `volatile: true` when the function should be
|
|
1082
|
+
* re-evaluated on every calc cycle (analogous to
|
|
1083
|
+
* built-in `RAND`, `NOW`). Currently reserved for
|
|
1084
|
+
* future use; the engine recomputes every formula on
|
|
1085
|
+
* each `calculateFormulas()` call regardless.
|
|
1086
|
+
*
|
|
1087
|
+
* ```ts
|
|
1088
|
+
* import { rvNumber } from "@cj-tech-master/excelts/formula";
|
|
1089
|
+
* workbook.registerFunction("DOUBLE", ([x]) => {
|
|
1090
|
+
* return rvNumber((x as any).value * 2);
|
|
1091
|
+
* }, { minArity: 1, maxArity: 1 });
|
|
1092
|
+
* ```
|
|
1093
|
+
*/
|
|
1094
|
+
registerFunction(name, fn, options) {
|
|
1095
|
+
if (!this.userFunctions) {
|
|
1096
|
+
this.userFunctions = new Map();
|
|
1097
|
+
}
|
|
1098
|
+
this.userFunctions.set(name.toUpperCase(), {
|
|
1099
|
+
minArity: options?.minArity ?? 0,
|
|
1100
|
+
maxArity: options?.maxArity ?? 255,
|
|
1101
|
+
invoke: fn,
|
|
1102
|
+
volatile: options?.volatile ?? false
|
|
1103
|
+
});
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Remove a user-registered function. No-op when the name isn't
|
|
1107
|
+
* registered; returns `true` when an entry was removed.
|
|
1108
|
+
*/
|
|
1109
|
+
unregisterFunction(name) {
|
|
1110
|
+
return this.userFunctions?.delete(name.toUpperCase()) ?? false;
|
|
1111
|
+
}
|
|
1063
1112
|
// ===========================================================================
|
|
1064
1113
|
// Themes
|
|
1065
1114
|
// ===========================================================================
|
|
@@ -17,7 +17,7 @@ const defaultNumFormats = {
|
|
|
17
17
|
19: { f: "h:mm:ss AM/PM" },
|
|
18
18
|
20: { f: "h:mm" },
|
|
19
19
|
21: { f: "h:mm:ss" },
|
|
20
|
-
22: { f:
|
|
20
|
+
22: { f: "m/d/yy h:mm" },
|
|
21
21
|
27: {
|
|
22
22
|
"zh-tw": "[$-404]e/m/d",
|
|
23
23
|
"zh-cn": 'yyyy"年"m"月"',
|
|
@@ -75,8 +75,8 @@ const defaultNumFormats = {
|
|
|
75
75
|
},
|
|
76
76
|
37: { f: "#,##0 ;(#,##0)" },
|
|
77
77
|
38: { f: "#,##0 ;[Red](#,##0)" },
|
|
78
|
-
39: { f: "#,##0.00
|
|
79
|
-
40: { f: "#,##0.00
|
|
78
|
+
39: { f: "#,##0.00;(#,##0.00)" },
|
|
79
|
+
40: { f: "#,##0.00;[Red](#,##0.00)" },
|
|
80
80
|
45: { f: "mm:ss" },
|
|
81
81
|
46: { f: "[h]:mm:ss" },
|
|
82
82
|
47: { f: "mmss.0" },
|
|
@@ -18,7 +18,7 @@ class CommentXform extends BaseXform {
|
|
|
18
18
|
const renderModel = model || this.model;
|
|
19
19
|
xmlStream.openNode("comment", {
|
|
20
20
|
ref: renderModel.ref,
|
|
21
|
-
authorId: 0
|
|
21
|
+
authorId: renderModel.authorId ?? 0
|
|
22
22
|
});
|
|
23
23
|
xmlStream.openNode("text");
|
|
24
24
|
if (renderModel && renderModel.note && renderModel.note.texts) {
|
|
@@ -41,7 +41,8 @@ class CommentXform extends BaseXform {
|
|
|
41
41
|
note: {
|
|
42
42
|
texts: []
|
|
43
43
|
},
|
|
44
|
-
|
|
44
|
+
ref: node.attributes.ref,
|
|
45
|
+
authorId: node.attributes.authorId != null ? Number(node.attributes.authorId) : undefined
|
|
45
46
|
};
|
|
46
47
|
return true;
|
|
47
48
|
case "r":
|
|
@@ -8,6 +8,14 @@ declare class CommentsXform extends BaseXform<CommentsModel> {
|
|
|
8
8
|
[key: string]: CommentXform;
|
|
9
9
|
};
|
|
10
10
|
parser: any;
|
|
11
|
+
/** Authors collected while parsing the <authors> element. */
|
|
12
|
+
private _authors;
|
|
13
|
+
/** Whether we are currently inside the <authors> element. */
|
|
14
|
+
private _inAuthors;
|
|
15
|
+
/** Whether we are currently inside an <author> element (collecting text). */
|
|
16
|
+
private _inAuthor;
|
|
17
|
+
/** Accumulator for the current <author> text content. */
|
|
18
|
+
private _currentAuthor;
|
|
11
19
|
constructor();
|
|
12
20
|
render(xmlStream: any, model?: CommentsModel): void;
|
|
13
21
|
parseOpen(node: any): boolean;
|