@gui-chat-plugin/spreadsheet 4.1.0 → 4.2.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.
Files changed (62) hide show
  1. package/README.md +34 -4
  2. package/dist/core/contentVersion.d.ts +5 -0
  3. package/dist/core/definition.d.ts +1 -1
  4. package/dist/core/dispatch.d.ts +3 -3
  5. package/dist/core/dispatchReplies.d.ts +19 -0
  6. package/dist/core/index.d.ts +1 -1
  7. package/dist/core/rangeValues.d.ts +2 -1
  8. package/dist/core/types.d.ts +14 -1
  9. package/dist/core-CwIoDrlM.js +52 -0
  10. package/dist/core-DHWKHgsJ.cjs +1 -0
  11. package/dist/core.cjs +1 -1
  12. package/dist/core.js +3 -3
  13. package/dist/engine/calculator.d.ts +0 -14
  14. package/dist/engine/cellEmpty.d.ts +3 -0
  15. package/dist/engine/cellFormatting.d.ts +3 -2
  16. package/dist/engine/concatOperand.d.ts +3 -0
  17. package/dist/engine/concatPrecedence.d.ts +32 -0
  18. package/dist/engine/customFunctionSpecs.d.ts +30 -0
  19. package/dist/engine/customFunctions.d.ts +32 -0
  20. package/dist/engine/date-calendar.d.ts +32 -0
  21. package/dist/engine/date-utils.d.ts +4 -1
  22. package/dist/engine/dateDisplay.d.ts +20 -0
  23. package/dist/engine/escapes.d.ts +10 -0
  24. package/dist/engine/evaluator.d.ts +6 -1
  25. package/dist/engine/formatter.d.ts +4 -0
  26. package/dist/engine/functions/aliases.d.ts +6 -0
  27. package/dist/engine/functions/analysis-math.d.ts +3 -0
  28. package/dist/engine/functions/calendar.d.ts +9 -0
  29. package/dist/engine/functions/date.d.ts +1 -1
  30. package/dist/engine/functions/distribution-math.d.ts +44 -0
  31. package/dist/engine/functions/distributions.d.ts +7 -0
  32. package/dist/engine/functions/index.d.ts +5 -0
  33. package/dist/engine/functions/regression-math.d.ts +25 -0
  34. package/dist/engine/functions/regression.d.ts +5 -0
  35. package/dist/engine/functions/shape-math.d.ts +21 -0
  36. package/dist/engine/functions/shape.d.ts +5 -0
  37. package/dist/engine/functions/special-functions.d.ts +17 -0
  38. package/dist/engine/functions/statistical-analysis.d.ts +8 -1
  39. package/dist/engine/functions/statistical.d.ts +11 -1
  40. package/dist/engine/jsonCellLocator.d.ts +0 -16
  41. package/dist/engine/math-ops.d.ts +4 -2
  42. package/dist/engine/numericCoercion.d.ts +6 -0
  43. package/dist/engine/registry.d.ts +29 -1
  44. package/dist/engine/textCollation.d.ts +8 -0
  45. package/dist/engine/textComparison.d.ts +22 -0
  46. package/dist/engine/translateFormula.d.ts +16 -5
  47. package/dist/index.cjs +1 -1
  48. package/dist/index.js +3 -3
  49. package/dist/lang/messages.d.ts +5 -0
  50. package/dist/samples-DBNVoegC.js +4398 -0
  51. package/dist/samples-DyQFcwBX.cjs +2 -0
  52. package/dist/style.css +1 -1
  53. package/dist/vue/fileFollow.d.ts +7 -0
  54. package/dist/vue/sheetSession.d.ts +10 -4
  55. package/dist/vue/useCustomFunctions.d.ts +7 -0
  56. package/dist/vue.cjs +32 -32
  57. package/dist/vue.js +3099 -2921
  58. package/package.json +4 -2
  59. package/dist/core-CaJMHb3p.js +0 -44
  60. package/dist/core-PwJLsuHs.cjs +0 -1
  61. package/dist/samples-B6CgK8O-.cjs +0 -1
  62. package/dist/samples-miYeCJeQ.js +0 -2856
package/README.md CHANGED
@@ -74,11 +74,13 @@ The View sends two dispatch calls:
74
74
 
75
75
  | `kind` | other args | result |
76
76
  |--------|-----------|--------|
77
- | `loadSpreadsheet` | `path` | `{ data: { sheets } }` |
78
- | `saveSpreadsheet` | `path`, `sheets` | `{ data: { sheets: path } }` |
77
+ | `loadSpreadsheet` | `path` | `{ data: { sheets, version } }` |
78
+ | `saveSpreadsheet` | `path`, `sheets`, `baseVersion?` | `{ data: { sheets: path, version } }`, or `{ data: { sheets, version, conflict: true } }` |
79
79
 
80
80
  `path` must be a `.json` file under `artifacts/spreadsheets/`.
81
81
 
82
+ `version` is the SHA-256 of the file's text. The View saves with the `baseVersion` of the sheets it shows, and the save is written only while the file still has that version. When an agent or another View wrote the file in between, nothing is written: the answer carries the file's current `sheets` and `version` with `conflict: true`, and the View asks the user to keep that version or save their edit over it. A save without `baseVersion` is written unconditionally, as before. Saves of one file through the plugin are serialized, so two Views cannot both pass the check; a write that bypasses the plugin can still land between a save's check and its write, because `files.artifacts` has no compare-and-write.
83
+
82
84
  A host that routes the View's `dispatch` to the plugin's own `execute` (as MulmoTerminal does) needs nothing more: `pluginCore.execute` tells the two calls apart by `kind`. A host with its own dispatch route can call `executeSpreadsheetDispatch(files.artifacts, args)` after checking `isSpreadsheetDispatchArgs(args)`.
83
85
 
84
86
  The View must be rendered inside the host's `PLUGIN_RUNTIME_KEY` provider to load or save a saved workbook; it also takes the UI language from that runtime (`en`, `ja`, `de`, `es`, `fr`, `ko`, `pt-BR`, `zh`, falling back to English).
@@ -109,7 +111,11 @@ The View must be rendered inside the host's `PLUGIN_RUNTIME_KEY` provider to loa
109
111
  `CONCAT`, `CONCATENATE`, `EXACT`, `FIND`, `LEFT`, `LEN`, `LOWER`, `MID`, `PROPER`, `REPLACE`, `RIGHT`, `SEARCH`, `SUBSTITUTE`, `TEXT`, `TRIM`, `UPPER`, `VALUE`
110
112
 
