Expressions de valeur (Value Expressions)

Dernière mise à jour : 20 juillet 2026

Chaque endroit d'un Script où une valeur est nécessaire (une URL, un body de requête, une valeur de champ, une condition, une valeur de filtre, un id de cible, etc.) prend l'une des trois formes ci-dessous. Ce document décrit ces trois formes, d'où viennent les valeurs (les racines de contexte) et les règles de mappage de locale propres aux données de WEEGLOO. Tous les champs du Catalogue des statements suivent ces règles.

Les trois formes

FormeRègleExemple
Référence (reference)Résout le { /json-pointer } contenu dans une chaîne contre le contexte."{ /payload/fields/title }"
Littéral (literal)Une valeur sans { /ptr } (chaîne, nombre, booléen, objet, tableau). Utilisée telle quelle."draft", 42, true, { "a": 1 }
Opérations et conditions (JsonLogic)Un objet dont l'unique clé est un opérateur. Ses opérandes sont à leur tour des expressions de valeur (référence, littéral, imbrication).{ "+": [ "{ /vars/n }", 1 ] }

Les trois formes s'imbriquent. On les combine en plaçant une référence comme opérande de JsonLogic, puis en réinjectant le résultat d'une référence dans une opération.

Référence : { /json-pointer }

Dans les accolades, on place un JSON Pointer RFC 6901 (qui doit commencer par /). Les espaces autour des accolades sont autorisés ({ /a/b } est identique à {/a/b}).

