Makros: GET/POST-Anfragen mit JSON-Ergebnis und FOR-Iteration
Erweitert die Makro-Sprache um Netzwerkzugriff: "x = GET(url)"/ "x = POST(url; body)" binden die geparste JSON-Antwort an eine Variable; FOR item IN x DO ... END iteriert, wenn x ein JSON-Array ist, über dessen Elemente; JSONGET(wert; pfad) liest ein Feld heraus (punktgetrennt, Zahl = Array-Index) und funktioniert – anders als GET/POST – überall in einem Ausdruck verschachtelt, nicht nur als ganze Zuweisung. Da ein echter Netzwerkaufruf nicht synchron laufen kann, ohne den Tab einzufrieren, bekommt der Makro-Interpreter einen separaten asynchronen Zweig (execBlockAsync/execStatementAsync); der bestehende synchrone Interpreter, den auch gewöhnliche "Mit Schleife"-Funktionen mitten in der synchronen Neuberechnung nutzen, bleibt unangetastet. Netzwerkaufrufe werden pro Makro einmalig mit Zielname bestätigt (dauerhaft gemerkt); die bestehende "ein Lauf = ein Undo-Schritt"-Garantie, die bislang auf Synchronität beruhte, wird jetzt explizit wiederhergestellt statt sich weiter auf die Zeit-Koaleszenz zu verlassen. Zwei echte Lücken erst beim eigenen Live-Test gefunden und behoben: (1) JSONGET direkt in eine Aktion verschachtelt (statt erst einer Variable zugewiesen) scheiterte zunächst an #NAME?; (2) JSONGET(...) direkt als FOR-Quelle (ohne Zwischenvariable) scheiterte sowohl an der Speicher-Zeit-Prüfung als auch zur Laufzeit, da substitute() einen Funktionsaufruf nie auswertet. Live gegen eine neue same-origin-Fixture (public/test-fixtures/sample.json) verifiziert: echter GET, echter Bestätigungsdialog, FOR/JSONGET über die echte Antwort, kein erneuter Dialog beim zweiten Lauf. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -449,13 +449,59 @@ Schleifenvariable); alle anderen Argumente sind normale Ausdrücke.
|
||||
normal (berechnet einen Wert), kann aber selbst nie schreiben — ihr
|
||||
Funktionskörper wird immer ohne Schreib-Rechte geparst.
|
||||
|
||||
**GET/POST + JSON-Ergebnis mit Iteration**: `r = GET(url)` und
|
||||
`r = POST(url; body)` rufen eine externe Adresse auf und binden die
|
||||
geparste JSON-Antwort an `r` — genau wie jede andere Zuweisung, aber die
|
||||
einzige Stelle in der Sprache, die wirklich auf ein Netzwerk-Roundtrip
|
||||
wartet. `FOR item IN r DO … END` (oder direkt `FOR item IN JSONGET(r;
|
||||
"pfad") DO … END`) iteriert, sobald `r` ein JSON-**Array** ist, über dessen
|
||||
Elemente — dieselbe `FOR`-Syntax wie bei einem Zell-/Bereichsbezug, nur
|
||||
mit einer neuen Quellart. **`JSONGET(wert; pfad)`** liest ein Feld heraus
|
||||
(`"a.b.0.c"` — punktgetrennt, eine Zahl indiziert ein Array, alles andere
|
||||
einen Objekt-Schlüssel; ein fehlender Pfad ergibt JSON-`null`, kein
|
||||
Fehler) — anders als `GET`/`POST` rein synchron und deshalb überall in
|
||||
einem Ausdruck einsetzbar (`SETVALUE(Ziel; JSONGET(item; "name"))`,
|
||||
verschachtelt in einer `IF`-Bedingung, …), nicht nur als ganze rechte
|
||||
Seite einer Zuweisung. Ein JSON-Wert, direkt (ohne `JSONGET`) an einer
|
||||
gewöhnlichen Werteposition verwendet, kollabiert automatisch: Text/Zahl
|
||||
bleiben sich selbst, ein Bool wird `1`/`0`, ein Objekt/Array wird sein
|
||||
JSON-Text — praktisch, um z. B. die rohe Antwort unverändert in eine Zelle
|
||||
zu schreiben.
|
||||
|
||||
- **Verbindung wird pro Makro einmalig bestätigt.** Beim ersten Kontakt
|
||||
eines Makros zu einem neuen Host (Domain **inkl. Port**) erscheint ein
|
||||
Bestätigungsdialog mit Makro-Name und Ziel-Host; wird zugestimmt, ist
|
||||
dieser Host für **dieses** Makro dauerhaft freigegeben (gespeichert,
|
||||
Teil des JSON-Exports) — kein erneutes Nachfragen bei künftigen Läufen,
|
||||
auch nicht in einer neuen Sitzung. Bewusst **pro Makro statt pro
|
||||
Dokument**: ein importiertes Dokument mit mehreren kleinen Makros, die
|
||||
denselben Host kontaktieren, soll nicht durch eine einzige Bestätigung
|
||||
alle auf einmal freischalten — jedes Makro trifft seine eigene, einmalige
|
||||
Entscheidung. Eine Ablehnung bricht das Makro ab, ohne den Host zu
|
||||
speichern.
|
||||
- **`GET`/`POST` sind nur als ganze rechte Seite einer Zuweisung gültig**
|
||||
(`x = GET(url)`), nicht verschachtelt in einem Ausdruck — sie brauchen
|
||||
einen echten `await`, den nur diese eine Stelle in der Sprache erlaubt.
|
||||
Innerhalb einer normalen benutzerdefinierten Funktion sind `GET`/`POST`/
|
||||
`JSONGET` von vornherein unerreichbar (Speicher-Zeit-Fehler mit klarer
|
||||
Meldung) — Netzwerkzugriff bleibt strikt auf Makros beschränkt.
|
||||
- **Nicht-2xx-Antwort oder ungültiges JSON** brechen den Lauf mit einer
|
||||
klaren Fehlermeldung ab, wie jede andere Aktion.
|
||||
|
||||
**Bewusst ohne** (Stand jetzt): Makros haben keine Parameter (ein Klick
|
||||
übergibt keine Argumente); mehrere Struktur-Aktionen in einer Schleife
|
||||
lösen weiterhin je eine eigene Neuberechnung aus statt gebündelt einmal am
|
||||
Ende (das kleinere Schrittbudget hält das Restrisiko klein, spätere
|
||||
Optimierung möglich); ein `TabellenRef`-String wird am *ersten* `!`
|
||||
gesplittet (ein Tabellenname mit eigenem `!` darin ist so nicht
|
||||
adressierbar).
|
||||
adressierbar); `POST` hat keine eigenen Header/Authentifizierung (immer
|
||||
`Content-Type: application/json`, der Body wird vom Makro-Autor selbst als
|
||||
Text — z. B. per `&`-Verkettung — zusammengesetzt), `GET` hat keinen Body;
|
||||
kein eigenes Timeout (folgt dem Browser-`fetch()`-Standard — ein
|
||||
hängender Request blockiert den Makrolauf unbegrenzt); `FOR` über ein
|
||||
JSON-*Objekt* (statt Array) ist ein klarer Fehler, keine implizite
|
||||
„über die Werte/Einträge iterieren"-Zweitbedeutung; GET/POST teilen sich
|
||||
das normale Schrittbudget (kein eigenes, kleineres Netzwerk-Kontingent).
|
||||
|
||||
### Zeilen & Spalten einfügen/löschen
|
||||
|
||||
@@ -1170,6 +1216,30 @@ Grundrechenarten: `Übersicht!B2 = =SUM(Umsatz!B2:E2)`, `D2 = =B2-C2`,
|
||||
letzte Blatt als echten Fehlschlag statt stillem No-op, `ADDTABLE` auf ein
|
||||
*anderes* Blatt lässt die aktive Ansicht/Auswahl unangetastet (reiner
|
||||
Seiteneffekt-Fix, live per Playwright gefunden), JSON-Round-Trip.
|
||||
- **Makros: GET/POST/JSONGET** (`macros.spec.ts`) — Ergebnis-Bindung +
|
||||
Kollaps-Regel (Text/Zahl/Bool/Objekt/Array) gegen einen gemockten
|
||||
`MacroNetworkHost`, `JSONGET`-Pfadauflösung (verschachtelt, Array-Index,
|
||||
fehlender Pfad → `null`, falscher Werttyp → Fehler), `FOR` über ein
|
||||
JSON-Array direkt **und** über einen `JSONGET(...)`-Aufruf direkt als
|
||||
Quelle (letzteres ein live gefundener Lücke-Fix: `substitute()` allein
|
||||
wertet einen Funktionsaufruf nie aus), `FOR` über ein JSON-Objekt/
|
||||
Einzelwert → klarer Fehler, `GET`/`POST` außerhalb einer reinen Zuweisung
|
||||
→ `#NAME?` (belegt die eindämmungsfreie Absicherung empirisch),
|
||||
`JSONGET` dagegen funktioniert überall verschachtelt (rein synchron).
|
||||
Store-Ebene (`document.spec.ts`): `GET`/`POST`/`JSONGET` in einer
|
||||
benutzerdefinierten Funktion (Ausdruck **und** Block) abgelehnt;
|
||||
`confirm()` gemockt — erster Lauf fragt und persistiert, zweiter Lauf
|
||||
zum selben Host fragt nicht mehr, ein anderer Host fragt erneut, eine
|
||||
Ablehnung bricht ab, ohne den Host zu speichern; nicht-2xx-Antwort
|
||||
bricht sauber ab; **Pflichttest**: `SETVALUE` → ein absichtlich
|
||||
langsames `GET` (300 ms, über der 150-ms-Undo-Koaleszenz) → `SETVALUE`
|
||||
erzeugt trotzdem genau einen Undo-Schritt — beweist den
|
||||
`macroRunActive`-Fix direkt; JSON-Round-Trip von `approvedHosts`.
|
||||
Live per Playwright gegen eine echte same-origin-Fixture
|
||||
(`public/test-fixtures/sample.json`) verifiziert: echter `GET`, echter
|
||||
Bestätigungsdialog mit Makro-/Host-Namen, `FOR`/`JSONGET` über die
|
||||
echte Antwort, kein erneuter Dialog beim zweiten Lauf, null
|
||||
Konsolenfehler.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user