111
113
  ### Date & Time
112
- `DATE`, `DATEDIF`, `DAY`, `HOUR`, `MINUTE`, `MONTH`, `NOW`, `SECOND`, `TIME`, `TODAY`, `YEAR`
114
+ `DATE`, `DATEDIF`, `DAY`, `DAYS`, `EDATE`, `EOMONTH`, `HOUR`, `MINUTE`, `MONTH`, `NETWORKDAYS`, `NOW`, `SECOND`, `TIME`, `TODAY`, `WEEKDAY`, `WORKDAY`, `YEAR`
115
+
116
+ A formula without a format code shows its number as a date only when the number is a date by origin: the formula starts with DATE, TODAY, EDATE, EOMONTH or WORKDAY, or its first reference is a date (a cell with a date format, typed as a date, or itself such a formula, on any sheet). A total that lands on 52,345 stays a number. Give a formula a format code to choose its display yourself.
117
+
118
+ Dates are serial numbers on the real calendar, as in LibreOffice and Google Sheets. Excel counts a 1900-02-29 that never existed, so a serial before 61 (1900-03-01) is one day earlier here than in Excel; from 61 on they are the same.
113
119
 
114
120
  ### Logical
115
121
  `AND`, `FALSE`, `IF`, `IFERROR`, `IFNA`, `IFS`, `NOT`, `OR`, `TRUE`
@@ -118,11 +124,35 @@ The View must be rendered inside the host's `PLUGIN_RUNTIME_KEY` provider to loa
118
124
  `HLOOKUP`, `INDEX`, `MATCH`, `VLOOKUP`, `XLOOKUP`
119
125
 
120
126
  ### Statistical
121
- `AVERAGE`, `AVERAGEIF`, `AVERAGEIFS`, `CORREL`, `COUNT`, `COUNTA`, `COUNTIF`, `COUNTIFS`, `INTERCEPT`, `LARGE`, `MAX`, `MEDIAN`, `MIN`, `MODE`, `PERCENTILE`, `QUARTILE`, `RANK`, `RSQ`, `SLOPE`, `SMALL`, `STDEV`, `STDEVP`, `SUM`, `SUMIF`, `SUMIFS`, `VAR`, `VARP`
127
+ `AVERAGE`, `AVERAGEIF`, `AVERAGEIFS`, `CONFIDENCE.NORM`, `CONFIDENCE.T`, `CORREL`, `COUNT`, `COUNTA`, `COUNTIF`, `COUNTIFS`, `COVARIANCE.P`, `COVARIANCE.S`, `FORECAST`, `FORECAST.LINEAR`, `GEOMEAN`, `HARMEAN`, `INTERCEPT`, `KURT`, `LARGE`, `MAX`, `MAXIFS`, `MEDIAN`, `MIN`, `MINIFS`, `MODE`, `NORM.DIST`, `NORM.INV`, `NORM.S.DIST`, `NORM.S.INV`, `PEARSON`, `PERCENTILE`, `PERCENTILE.INC`, `PERCENTRANK`, `PERCENTRANK.INC`, `QUARTILE`, `QUARTILE.INC`, `RANK`, `RANK.EQ`, `RSQ`, `SKEW`, `SLOPE`, `SMALL`, `STANDARDIZE`, `STDEV`, `STDEV.P`, `STDEV.S`, `STDEVP`, `STEYX`, `SUM`, `SUMIF`, `SUMIFS`, `T.DIST`, `T.DIST.2T`, `T.DIST.RT`, `T.INV`, `T.INV.2T`, `T.TEST`, `TREND`, `TTEST`, `VAR`, `VAR.P`, `VAR.S`, `VARP`
122
128
 
123
129
  ### Financial
124
130
  `FV`, `IPMT`, `IRR`, `NPER`, `NPV`, `PMT`, `PPMT`, `PV`, `RATE`
125
131
 
