@sheetxl/query 0.7.28-beta.4 → 0.8.0-beta.2

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 (32) hide show
  1. package/browser/cjs/index.cjs +44 -25
  2. package/browser/esm/index.mjs +3094 -1131
  3. package/node/esm/index.mjs +3331 -1334
  4. package/package.json +3 -3
  5. package/types/src/Tool.d.ts +38 -0
  6. package/types/src/api/apiTool.d.ts +22 -0
  7. package/types/src/api/index.d.ts +4 -0
  8. package/types/src/api/lookupApi.d.ts +127 -0
  9. package/types/src/api/renderApi.d.ts +13 -0
  10. package/types/src/grep/GrepTypes.d.ts +75 -17
  11. package/types/src/grep/grep.d.ts +4 -1
  12. package/types/src/index.d.ts +9 -0
  13. package/types/src/markdown/appendDependencies.d.ts +106 -0
  14. package/types/src/markdown/appendPivotTables.d.ts +22 -0
  15. package/types/src/markdown/appendSections.d.ts +37 -108
  16. package/types/src/markdown/describeChart.d.ts +72 -0
  17. package/types/src/markdown/describeHistogram.d.ts +186 -0
  18. package/types/src/markdown/describeRegionPayload.d.ts +1 -1
  19. package/types/src/markdown/findLabels.d.ts +26 -0
  20. package/types/src/markdown/index.d.ts +3 -0
  21. package/types/src/markdown/profileRegion.d.ts +56 -1
  22. package/types/src/markdown/registry.d.ts +11 -2
  23. package/types/src/markdown/renderCell.d.ts +13 -11
  24. package/types/src/markdown/renderCellRange.d.ts +3 -2
  25. package/types/src/markdown/renderModules.d.ts +55 -0
  26. package/types/src/markdown/renderMovable.d.ts +69 -13
  27. package/types/src/markdown/renderNames.d.ts +2 -2
  28. package/types/src/markdown/renderProtection.d.ts +81 -0
  29. package/types/src/markdown/renderRegions.d.ts +1 -0
  30. package/types/src/markdown/renderSheet.d.ts +6 -7
  31. package/types/src/markdown/renderTable.d.ts +11 -3
  32. package/types/src/markdown/renderWorkbook.d.ts +33 -26
@@ -1,4 +1,4 @@
1
- import { ICellRange, IAnchored, ICellRanges, INamed } from '@sheetxl/sdk';
1
+ import { ICellRange, IAnchored, ICellRanges, ICellRegion, INamed } from '@sheetxl/sdk';
2
2
  import { MarkdownBuilder } from './MarkdownBuilder';
3
3
  /**
4
4
  * Options for the feature sections.
@@ -13,7 +13,7 @@ export interface AppendFeatureOptions {
13
13
  * A **reporting** filter, not a query one. Partitioning by feature is what
14
14
  * {@link ICellRange.getRegions} is for and this does not duplicate it — it decides which of
15
15
  * those partitions a report bothers to print, which is why it lives on the renderer and not on
16
- * the range. `--features fill,border` on a sheet with forty formatted regions is the
16
+ * the range. `--features fill,borders` on a sheet with forty formatted regions is the
17
17
  * difference between an answer and a haystack.
18
18
  *
19
19
  * The scalar kinds are accepted and reach `Counts`; they have no partition to list, so they
@@ -69,7 +69,7 @@ export interface AppendFeatureOptions {
69
69
  */
70
70
  export declare const REPORTED_FEATURES: readonly ICellRange.Feature[];
71
71
  /**
72
- * Parses a comma-separated feature list — the `--features fill,border` flag's value.
72
+ * Parses a comma-separated feature list — the `--features fill,borders` flag's value.
73
73
  *
74
74
  * @remarks
75
75
  * Matching is case-insensitive against the enum's values, so `Fill`, `fill` and `numberFormat`
@@ -118,26 +118,12 @@ export declare const describeQualifiedExtent: (range: ICellRange) => string;
118
118
  * Appends the `Kind` section — what the contentful cells ARE, kind by kind.
119
119
  *
120
120
  * @remarks
121
- * The heading carries the contentful count; the fact lines are the scalar kinds. This replaced
122
- * the old `Counts` section, which mixed two vocabularies: the kinds (which have no partition to
123
- * list) and the features (which do, and now carry their cell counts on their own section
124
- * headings). What remains here is exactly the value-shape question — "5 cells: 3 strings, 2
125
- * numbers".
121
+ * The heading carries the contentful count; the lines are the census, largest first, and they
122
+ * sum to it — see {@link countKinds}, which the workbook's `content` row reads too, so a sheet is
123
+ * described in the same words and the same numbers at both altitudes. Features are not here: each
124
+ * has a partition to list, and carries its cell count on its own section heading.
126
125
  *
127
- * Read off `range.getStats().getTypedCounts()` — the same single value-scan `renderStats` and
128
- * `profileKinds` already read — rather than `getCounts()`: `getCounts([Feature.Number, ...])` is a
129
- * SECOND, independent value-scan inside the engine (`Sheet._featureCounts`'s own comment says so
130
- * — "the scalar kinds ... count from values in one pass"), answering the identical question. One
131
- * scan, one source of truth, and `RichData` is no longer a silent zero — it falls out of the same
132
- * typed counts for free, where the old `Feature`-keyed list had nowhere to carry it (`Feature` has
133
- * no `RichData` member).
134
- *
135
- * `Date` is the one line still read through a dedicated pass — `countDates`, a value scan via
136
- * `getInteropType()`. It is not a `ScalarType` at all — it is numeric value ∩ date-category
137
- * format — and `Feature.DateFormat` alone would overcount (a blank or text cell carrying that
138
- * format is not a date). A date cell counts as both `Number` and `Date`, so the lines need not
139
- * sum to the heading. Zero kinds are elided, and blanks appear nowhere — empty is not a kind of
140
- * content.
126
+ * Zero kinds are elided, and blanks appear nowhere — empty is not a kind of content.
141
127
  */
