Text-Vergleich, &-Verkettung und benannte Bereiche

- Vergleichsoperatoren (= <> > < >= <=) unterscheiden jetzt Text- von
  Zahlenvergleich statt jede Seite zwangsweise durch toNumber() zu
  schicken (=A1="Nord" gab vorher #VALUE! statt 1); ermöglicht
  Text-Kriterien in selbstgebauten COUNTIF/SUMIF/AVERAGEIF-Funktionen
  (neue README-Sektion "SUMIF/COUNTIF/AVERAGEIF nachbauen").
- Neuer &-Operator (Excel-Präzedenz zwischen Vergleich und +/-) plus
  CONCAT/CONCATENATE als Funktions-Äquivalent.
- Benannte Bereiche: neuer Toolbar-Button "🏷" verwaltet dokumentweite
  Namen für eine feste Zelle/einen festen Bereich (z. B. Umsatz_Q1statt
  Umsatz!B2:B6), unqualifiziert in jeder Top-Level-Formel nutzbar.
  Live gegen die Tabellen-ID aufgelöst (übersteht Tabellen-Umbenennung),
  bewusst nicht innerhalb einer benutzerdefinierten Funktion selbst
  nutzbar (Aufrufer können sie aber als Argument übergeben).
- Nebenbei: COUNT2s Autovervollständigungs-Hint korrigiert (zeigte
  "COUNT(...)" statt "COUNT2(...)").

374 Tests, vue-tsc/eslint/build sauber, Playwright-live-verifiziert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
wkh
2026-09-08 21:59:47 +02:00
co-authored by Claude Sonnet 5
parent 9015a991aa
commit 2c54537427
22 changed files with 1460 additions and 86 deletions
+32
View File
@@ -58,6 +58,22 @@ export interface CellRef extends Coord {
tableId: string;
}
/** A document-defined name resolving to a fixed cell/range on a specific
* table -- fed into {@link Workbook} (see workbook.ts) so it can implement
* {@link EngineHost.resolveNamedRange}. Unlike a custom function, there is
* no expression/formula of its own, just fixed coordinates -- so there is
* nothing that could cyclically reference itself. `tableId` (not a table
* *name*) so a named range survives its target table being renamed; the
* host resolves it to that table's *current* name on lookup, the same
* qualifier a formula's own `Tabelle!Zelle` reference would carry. */
export interface NamedRangeDef {
id: string;
name: string;
tableId: string;
start: Coord;
end: Coord;
}
/** Stable string key for a cell across the whole document. */
export function keyOf(tableId: string, col: number, row: number): string {
return `${tableId}␟${col}␟${row}`;
@@ -99,6 +115,22 @@ export interface EngineHost {
* (`#REF` -- the formula needs an explicit sheet qualifier).
*/
resolveTableName(name: string, sheetName?: string | null): string | null;
/**
* Resolve a *named range* (as written, unqualified, in a formula -- e.g.
* `Umsatz_Q1`) to the table-qualified cell/range it currently stands for.
* Matching is case-insensitive and tolerant of surrounding whitespace,
* same as {@link resolveTableName}. `null` when the name is unknown (or
* its target table has since been deleted) -- the caller turns that into
* `#NAME?`, the same error class an unknown function name gets.
*
* Resolved by *name*, live, every time -- never baked into the AST -- so a
* named range survives its target table being renamed, the same way a
* `Tabelle!Zelle` reference's table name is looked up fresh on every
* evaluation rather than resolved once at parse time.
*/
resolveNamedRange(
name: string,
): { qualifier: string; sheetQualifier?: string; start: Coord; end: Coord } | null;
/** Dimensions of a table, used for range clamping and #REF detection. */
tableSize(tableId: string): { cols: number; rows: number } | null;
/**