132
+ ## Workbook functions
133
+
134
+ A workbook can define functions of its own, for an analysis no built-in function does. Each sheet may carry an optional `functions` list; a function defined on any sheet is callable from every sheet of that workbook:
135
+
136
+ ```json
137
+ {
138
+ "name": "Data",
139
+ "functions": [
140
+ {
141
+ "name": "MOVING.AVG",
142
+ "params": ["values", "n"],
143
+ "body": "const xs = values.flat().filter((v) => typeof v === 'number'); const tail = xs.slice(-n); return tail.reduce((a, b) => a + b, 0) / tail.length;"
144
+ }
145
+ ],
146
+ "data": [[{ "v": 100 }, { "v": "=MOVING.AVG(A1:A30, 7)" }]]
147
+ }
148
+ ```
149
+
150
+ - A function body is JavaScript, run in [QuickJS](https://github.com/justjake/quickjs-emscripten) (WebAssembly) with no DOM, network, file system or timers, at most 50 ms per call, 2 s per calculation and 16 MB of memory. Each function has a global scope of its own.
151
+ - A range argument arrives as rows of cells (an array of arrays, a blank cell as `null`); a single cell and any other argument as its value. A whole column or row (`A:A`, `2:2`) is `#VALUE!`: the engine does not read those. An argument that is an error is passed on without calling the function.
152
+ - Return a number, text or `true`/`false`. A time-out or a non-finite number shows `#NUM!`; a thrown error or any other return value shows `#VALUE!`.
153
+ - A name is letters and digits, parts joined by dots, and cannot be a built-in function's. `presentSpreadsheet` says in its reply which definitions could not be used.
154
+ - QuickJS loads only for a workbook that defines functions. The View and `readCalculatedRange` load it themselves; a host calling `calculatedRange` directly passes the set from `loadCustomFunctions`.
155
+
126
156
  ## Development
127
157
 
128
158
  ```bash
@@ -0,0 +1,5 @@
1
+ /** The SHA-256 of `text`, in hex. Two texts get the same version only when they are equal. */
2
+ export declare function contentVersion(text: string): Promise<string>;
3
+ /** Whether a save based on `baseVersion` must not be written over a file now at `currentVersion`.
4
+ * A save without a base (an older View) and a file that is gone are written as before. */
5
+ export declare const isStaleBase: (baseVersion: string | undefined, currentVersion: string | null) => boolean;
@@ -4,4 +4,4 @@
4
4
  import type { ToolDefinition } from "gui-chat-protocol";
5
5
  export declare const TOOL_NAME = "presentSpreadsheet";
6
6
  export declare const TOOL_DEFINITION: ToolDefinition;
7
- export declare const SYSTEM_PROMPT = "Use presentSpreadsheet whenever the user needs a spreadsheet-style table, multi-step math, or dynamic what-if analysis\u2014do not summarize in text. Build LIVE sheets where every cell is an object {\"v\": value, \"f\": format}. For formulas, set \"v\" to a string starting with \"=\" (e.g., {\"v\": \"=B2*1.05\", \"f\": \"$#,##0.00\"}). For dates, use date strings like \"01/15/2025\" or date formulas like \"=TODAY()\" or \"=DATE(2025,1,15)\". The spreadsheet auto-parses common date formats (MM/DD/YYYY, YYYY-MM-DD, DD-MMM-YYYY) into date serial numbers for calculations. Date arithmetic works: \"=B2-TODAY()\" calculates days between dates. Never pre-calculate; let the spreadsheet compute using cell refs, functions (SUM, AVERAGE, IF, TODAY, DATE, DATEDIF, etc.), and arithmetic. Standard formats: \"$#,##0.00\" currency, \"#,##0\" integer, \"0.00%\" percent, \"0.00\" decimal, \"MM/DD/YYYY\" date, \"DD-MMM-YYYY\" date, \"YYYY-MM-DD\" ISO date. Format is optional for plain text/numbers.";
7
+ export declare const SYSTEM_PROMPT = "Use presentSpreadsheet whenever the user needs a spreadsheet-style table, multi-step math, or dynamic what-if analysis\u2014do not summarize in text. Build LIVE sheets where every cell is an object {\"v\": value, \"f\": format}. For formulas, set \"v\" to a string starting with \"=\" (e.g., {\"v\": \"=B2*1.05\", \"f\": \"$#,##0.00\"}). For dates, use date strings like \"01/15/2025\" or date formulas like \"=TODAY()\" or \"=DATE(2025,1,15)\". The spreadsheet auto-parses common date formats (MM/DD/YYYY, YYYY-MM-DD, DD-MMM-YYYY) into date serial numbers for calculations. Date arithmetic works: \"=B2-TODAY()\" calculates days between dates. Never pre-calculate; let the spreadsheet compute using cell refs, functions (SUM, AVERAGE, IF, TODAY, DATE, DATEDIF, etc.), and arithmetic. Standard formats: \"$#,##0.00\" currency, \"#,##0\" integer, \"0.00%\" percent, \"0.00\" decimal, \"MM/DD/YYYY\" date, \"DD-MMM-YYYY\" date, \"YYYY-MM-DD\" ISO date. Format is optional for plain text/numbers. When an analysis needs a method no built-in function has, define it once in the sheet's \"functions\" and call it from formulas, rather than pasting a computed number: it then recalculates when the data changes.";
@@ -1,8 +1,8 @@
1
- import type { FileOps, ToolResult } from "gui-chat-protocol";
2
- import type { SpreadsheetDispatchArgs, SpreadsheetToolData } from "./types";
1
+ import { type FileOps, type ToolResult } from "gui-chat-protocol";
2
+ import type { SpreadsheetDispatchArgs, SpreadsheetFileData } from "./types";
3
3
  export declare function isSpreadsheetDispatchArgs(value: unknown): value is SpreadsheetDispatchArgs;
4
4
  /** `files.artifacts` off a host context, when the host provides it. The
5
5
  * protocol's `ToolContext` does not declare `files`, so it is checked rather
6
6
  * than assumed. */
7
7
  export declare function artifactsFileOps(context: unknown): FileOps | null;
8
- export declare function executeSpreadsheetDispatch(artifacts: FileOps, args: SpreadsheetDispatchArgs): Promise<ToolResult<SpreadsheetToolData, never>>;
8
+ export declare function executeSpreadsheetDispatch(artifacts: FileOps, args: SpreadsheetDispatchArgs): Promise<ToolResult<SpreadsheetFileData, never>>;
@@ -0,0 +1,19 @@
1
+ import type { SpreadsheetSheet } from "./types";
2
+ export interface LoadedWorkbook {
3
+ sheets: SpreadsheetSheet[];
4
+ /** Absent when the answering plugin predates versions; saves are then unconditional. */
5
+ version: string | undefined;
6
+ }
7
+ export type SaveReply = {
8
+ kind: "saved";
9
+ version: string | undefined;
10
+ } | {
11
+ kind: "conflict";
12
+ sheets: SpreadsheetSheet[];
13
+ version: string;
14
+ };
15
+ /** The workbook a load answered, or null when the answer holds no sheets. */
16
+ export declare function readLoadReply(raw: unknown): LoadedWorkbook | null;
17
+ /** What a save answered, or null for a conflict that does not carry the file's sheets and
18
+ * version. Any other answer is a save: an older plugin answers `{ sheets: path }` only. */
19
+ export declare function readSaveReply(raw: unknown): SaveReply | null;
@@ -4,7 +4,7 @@
4
4
  * This module exports the core plugin logic without UI components.
5
5
  * Import from "@gui-chat-plugin/spreadsheet" or "@gui-chat-plugin/spreadsheet/core"
6
6
  */
7
- export type { SpreadsheetCell, SpreadsheetCellValue, StorableCell, SpreadsheetSheet, SpreadsheetToolData, SpreadsheetArgs, SpreadsheetDispatchArgs, } from "./types";
7
+ export type { SpreadsheetCell, SpreadsheetCellValue, StorableCell, SpreadsheetSheet, SpreadsheetToolData, SpreadsheetArgs, SpreadsheetDispatchArgs, SpreadsheetFileData, } from "./types";
8
8
  export { TOOL_NAME, TOOL_DEFINITION, SYSTEM_PROMPT, executeSpreadsheet, pluginCore } from "./plugin";
9
9
  export { executeSpreadsheetDispatch, isSpreadsheetDispatchArgs } from "./dispatch";
10
10
  export { isSpreadsheetArtifactPath } from "./paths";
@@ -1,5 +1,6 @@
1
1
  import type { FileOps } from "gui-chat-protocol";
2
2
  import { type StoredCellValue } from "../engine";
3
+ import { type CustomFunctionSet } from "../engine/customFunctions";
3
4
  import type { SpreadsheetSheet } from "./types";
4
5
  /** One cell as a chart reads it: a number to plot, a label, or nothing. */
5
6
  export type RangeCell = string | number | null;
@@ -28,7 +29,7 @@ export declare function rangeCellValue(storedCell: unknown, calculated: StoredCe
28
29
  * Throws when the range is malformed, too large, or names a sheet the workbook
29
30
  * does not have.
30
31
  */
31
- export declare function calculatedRange(sheets: SpreadsheetSheet[], range: string): RangeCell[][];
32
+ export declare function calculatedRange(sheets: SpreadsheetSheet[], range: string, functions?: CustomFunctionSet): RangeCell[][];
32
33
  /** `calculatedRange` of the workbook saved at `path` (`artifacts/spreadsheets/…json`). */
33
34
  export declare function readCalculatedRange(artifacts: FileOps, path: string, range: string): Promise<RangeCell[][]>;
34
35
  export {};
@@ -5,6 +5,7 @@
5
5
  * Common types are imported from gui-chat-protocol.
6
6
  */
7
7
  /** Mirrors the engine's `StoredCellValue`. */
8
+ import type { CustomFunctionSpec } from "../engine/customFunctionSpecs";
8
9
  export type SpreadsheetCellValue = string | number | boolean;
9
10
  export interface SpreadsheetCell {
10
11
  v: SpreadsheetCellValue;
@@ -22,6 +23,8 @@ export type StorableCell = SpreadsheetCell | {
22
23
  export interface SpreadsheetSheet {
23
24
  name: string;
24
25
  data: StorableCell[][];
26
+ /** Functions this workbook defines, usable from any of its sheets (#114). */
27
+ functions?: CustomFunctionSpec[];
25
28
  }
26
29
  /** `sheets` is the workbook itself, or — when the host gave the plugin
27
30
  * `files.artifacts` — the workspace-relative path it was saved to. */
@@ -32,7 +35,8 @@ export interface SpreadsheetArgs {
32
35
  title: string;
33
36
  sheets: SpreadsheetSheet[];
34
37
  }
35
- /** What the View sends through `useRuntime().dispatch`. */
38
+ /** What the View sends through `useRuntime().dispatch`. A save with `baseVersion` is written
39
+ * only while the file still holds that version, so it cannot overwrite a change made since. */
36
40
  export type SpreadsheetDispatchArgs = {
37
41
  kind: "loadSpreadsheet";
38
42
  path: string;
@@ -40,4 +44,13 @@ export type SpreadsheetDispatchArgs = {
40
44
  kind: "saveSpreadsheet";
41
45
  path: string;
42
46
  sheets: SpreadsheetSheet[];
47
+ baseVersion?: string;
43
48
  };
49
+ /** What a load or save dispatch answers. `version` names the file's content as the answer
50
+ * leaves it. With `conflict`, the save was not written: the file had changed since
51
+ * `baseVersion`, and `sheets` is the file as it is now. */
52
+ export interface SpreadsheetFileData {
53
+ sheets: SpreadsheetSheet[] | string;
54
+ version: string;
55
+ conflict?: true;
56
+ }
@@ -0,0 +1,52 @@
1
+ import { C as e, a as t, b as n, c as r, f as i, i as a, l as o, p as s, u as c, v as l, y as u } from "./samples-DBNVoegC.js";
2
+ //#region src/core/rangeValues.ts
3
+ var d = 1e5, f = (e) => {
4
+ if (!e) return null;
5
+ let t = e.slice(0, -1);
6
+ return t.startsWith("'") && t.endsWith("'") ? t.slice(1, -1).replaceAll("''", "'") : t;
7
+ };
8
+ function p(e) {
9
+ let t = e.lastIndexOf("!"), n = e.slice(t + 1), r = i(n.includes(":") ? e : `${e}:${n}`);
10
+ return !r || !s(n.split(":")[0] ?? "") ? null : {
11
+ sheetName: f(r.sheetPrefix),
12
+ startRow: Math.min(r.startRow, r.endRow) - 1,
13
+ endRow: Math.max(r.startRow, r.endRow) - 1,
14
+ startCol: Math.min(r.startCol, r.endCol),
15
+ endCol: Math.max(r.startCol, r.endCol)
16
+ };
17
+ }
18
+ var m = /[ymdhs]/i, h = (t) => e(t) && typeof t.f == "string" && t.f !== "" && !m.test(t.f);
19
+ function g(e, t, n) {
20
+ return n === void 0 || n === "" ? null : typeof n == "number" ? n : typeof t == "number" && h(e) ? t : typeof n == "boolean" ? String(n).toUpperCase() : n;
21
+ }
22
+ var _ = (e) => ({
23
+ name: e.name,
24
+ data: t(e.data)
25
+ }), v = ({ startRow: e, endRow: t }) => Array.from({ length: t - e + 1 }, (t, n) => e + n), y = ({ startCol: e, endCol: t }) => Array.from({ length: t - e + 1 }, (t, n) => e + n);
26
+ function b(e, t, n = r) {
27
+ let i = p(t.trim());
28
+ if (!i) throw Error(`"${t}" is not a range such as Data!A1:C13`);
29
+ let s = (i.endRow - i.startRow + 1) * (i.endCol - i.startCol + 1);
30
+ if (s > 1e5) throw Error(`"${t}" has ${s} cells; the limit is ${d}`);
31
+ let c = i.sheetName === null ? 0 : e.findIndex((e) => e.name === i.sheetName), l = e[c];
32
+ if (c < 0 || !l) throw Error(`the spreadsheet has no sheet named "${i.sheetName ?? ""}"`);
33
+ let u = e.map(_), f = u[c] ?? _(l), { calculated: m, displayed: h } = o(n, () => ({
34
+ calculated: a(f, u, { skipFormatting: !0 }).data,
35
+ displayed: a(f, u).data
36
+ }));
37
+ return v(i).map((e) => y(i).map((t) => g(f.data[e]?.[t], x(m[e]?.[t]), x(h[e]?.[t]))));
38
+ }
39
+ var x = (e) => typeof e == "string" || typeof e == "number" || typeof e == "boolean" ? e : void 0;
40
+ async function S(e, t, r) {
41
+ if (!u(t)) throw Error("path must be a .json file under artifacts/spreadsheets/");
42
+ let i = l(JSON.parse(await e.read(n(t))));
43
+ if (!i) throw Error(`${t} does not hold an array of sheets`);
44
+ let a = await c(i);
45
+ try {
46
+ return b(i, r, a);
47
+ } finally {
48
+ a.dispose();
49
+ }
50
+ }
51
+ //#endregion
52
+ export { b as n, S as r, d as t };
@@ -0,0 +1 @@
1
+ const e=require("./samples-DyQFcwBX.cjs");var t=1e5,n=e=>{if(!e)return null;let t=e.slice(0,-1);return t.startsWith(`'`)&&t.endsWith(`'`)?t.slice(1,-1).replaceAll(`''`,`'`):t};function r(t){let r=t.lastIndexOf(`!`),i=t.slice(r+1),a=e.f(i.includes(`:`)?t:`${t}:${i}`);return!a||!e.p(i.split(`:`)[0]??``)?null:{sheetName:n(a.sheetPrefix),startRow:Math.min(a.startRow,a.endRow)-1,endRow:Math.max(a.startRow,a.endRow)-1,startCol:Math.min(a.startCol,a.endCol),endCol:Math.max(a.startCol,a.endCol)}}var i=/[ymdhs]/i,a=t=>e.C(t)&&typeof t.f==`string`&&t.f!==``&&!i.test(t.f);function o(e,t,n){return n===void 0||n===``?null:typeof n==`number`?n:typeof t==`number`&&a(e)?t:typeof n==`boolean`?String(n).toUpperCase():n}var s=t=>({name:t.name,data:e.a(t.data)}),c=({startRow:e,endRow:t})=>Array.from({length:t-e+1},(t,n)=>e+n),l=({startCol:e,endCol:t})=>Array.from({length:t-e+1},(t,n)=>e+n);function u(n,i,a=e.c){let u=r(i.trim());if(!u)throw Error(`"${i}" is not a range such as Data!A1:C13`);let f=(u.endRow-u.startRow+1)*(u.endCol-u.startCol+1);if(f>1e5)throw Error(`"${i}" has ${f} cells; the limit is ${t}`);let p=u.sheetName===null?0:n.findIndex(e=>e.name===u.sheetName),m=n[p];if(p<0||!m)throw Error(`the spreadsheet has no sheet named "${u.sheetName??``}"`);let h=n.map(s),g=h[p]??s(m),{calculated:_,displayed:v}=e.l(a,()=>({calculated:e.i(g,h,{skipFormatting:!0}).data,displayed:e.i(g,h).data}));return c(u).map(e=>l(u).map(t=>o(g.data[e]?.[t],d(_[e]?.[t]),d(v[e]?.[t]))))}var d=e=>typeof e==`string`||typeof e==`number`||typeof e==`boolean`?e:void 0;async function f(t,n,r){if(!e.y(n))throw Error(`path must be a .json file under artifacts/spreadsheets/`);let i=e.v(JSON.parse(await t.read(e.b(n))));if(!i)throw Error(`${n} does not hold an array of sheets`);let a=await e.u(i);try{return u(i,r,a)}finally{a.dispose()}}Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return t}});
package/dist/core.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./samples-B6CgK8O-.cjs"),t=require("./core-PwJLsuHs.cjs");exports.MAX_RANGE_CELLS=t.t,exports.SYSTEM_PROMPT=e.b,exports.TOOL_DEFINITION=e.x,exports.TOOL_NAME=e.S,exports.calculatedRange=t.n,exports.executeSpreadsheet=e.u,exports.executeSpreadsheetDispatch=e.f,exports.isSpreadsheetArtifactPath=e.h,exports.isSpreadsheetDispatchArgs=e.p,exports.pluginCore=e.d,exports.readCalculatedRange=t.r,exports.samples=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./samples-DyQFcwBX.cjs"),t=require("./core-DHWKHgsJ.cjs");exports.MAX_RANGE_CELLS=t.t,exports.SYSTEM_PROMPT=e.w,exports.TOOL_DEFINITION=e.T,exports.TOOL_NAME=e.E,exports.calculatedRange=t.n,exports.executeSpreadsheet=e.o,exports.executeSpreadsheetDispatch=e.g,exports.isSpreadsheetArtifactPath=e.y,exports.isSpreadsheetDispatchArgs=e._,exports.pluginCore=e.s,exports.readCalculatedRange=t.r,exports.samples=e.t;
package/dist/core.js CHANGED
@@ -1,3 +1,3 @@
1
- import { S as e, b as t, d as n, f as r, h as i, p as a, t as o, u as s, x as c } from "./samples-miYeCJeQ.js";
2
- import { n as l, r as u, t as d } from "./core-CaJMHb3p.js";
3
- export { d as MAX_RANGE_CELLS, t as SYSTEM_PROMPT, c as TOOL_DEFINITION, e as TOOL_NAME, l as calculatedRange, s as executeSpreadsheet, r as executeSpreadsheetDispatch, i as isSpreadsheetArtifactPath, a as isSpreadsheetDispatchArgs, n as pluginCore, u as readCalculatedRange, o as samples };
1
+ import { E as e, T as t, _ as n, g as r, o as i, s as a, t as o, w as s, y as c } from "./samples-DBNVoegC.js";
2
+ import { n as l, r as u, t as d } from "./core-CwIoDrlM.js";
3
+ export { d as MAX_RANGE_CELLS, s as SYSTEM_PROMPT, t as TOOL_DEFINITION, e as TOOL_NAME, l as calculatedRange, i as executeSpreadsheet, r as executeSpreadsheetDispatch, c as isSpreadsheetArtifactPath, n as isSpreadsheetDispatchArgs, a as pluginCore, u as readCalculatedRange, o as samples };
@@ -4,24 +4,10 @@
4
4
  * Core calculation engine with circular reference detection and cross-sheet support
