Ukazka tela webhooku shazovala builder pri psani cesty parametru

Zapisovalo se do retezce: `exampleValue` vraci u obycejneho parametru text
'text', a kdyz cesta jineho parametru vedla skrz nej, `target[key] = ...`
skoncilo na "Cannot create property 'data' on string 'text'" a spadl cely
builder.

Neni to okrajovy stav. Prijde cely objekt a vedle nej se vytahuje konkretni
hodnota z jeho nitra, takze parametr, kterym vede cesta jineho parametru, je
bezna vec - a pri psani cesty `zprava.data` je `zprava` chvili hotovy parametr
sam o sobe, takze to padalo pri kazdem stisku klavesy.

Dve zmeny:
- do cesty se da zanorit vzdy. Kdyz na miste je skalar, nahradi se schrankou
- parametr, kterym vede cesta jineho parametru, uz nedostane zastupnou hodnotu
  podle typu. Plati vnitrni struktura, protoze prave tu ma ukazka ukazat -
  zastupna hodnota by ji prepsala, a u objektu a poli je to to podstatne

Overeno na obou poradich (skalar driv i pozdeji nez hlubsi cesta), na objektu
s vnitrkem a na poli s ciselnym indexem.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
JiriUhlir
2026-08-28 11:25:08 +02:00
co-authored by Claude Opus 5
parent 4d156d2837
commit 00d9d2d4b1
@@ -286,20 +286,52 @@ function exampleBody(fields: TriggerField[]): string {
if (fields.length === 0) return '{\n "cokoliv": "co pošle odesílatel"\n}';
const body: Record<string, unknown> = {};
const paths = fields.map((field) => field.path ?? field.name);
for (const field of fields) {
const path = (field.path ?? field.name).split('.');
const full = field.path ?? field.name;
const path = full.split('.');
let target = body;
/*
* Parametr, kterym vede cesta jineho parametru.
*
* Deje se to bezne: prijde cely objekt a vedle nej se vytahuje konkretni
* hodnota z jeho nitra. Pak plati ta vnitrni struktura, ne zastupna
* hodnota typu - ta by prepsala presne to, co ma ukazka ukazat.
*/
const isParent = paths.some((other) => other !== full && other.startsWith(`${full}.`));
for (let i = 0; i < path.length - 1; i += 1) {
const key = path[i];
const next = path[i + 1];
// Cislo v ceste znamena pole, ne objekt s klicem "0".
if (target[key] === undefined) target[key] = /^\d+$/.test(next) ? [] : {};
const current = target[key];
/*
* Do cesty se musi dat zanorit. Kdyz uz na tom miste hodnota je, protoze
* jiny parametr konci tam, kde tenhle pokracuje, prepise se schrankou.
*
* Bez toho by se zapisovalo do retezce a **spadl by cely builder**. Neni
* to okrajovy stav: pri psani cesty `zprava.data` je `zprava` chvili
* hotovy parametr sam o sobe, takze staci mit oba a ukazka se rozbije
* pri kazdem stisku klavesy.
*
* Cislo v ceste znamena pole, ne objekt s klicem "0".
*/
if (current === null || typeof current !== 'object') {
target[key] = /^\d+$/.test(next) ? [] : {};
}
target = target[key] as Record<string, unknown>;
}
target[path[path.length - 1]] = exampleValue(field.type);
const last = path[path.length - 1];
if (isParent) {
// Schranku nechat, at uz ji postavily vnorene parametry, nebo teprve
// prijdou na radu. Prepsat ji zastupnou hodnotou znamena je zahodit.
const current = target[last];
if (current === null || typeof current !== 'object') target[last] = {};
} else {
target[last] = exampleValue(field.type);
}
}
return JSON.stringify(body, null, 2);