142
128
  export declare function appendKinds(md: MarkdownBuilder, range: ICellRange): void;
143
129
  /**
@@ -161,6 +147,21 @@ export declare function appendKinds(md: MarkdownBuilder, range: ICellRange): voi
161
147
  * sees which before paying for a drill.
162
148
  */
163
149
  export declare function appendRegions(md: MarkdownBuilder, range: ICellRange, options?: AppendFeatureOptions): void;
150
+ /**
151
+ * The blocks of content in `range` — occupancy, cut where an authored table begins and ends.
152
+ *
153
+ * @remarks
154
+ * Occupancy alone yields maximal SOLID rectangles, and a table is not one: a title sitting over
155
+ * its first column makes that column run one cell longer than the rest, so the table came back as
156
+ * `C3:J111` plus a `B2:B111` list — two blocks, neither of them the table, at a size the `Tables`
157
+ * section contradicts. A table's edge is a boundary its author drew, so the partition honors it:
158
+ * the table is one block, at its own extent, and the title is a 1×1 above it.
159
+ *
160
+ * Refinement only ever cuts at a table's edge, so a sheet with no tables partitions exactly as
161
+ * occupancy does. A refined partition yields every region carrying EITHER feature, so a blank cell
162
+ * inside a table comes back too; a region is uniform, which makes its anchor the test.
163
+ */
164
+ export declare const contentfulBlocks: (range: ICellRange) => ICellRegion[];
164
165
  /**
165
166
  * Options for {@link appendNames}.
166
167
  */
@@ -246,91 +247,7 @@ export declare const describeQualifiedName: (named: INamed) => string;
246
247
  * `Hidden` and `Comment` appear only when some row has one — per block. `false` on every visible
247
248
  * row is token noise, and blank-means-normal is how these reports already speak.
248
249
  */