5
5
  */
6
6
  import type { SheetData, CalculatedSheet, SpreadsheetCell, CalculateOptions } from "./types";
7
- /**
8
- * Normalize malformed data structures
9
- * Some models generate flat arrays instead of 2D arrays - fix them
10
- *
11
- * @param data - Potentially malformed sheet data
12
- * @returns Normalized 2D array
13
- */
14
7
  export declare function normalizeData(data: any): SpreadsheetCell[][];
15
8
  type SheetCalculateOptions = CalculateOptions & {
16
9
  skipFormatting?: boolean;
17
10
  };
18
- /**
19
- * Calculate formulas in a single sheet
20
- *
21
- * @param sheet - Sheet data to calculate
22
- * @param allSheets - All sheets for cross-sheet references
23
- * @returns Calculated sheet with formulas evaluated
24
- */
25
11
  export declare function calculateSheet(sheet: SheetData, allSheets?: SheetData[], options?: SheetCalculateOptions): CalculatedSheet;
26
12
  /**
27
13
  * Calculate all sheets in a workbook
@@ -11,3 +11,6 @@
11
11
  * string, in either the bare or the `{ v }` form. A cell containing the number
12
12
  * 0, `false`, or any non-empty text is NOT empty. */
13
13
  export declare function isEmptyCell(cell: unknown): boolean;