Pointer unique et modèle mixte : règles de type

  • Quand toute la chaîne est un pointer unique, la valeur conserve son type original (si c'est un nombre, un nombre ; si c'est un objet, un objet ; si c'est un tableau, un tableau).
  • Quand elle est mélangée à du texte littéral, il y a concaténation de chaînes (concatenation).
"{ /payload/fields/count }"                 // si nombre, nombre tel quel (p. ex. 42)
"{ /payload/fields/tags }"                  // si tableau, tableau tel quel
"page-{ /payload/fields/n }-of-10"          // concaténation de chaînes → "page-42-of-10"
"Bearer { /payload/fields/token }"          // concaténation de chaînes → "Bearer abc123"

Valeurs absentes et échappement

  • Si le chemin n'existe pas ou si la valeur est vide, un pointer unique devient null et un modèle mixte devient une chaîne vide.
  • Pour utiliser { comme littéral, on l'échappe avec \{ (à cet endroit, il n'est pas interprété comme un pointer).

Racines de contexte : d'où viennent les valeurs

Le segment de plus haut niveau d'un { /pointer } est l'un des cinq suivants.

RacineContenu
/payloadLe payload JSON (l'entrée) transmis lors de l'appel. Exemple : { /payload/fields/email }
/headersLes en-têtes HTTP de la requête transmis lors de l'appel. Les clés sont en minuscules et il y a une seule valeur par nom. Exemple : { /headers/authorization }
/<name>Le résultat d'un statement précédent portant ce name. Exemple : { /order/sys/id }
/vars/<name>Une variable mutable à portée de script déclarée avec SetVar. Exemple : { /vars/total }
/errorUtilisée uniquement dans le bloc catch d'un Try. L'erreur capturée { message, statement }. Exemple : { /error/message }

Forme du résultat d'un statement

La forme du résultat d'un statement portant un name varie selon le type.

StatementForme du résultatExemple de référence
Http{ status, body }{ /resp/status }, { /resp/body/choices/0/message/content }
ResourceCreate, ResourceRead (individuel), ResourceFind (individuel)La ressource elle-même{ /post/sys/id }, { /post/fields/title/en-US }
ResourcePageRead{ items, next }{ /page/items/0/sys/id }, { /page/next }
  • ResourceFind lie null s'il n'y a pas de correspondance. On teste l'existence avec { "==": [ "{ /found }", null ] }.
  • ResourceRead (individuel) est une erreur si la cible n'existe pas (gérable avec Try). Les détails sont traités dans Lecture de ressources dans le Catalogue des statements.

Opérations et conditions : JsonLogic

Lorsqu'un calcul ou une condition est nécessaire, on utilise l'objet opérateur de la spécification jsonlogic.com.

  • L'accès aux données est unifié via des références { /ptr }, et non via le var vanilla (dot-path). Le moteur résout d'abord les pointers des opérandes, puis applique l'opérateur.
  • Si la clé d'un objet à clé unique est un opérateur enregistré, il est traité comme une opération ; sinon, comme un objet ordinaire.

Tableau des opérateurs

CatégorieOpérateurSignification et exemple
Conditionif (alias ?:){ "if": [cond, alors, cond2, alors2, …, défaut] }. La valeur de la première condition vraie ; s'il n'y en a pas, la dernière valeur par défaut.
Logiqueand, orÉvaluation en court-circuit. and renvoie le premier falsy (ou le dernier), or le premier truthy (ou le dernier), comme valeur.
Logique! (not), !! (to-bool){ "!": x } nie le truthy, { "!!": x } indique si c'est truthy. Pour les contrôles d'existence, on utilise souvent !!.
Égalité==, !=Comparaison souple (comparaison après conversion numérique forcée ; "1"==1 est vrai).
Égalité===, !==Comparaison stricte (y compris le type).
Comparaison<, <=, >, >=Enchaînable : { "<": [1,2,3] } équivaut à 1<2 AND 2<3. Non convertible en nombre (NaN) donne false.
Arithmétique+La somme de tous les opérandes.
Arithmétique-Avec un seul opérande, négation ; avec deux, soustraction.
Arithmétique*, /, %Multiplication, division, reste.
Agrégationmin, maxLe minimum et le maximum des opérandes.
ChaînecatConcatène tous les opérandes en une chaîne.
Appartenancein{ "in": [needle, haystack] }. Si haystack est une chaîne, sous-chaîne ; si c'est une collection, appartenance d'un élément.
TableaumergeAplatit plusieurs tableaux ou valeurs en un seul tableau (utilisé pour l'accumulation).

Les opérateurs d'itération de tableau (map, filter, reduce, all, some, none) ne sont pas pris en charge. Script itère sur les tableaux avec Loop (Loop dans le Catalogue des statements).

Conversion numérique et exemples

Les règles de conversion numérique sont les suivantes. Un nombre reste tel quel, true devient 1, false devient 0, une chaîne est analysée (si elle n'est pas analysable, le calcul produit une valeur d'échec) et null devient 0.

{ "-":  [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] }   // solde - coût
{ "<":  [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] }   // solde < coût → boolean
{ "and": [ { "<": [ "{ /a/body/risk }", 0.5 ] }, { ">=": [ "{ /b/body/score }", 700 ] } ] }
{ "cat": [ "id-", "{ /payload/sys/id }" ] }                                    // "id-<uuid>"
{ "!!": "{ /found/sys/id }" }                                                  // true s'il existe
{ "merge": [ "{ /vars/ids }", [ "{ /row/sys/id }" ] ] }                        // accumule un élément dans le tableau
{ "if": [ "{ /page/next }", "{ /page/next }", "END" ] }                        // next s'il existe, sinon "END"

Évaluation du vrai et du faux (Truthiness)

if, and, or, !, !! ainsi que If.condition et Loop.while déterminent le vrai et le faux selon les règles suivantes.

  • falsy : null, false, le nombre 0, la chaîne vide "", une collection vide (un tableau vide).
  • truthy : tout le reste (les nombres différents de 0, les chaînes et tableaux non vides, et tous les objets).

Les clés aussi peuvent être des références

La clé d'un mappage comme fields prend elle aussi en charge les références { /ptr }. La clé est résolue à l'exécution.

"fields": { "{ /payload/fields/fieldName }": { "en-US": "{ /payload/fields/fieldValue }" } }

Si deux clés se résolvent à la même valeur, il y a collision et c'est une erreur du moteur.

Mappage de locale (LocaleValueMap) : règles spécifiques à Content et Media

Dans WEEGLOO, chaque champ d'un Content ou d'un Media n'est pas une valeur mais un mappage par locale (par exemple, balance vaut { "en-US": 1, "ko-KR": 10 }). Il faut donc gérer la locale conjointement lors de la lecture et de l'écriture. Pour Media aussi, title et description (des scalaires) ainsi que file (l'instruction d'ingestion) sont des mappages de locale. Le JSON qui n'est ni Content ni Media, comme /payload ou une réponse HTTP, n'est pas concerné par cette règle (il conserve la structure définie par le schéma, et un scalaire reste un scalaire).

Lecture

  • Pour obtenir un scalaire, on précise jusqu'à la locale : { /<name>/fields/<field>/<locale> } (par exemple, { /post/fields/title/en-US }).
  • Sans locale, { /<name>/fields/<field> } renvoie l'objet complet du mappage de locale.
  • Un champ localized:false se trouve uniquement dans le bucket de la locale par défaut, on le lit donc avec le code de cette locale par défaut.

Écriture (les fields de ResourceCreate, ResourceUpdate, ResourcePatch)

La valeur est un mappage de locale { "<locale>": <expression de valeur scalaire> }. C'est symétrique à la lecture.

"fields": {
  "title":  { "en-US": "Hello", "ko-KR": "안녕" },   // énumère les buckets pour plusieurs locales
  "status": { "en-US": "paid" }
}
  • ResourceCreate doit obligatoirement inclure le bucket de la locale par défaut du Space dans chaque champ renseigné (la règle default-locale).
  • ResourceUpdate est un remplacement complet. Les champs et les locales absents de fields sont supprimés (y compris le fichier).
  • ResourcePatch ne met à jour que les champs et buckets spécifiés (les autres champs et locales sont conservés).
  • Suppression avec un null littéral : si la valeur est un null littéral, le bucket (field, locale) correspondant est supprimé (la méthode standard pour vider une locale précise dans un Patch). "" (chaîne vide) n'est pas une suppression, mais l'affectation d'une valeur vide. Si une expression de valeur ({ /ptr }) s'évalue à null à l'exécution, ce n'est pas une suppression mais une erreur (un payload manquant n'est pas avalé silencieusement). Seul un null littéral supprime.
  • Media file : la valeur n'est pas un scalaire mais une instruction d'ingestion { "source": …, "encoding": "url"|"base64" }. Une écriture incluant un fichier est réservée au mode Async (ResourceCreate dans le Catalogue des statements).
  • Un champ localized:false n'est placé que dans le bucket de la locale par défaut.
  • Le code de locale (la clé du mappage) peut lui aussi être une référence { /ptr } (voir ci-dessus Les clés aussi peuvent être des références). On l'utilise pour créer des locales dynamiques.

Champ de commodité locale

Si l'on donne un locale à ResourceCreate, ResourceUpdate ou ResourcePatch, le moteur enveloppe automatiquement chaque valeur de fields dans un bucket { <locale>: valeur }. Il suffit donc de donner des scalaires.

// les deux suivants sont identiques
{ "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_post" } },
  "locale": "en-US", "fields": { "title": "Hello" } }
 
{ "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_post" } },
  "fields": { "title": { "en-US": "Hello" } } }

Si l'on donne locale et que la valeur imbrique déjà un mappage de locale ({ "en-US": … }), on obtient une double imbrication { <locale>: { "en-US": … } } (erreur de l'auteur). On unifie sur un seul style : avec locale, uniquement des scalaires ; sans lui, uniquement des mappages de locale explicites.

La locale dans where et order

  • Dans where et order, pour fields.X, le moteur applique automatiquement la locale par défaut du Space (comme pour une requête CMA).
  • Pour viser une locale précise, on la spécifie avec fields.X.<locale>.
"where": { "fields.slug": { "eq": "{ /payload/fields/slug }" } }   // slug de la locale par défaut
"where": { "fields.title.ko-KR": { "prefix": "안" } }              // locale précise