249
- export declare function appendNames(md: MarkdownBuilder, names: readonly INamed[], options?: AppendNamesOptions): void;
250
- /**
251
- * Options for the dependency trees.
252
- */
253
- export interface AppendDependencyOptions {
254
- /**
255
- * How many hops from the subject to walk.
256
- *
257
- * @defaultValue 3
258
- */
259
- maxDepth?: number;
260
- /**
261
- * Cap on nodes per tree; the tree notes truncation when exceeded.
262
- *
263
- * @defaultValue 50
264
- */
265
- maxNodes?: number;
266
- }
267
- /** The calculation-graph surface shared by {@link ICell} and {@link ICellRange}. */
268
- export interface DependencySource {
269
- getDirectPrecedents(): ICellRanges | null;
270
- getPrecedents(): ICellRanges | null;
271
- getDirectDependents(): ICellRanges | null;
272
- getDependents(): ICellRanges | null;
273
- }
274
- /**
275
- * Appends the `Precedents` and `Dependents` trees for anything that exposes the calculation
276
- * graph — a cell or a range, which answer the same questions with the same shape.
277
- *
278
- * @remarks
279
- * **A tree, walked one hop at a time, rather than a `direct`/`all` pair.** The flat form gives
280
- * the two ends of the chain and throws away everything between them: `D6` reading `B2:D4`
281
- * "eventually" does not say whether that is one indirection or nine, and the shape is the thing a
282
- * reader is actually trying to see. Repeated `getDirect*` calls cost the same as one `getAll*`
283
- * — the graph is indexed either way — so the tree is strictly more answer for the same work.
284
- *
285
- * Each node carries its **payload at the right altitude**: a single cell shows its value, a
286
- * multi-cell range shows its size. A range node is not expanded into cells; that is the same
287
- * expansion the region rules exist to prevent.
288
- *
289
- * Bounded three ways, each stated in the output rather than applied silently — depth, node count,
290
- * and revisits.
291
- *
292
- * **The two kinds of revisit get different marks, and that distinction is the point.** A node
293
- * reached twice by different branches is a re-convergence: completely normal in any model, and
294
- * marked `↑ shown above`. A node reached again while it is still on the current path is a
295
- * genuine cycle — a defect, or a deliberate iterative calculation — and is marked `↺ circular`.
296
- * One glyph for both would bury the second inside a busy tree, and it is the one finding here
297
- * that cannot afford to be missed.
298
- */
299
- export declare function appendDependencies(md: MarkdownBuilder, target: DependencySource, options?: AppendDependencyOptions): void;
300
- /**
301
- * How a graph member LABELS itself: its address, the sheet it lives on, and whether it is a name.
302
- *
303
- * @remarks
304
- * Shared by the tree and the flat {@link ICellRanges} listing, so the two cannot label the same
305
- * member differently — the flat list is the tree's rows without the hop structure, and a reader
306
- * comparing them is comparing the same text.
307
- *
308
- * A name member leads with its NAME: its address is only an anchor, and two names authored from
309
- * the same cell would otherwise print as identical, anonymous cells.
310
- *
311
- * The address comes back **unqualified**. A listing standing on one sheet says so once, in its
312
- * heading; a qualifier goes back on every row only when the collection spans sheets, which is the
313
- * caller's decision because only the caller has seen every member. A trailing `!` is `#REF!`, not
314
- * a qualifier, so it is left whole.
315
- */
316
- export declare function describeNodeLabel(range: ICellRange): {
317
- address: string;
318
- sheet: string;
319
- isName: boolean;
320
- };
321
- /**
322
- * A node's payload: the value for a single cell, the size for a range.
323
- *
324
- * @remarks
325
- * The whole point of walking as a tree rather than listing addresses — `1,204,880` beside
326
- * `Model!O30` is what makes the chain readable as a model rather than as a set of coordinates.
327
- * A formula node shows its expression too, because at that point the node explains itself.
328
- *
329
- * Shared with the flat {@link ICellRanges} listing (`renderRanges`) for the same reason
330
- * {@link describeNodeLabel} is: the flat list is these rows without the hop structure, so the two
331
- * shapes cannot be allowed to drift into describing one member two ways.
332
- */
333
- export declare function describeNode(range: ICellRange): string;
250
+ export declare function appendNames(md: MarkdownBuilder, names: readonly INamed[], options?: AppendNamesOptions): Promise<void>;
334
251
  /**
335
252
  * One rule listing — `## Conditional Formats (2)` over ` A1:D10 > 100 → fill #FFFF00` rows.
336
253
  *
@@ -346,6 +263,18 @@ export declare function describeNode(range: ICellRange): string;
346
263
  * listing would hide the very relationship `stop if true` is read against.
347
264
  */
348
265
  export declare function appendRules<T extends IAnchored>(md: MarkdownBuilder, heading: string, items: readonly T[], describe: (item: T) => string): void;
266
+ /**
267
+ * The defined names whose target region intersects `range`, in collection order.
268
+ *
269
+ * @remarks
270
+ * Scope-checked, not merely rectangle-checked: a name pointing at `Sheet2!A1:D4` overlaps this
271
+ * sheet's `A1:D4` as coordinates and is a different region entirely. Defined names only — a
272
+ * table's name has its own section.
273
+ *
274
+ * @param includeOwned Also admit this sheet's private names that designate no region
275
+ * (`TaxRate = 0.21`), which have nothing to intersect and belong to the sheet by ownership.
276
+ */
277
+ export declare function findNames(range: ICellRange, includeOwned?: boolean): INamed[];
349
278
  /**
350
279
  * Appends the sheet-level objects that intersect `range`: named ranges, hidden headers, tables,
351
280
  * conditional formats and data validations.
@@ -360,5 +289,5 @@ export declare function appendRules<T extends IAnchored>(md: MarkdownBuilder, he
360
289
  * token cost on the common path, and it buries the sections that do carry something. Absence is
361
290
  * already how these reports say "not here".
362
291
  */
363
- export declare function appendSheetObjects(md: MarkdownBuilder, range: ICellRange): void;
292
+ export declare function appendSheetObjects(md: MarkdownBuilder, range: ICellRange): Promise<void>;
364
293
  //# sourceMappingURL=appendSections.d.ts.map