14
+ /** True when a cell holds nothing and is not a formula error. A calculated error is an object
15
+ * without `v`, which `isEmptyCell` alone counts as empty — and a blank reads as 0. */
16
+ export declare function isBlankCell(cell: unknown): boolean;
@@ -16,10 +16,11 @@ export declare const isLikelyDateSerial: (value: CellValue) => boolean;
16
16
  *
17
17
  * - A formula error renders as its code, so the cell still reads `#NUM!`.
18
18
  * - Explicit format code wins (currency, percentage, date, ...).
19
- * - A formula that produced a date serial auto-formats as a date.
19
+ * - A formula whose number is a date by origin (`showsDate`, see dateDisplay.ts) and lands in
20
+ * the date-serial window auto-formats as a date.
20
21
  * - Everything else (text, plain numbers, empty) passes through unchanged.
21
22
  *
22
23
  * The result is always a STORED value: this is the boundary where a computed
23
24
  * error becomes the text a cell shows and a workbook serializes.
24
25
  */
25
- export declare const formatCellForDisplay: (originalCell: unknown, calculatedValue: CellValue, preferDDMMYYYY: boolean) => StoredCellValue;
26
+ export declare const formatCellForDisplay: (originalCell: unknown, calculatedValue: CellValue, preferDDMMYYYY: boolean, showsDate: boolean) => StoredCellValue;
@@ -0,0 +1,3 @@
1
+ /** Whether `expr.slice(start, end)` is a whole operand of a `&`: only brackets and spaces
2
+ * between it and a `&` on one side, and a `&` or the end of the expression on the other. */
3
+ export declare function standsAloneInConcat(expr: string, start: number, end: number): boolean;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Excel `&` with Excel's precedence.
3
+ *
4
+ * `&` binds looser than `+ - * / ^`, so `"a"&1+2` is `"a"&(1+2)` = `a3`. Rewriting
5
+ * `&` to JS `+` in place made it bind as tightly as `+` and evaluate left to
6
+ * right: `"a"+1+2` is `a12`. Here each `&` operand is parenthesised before the
7
+ * join, so its arithmetic runs first, and the join starts from `""` so it is a
8
+ * string concatenation whatever the operands are (`5&6` is `56`, not 11).
9
+ */
10
+ export interface Place {
11
+ char: string;
12
+ inLiteral: boolean;
13
+ /** Paren nesting outside literals; a `(` or `)` counts at its outer level. */
14
+ depth: number;
15
+ }
16
+ /** Each character with whether it sits in a string literal and how deeply it is nested. */
17
+ export declare function placesOf(expr: string): Place[];
18
+ /**
19
+ * Excel `&` → a JS expression that concatenates with Excel's precedence.
20
+ *
21
+ * Returns the plain in-place rewrite when the expression compares (`=`, `<`, `>`
22
+ * outside a literal) or an operand is empty (a leading or trailing `&`). The
23
+ * evaluator's concatenation gate rejects that rewrite, so those formulas come out
24
+ * exactly as they did before: comparing a joined string needs text comparison,
25
+ * which the evaluator does not have, and treating `&` as `+` there would answer
26
+ * `=A1&B1=3` TRUE where Excel compares "12" with 3.
27
+ */
28
+ export declare function concatToSum(expr: string): string;
29
+ /** Every operand of every `&` in `expr`, nested groups included, so the evaluator
30
+ * can check each one the way it checks an expression without `&`: joined as text,
31
+ * `1/0` would read "Infinity" where Excel answers #DIV/0!. */
32
+ export declare function concatOperands(expr: string): string[];
@@ -0,0 +1,30 @@
1
+ /**
2
+ * A workbook's own functions as it stores them (#114), and the rules a definition must meet before
3
+ * any of it runs. Pure: no QuickJS here, so every rule is testable on its own.
4
+ */
5
+ /** One function a workbook defines: `=MOVING.AVG(B2:B100, 7)` calls `body` with `values` and `n`. */
6
+ export interface CustomFunctionSpec {
7
+ name: string;
8
+ params: string[];
9
+ body: string;
10
+ description?: string;
11
+ }
12
+ /** A definition that cannot be used, and why — said to whoever wrote it. */
13
+ export interface CustomFunctionProblem {
14
+ name: string;
15
+ reason: string;
16
+ }
17
+ /** The specs a sheet's `functions` holds, skipping anything not shaped like one. */
18
+ export declare function specsOf(functions: unknown): CustomFunctionSpec[];
19
+ /** Why `spec` cannot be used, or null when it can. `isBuiltIn` says whether a name is the engine's own. */
20
+ export declare function problemWith(spec: CustomFunctionSpec, isBuiltIn: (name: string) => boolean): string | null;
21
+ /** The usable definitions, keyed by upper-case name, and the problems with the rest. A name defined
22
+ * twice is a problem for the second: which one a formula means would otherwise depend on order. */
23
+ export declare function checkedSpecs(specs: CustomFunctionSpec[], isBuiltIn: (name: string) => boolean): {
24
+ usable: Map<string, CustomFunctionSpec>;
25
+ problems: CustomFunctionProblem[];
26
+ };
27
+ /** The source QuickJS evaluates to get `spec` as a function. A body can still close the function
28
+ * early (QuickJS's `Function` joins its source as text); what contains that is the sandbox, and a
29
+ * context of its own per function, not this string. */
30
+ export declare const functionSource: (spec: CustomFunctionSpec) => string;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * A workbook's own functions, run in QuickJS (#114).
3
+ *
4
+ * QuickJS is a JavaScript engine compiled to WebAssembly: a function runs inside it with no DOM,
5
+ * no network, no file system and no timers, under a memory cap and a deadline, and a call is
6
+ * synchronous — so the engine's synchronous handlers can call it directly. Only loading the
7
+ * WebAssembly is asynchronous, which is why a caller loads a workbook's functions before
8
+ * calculating it, and a workbook without functions never loads QuickJS at all.
9
+ */
10
+ import { type FunctionDefinition } from "./registry";
11
+ import "./functions";
12
+ import { type CustomFunctionProblem } from "./customFunctionSpecs";
13
+ import type { CellValue } from "./types";
14
+ /** A workbook's functions, ready to be made visible to a calculation with {@link calculateWith}. */
15
+ export interface CustomFunctionSet {
16
+ definitions: ReadonlyMap<string, FunctionDefinition>;
17
+ /** The definitions that could not be used, and why. */
18
+ problems: CustomFunctionProblem[];
19
+ /** Marks the start of one calculation, for {@link CALCULATION_LIMIT_MS}. */
20
+ startCalculation(): void;
21
+ dispose(): void;
22
+ }
23
+ /** The set for a workbook that defines no functions. */
24
+ export declare const NO_CUSTOM_FUNCTIONS: CustomFunctionSet;
25
+ /** Calculate with `set`'s functions visible: `calculateWith(set, () => engine.calculate(sheet, sheets))`. */
26
+ export declare function calculateWith<T>(set: CustomFunctionSet, calculate: () => T): T;
27
+ /** The functions defined across `sheets` (each sheet's optional `functions`). */
28
+ export declare function loadCustomFunctions(sheets: readonly {
29
+ functions?: unknown;
30
+ }[]): Promise<CustomFunctionSet>;
31
+ /** What a function returned, as a cell holds it: a finite number, text or a logical; else an error. */
32
+ export declare function asCellValue(value: unknown): CellValue;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Calendar rules for WEEKDAY, DAYS, EDATE, EOMONTH, WORKDAY and NETWORKDAYS, on
3
+ * Excel serial numbers. Pure, so each rule is tested without a sheet. A serial's
4
+ * time of day is dropped first, as Excel does.
5
+ *
6
+ * Serials follow the engine's own conversion (date-utils.ts: day 0 is 1899-12-30),
7
+ * which agrees with Excel from 1900-03-01 on. Excel's fictitious 1900-02-29 is
8
+ * not reproduced here, as it is not by YEAR, MONTH or DAY.
9
+ */
10
+ import { type SpreadsheetError } from "./spreadsheet-errors";
11
+ /** 9999-12-31, Excel's last date. A result or a span beyond it is #NUM!, which also
12
+ * keeps WORKDAY's walk and NETWORKDAYS' count bounded. */
13
+ export declare const LAST_SERIAL = 2958465;
14
+ /** WEEKDAY: 1–7 counted from the day the return type starts on (type 1, the
15
+ * default, starts on Sunday); type 3 counts Monday as 0. Any other type, or a
16
+ * serial outside Excel's dates, is `#NUM!`. */
17
+ export declare function weekdayOf(serial: number, returnType?: number): number | SpreadsheetError;
18
+ /** DAYS: whole days from `start` to `end`. */
19
+ export declare function daysBetween(end: number, start: number): number | SpreadsheetError;
20
+ /** EDATE: the same day `months` months on, moved back to the month's last day
21
+ * when the month is shorter (31 January + 1 month is 28 or 29 February). */
22
+ export declare function addMonths(serial: number, months: number): number | SpreadsheetError;
23
+ /** EOMONTH: the last day of the month `months` months on. */
24
+ export declare function endOfMonth(serial: number, months: number): number | SpreadsheetError;
25
+ /** WORKDAY: the date `days` working days on (back, when negative), skipping
26
+ * weekends and `holidays`. Zero days is the start date itself. A walk that leaves
27
+ * Excel's dates is `#NUM!`, which bounds it. */
28
+ export declare function addWorkdays(serial: number, days: number, holidays?: readonly number[]): number | SpreadsheetError;
29
+ /** NETWORKDAYS: the working days from `start` to `end`, both included, negative
30
+ * when `end` comes first. Times of day are dropped before the order is decided;
31
+ * a holiday counts once, and only when it falls on a weekday in the span. */
32
+ export declare function countWorkdays(start: number, end: number, holidays?: readonly number[]): number | SpreadsheetError;
@@ -3,7 +3,10 @@
3
3
  *
