Makros: Engine- und Store-Fundament (Zellen/Zeilen/Spalten/Tabellen/Blätter per Skript)
Erster von zwei Commits (UI folgt separat): neue, explizit ausgelöste Makro-Sprache — dieselbe block-mode-Grammatik wie bei "Mit Schleife"- Funktionen (FOR/IF/RETURN), plus ein neues Schreib-Vokabular (SETVALUE, INSERTROW/DELETEROW/INSERTCOL/DELETECOL, ADDTABLE/RENAMETABLE/DELETETABLE, ADDSHEET/RENAMESHEET/DELETESHEET), adressiert mit der bestehenden Blatt!Tabelle::Zelle-Syntax. Bewusst außerhalb der normalen Neuberechnung: ein Makro läuft nie aus einer Zellformel heraus, sondern nur explizit getriggert (store.runMacro), und mutiert ausschließlich über die bereits vorhandenen Store-Primitiven (setCellInput, insertRow, addTable, addSheet, …) — Workbook/EngineHost/ DependencyGraph bleiben unverändert rein lesend. Ein ganzer synchroner Makro-Lauf wird automatisch zu einem einzigen Undo-Schritt. 50 neue Tests (Engine + Store), inkl. eines gezielten Regressionstests für die zentrale Korrektheits-Fallgrube: eine strukturelle Aktion mitten im Lauf ersetzt die Workbook-Instanz komplett, jeder Host-Zugriff muss daher frisch aufgelöst werden statt eine Referenz zu cachen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import type {
|
||||
CustomFunction,
|
||||
DocumentState,
|
||||
HAlign,
|
||||
Macro,
|
||||
NamedRange,
|
||||
Sheet,
|
||||
SheetObject,
|
||||
@@ -100,6 +101,32 @@ function normaliseNamedRanges(x: unknown, tableIds: ReadonlySet<string>): NamedR
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Defaults to `[]` -- absent in every document saved before this feature
|
||||
* existed. Unlike a named range, a macro carries no `tableId`/other
|
||||
* document-internal reference to validate against -- its body is a plain
|
||||
* string, parsed and validated lazily (store/document.ts's `validateMacro`)
|
||||
* only when actually edited/run, same lenient convention as a custom
|
||||
* function's `body` (an import doesn't re-run every save-time check, only
|
||||
* shape validation). */
|
||||
function normaliseMacros(x: unknown): Macro[] {
|
||||
if (!Array.isArray(x)) return [];
|
||||
const out: Macro[] = [];
|
||||
for (const m of x) {
|
||||
if (
|
||||
!m ||
|
||||
typeof m !== 'object' ||
|
||||
typeof (m as { id?: unknown }).id !== 'string' ||
|
||||
typeof (m as { name?: unknown }).name !== 'string' ||
|
||||
typeof (m as { body?: unknown }).body !== 'string'
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const rec = m as Macro;
|
||||
out.push({ id: rec.id, name: rec.name, body: rec.body });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const HEX_COLOR = /^#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
|
||||
function colorOrUndef(x: unknown): string | undefined {
|
||||
return typeof x === 'string' && HEX_COLOR.test(x) ? x : undefined;
|
||||
@@ -375,6 +402,7 @@ export function validateDocument(x: unknown): DocumentState {
|
||||
csvDelimiter: doc.csvDelimiter === ';' ? ';' : ',',
|
||||
customFunctions: normaliseCustomFunctions(doc.customFunctions),
|
||||
namedRanges: normaliseNamedRanges(doc.namedRanges, tableIds),
|
||||
macros: normaliseMacros(doc.macros),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -439,6 +467,7 @@ export function migrateToV2(x: unknown): DocumentState {
|
||||
csvDelimiter: ',',
|
||||
customFunctions: [],
|
||||
namedRanges: [],
|
||||
macros: [],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user