@@ -0,0 +1,72 @@
1
+ import { ISheet, ICellRange, ICellRanges, IChart, IMovable } from '@sheetxl/sdk';
2
+ import { MarkdownBuilder } from './MarkdownBuilder';
3
+ /** The chart a movable holds, or `null` for any other content. */
4
+ export declare const chartOf: (movable: IMovable) => IChart | null;
5
+ /**
6
+ * `line · 8 series · values NOI!C4:J111 · categories NOI!B4:B111` — a chart as one listing row's
7
+ * prose, or `null` when nothing about it is known.
8
+ *
9
+ * @remarks
10
+ * What the chart PLOTS leads, because it is the fact that ties the floating layer to the cells: it
11
+ * says which ranges the author treats as the output, and it is what breaks when the sheet under
12
+ * it is restructured. Series that do not collapse to one block are counted here and listed on the
13
+ * chart's own report.
14
+ *
15
+ * Each range is labeled with its role. `A by B` read as a formula to anyone who did not already
16
+ * know the convention, and `by` is the word the series line uses for orientation (`by column`).
17
+ */
18
+ export declare function describeChartRow(chart: IChart): string | null;
19
+ /**
20
+ * A chart's facts as `label`/`value` pairs — the lines a `Charts` section indents under its row,
21
+ * the way a `Tables` section does.
22
+ *
23
+ * @remarks
24
+ * The type is not here: it is the row's own column. Series that do not tile are counted, and
25
+ * listed one by one on the chart's own report.
26
+ */
27
+ export declare function describeChartDetails(chart: IChart): [label: string, value: string][];
28
+ /** `line`, for the type column of a `Charts` row; `''` where the model has no answer. */
29
+ export declare const describeChartType: (chart: IChart) => string;
30
+ /**
31
+ * The `Type` / `Title` / `Series` / `Axes` facts of a chart's own report.
32
+ *
33
+ * @remarks
34
+ * `Title: (none)` is printed rather than omitted: that a chart is untitled is information, and a
35
+ * reader asked to tidy a model wants it. An axis with no title says so for the same reason — axis
36
+ * titles are where a chart states its units, often the only place anything does.
37
+ */
38
+ export declare function appendChartFacts(md: MarkdownBuilder, chart: IChart): void;
39
+ /** A series reference that no longer names cells. */
40
+ export interface BrokenChartReference {
41
+ movable: IMovable;
42
+ /** `series "South" values Data!#REF!` */
43
+ detail: string;
44
+ }
45
+ /**
46
+ * Every series on `sheet` whose name, values or categories reference is `#REF!`.
47
+ *
48
+ * @remarks
49
+ * A broken series reference is an audit finding exactly like one in a formula — the chart has
50
+ * stopped plotting what its author pointed it at — and no cell carries it, so no cell scan finds it.
51
+ */
52
+ export declare function collectBrokenChartReferences(sheet: ISheet): BrokenChartReference[];
53
+ /** A chart that plots the subject of a report, or something computed from it. */
54
+ export interface ChartReader {
55
+ movable: IMovable;
56
+ /** `true` when a series names the subject's own cells; `false` when it names cells that depend on them. */
57
+ direct: boolean;
58
+ }
59
+ /**
60
+ * The charts that read `subject`, or that read what depends on it.
61
+ *
62
+ * @remarks
63
+ * A chart is a dependent the calculation graph does not hold: it reads cells and is changed by
64
+ * them, and nothing recalculates it. For "what else moves if I write here" it belongs in the same
65
+ * answer, so this is the graph's dependents carried one step further — into the floating layer.
66
+ *
67
+ * @param dependents The subject's full downstream reach, as the graph answers it.
68
+ */
69
+ export declare function findChartReaders(subject: ICellRange, dependents: ICellRanges | null): ChartReader[];
70
+ /** `Charts!B2:H15 "Chart 1"`, marked when the chart reads the subject only through its dependents. */
71
+ export declare const describeChartReader: (reader: ChartReader) => string;
72
+ //# sourceMappingURL=describeChart.d.ts.map
@@ -0,0 +1,186 @@
1
+ import { ICellRange, ICellRegion, IRange, ISheet, IStyle } from '@sheetxl/sdk';
2
+ /**
3
+ * Per-attribute histograms for the style feature sections.
4
+ *
5
+ * @remarks
6
+ * A style partition lists blocks; a reader wants **conventions**: which colors mean input, how
7
+ * many fonts there are, whether one cell is formatted differently from its row. A histogram per
8
+ * *attribute* answers that on one line each — `color blue ×216 · white ×18 · #0070C0 ×1 R13` — and
9
+ * degrades to a count when there is no convention to find.
10
+ *
11
+ * Pipeline, per feature: **project** each region's authored style onto one attribute → **coalesce**
12
+ * adjacent rectangles with the same projected value (a region is uniform in the whole feature,
13
+ * so `bold 10pt` and `10pt` are two regions with one family) → **promote** whole-column and
14
+ * whole-row rectangles to their own tiers, the way the file format does, so a column style is
15
+ * named once instead of counted as a million cells → **histogram** the cell tier.
16
+ *
17
+ * Every count is cells, never blocks. Content cells lead — the intersection with the
18
+ * `Contentful` partition — and the styled cells that hold nothing follow in parentheses, so a
19
+ * format over empty cells (`Currency 0dp ×0 (+1 blank) K2`) is stated rather than hidden. A value that lives
20
+ * in one block prints its address whatever its size; a scattered one prints its largest block
21
+ * and how many more.
22
+ *
23
+ * **Only authored differences are histogrammed.** An attribute equal to the workbook's `Normal`
24
+ * style is not a choice anyone made — every cell has *some* family — so it does not appear; the
25
+ * base itself is stated once, on the `normal` line, which is where "Calibri is the base" comes
26
+ * from without any clustering.
27
+ */
28
+ /** A rectangle in sheet coordinates, closed on both ends. */
29
+ type Rect = Readonly<IRange.Coords>;
30
+ /**
31
+ * Merges adjacent rectangles that share a key into maximal rectangles.
32
+ *
33
+ * @remarks
34
+ * Greedy: a column pass joins horizontal neighbors with equal row extents, a row pass joins
35
+ * vertical neighbors with equal column extents, repeated until nothing merges. Not guaranteed
36
+ * minimal, but the input is already a partition (no overlaps), the count is blocks not cells, and
37
+ * the store's own seams are exactly the horizontal-then-vertical cuts this undoes.
38
+ */
39
+ export declare function coalesceRects<T extends Rect & {
40
+ key: string;
41
+ }>(rects: readonly T[]): T[];
42
+ /** One value of one attribute: where it is and how much of it there is. */
43
+ export interface HistogramEntry {
44
+ /** Display form of the value. */
45
+ label: string;
46
+ /** Cells carrying the value that also hold content. */
47
+ content: number;
48
+ /** All cells carrying the value (cell tier only — never a whole column). */
49
+ styled: number;
50
+ /** The value's blocks, largest first. */
51
+ blocks: readonly Rect[];
52
+ }
53
+ /**
54
+ * Options for {@link describeHistogramLine}.
55
+ */
56
+ export interface HistogramLineOptions {
57
+ /** Values printed in full before the line degrades to a count. @defaultValue 8 */
58
+ maxValues?: number;
59
+ /** Above this many distinct values the line leads with the count, not the values. @defaultValue 20 */
60
+ manyDistinct?: number;
61
+ /** How to get the rest — appended after `+n more`. */
62
+ recovery?: string;
63
+ /**
64
+ * A label to leave off the line — the attribute's own name, for a boolean attribute whose
65
+ * value IS its name (`bold 87` rather than `bold bold 87`).
66
+ */
67
+ hideLabel?: string;
68
+ /**
69
+ * How a count reads: `cells` (`blue ×216 (+105 blank)` — content cells, then the styled cells
70
+ * holding nothing) for a style attribute, `times` (`2.5 ×4`) for a value, whose count is
71
+ * occurrences and has no second figure.
72
+ *
73
+ * @defaultValue `'cells'`
74
+ */
75
+ countStyle?: 'cells' | 'times';
76
+ }
77
+ /** Width of the attribute-name column; every line of a histogram section aligns on it. */
78
+ export declare const HISTOGRAM_LABEL_WIDTH = 10;
79
+ /**
80
+ * One histogram line — the values of one attribute, most common first, degrading to a count.
81
+ *
82
+ * @remarks
83
+ * The flood rule, stated once for every histogram (style attributes, formulas, values):
84
+ *
85
+ * 1. Up to `maxValues` distinct values print in full, sorted by content cells (then styled).
86
+ * 2. Beyond that, the top half of the budget prints, then the **rarest values that hold
87
+ * content** — a one-off format on a data cell is the finding, and a sort by count alone
88
+ * would bury it — then `+n more` with the call that lists everything.
89
+ * 3. Beyond `manyDistinct`, the line leads with the count and says **no convention** when the
90
+ * most common value does not even cover half the content: a random-color sheet is described
91
+ * by its count, not by a sample of its colors, and it costs one line however many there are.
92
+ */
93
+ export declare function describeHistogramLine(entries: readonly HistogramEntry[], options?: HistogramLineOptions): string;
94
+ /**
95
+ * `Accounting 1dp` — the dialog category plus its decimals, so ten spellings of one intent read
96
+ * as one value. `General` is the absence of a format and contributes nothing.
97
+ */
98
+ export declare function describeNumberFormatCategory(code: string | null | undefined): string | null;
99
+ /** Whether a feature gets a histogram. */
100
+ export declare const hasStyleHistogram: (feature: ICellRange.Feature) => boolean;
101
+ /**
102
+ * One feature's histogram: the tier lines and one line per attribute, ready to append.
103
+ */
104
+ export interface StyleHistogram {
105
+ /** Distinct authored payloads across every region of the feature. */
106
+ distinct: number;
107
+ /**
108
+ * Styled cells in the cell tier, inside the used range — the finite number a heading can
109
+ * carry. The column and row tiers are named on their own lines, never counted.
110
+ */
111
+ cells: number;
112
+ /** `normal Arial Narrow · 11pt · #000000` — what `Normal` says about this feature; see {@link describeNormal}. */
113
+ normal: string | null;
114
+ /** `sheet` / `columns` / `rows` tier lines, each `label runs payload`. */
115
+ tiers: string[];
116
+ /**
117
+ * `family Open Sans ×355 (+230 blank) B14:M25, +38 blocks · …`, one per attribute with a value —
118
+ * or, for number formats, one row per category (see `describeNumberFormatRows`).
119
+ */
120
+ attributes: string[];
121
+ }
122
+ /**
123
+ * Builds the histogram for a style feature over a whole sheet.
124
+ *
125
+ * @remarks
126
+ * Reads the sheet's **entire** partition rather than the used range's, because a column style
127
+ * is only recognizable unclipped: the used-range view cuts `O:Q` to `O1:Q43` and it looks like a
128
+ * block. Cell counts are then taken inside the used range, where finite numbers live.
129
+ */
130
+ export declare function describeStyleHistogram(sheet: ISheet, feature: ICellRange.Feature, normal: IStyle | null, options?: HistogramLineOptions & {
131
+ /** The sheet's contentful rectangles, when the caller already has them (one partition serves every feature). */
132
+ content?: readonly IRange.Coords[];
133
+ }): StyleHistogram | null;
134
+ /** The formula section's histogram lines. */
135
+ export interface FormulaHistogram {
136
+ /** Distinct formulas by R1C1 text — `=SUM(B5:B7)` and `=SUM(C5:C7)` are one. */
137
+ distinct: number;
138
+ /** `distinct =R[-3]C-R[-1]C ×26 B11:N11, +1 block · …` and `functions SUM ×44 · no function ×52`. */
139
+ lines: string[];
140
+ }
141
+ /**
142
+ * Builds the formula section's histograms from its partition.
143
+ *
144
+ * @remarks
145
+ * The partition already groups by R1C1 — a region IS one formula filled across cells — so the
146
+ * `distinct` line is the partition re-keyed: the same R1C1 in several regions (a total column
147
+ * split by blank rows) is one value with several blocks. A one-off R1C1 in a row of thirteen is
148
+ * the H26 finding, printed with its address. `functions` counts cells, not regions, so `SUM ×44`
149
+ * is how many cells sum; `no function` is arithmetic-only cells — on a P&L that is most of them.
150
+ *
151
+ * `most complex` is deliberately absent: by function count every formula on a typical model ties
152
+ * at one, and a tie printed as a superlative is a lie. It arrives with the precedents depth.
153
+ */
154
+ export declare function describeFormulaHistogram(regions: readonly ICellRegion[], options?: HistogramLineOptions): FormulaHistogram | null;
155
+ /**
156
+ * The kind census of `range` — `number 864 · date 108 · text 10` — largest first.
157
+ *
158
+ * @remarks
159
+ * **Disjoint, so the counts sum to the contentful cells.** Every cell is counted under exactly
160
+ * one kind, which is what lets a reader check the census against the heading above it; a census
161
+ * whose lines overlap cannot be told from one that is wrong.
162
+ *
163
+ * A formula cell's value is a number or a string too, so the typed counts alone say `number 313`
164
+ * where 96 of those are computed; the reader wants how much was TYPED (the inputs) against how
165
+ * much is formula (the model). Formula cells are counted once, under `formula`, and their values
166
+ * are subtracted from the typed kinds — read off the formula partition's own stats.
167
+ *
168
+ * `date` is carved out of `number` the same way: a date IS a number, under a date-category format,
169
+ * and a column of them is a time axis — the one fact about a block of numbers that changes how
170
+ * every other column in it is read.
171
+ */
172
+ export declare function countKinds(range: ICellRange, formulaRegions: readonly ICellRegion[]): [label: string, count: number][];
173
+ /** The census as one row's prose: `number ×217 · formula ×96 · text ×45`, or `null` when empty. */
174
+ export declare function describeKinds(range: ICellRange, formulaRegions: readonly ICellRegion[]): string | null;
175
+ /**
176
+ * What the workbook's `Normal` style says about `feature`, or `null` when it says nothing.
177
+ *
178
+ * @remarks
179
+ * **The style of every cell no section lists.** A font always has one — and the font lines are
180
+ * differences from it, so it is always stated. For the rest `Normal` is nearly always empty, and
181
+ * then there is no line; but a `Normal` that carries a fill or a number format paints every
182
+ * untouched cell in the book, and no region reports it, because nobody authored it on a cell.
183
+ */
184
+ export declare function describeNormal(feature: ICellRange.Feature, normal: IStyle): string | null;
185
+ export {};
186
+ //# sourceMappingURL=describeHistogram.d.ts.map
@@ -38,7 +38,7 @@ export declare function regionPayload(feature: ICellRange.Feature, normal: IStyl
38
38
  * payload and they join in the order the caller named them, so the row reads as the tuple the
39
39
  * partition actually splits on.
40
40
  *
41
- * Features with nothing to say per region (`AutoTable`, `Unlock`) contribute nothing rather than
41
+ * Features with nothing to say per region (`AutoTable`) contribute nothing rather than
42
42
  * an empty column, and a partition where none of them do returns `undefined` so the listing stays
43
43
  * addresses-only.
44
44
  */
@@ -0,0 +1,26 @@
1
+ import { IRange, ISheet } from '@sheetxl/sdk';
2
+ /** A label and where it was read from. */
3
+ export interface FoundLabel {
4
+ text: string;
5
+ address: string;
6
+ }
7
+ /**
8
+ * The text that labels a cell's row (`'row'`) or column (`'column'`).
9
+ *
10
+ * @remarks
11
+ * Deterministic, and the address is always returned so a reader can judge it:
12
+ *
13
+ * 1. The first cell of the line within the cell's current region (Ctrl+Shift+*), when it is text —
14
+ * the row label at the left edge of the block, the header at its top.
15
+ * 2. Otherwise the nearest text cell before the cell on that line — leftward for a row, upward for
16
+ * a column. Only contentful cells are visited, so the walk costs the populated cells between,
17
+ * not the distance; there is no cap, because a cap is only a different arbitrary answer.
18
+ *
19
+ * `null` when the cell is itself the first cell of the line or nothing before it is text.
20
+ */
21
+ export declare function findLabel(sheet: ISheet, cell: IRange.CellCoords, axis: 'row' | 'column'): FoundLabel | null;
22
+ /** `"JUN" (G4)` — a label as the reports print it. */
23
+ export declare const describeLabel: (label: FoundLabel | null) => string | null;
24
+ /** 0-based column index to its A1 letter. */
25
+ export declare function columnLetter(index: number): string;
26
+ //# sourceMappingURL=findLabels.d.ts.map
@@ -1,3 +1,4 @@
1
+ export * from './appendDependencies';
1
2
  export * from './appendSections';
2
3
  export * from './describeRegionPayload';
3
4
  export * from './describeRule';
@@ -11,8 +12,10 @@ export * from './renderConditionalFormat';
11
12
  export * from './renderCounts';
12
13
  export * from './renderDataValidation';
13
14
  export * from './renderFormula';
15
+ export * from './renderModules';
14
16
  export * from './renderMovable';
15
17
  export * from './renderNames';
18
+ export * from './renderProtection';
16
19
  export * from './renderRecords';
17
20
  export * from './renderRanges';
18
21
  export * from './renderRegions';
@@ -1,4 +1,5 @@
1
1
  import { ICellRange, ICellRegion } from '@sheetxl/sdk';
2
+ import { FoundLabel } from './findLabels';
2
3
  /**
3
4
  * What {@link profileRegion} needs to read — the anchor cell and the extent, nothing a partition
4
5
  * knows that a plain range does not.
@@ -48,6 +49,10 @@ export interface ProfileRegionOptions {
48
49
  * exactly one, and a block has one per column (or row). This is the same discipline that keeps a
49
50
  * range from rendering cell facets — bounded by construction rather than by a limit that has to
50
51
  * fire.
52
+ *
53
+ * Data for a caller, never printed: a listing row already carries the size (`1×1`, `110×1`) and
54
+ * the header note, so a shape word beside them is a second vocabulary for the same fact — and
55
+ * `table` has to stay free to mean an authored {@link ITable}.
51
56
  */
52
57
  export type RegionShape = 'cell' | 'list' | 'table' | 'block';
53
58
  /**
@@ -58,7 +63,7 @@ export type RegionShape = 'cell' | 'list' | 'table' | 'block';
58
63
  */
59
64
  export interface RegionProfile {
60
65
  shape: RegionShape;
61
- /** The one-line description that sits beside the address — `table · header row 1`. */
66
+ /** The one-line description that sits beside the address — `header row 1`, or a 1×1's value. */
62
67
  summary: string;
63
68
  /** One line per column (or row); empty for `cell` and `list`, whose profile is in `summary`. */
64
69
  series: string[];
@@ -88,6 +93,56 @@ export interface RegionProfile {
88
93
  * elision is explicit, per the same rule that governs every truncated listing here.
89
94
  */
90
95
  export declare function profileRegion(region: ProfileSource, options?: ProfileRegionOptions): RegionProfile;
96
+ /** A line the stats leave out, and why. */
97
+ export interface TotalsLine {
98
+ /** Absolute row (or column, on a block profiled by row). */
99
+ index: number;
100
+ label: FoundLabel | null;
101
+ /** Set on the first line only when it was found by value: how it compares with the Σ above it. */
102
+ sums?: TotalsSums;
103
+ }
104
+ /** How a totals line's values compare with the sums of the body above them. */
105
+ export interface TotalsSums {
106
+ matches: number;
107
+ candidates: number;
108
+ /** The line holds no formulas. */
109
+ typed: boolean;
110
+ /** The sums run down columns (the line is a row) rather than across rows. */
111
+ byColumn: boolean;
112
+ /** The cells that do not equal their Σ — `H26 text`, `C26 400 ≠ Σ 411`. */
113
+ misses: string[];
114
+ }
115
+ /** Where a block's body stops. */
116
+ export interface Totals {
117
+ /** The block runs down its rows (`true`) or across its columns. */
118
+ byColumn: boolean;
119
+ /** Absolute index of the first line left out of the body. */
120
+ start: number;
121
+ /** Every line from {@link start} to the block's end. */
122
+ lines: TotalsLine[];
123
+ /** The profile summary's fragment — `rows 26:27 not profiled: …`. */
124
+ note: string;
125
+ }
126
+ /**
127
+ * Where a block's body stops: the first line whose values equal the Σ of the body above them.
128
+ *
129
+ * @remarks
130
+ * One deterministic test, the same for a `=SUM` row and a pasted one — a total equals the sum it
131
+ * totals by value, however it was entered. It needs two matches and a majority of the numeric
132
+ * series, so a coincidence in one column does not end a block. A table's totals row is taken as
133
+ * authored.
134
+ *
135
+ * Every line from there to the end of the block is left out of the stats, and each is named with
136
+ * its label so a reader can see what was set aside: the total, and whatever runs on below it
137
+ * (`Earnings Before Interest & Taxes` under `Total Expenses`). Labels are reported, never
138
+ * interpreted — deciding by its wording that a line is "a total" is the call a reader makes better.
139
+ *
140
+ * The first line's comparison is part of the fact: `typed` when it holds no formulas, and the cells
141
+ * that do not match, which on a pasted total are the finding.
142
+ */
143
+ export declare function detectTotals(range: ICellRange, maxProfileCells?: number): Totals | null;
144
+ /** `= Σ above (13 of 13)` / `typed, = Σ above (12 of 13; H26 text)` / `= Σ to the left (2 of 2)`. */
145
+ export declare function describeSums(sums: TotalsSums): string;
91
146
  /**
92
147
  * Per-kind stats, pooled across the WHOLE range regardless of column — "what's actually in here,
93
148
  * broken down by type" in one shot, as opposed to {@link profileSeries}'s per-column breakdown.
@@ -1,7 +1,8 @@
1
1
  import { IWorkbook } from '@sheetxl/sdk';
2
- import { AppendDependencyOptions } from './appendSections';
2
+ import { AppendDependencyOptions } from './appendDependencies';
3
3
  import { RenderCellRangeOptions } from './renderCellRange';
4
4
  import { RenderFormulaOptions } from './renderFormula';
5
+ import { RenderModulesOptions } from './renderModules';
5
6
  import { RenderNamesOptions } from './renderNames';
6
7
  import { RenderRecordsOptions } from './renderRecords';
7
8
  import { RenderRangesOptions } from './renderRanges';
@@ -31,7 +32,7 @@ export declare namespace Renderer {
31
32
  * alternative is making the caller name the kind, which is the dispatch the registry exists
32
33
  * to remove.
33
34
  */
34
- type Options = RenderCellRangeOptions & RenderSheetOptions & RenderRegionsOptions & RenderValuesOptions & RenderFormulaOptions & RenderRecordsOptions & RenderNamesOptions & RenderRangesOptions & AppendDependencyOptions;
35
+ type Options = RenderCellRangeOptions & RenderSheetOptions & RenderRegionsOptions & RenderValuesOptions & RenderFormulaOptions & RenderRecordsOptions & RenderNamesOptions & RenderRangesOptions & RenderModulesOptions & AppendDependencyOptions;
35
36
  /**
36
37
  * One renderable kind.
37
38
  */
@@ -54,6 +55,14 @@ export declare namespace Renderer {
54
55
  * must be read as a table rather than as its first element or as N reports.
55
56
  */
56
57
  export declare const RENDERERS: readonly Renderer.Entry[];
58
+ /**
59
+ * The name of every renderable kind, in dispatch order.
60
+ *
61
+ * @remarks
62
+ * What a host's help text lists. Derived, because a hand-written copy of this list is a second
63
+ * registry that nothing keeps in step with the first.
64
+ */
65
+ export declare const RENDERABLE_KINDS: readonly string[];
57
66
  /**
58
67
  * Thrown by {@link renderMarkdown} when nothing in the registry accepts the value.
59
68
  *