4
4
  * Shared utilities for converting between JavaScript Date objects and Excel serial numbers.
5
5
  * Excel stores dates as sequential serial numbers so they can be used in calculations.
6
- * January 1, 1900 is serial number 1.
6
+ *
7
+ * Serial 0 is 1899-12-30 and the calendar is the real one, as in LibreOffice and Google
8
+ * Sheets: Excel's serial 60 is a 1900-02-29 that never existed, so its serials 1–59 sit
9
+ * one day later than these. From 1900-03-01 (serial 61) on, the two agree.
7
10
  */
8
11
  /**
9
12
  * Convert JavaScript Date to Excel Serial Number
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Whether a formula's number is a date to show as one, when its cell has no format of its own.
3
+ * Excel decides from where the number came from, not from its size: a formula that starts with
4
+ * a date function, or whose first reference is a date, shows a date; a sum that happens to land
5
+ * on 52345 does not. Taking the size alone turned ordinary totals into 2043 dates.
6
+ */
7
+ /** What the date decision reads of a referenced cell: its own format, its formula if it has one,
8
+ * and the sheet that formula's references are read on. */
9
+ export interface DateCell {
10
+ format: string;
11
+ formula: string | null;
12
+ sheet: string;
13
+ }
14
+ /** Looks up a reference (`A1`, `Data!A1`, `'My Sheet'!A1`) written on `sheet`. */
15
+ export type DateSource = (ref: string, sheet: string) => DateCell | null;
16
+ /** The function a formula body starts with — `DATE` in `DATE(…)+1` or `(DATE(…))` — or null. */
17
+ export declare function leadingCall(body: string): string | null;
18
+ /** Whether the formula (with its leading `=`), written on `sheet`, shows a date: it starts with a
19
+ * date function, or its first reference is a date — by its format, or by its own formula. */
20
+ export declare function formulaShowsDate(formula: string, sheet: string, source: DateSource, seen?: ReadonlySet<string>): boolean;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Whether the character at `index` is backslash-escaped: preceded by an ODD run of
3
+ * backslashes. Checking only the one character before it is wrong for a literal
4
+ * ending in a backslash, `"a\\"`, where the closing quote follows an escaped
5
+ * backslash and does close the literal.
6
+ *
7
+ * Counts backwards over the run only. Scanners ask it about quote characters
8
+ * alone, so a long text of backslashes is walked once per following quote.
9
+ */
10
+ export declare function isEscapedAt(text: string, index: number): boolean;
@@ -11,9 +11,14 @@ export interface EvaluatorContext {
11
11
  getCellValue: (ref: string) => CellValue;
12
12
  getRangeValues: (range: string) => CellValue[];
13
13
  getRangeValuesRaw?: ((range: string) => CellValue[]) | undefined;
14
+ getRangeValuesKeepingBlanks?: ((range: string) => CellValue[]) | undefined;
15
+ countFilledCells?: ((range: string) => number) | undefined;
14
16
  evaluateFormula: (formula: string) => CellValue;
15
17
  /** Reading order for an ambiguous slash date; see engine/date-locale.ts. */
16
18
  preferDDMMYYYY?: boolean | undefined;
19
+ /** Whether the referenced cell holds nothing. `getCellValue` reads such a cell as 0, which
20
+ * is right for arithmetic and wrong for `&`, where a blank cell joins as "". */
21
+ isCellEmpty?: ((ref: string) => boolean) | undefined;
17
22
  }
18
23
  /** Render a cell's value as the text that stands in for it inside an
19
24
  * expression. Strings are quoted so they cannot be read as identifiers or
@@ -51,7 +56,7 @@ export declare function findCellRefs(expr: string): CellRefSpan[];
51
56
  * string replace rewrote every occurrence of the shorter reference first, so
52
57
  * `=A1+A10` had its `A10` broken into `<A1's value>0` and produced a plausible
53
58
  * wrong number (#2357). */
54
- export declare function substituteCellRefs(expr: string, cellRefs: CellRefSpan[], render: (ref: string) => string): string;
59
+ export declare function substituteCellRefs(expr: string, cellRefs: CellRefSpan[], render: (ref: string, start: number) => string): string;
55
60
  /**
56
61
  * Parse function arguments, handling nested functions and quoted strings
57
62
  *
@@ -3,6 +3,10 @@
3
3
  *
4
4
  * Handles Excel-style format codes for currency, percentages, decimals, dates, etc.
5
5
  */
6
+ /**
7
+ * Check if a format code is for dates
8
+ */
9
+ export declare function isDateFormat(format: string): boolean;
6
10
  /**
7
11
  * Insert thousands separators into a run of digits ("1234567" → "1,234,567").
8
12
  * Regex free on purpose: the classic `\B(?=(\d{3})+(?!\d))` lookahead
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The names current Excel writes for functions this engine already has. A model
3
+ * writing `PERCENTILE.INC` means exactly `PERCENTILE`, so each alias is the same
4
+ * definition under a second name.
5
+ */
6
+ export {};
@@ -10,6 +10,8 @@ export interface NumericPairs {
10
10
  ys: number[];
11
11
  xs: number[];
12
12
  }
13
+ export declare const mean: (values: number[]) => number;
14
+ export declare const sumOfSquaredDeviations: (values: number[]) => number;
13
15
  /**
14
16
  * Pair two ranges by position, keeping only the pairs where both cells hold a
15
17
  * number. Excel skips a pair with a blank or text on either side, rather than
@@ -17,6 +19,7 @@ export interface NumericPairs {
17
19
  * different sizes have no pairing, so Excel answers `#N/A`.
18
20
  */
19
21
  export declare function numericPairs(yValues: CellValue[], xValues: CellValue[]): NumericPairs | SpreadsheetError;
22
+ export declare const sumOfCrossDeviations: ({ ys, xs }: NumericPairs) => number;
20
23
  /** Pearson correlation (CORREL). Fewer than two pairs, or a side that never
21
24
  * varies, leaves a zero denominator: `#DIV/0!`. */
22
25
  export declare function correlation(pairs: NumericPairs): number | SpreadsheetError;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Calendar functions: WEEKDAY, DAYS, EDATE, EOMONTH, WORKDAY, NETWORKDAYS. The
3
+ * rules live in date-calendar.ts; this file reads the arguments.
4
+ *
5
+ * Arguments are read strictly, as Excel does: a date given as text has already
6
+ * become a serial when the argument is evaluated, so text that is still text is
7
+ * #VALUE!, and an error in an argument is the function's answer.
8
+ */
9
+ export {};
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Date and Time Functions
3
3
  * Excel stores dates as sequential serial numbers so they can be used in calculations.
4
- * January 1, 1900 is serial number 1.
4
+ * Serial 0 is 1899-12-30 on the real calendar, so 1900-01-01 is serial 2 (see date-utils.ts).
5
5
  */
6
6
  export {};
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The t and normal distributions and the t-test, as pure numerics. Tails are computed
3
+ * directly rather than as 1 − (the rest), so a small p-value keeps its relative precision.
4
+ * The spreadsheet rules (argument checks, #NUM!) live in distributions.ts.
5
+ */
6
+ export declare const normalDensity: (z: number) => number;
7
+ /** P(Z > z) for the standard normal. erfc(x) is Q(1/2, x²), so the upper tail is half of it. */
8
+ export declare function normalUpperTail(z: number): number;
9
+ /** P(Z ≤ z) for the standard normal. */
10
+ export declare const normalCdf: (z: number) => number;
11
+ /** The z with P(Z ≤ z) = p, for 0 < p < 1. */
12
+ export declare function normalQuantile(p: number): number;
13
+ /** The z with P(Z > z) = q, for 0 < q < 1. */
14
+ export declare const normalUpperQuantile: (q: number) => number;
15
+ /** The t density with `df` degrees of freedom: 1 / (√ν B(ν/2, 1/2)) · (1 + t²/ν)^(−(ν+1)/2). */
16
+ export declare function studentDensity(t: number, df: number): number;
17
+ /** P(T > t). For t ≥ 0 it is ½ · I_x(ν/2, ½) with x = ν / (ν + t²) = r / (1 + r), r = ν / t².
18
+ * It goes through ln r, so t² never overflows and 1 − x keeps its digits for a small t. */
19
+ export declare function studentUpperTail(t: number, df: number): number;
20
+ /** P(T ≤ t). */
21
+ export declare const studentCdf: (t: number, df: number) => number;
22
+ /** The t with P(T > t) = q, for 0 < q < 1. */
23
+ export declare function studentUpperQuantile(q: number, df: number): number;
24
+ /** The t with P(T ≤ t) = p, for 0 < p < 1. */
25
+ export declare const studentQuantile: (p: number, df: number) => number;
26
+ export interface SampleSummary {
27
+ count: number;
28
+ mean: number;
29
+ /** The sample variance, divided by n − 1. */
30
+ variance: number;
31
+ }
32
+ export declare function summarize(values: number[]): SampleSummary;
33
+ export interface TStatistic {
34
+ t: number;
35
+ df: number;
36
+ }
37
+ /** Paired: the one-sample t of the differences. */
38
+ export declare function pairedT(differences: number[]): TStatistic;
39
+ /** Two samples with a pooled (equal) variance. */
40
+ export declare function pooledT(first: SampleSummary, second: SampleSummary): TStatistic;
41
+ /** Two samples with unequal variances (Welch). The Welch–Satterthwaite df is not rounded. */
42
+ export declare function welchT(first: SampleSummary, second: SampleSummary): TStatistic;
43
+ /** The p-value of a t statistic: one tail, or both. */
44
+ export declare const tTestProbability: ({ t, df }: TStatistic, tails: 1 | 2) => number;