# BERKIOS Docs : documentation complète > Créez vos applications avec BERKIOS Studio, Code et Core. BERKIOS est une plateforme pour créer ses propres applications sans passer des années à apprendre à programmer. Elle comprend BERKIOS Studio (concevoir une interface à la souris), BERKIOS Code (décrire une application dans un fichier texte .bk, presque en langage naturel) et BERKIOS Core (un langage de programmation typé, fichiers .bks). Le code s'écrit en français, anglais, espagnol ou swahili. BERKIOS a été créé par Kionga Timothée Splane ; le nom vient de BER (Bernadette), KIO (Kionga) et S (Splane). Studio à télécharger : https://graphic.berkios.online/download.html --- # Studio, Core ou Code : que choisir ? Source : https://docs.berkios.online/commencer/choisir/ · Section : Démarrer · Documentation officielle BERKIOS (https://docs.berkios.online) BERKIOS propose trois façons de créer une application. Elles partagent le même moteur : on peut commencer avec l'une et passer à l'autre sans repartir de zéro. | | **BERKIOS Studio** | **BERKIOS Code** | **BERKIOS Core** | |---|---|---|---| | Principe | Concevoir en dessinant l'interface | Décrire l'application en langage naturel | Programmer avec un langage typé | | Fichiers | `.berkios.json` | `.bk` | `.bks` | | Pour qui | Débutants, concepteurs, métiers | Débutants et intermédiaires | Développeurs, logique complexe | | Ce que vous écrivez | Peu de code : scripts courts sur les composants | Interfaces, modèles de données, commandes | Fonctions, types, classes, modules | | Résultat | Application Windows, Android… | Projet ouvrable dans le Studio, outil en ligne de commande | Programme exécutable, logique réutilisable | > Dans les fichiers du projet, le Studio s'appelle aussi **BERKIOS GRAPHIC**. Les leçons de la section Studio utilisent ce nom dans leurs titres. ## Mon conseil de parcours 1. **Je n'ai jamais programmé** → commencez par le [Studio](https://docs.berkios.online/studio/01-demarrer/). Vous voyez le résultat à chaque étape. 2. **Je préfère écrire que cliquer** → essayez [BERKIOS Code](https://docs.berkios.online/code/premier-fichier/) : un fichier texte lisible décrit toute l'application. 3. **Je veux apprendre un vrai langage** → passez à [BERKIOS Core](https://docs.berkios.online/core/premiers-pas/) : variables, fonctions, classes, modules. > Les trois parcours sont indépendants. Vous n'avez pas besoin de terminer le Studio pour commencer Core. ## Langues Le code BERKIOS s'écrit dans votre langue : français, anglais, espagnol ou swahili selon l'outil. **Un fichier = une seule langue** : un fichier qui mélange les langues est refusé avec un message explicite. --- # Télécharger BERKIOS GRAPHIC Studio Source : https://docs.berkios.online/commencer/telecharger/ · Section : Démarrer · Documentation officielle BERKIOS (https://docs.berkios.online) Le Studio s'installe sous **Windows** avec un installateur, au format **`.exe`** ou **`.msi`**. [Télécharger BERKIOS GRAPHIC](https://graphic.berkios.online/download.html) La page de téléchargement récupère automatiquement les fichiers de la dernière version publiée. Téléchargez toujours le Studio depuis **graphic.berkios.online** et nulle part ailleurs. ## Quel fichier choisir ? | Format | Pour qui | |---|---| | **`.exe`** | Le plus simple : double-clic, puis suivez les étapes. | | **`.msi`** | Le format Windows Installer, adapté au déploiement sur plusieurs postes (entreprise, école). | ## Ce qu'il vous faut - Windows 10 ou Windows 11, en 64 bits. - Des droits d'installation : Windows peut demander l'autorisation d'un administrateur. - Une connexion Internet pour le téléchargement. ## Installer en cinq étapes 1. Ouvrez [graphic.berkios.online/download.html](https://graphic.berkios.online/download.html) et téléchargez le `.exe` ou le `.msi`. 2. Lancez le fichier téléchargé. 3. Si Windows demande une confirmation, vérifiez que le fichier vient bien de la page officielle, puis acceptez. 4. Suivez les étapes de l'installateur. 5. Ouvrez **BERKIOS GRAPHIC Studio** depuis le menu Démarrer ou le raccourci créé. > Si Windows SmartScreen affiche un avertissement, c'est que l'installateur n'est pas encore reconnu par Microsoft. Vérifiez l'origine du fichier avant de continuer. ## Ce que contient l'installateur Un seul fichier installe le Studio, le Bridge (le service qui relie le Studio à votre ordinateur), le moteur Excel, les exemples et le complément Excel BERKIOS. **Vous n'avez pas besoin d'installer Node.js ni Flutter pour utiliser le Studio.** ## Pour générer et compiler des applications Concevoir une interface et la tester dans l'aperçu ne demande rien de plus. En revanche, **compiler** une application pour une plateforme demande les outils de cette plateforme : | Cible | Outil à installer | |---|---| | Applications Flutter | **Flutter SDK** (ajoutez son dossier `bin` au `PATH`) | | Application Windows de bureau | **Visual Studio Build Tools**, charge « Développement Desktop en C++ » | | Application Android | **Android Studio** (SDK, outils de plateforme, licences acceptées) | | Outils JavaScript, BERKIOS CODE et Core | **Node.js** (version LTS) | | Facultatif | **Git** | Redémarrez le Studio après toute modification des variables d'environnement. ## Vérifier votre installation Dans un terminal : ```bash where.exe flutter flutter --version flutter doctor -v where.exe node node --version ``` ## En cas de problème - **« Commande non reconnue »** : vérifiez le `PATH`, puis rouvrez le terminal. Si PowerShell ne lance pas l'outil, essayez l'invite de commandes (CMD). - **Échec de compilation** : lisez d'abord la première erreur réelle du journal ; les erreurs suivantes en découlent souvent. - **Chemins** : utilisez le chemin réel de votre machine, pas un chemin d'exemple copié d'un guide. Le [guide d'installation officiel](https://graphic.berkios.online/installation.html) détaille chaque outil. Besoin d'aide pour démarrer ? [Contactez nos experts](https://docs.berkios.online/formation/experts/). ## Et ensuite ? Lancez le Studio, ouvrez **Mes projets**, choisissez un modèle, puis suivez [Démarrer avec le Studio](https://docs.berkios.online/studio/demarrer/). --- # Installer depuis les sources, Code et Core Source : https://docs.berkios.online/commencer/installer/ · Section : Démarrer · Documentation officielle BERKIOS (https://docs.berkios.online) > Vous voulez simplement utiliser le Studio ? [Téléchargez l'installateur](https://docs.berkios.online/commencer/telecharger/). Cette page s'adresse à ceux qui travaillent depuis l'archive du projet ou qui veulent l'outil `berkios` en ligne de commande. ## Ce qu'il vous faut - Un ordinateur **Windows** pour le Studio et les applications Windows. - **Node.js 22.18 ou plus récent** (nécessaire pour le Studio, BERKIOS Code et BERKIOS Core). - Un navigateur récent. Pour générer des applications Windows ou Android, il faut en plus Flutter et, sous Windows, Visual Studio avec la charge « Développement Desktop en C++ ». Pour produire un installateur `.exe`, installez Inno Setup. Ces outils ne sont pas nécessaires pour apprendre. ## Installer le Studio 1. Décompressez l'archive BERKIOS GRAPHIC. 2. Double-cliquez sur `install.bat` (connexion Internet requise pour les dépendances). 3. Lancez `start.bat` : le Studio s'ouvre dans le navigateur. 4. Ouvrez **Mes projets** pour choisir un modèle ou un exemple. Pour vérifier l'installation, lancez `test.bat`. ## Installer BERKIOS Code et Core BERKIOS Code et BERKIOS Core partagent le même outil en ligne de commande, `berkios`. ```bash npm install -g berkios-code berkios --lg --fr ``` La deuxième commande choisit le français comme langue de programmation. Pour en changer plus tard : `berkios -m --lg --en`. Depuis l'archive du projet (développement) : ```bash cd compiler npm link ``` ## Vérifier que tout fonctionne ```bash berkios nouveau main.bk berkios valider main.bk berkios apercu main.bk ``` La dernière commande ouvre l'application dans le navigateur ; chaque enregistrement du fichier recharge la page. ## Terrain de jeu en ligne Sans rien installer, le dossier `web/` du compilateur contient un **terrain de jeu** : on écrit du code, on voit les erreurs, l'application fonctionne à côté, et l'on peut copier un lien de partage. Les programmes Core (`.bks`) s'y exécutent aussi. --- # Leçon 1 — Démarrer avec BERKIOS GRAPHIC Source : https://docs.berkios.online/studio/demarrer/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) ## Objectif Ouvrir un projet, repérer l'interface principale et lancer l'aperçu. ## Étapes 1. Décompressez l'archive dans un dossier de travail. 2. Lancez le Studio selon la procédure de votre installation. 3. Ouvrez `examples/code-composants/01-bibliotheque-personnelle.berkios.json`. 4. Repérez la zone de conception, la liste des composants et le mode Aperçu. 5. Enregistrez une copie de travail avant de modifier l'exemple. ## Notions - Un **projet** contient les métadonnées et une ou plusieurs interfaces. - Une **interface** contient des composants. - Un **composant** a un identifiant, un type, un libellé et des propriétés. - Un **script de composant** est enregistré dans `widget.script.source`. ## Exercice Ouvrez `03-consommation-eau.berkios.json`, lancez l'aperçu et décrivez le rôle de chaque bouton. --- # Leçon 2 — Composants et identifiants Source : https://docs.berkios.online/studio/composants-et-identifiants/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) ## Pourquoi les identifiants comptent Les commandes `set`, `increment`, `decrement`, `show`, `hide`, `toggle` et `calculate` doivent retrouver le composant cible. Le moteur de l'aperçu cherche l'identifiant, le nom ou le texte visible du composant. Exemple : ```text quand clic increment "Litres consommés" 10 ``` Le texte `Litres consommés` doit correspondre au champ ciblé. ## Conseils - Donnez des noms courts et explicites aux composants. - Évitez d'avoir deux composants avec le même texte visible. - Après avoir renommé un composant, mettez à jour les scripts qui le ciblent. - Préférez des identifiants stables comme `liters`, `result` ou `instructions`. ## Exercice Dans `05-calculateur-facture.berkios.json`, identifiez le champ résultat et les deux champs utilisés pour le calcul. --- # Leçon 3 — Écrire son premier script Source : https://docs.berkios.online/studio/premier-script/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) ## Objectif Associer le comportement à un composant sans configurer des actions dans `events`. 1. Sélectionnez un bouton. 2. Ouvrez l'éditeur BERKIOS CODE du composant. 3. Écrivez le script ci-dessous : ```text quand clic message "Bonjour depuis le script du composant" ``` 4. Vérifiez et enregistrez. 5. Passez en aperçu et cliquez sur le bouton. ## Modifier un champ ```text quand clic set "Nom du participant" "Amina" message "Valeur préparée" ``` ## Incrémenter un nombre ```text quand clic increment "Personnes présentes" 1 ``` ## Important Les exemples de formation laissent `events` vide. Le script est la source de comportement recherchée. Ne copiez pas les anciennes actions d'événements JSON dans les nouveaux exemples. --- # Leçon 4 — Commandes et calculs Source : https://docs.berkios.online/studio/commandes-et-calculs/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) > **v0.7.76 :** 100 commandes supplémentaires (texte, nombres, listes, dates, validation, couleur, confirmation, export…) sont décrites dans [la leçon 8](https://docs.berkios.online/reference/cent-nouvelles-commandes/). ## Commandes disponibles dans l'interpréteur du Studio | Commande | Rôle | |---|---| | `message "Texte"` | Afficher une notification (types, fenêtre modale et confirmation : `message.info`, `message.modal`, `message.confirmer`… voir la [leçon 9](https://docs.berkios.online/studio/messages-et-dialogues/)) | | `set "Cible" "Valeur"` | Définir la valeur d'un composant | | `increment "Cible" 1` | Ajouter un incrément numérique | | `decrement "Cible" 1` | Soustraire un incrément numérique | | `show "Cible"` | Afficher un composant | | `hide "Cible"` | Masquer un composant | | `toggle "Cible"` | Basculer sa visibilité | | `calculate "Résultat" "A" * "B"` | Calculer avec deux champs | | `ajouter "Cible" "texte"` (`append`) | Ajouter du texte à la fin d'un champ | | `effacer "Cible"` (`clear`) | Vider un champ | | `retirer "Cible"` (`backspace`) | Supprimer le dernier caractère | | `evaluer "Expression" "Résultat" [silencieux]` (`evaluate`) | Calculer une expression (+ − × ÷ ^ % ( ), sin cos tan sqrt log ln abs, π, e ; angles en degrés) | | `toutes les 100 ms` (`every`) | En-tête de minuterie : les commandes qui suivent se répètent | | `si "Cible" >= 100 alors ouvrir "Interface"` | Condition sur une valeur | | `circuler "Cible"` / `arreter` | Texte en circulation / arrêt de la minuterie | | `avancer "Cible" 40` (`advance`) | Déplacer le composant vers la droite de 40 px (10 px par défaut) | | `reculer "Cible" 40` (`retreat`) | Déplacer vers la gauche | | `monter "Cible" 40` / `descendre "Cible" 40` (`up` / `down`) | Déplacer vers le haut / le bas | | `deplacer "Cible" dx dy` (`move`) | Déplacer de dx, dy pixels (valeurs négatives permises) | | `placer "Cible" x y` (`place`) | Placer le composant à la position x, y | | `quand touche espace` (`on key space`) | En-tête d'événement clavier : touches `espace`, `droite`, `gauche`, `haut`, `bas`, `entree`, `echap` ou une lettre (`a`) | | `aller "Interface"` (`go`) | Aller directement à une interface (sans empiler d'historique) : connexion, déconnexion, accueil | | `stocker "clé" "Cible"` (`store`) | Mémoriser la valeur d'un composant (conservée dans le navigateur) | | `lire "clé" "Cible" ["défaut"]` (`recall`) | Relire une valeur mémorisée dans un composant ou une variable `$nom` (vide si la clé n'existe pas) | | `quitter` (`return`) | Arrêter le script de l'événement en cours (ex. `si "nom" = "" alors quitter`) | | `audio jouer` / `pause` / `basculer` / `arreter` | Lecture, pause, lecture⇄pause, arrêt du lecteur audio | | `audio volume 50` (ou `+10`, `-10`) | Volume de 0 à 100 (absolu ou relatif) | | `audio avancer 10` / `reculer 10` / `position 30` | Se déplacer dans le morceau (secondes) | | `audio source "Cible"` | Choisir le morceau : un sélecteur de fichier (MP3, WAV, OGG…), un composant contenant une URL / `data:` ou une URL | | `audio boucle oui` | Répéter le morceau | | `requete "https://…" "$reponse"` (`http`, `fetch`) | Requête HTTP GET (Internet, serveur avec CORS) ; la réponse est placée dans un composant ou une variable. Le script attend la réponse avant la commande suivante | | `extraire "$reponse" "chemin.json" "$cible"` (`json`) | Lire une valeur dans un JSON : `current.temperature_2m`, `results.0.name` (vide si absente) | | `associer "$code" "$cible" "0:Clair\|1,2:Nuageux\|51-57:Bruine\|*:Autre"` (`map`) | Traduire une valeur par table (valeurs, listes `1,2`, plages `51-57`, `*` = défaut) | Lecture de l'état audio : `{audio.temps}`, `{audio.duree}`, `{audio.progression}` (0–100), `{audio.etat}`, `{audio.volume}`, `{audio.titre}` — par exemple `set "barre" "{audio.progression}"` dans un bloc `toutes les 250 ms`. Dans une adresse web, `{ville:url}` insère la valeur d'un composant encodée (accents, espaces). Dans un champ de saisie, la touche Entrée peut déclencher `quand touche entree`. Variables : `$nom` est une mémoire temporaire partagée par tous les scripts. Dans les textes (`message`, `set`, `ajouter`, clés), `{composant}` ou `{$variable}` est remplacé par sa valeur. À droite d'un `si`, un composant ou une variable écrit sans guillemets est comparé comme du texte (`si "saisie" != $mdp alors …`). Position lisible dans les scripts : `"brique.x"`, `"brique.y"`, `"brique.largeur"`, `"brique.hauteur"` (ex. `si "brique.x" >= 700 alors message "Arrivée !"`). Le composant ne sort jamais de la page, et sa position d'origine est rétablie en quittant l'aperçu. Les opérateurs de `calculate` sont `+`, `-`, `*` et `/`. ## Exemple : calcul de ligne ```text quand clic calculate "Total de ligne" "Prix unitaire" * "Quantité" message "Total de ligne mis à jour" ``` ## Exemple : panneau d'aide ```text quand clic toggle "instructions" ``` ## Exemple : une touche de calculatrice ```text quand clic ajouter "panneau_expression" "7" evaluer "panneau_expression" "panneau_resultat" silencieux ``` Voir `examples/calculatrice-scientifique.berkios.json` : chaque touche contient son code. ## Limites Il n'existe pas ici de fonctions définies par l'utilisateur ni d'exécution JavaScript générale (les variables `$nom` et, depuis la v0.7.76, `repeter` et `sauf-si` existent). N'inventez pas de commandes : vérifiez la syntaxe prise en charge par le moteur. --- # Leçon 9 — Messages typés et fenêtres de dialogue (v0.7.116) Source : https://docs.berkios.online/studio/messages-et-dialogues/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) La commande `message` reste valable telle quelle : `message "Bonjour"` affiche un bandeau d'information. Depuis la v0.7.116, on peut préciser le **type** du message avec `message.type`, l'afficher dans une **fenêtre de dialogue (modal)** et **réagir à la réponse**. ```text quand clic message.modal "Bienvenue" ``` ## Les types | Commande | Alias | Affichage par défaut | Rôle | |---|---|---|---| | `message.info "texte"` | `information`, `infos` | bandeau | Information. | | `message.succes "texte"` | `succès`, `reussite`, `ok`, `success` | bandeau vert | Opération réussie. | | `message.avertir "texte"` | `avertissement`, `attention`, `alerte`, `warning` | bandeau orange | Avertissement. | | `message.erreur "texte"` | `echec`, `échec`, `error` | bandeau rouge | Erreur. | | `message.modal "texte"` | `modale`, `dialogue`, `dialog`, `fenetre` | **fenêtre** | Information dans une fenêtre. Le script attend sa fermeture. | | `message.confirmer "question"` | `confirmation`, `confirm`, `question` | **fenêtre** Oui / Non | Pose une question : `$reponse` vaut `oui` ou `non`. | | `message.demander "question"` | `saisir`, `saisie`, `ask`, `prompt` | **fenêtre** avec un champ | Demande un texte : `$reponse` reçoit la saisie (vide si annulé). | Un type inconnu est signalé à l'analyse : `Type de message inconnu « message.joyeux » (info, succes, avertir, erreur, modal, confirmer, demander).` ## Options (dans n'importe quel ordre, après le texte) | Option | Effet | |---|---| | `modal` (`dialogue`, `popup`) | Affiche le message dans une fenêtre, même pour `info`, `succes`, `avertir`, `erreur`. | | `bandeau` (`toast`, `notification`) | Force le bandeau (impossible pour `confirmer` et `demander`). | | `titre "Titre"` | Titre de la fenêtre (par défaut : Information, Succès, Avertissement, Erreur, Confirmation, Saisie). | | `bouton "Compris"` / `boutons "Oui" "Non"` | Libellés des boutons (un seul bouton pour un message simple). | | `danger` | Bouton principal rouge (suppression, action irréversible). | | `"$cible"` ou `dans "$cible"` | `confirmer` / `demander` : écrit aussi la réponse dans cette cible, en plus de `$reponse`. | | `alors commande …` | Commande exécutée si la réponse est **Oui** (ou la saisie validée) ; pour un message simple, après sa fermeture. | | `sinon commande …` | Commande exécutée si la réponse est **Non** (ou la saisie annulée). Seulement avec `confirmer` et `demander`. | Le texte accepte `{Composant}` et `{$variable}` comme `set` ou `message`. ## Conditions Deux façons de réagir à une réponse, au choix du plus lisible : ```text quand clic # 1. Branches alors / sinon sur la même ligne message.confirmer "Supprimer ce client ?" danger boutons "Supprimer" "Garder" alors effacer "Nom" sinon message.info "Annulé" # 2. La réponse est toujours dans $reponse : on peut tester avec « si » message.confirmer "Continuer ?" si "$reponse" = oui alors message.succes "C'est parti" ``` `oui` / `non` se comparent aussi avec `true` / `false` / `vrai` / `faux` : `si "$reponse" = true …` fonctionne. Un message peut aussi se trouver derrière un `si` : ```text quand clic si "Stock" < 5 alors message.avertir "Stock bas : {Stock}" modal titre "Magasin" ``` ## Forme avec parenthèses (facultative) `message.confirmer("Supprimer ?", "$ok")` équivaut à `message.confirmer "Supprimer ?" "$ok"`. ## Limites - Après `alors`, **une seule commande** ; une commande de contrôle (`si`, `sauf-si`, `repeter`) y est refusée. Pour enchaîner plusieurs actions, appelez une **fonction** (`alors effacer-nom`, voir la v0.7.115). - La commande après `alors` ne peut pas contenir elle-même `sinon`. - Dans l'application Flutter générée, les fenêtres s'ouvrent avec `showDialog` (Material) ; `message.modal` ouvert pendant `quand chargement` s'affiche au premier affichage de l'interface. Exemple complet : `examples/code-composants/14-messages-types.berkios.json`. ## Le même principe dans le langage `.bk` (v0.7.123) Dans un fichier `.bk`, l'action d'un bouton `afficher le message` accepte les mêmes types, la fenêtre modale et des lignes `oui :` / `non :` : ```text bouton supprimer "Supprimer" quand on clique : afficher le message confirmation "Supprimer ce client ?" titre "Suppression" boutons "Supprimer" "Garder" danger oui : afficher le message succès "Client supprimé" non : afficher le message "Suppression annulée" bouton bienvenue "Bienvenue" quand on clique : afficher le message modal "Bienvenue dans BERKIOS !" titre "Bienvenue" bouton demander "Mon nom" quand on clique : afficher le message saisie "Quel est votre nom ?" dans nom ``` | Élément | Français | English | Español | Kiswahili | |---|---|---|---|---| | Types | `information`, `succès`, `avertissement`, `erreur`, `confirmation`, `saisie` | `info`, `success`, `warning`, `error`, `confirmation`, `input` | `información`, `éxito`, `advertencia`, `error`, `confirmación`, `entrada` | `taarifa`, `mafanikio`, `onyo`, `hitilafu`, `uthibitisho`, `ingizo` | | Affichage | `modal`, `bandeau` | `modal`, `banner` | `modal`, `banner` | `dirisha`, `arifa` | | Options | `titre "…"`, `boutons "OK" "Non"`, `danger`, `dans composant` | `title`, `buttons`, `danger`, `into` | `título`, `botones`, `peligro`, `hacia` | `kichwa`, `vitufe`, `hatari`, `ndani ya` | | Réponses | `oui :` / `non :` | `yes :` / `no :` | `sí :` / `no :` | `ndiyo :` / `hapana :` | - `afficher le message "texte"` (sans type) reste un bandeau d'information. - `confirmation` et `saisie` s'ouvrent toujours dans une fenêtre ; `oui` / `non` n'existent que sous elles. Une saisie écrit son texte dans le composant indiqué après `dans`. - Une ligne `oui :` / `non :` contient une seule action (ouvrir, fermer, montrer, message simple…). Une nouvelle confirmation ou saisie y est refusée. - `berkios traduire` convertit ces lignes dans les quatre langues. Exemples : `compiler/examples/messages.fr.bk` et `messages.en.bk`. - Dans le projet produit, le bouton reçoit `buttonAction` avec `messageKind`, `messageDisplay`, `messageTitle`, `okLabel`, `cancelLabel`, `danger`, `responseTargetWidgetId`, `onYes`, `onNo`. --- # 10 — Fonctions, variables locales et code d'interface Source : https://docs.berkios.online/studio/fonctions-et-code-interface/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) ## 1. Une fonction, sans accolades ```text fonction ligne prix quantite calculer "$montant" "$prix" * "$quantite" renvoyer "{$montant}" quand clic $total = ligne "Prix unitaire" "Quantité" set "Total de ligne" "{$total}" ``` - `fonction nom paramètres`, puis les commandes en retrait. - On appelle la fonction par son nom (ou `appeler nom …`). - `renvoyer valeur` écrit dans `$resultat` et termine la fonction. - `$x = ligne 12 3` copie le résultat dans `$x`. ## 2. Variables locales Les paramètres sont locaux. `local nom [valeur]` en ajoute. À la fin de l'appel, l'appelant retrouve ses propres valeurs. ## 3. Code de l'interface Clic droit sur le fond de l'interface > **Écrire du code de l'interface…** ```text $taux = 16 $devise = "CDF" fonction ttc montant … ``` - Les variables sont initialisées à chaque affichage de l'interface. - Les fonctions sont utilisables dans tous les composants de l'interface. - Un composant peut redéfinir une fonction du même nom. ## 4. Exercice Ajoutez au code de l'interface une fonction `remise montant` qui retire 10 %, puis utilisez-la dans deux boutons. Exemple complet : `examples/code-composants/15-code-interface-variables-globales.berkios.json`. --- # Leçon 5 — Débogage et bonnes pratiques Source : https://docs.berkios.online/studio/debogage-et-bonnes-pratiques/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) ## Méthode de diagnostic 1. Vérifiez que le script commence par un en-tête reconnu, par exemple `quand clic`. 2. Vérifiez l'orthographe de la commande. 3. Vérifiez le nom ou l'identifiant du composant cible. 4. Pour `calculate`, confirmez que les deux entrées et le champ résultat existent. 5. Testez une commande à la fois, puis ajoutez les commandes progressivement. 6. Consultez le message d'erreur affiché par le Studio. ## Bonnes pratiques - Une commande par ligne. - Utilisez des guillemets autour des noms ou textes comportant des espaces. - Commencez les commentaires par `#` ou `//`. - Préférez plusieurs petits scripts lisibles à un script difficile à diagnostiquer. - Testez les valeurs vides, zéro et les valeurs inhabituelles. - Enregistrez avant de fermer le projet. ## Sécurité L'interpréteur de composants est limité à des commandes explicitement autorisées. N'y placez pas de secrets, de mots de passe ni de clés d'API. --- # Leçon 6 — Travaux pratiques Source : https://docs.berkios.online/studio/projets-pratiques/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) ## Niveau débutant 1. Ouvrez `01-bibliotheque-personnelle.berkios.json`. 2. Modifiez le message de confirmation. 3. Testez les commandes `set` et `show`. 4. Ajoutez un bouton qui masque la fiche. ## Niveau intermédiaire 1. Ouvrez `02-convertisseur-unites.berkios.json`. 2. Entrez deux nombres. 3. Lancez le calcul. 4. Testez une valeur nulle et une valeur décimale. 5. Notez les limites de format numérique de l'aperçu. ## Niveau intermédiaire+ 1. Ouvrez `10-calculateur-prix-taxe.berkios.json`. 2. Calculez d'abord la taxe, puis le prix TTC. 3. Expliquez pourquoi l'ordre des opérations compte. 4. Ajoutez un bouton de réinitialisation à l'aide de `set`. ## Projet libre Créez un outil de suivi d'équipement. Il doit inclure : - un champ de nom d'équipement ; - un panneau de consignes ; - un bouton pour afficher ou masquer ce panneau ; - un bouton qui affiche une confirmation par `message` ; - aucun comportement configuré dans le tableau `events`. ## Critères de validation - Le projet s'ouvre sans erreur. - Les noms ciblés correspondent aux composants. - Les boutons exécutent les scripts en aperçu. - Les événements JSON restent vides. - Le développeur documente ce qui fonctionne et ce qui reste à implémenter. --- # Leçon 7 — Aperçu Studio et runtime généré Source : https://docs.berkios.online/studio/limites-runtime/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) ## Distinction essentielle Le fonctionnement d'un script dans l'aperçu du Studio ne prouve pas que le même script est exécuté dans une application Flutter exportée. Depuis la v0.7.77, l'application Flutter générée embarque un interpréteur BERKIOS CODE (`lib/berkios_script.dart`, écrit en Dart) : les 130 commandes (30 historiques + 100 de la leçon 8), les événements `clic`, `changement`, `soumettre`, `chargement`, `focus`, `blur`, les touches (`quand touche espace`) et les minuteries (`toutes les 500 ms`) y fonctionnent comme dans l'aperçu du Studio. Différences connues dans l'application Flutter : - `audio …` et `imprimer` ne sont pas encore pris en charge (message d'erreur clair) ; - `telecharger` enregistre le fichier dans le dossier Téléchargements de l'utilisateur (ordinateur uniquement) ; - `bip` joue le son d'alerte du système (fréquence et durée ignorées) ; - `monnaie` connaît EUR, USD, GBP, JPY, CAD, CHF, CDF, XAF, XOF, MAD, CNY, INR (formats `fr` et `en`) ; - `couleur` accepte `#rgb`, `#rrggbb`, `#rrggbbaa` et une trentaine de noms de couleurs (français et anglais) ; - `stocker` / `lire` sont enregistrés dans un fichier JSON à côté de la base SQLite. La persistance des données et l'accès complet aux modèles restent gérés par les actions de données existantes. Cet interpréteur n'a pas pu être compilé dans l'environnement de développement de l'archive (pas de Flutter) : vérifiez le build avec `flutter analyze` avant de livrer. ## Avant de livrer une application - Tester le projet dans le Studio. - Générer l'application. - Vérifier séparément les actions dans l'application générée. - Ne pas annoncer une fonction comme disponible dans toutes les plateformes avant de l'avoir testée. - Documenter les différences de comportement observées. ## Architecture cible BERKIOS CODE fournit le code source du composant ; BERKIOS Core doit fournir une sémantique commune ; le Bridge doit transmettre ou compiler le code ; le runtime généré doit exécuter les mêmes opérations de façon contrôlée. Les quatre parties doivent être validées ensemble. --- # Modules d'application et CetteApplication Source : https://docs.berkios.online/studio/modules-application/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) Pour construire des applications robustes (client seul, serveur seul ou client-serveur offline-first), un projet peut contenir des **modules de code** et, au plus, un fichier **CetteApplication**. Les deux sont **optionnels**. > **Vocabulaire.** Une **interface** est un écran (avant v0.7.297 le dossier de projet l'appelait « module »). Un **module** est un fichier de code Core. Dans le compilateur, `modules[]` désignait déjà des fichiers Core : ils gagnent un cycle de vie, rien n'y est renommé. ## Dans le Studio - Panneau **MODULES** de la barre latérale (replié par défaut) : `+` crée un module (nom → identifiant `gestionnaire_chemins`, fichier `modules/.bk`, modèle de code valide), clic = éditeur de code, ⚙ = réglages (cible, dépendances, événements, tâches), ✎ renomme (l'identifiant reste), ✕ supprime (et retire le module des dépendances des autres). « Créer CetteApplication » ajoute le fichier unique `CetteApplication.bk`. - L'éditeur de code ouvre un module ou CetteApplication en mode Core ; **Vérifier** et la vérification en direct utilisent l'analyseur du compilateur (syntaxe, types, imports `importer "./autre.bk"`), sans Bridge. Une pastille ⚠ signale un fichier en erreur (code, dépendance inconnue, cycle, événement ou tâche sans fonction, cibles incompatibles). - Les modules sont enregistrés dans le projet (`appModules`, `application`) et suivent annuler / rétablir. ### Dossier de projet (format 2.1) ``` manifest.json { interfaces: [...], modules: [...], application: { entry } } interfaces/.interface.json + .bk (code BERKIOS CODE de l'interface) modules/.bk modules de code CetteApplication.bk code partagé (facultatif) ``` `manifest.modules` et `manifest.application` ont exactement la forme que lit `loadProjectModules` du compilateur. Le format 2.0 (`modules/*.module.json`) reste lisible. Anciens noms conservés comme alias dépréciés : `moduleGraph`, `ModuleContract`, `module-contracts.ts`. ## Module = un fichier de code (`.bk`) Déclaré dans `berkios.project.json` : ```json { "application": { "entry": "CetteApplication.bk" }, "modules": [ { "id": "connection_manager", "entry": "modules/connection_manager.bk", "dependencies": ["gestionnaire_chemins"], "target": "client", "events": { "reseau:change": "surChangementReseau" }, "tasks": [{ "function": "verifierReseau", "everyMs": 5000 }] } ] } ``` | Champ | Rôle | |---|---| | `id`, `entry` | identifiant et fichier Core (obligatoires) | | `dependencies` | modules à démarrer avant ; inconnu ou cycle = erreur au chargement | | `target` | `client`, `serveur` ou `les-deux` (défaut). L'hôte ignore les modules d'une autre cible | | `events` | événement → fonction du module appelée avec la charge utile | | `tasks` | fonctions rappelées périodiquement (≥ 100 ms), jamais en double, erreurs isolées | ### Cycle de vie (tout est facultatif) `initialiser()` → (abonnement aux événements) → `demarrer()` ; à l'arrêt `arreter()` dans l'ordre inverse des dépendances. Noms anglais acceptés : `initialize`, `start`, `stop`. Ces fonctions sont réservées à l'hôte : jamais importées ni appelables de l'extérieur. ### API publique Une fonction marquée `publique` est appelable par l'hôte (`host.call`) et par les imports. Si aucune n'est marquée, toutes le sont (compatibilité) ; `privée` exclut. L'hôte n'expose jamais les fonctions qu'un module a importées d'un autre. ``` publique fonction verifierReseau() -> Texte privée fonction aide() -> Entier ``` ### Parler aux autres : état partagé et événements Le Core n'a pas de variables globales. Les modules partagent : - `etat_notifier("cle", valeur)` / `etat_observer("cle")` → `{key, value, exists}` (pas de valeur nulle en Core : absent = `exists` faux, `value` = `""`) ; - `evenement_emettre("nom", {...})`, reçu par les modules qui déclarent l'événement dans `events`. Événements système : `reseau:change`, `session:connexion`, `app:erreur`, `app:demarree`. ## CetteApplication = code partagé par toutes les interfaces Fichier Core unique, optionnel. L'hôte appelle les procédures qui existent : | Procédure | Moment | |---|---| | `configurerTheme()` | tout début | | `auDemarrage()` | avant les modules | | `quandPret()` | après démarrage de tous les modules | | `surChangementReseau(info)` | événement `reseau:change` | | `apresConnexion(info)` | événement `session:connexion` | | `surErreur(erreur)` | toute erreur d'un module, d'une tâche ou d'un écouteur (`module`, `fonction`, `message`) | | `avantFermeture()` | début de l'arrêt | Noms anglais acceptés : `configureTheme`, `onStart`, `onReady`, `onNetworkChange`, `onLogin`, `onError`, `onClose`. ## Utiliser l'hôte ```js import { loadProjectModules, createApplicationHost } from './compiler/src/index.mjs'; const loaded = loadProjectModules(manifest, manifestFile, { interfaces: [] }); const host = createApplicationHost({ modules: loaded.coreModules, application: loaded.application, target: 'client', commands }); await host.start(); host.call('sync_manager', 'enregistrerEcriture', ['clients', 'upsert', { id: 1 }, 1]); await host.stop(); ``` `commands(commande, args, {moduleId})` fournit les commandes système (réseau, SQL, disque…) : le Bridge en production, une plateforme simulée dans l'exemple. L'hôte traite lui-même `evenement-emettre`, `etat-notifier` et `etat-observer`. ## Correctifs du langage Core livrés avec cette fonctionnalité - Une affectation à une variable déjà déclarée, faite dans un bloc `si` / `pour` / `essayer`, était **perdue** à la sortie du bloc. Elle est désormais conservée (un `soit` dans le bloc reste local). - `retourner` dans un `essayer` n'est plus pris pour une erreur. - Le mot `o` est un mot-clé (« ou » espagnol) : ne pas l'utiliser comme nom de variable. ## Limites connues - Le Core est synchrone. Les commandes du Bridge sont asynchrones (HTTP) : l'hôte actuel les consomme via un adaptateur **synchrone** (`commands`). Brancher le vrai Bridge demande un exécuteur Core asynchrone, qui n'existe pas encore. - Pas de valeur nulle ni de variables globales en Core ; les helpers privés de deux modules importés ensemble partagent un espace de noms plat (préfixer les noms). - Le Studio édite et vérifie les modules mais ne les **exécute pas** dans l'Aperçu, et les actions des interfaces ne les appellent pas encore : l'API est `host.call(...)`. - Le dossier de projet (format 2.1) n'est pas encore branché sur « Enregistrer / Ouvrir » du Studio (fonctions `splitProject` / `assembleProject`). ## Exemple complet `examples/application/offline-first` : client offline-first avec les modules `gestionnaire_chemins`, `connection_manager`, `abonnement_manager`, `sync_manager`, `rapports` et un `CetteApplication.bk`. `node examples/application/offline-first/demo.mjs` déroule un scénario hors ligne → en ligne. --- > Vocabulaire (v0.7.297) : dans le Studio, un écran s'appelle **interface** ; **module** désigne un fichier de code. Voir `modules-application.md`. Source : https://docs.berkios.online/studio/ecrans-modulaires/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) # Écrans modulaires BERKIOS Les projets peuvent séparer leurs écrans graphiques en fichiers `.bk` dédiés. Le manifeste `berkios.project.json` relie chaque écran à son fichier avec la propriété `file`. ```json { "entry": "main.bk", "initialScreen": "accueil", "modules": [{ "id": "navigation", "entry": "src/screens/navigation.bk", "screens": [ { "name": "accueil", "file": "src/screens/accueil-ui.bk" } ] }] } ``` Un fichier `accueil-ui.bk` contient une application de type interface et une déclaration d'interface : ```berkios langue français application "Écran d'accueil" type interface interface Accueil titre "Bienvenue" étiquette message "Mon écran est indépendant." ``` `interfaceId` est facultatif si le fichier ne contient qu'une interface. Le compilateur déduit alors son identifiant. S'il y a plusieurs interfaces dans le même fichier, il faut préciser `interfaceId` pour chaque écran. Les chemins sont relatifs à la racine du projet. Les chemins inexistants, les liens sortant du dossier projet, les interfaces en double et les fichiers qui ne compilent pas sont refusés. Les fichiers sont suivis par le rechargement à chaud de l'aperçu. Les modules Core sont indépendants : ils restent déclarés avec `modules[].entry` et peuvent importer des services `.bk` avec la syntaxe Core existante. ## Lancer l'exemple Depuis le dossier `compiler` : ```bash node bin/berkios.mjs apercu ../examples/application-modulaire/main.bk ``` Le manifeste `berkios.project.json` doit se trouver à côté de `main.bk`. --- # Code d'interface BERKIOS — contrat et exemple de navigation Source : https://docs.berkios.online/studio/code-interface-et-navigation/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) Ce document définit le comportement attendu du code d'interface. Dans la v0.7.96, les commandes BERKIOS existantes peuvent déjà être placées dans les scripts des composants et les commandes `aller`/`goto` permettent de naviguer entre les interfaces. L'éditeur dédié au code global d'interface et son exécution automatique restent une étape ultérieure. ## Portées et héritage proposés | Portée | Durée | Exemple | Héritage | |---|---|---|---| | Globale du projet | Durée de vie de l'application | `$utilisateur`, `$langue`, `$droits` | Partagée par toutes les interfaces du même projet | | Locale à une interface | Tant que l'interface existe dans la session | `$rechercheClients`, `$pageCourante` | Non partagée, sauf déclaration explicite | | Locale à un événement/composant | Une exécution d'événement | variables temporaires de calcul | Non héritée | Les variables de script temporaires `$nom` du Studio sont désormais isolées par projet pour que l'aperçu d'un projet ne contamine pas celui d'un autre. Cela ne les rend pas encore persistantes après fermeture de l'application. Pour conserver une valeur, utiliser les commandes `stocker` et `lire`. ## Propriétés d'interface à hériter - Thème et famille de polices : hériter du projet si l'interface ne définit pas de valeur. - Disposition : hériter du projet si `layout` est absent ; sinon l'interface peut la remplacer. - Paramètres de fenêtre : hériter des valeurs du projet/du conteneur de bureau lorsqu'une propriété est absente. - Variables globales : partagées par toutes les interfaces du même projet. - Composants et variables locales : ne sont pas hérités automatiquement d'une interface sœur. - Le code global s'exécute une fois au démarrage ; le code d'interface s'exécute à l'ouverture de cette interface ; le code de composant s'exécute à son événement. Cette séparation est le contrat recommandé, pas encore une fonctionnalité complète de l'éditeur dans cette version. ## Exemple : barre latérale qui change le contenu à droite Créer les interfaces `Accueil`, `Clients`, `Stock` et `Ventes`. Conserver la barre latérale sur la page principale ou la dupliquer dans les pages, puis configurer chaque bouton de menu avec son script : ```text quand clic aller "Accueil" ``` ```text quand clic aller "Clients" ``` ```text quand clic aller "Stock" ``` ```text quand clic aller "Ventes" ``` Le contenu affiché à droite est l'interface cible. Pour afficher le nom de l'utilisateur courant sur chaque page, stocker sa valeur dans une variable globale au niveau applicatif et la recopier dans le libellé local lors de l'événement `chargement` de chaque interface. La prise en charge native d'un conteneur permanent (barre latérale fixe + panneau droit remplaçable) sera ajoutée séparément : la navigation entre pages existe déjà, mais ne doit pas être confondue avec un conteneur de navigation imbriqué. ## Fichiers La bibliothèque `libraries-repo/libraries/fichiers.bkl` fournit un espace virtuel persistant par application, utilisable en Web et sur les plateformes qui ne disposent pas d'un accès système autorisé. L'application de bureau pourra utiliser un adaptateur natif séparé avec un dossier de travail imposé ; il ne faut jamais transformer les chemins fournis par le code utilisateur en accès arbitraire à l'ensemble du disque. --- # Actions de données SQLite — schéma 1.3 Source : https://docs.berkios.online/studio/sqlite-actions/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) Le runtime Flutter générique implémente quatre types d'action, dans `buttonAction` ou dans `events[].actions` : | Type | Champs | Effet | |---|---|---| | `data-create` | `modelId`, `values` | Crée un enregistrement et génère un identifiant local. | | `data-read` | `modelId`, `targetWidgetId` facultatif | Lit les enregistrements du modèle ; si la cible est indiquée, affiche le résultat JSON dans ce composant. | | `data-update` | `modelId`, `recordId`, `values` | Fusionne les champs fournis avec l'enregistrement existant. | | `data-delete` | `modelId`, `recordId` | Supprime l'enregistrement ciblé. | `values` est un objet JSON clé/valeur. Les valeurs textuelles peuvent contenir `{{nomDuComposant}}` ; le runtime remplace ce marqueur par la valeur du contrôle dont le champ `name` correspond. Les actions signalent les erreurs de stockage ou les identifiants obligatoires manquants via un message dans l'interface. Dans le **Studio desktop Electron** (depuis la v0.7.140), chaque projet a sa propre base SQLite et chaque modèle une **table typée** (voir `data-core/README.md`). La table générique `berkios_records` (`model_id`, `record_id`, `payload` JSON, `updated_at`) reste utilisée par le runtime Flutter généré et par la coque Tauri ; elle est reprise automatiquement par le Studio Electron à la première synchronisation. Sur Windows, macOS et Linux, elle utilise SQLite FFI ; sur Android et iOS, elle utilise SQLite natif via `sqflite`. ## Limites actuelles - Tables typées générées à partir de `dataModels[].fields` : **Studio desktop Electron uniquement**. Le runtime Flutter généré et la coque Tauri utilisent encore la table générique JSON. - Les valeurs de `recordId` doivent être disponibles explicitement pour les actions de mise à jour et suppression ; la sélection visuelle d'un enregistrement n'est pas encore fournie automatiquement. - La liaison bidirectionnelle automatique entre modèles et contrôles n'est pas encore implémentée. - Le générateur spécialisé de gestion de stock garde son état en mémoire. - Les builds Flutter natifs doivent être exécutés sur une machine avec le SDK Flutter et les outils de compilation correspondants. --- # Commandes BERKIOS — tableaux, médias, SQL et stockage (v0.7.176) Source : https://docs.berkios.online/studio/tableaux-medias-sql/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) Les commandes sont enregistrées dans `bridge/system-command-registry.mjs` et exécutées par `bridge/system-commands.mjs`. ## Tableaux structurés - `tableau-creer(rows)` : clone une liste de lignes objet. - `tableau-ligne(rows, row)` : retourne le tableau avec une ligne ajoutée. - `tableau-colonne(rows, column, values?)` : ajoute une colonne ; `values` doit avoir le même nombre d'éléments que `rows`. - `tableau-trier-par-colonne(rows, column, direction?)` : `asc` par défaut, ou `desc`. - `tableau-filtrer(rows, column, operator, value)` : opérateurs `egal`, `different`, `contient`, `superieur`, `inferieur`, `superieur_ou_egal`, `inferieur_ou_egal`. - `tableau-agreger(rows, groupBy, aggregates?)` : agrégations `count`, `sum`, `avg`, `min`, `max`. - `tableau-pivoter(rows, {index, column, value, operation?})` : `sum`, `avg`, `count`. Les tableaux sont des listes d'objets, pas des chaînes séparées par virgules : les types, nombres, booléens et valeurs nulles sont préservés. ## SQL - `sql-lire(table, filters?)`, `sql-inserer(table, data)`, `sql-mettre-a-jour(table, data, where)`, `sql-supprimer(table, where)`. - `sql-executer(sql, params?)` exécute une instruction avec paramètres séparés. - `sql-requete-parametree(sql, params?)` lit une requête paramétrée. - `sql-transaction(actions)` exécute les actions atomiquement et tente un rollback en cas d'échec. Les noms de tables/colonnes sont validés comme identifiants SQL simples. Les valeurs sont toujours transmises avec des placeholders. `sql-supprimer` exige au moins une condition pour éviter un effacement accidentel de table. L'hôte doit vérifier les permissions SQL avant d'appeler le moteur. L'adaptateur DB doit exposer `prepare(sql)` avec `run/all`, et `exec(sql)` ou `transaction(fn)` pour les transactions. ## Stockage - `stocker(key, value)`, `charger(key)`, `oublier(key)` utilisent `options.storage` fourni par l'hôte (`get`, `set`, `delete`). Un `Map` fonctionne pour les tests et le stockage temporaire, mais n'est pas persistant au redémarrage. Pour la persistance réelle, l'hôte doit fournir un adaptateur durable (par exemple SQLite ou stockage local). ## Médias - `image-charger`, `image-redimensionner`, `image-compresser`, `photo-prendre`, `fichier-choisir`, `audio-jouer`, `audio-enregistrer` délèguent aux fonctions de `options.media`. Ces opérations nécessitent une implémentation native/web et les permissions correspondantes. Si l'adaptateur n'est pas présent, le moteur renvoie `media_unavailable` au lieu de simuler une réussite. ## Intégration et tests L'API exécutable se trouve dans `bridge/data-media-sql-commands.mjs`; le dispatcher du Bridge est `executeSystemCommand` dans `bridge/system-commands.mjs`. Voir `bridge/tests/data-media-sql-commands.test.mjs`. --- # Accès aux fichiers externes dans BERKIOS CODE Source : https://docs.berkios.online/studio/acces-fichiers-externes/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) ## Autoriser un dossier ```text quand clic autoriser-dossier-externe "$dossier" fichier-lire-disque "$dossier/clients.csv" "$contenu" ``` La commande ouvre un sélecteur de dossier système. La variable `$dossier` reçoit le chemin absolu choisi. L'autorisation reste active seulement pendant la session de l'application. L'utilisateur peut choisir Téléchargements, Documents, un disque externe ou un dossier réseau monté par son système. Les commandes `fichier-lire-disque`, `fichier-ecrire-disque`, `dossier-lister-disque`, `dossier-creer-disque` et `dossier-supprimer-disque` acceptent soit les chemins relatifs au workspace, soit les chemins absolus dans une racine autorisée. Les commandes de suppression refusent la racine autorisée elle-même. ## Lire un lien ```text quand clic fichier-lire-lien "https://example.org/public/rapport.txt" "$contenu" ``` La cible doit servir du texte, être accessible sans identifiants intégrés à l'URL et répondre dans les 15 secondes. La limite de réponse est 10 Mio. En Web, le serveur doit autoriser l'origine BERKIOS via CORS. Pour une API privée, utiliser une action API dédiée avec authentification explicite; ne jamais mettre un secret dans l'URL. ## Différences de plateformes - **Desktop Tauri** : accès natif après sélection explicite d'un dossier; les autorisations sont temporaires à la session. - **Web** : aucun chemin arbitraire n'est accessible. Utiliser un sélecteur de fichiers/dossiers compatible navigateur, ou un lien HTTP/HTTPS qui autorise CORS. - **Applications Flutter générées** : cette version n'ajoute pas encore un sélecteur de dossier natif au runtime Flutter. Les opérations restent limitées au workspace jusqu'à l'intégration d'un plugin de sélection/permissions propre à chaque plateforme. --- # Sécurité applicative avancée (Bridge, v0.7.192) Source : https://docs.berkios.online/studio/securite-avancee/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) 21 commandes système implémentées dans `bridge/security-advanced.mjs` (Node.js natif : `node:crypto`, `node:tls`), enregistrées dans le registre du Bridge et dans `compiler/src/system-command-registry.json`. Comme toutes les commandes système, elles sont **exécutées par le Bridge** (desktop/serveur), avec la permission indiquée accordée explicitement par l'hôte. `permission-verifier` existait déjà. | Commande | Arguments | Résultat | Permission | |---|---|---|---| | `chiffrer-symetrique` | texte, clé (≥ 16 o), contexte? | `bkx1.…` (AES-256-GCM, clé dérivée par scrypt, sel et IV aléatoires) | `security.crypto` | | `dechiffrer-symetrique` | texte chiffré, clé, contexte? | texte clair ; erreur `decryption_failed` si clé/contexte faux ou données altérées | `security.crypto` | | `signer-donnee` | texte, clé, algorithme? | signature base64url. Algorithmes : `hmac-sha256` (défaut), `hmac-sha512`, `rsa-pss-sha256`, `rsa-sha256`, `ecdsa-p256` (IEEE P1363) | `security.crypto` | | `verifier-signature` | texte, signature, clé, algorithme? | booléen (comparaison en temps constant pour HMAC ; clé publique ou privée PEM pour RSA/ECDSA) | `security.crypto` | | `cle-signature-generer` | `ecdsa` (défaut) ou `rsa` | `{ publique, privee }` PEM (EC P-256, RSA 3072) — ajoutée pour rendre RSA/ECDSA utilisables | `security.generate` | | `certificat-verifier` | url, empreinte SHA-256?, port?, exiger-chaine? (`non`) | `{ value, chaineValide, empreinteCorrespond, empreinte, sujet, emetteur, valideJusqu… }` | `network.read` | | `secret-lire` / `secret-ecrire` | nom [, valeur] | valeur / `{ value, remplace }` | `security.vault` | | `jeton-generer` | charge JSON, secret (≥ 32 o), durée? (s, défaut 3600, max 30 j) | JWT HS256 avec `iat`, `exp`, `jti` | `security.crypto` | | `jeton-verifier` | jeton, secret | `{ value, charge }` ou `{ value:false, raison }` (`format`, `algorithme`, `signature`, `expire`, `pas_encore_valide`) | `security.crypto` | | `jeton-renouveler` | jeton valide, secret, durée? | nouveau JWT (même charge, nouveau `jti`) ; refus si expiré ou invalide | `security.crypto` | | `session-creer` | utilisateur, rôles? (`a,b` ou JSON), durée? (s, max 24 h) | `{ value: jeton opaque, expiresAt }` | `security.session` | | `session-verifier` / `session-detruire` | jeton | `{ value, utilisateur, roles }` / booléen | `security.session` | | `csrf-generer` | contexte | jeton lié au contexte (HMAC, horodaté) | `security.crypto` | | `csrf-verifier` | jeton, contexte, âge max? (s, défaut 7200) | booléen | `security.crypto` | | `limiter-tentatives` | clé, maximum, fenêtre (s) | `{ value: autorisé, restant, reinitialiseDansSecondes }` — fenêtre glissante, les refus ne prolongent pas le blocage | `security.session` | | `verrouiller-compte` | identifiant, mode? (`verrouiller` défaut, `deverrouiller`, `statut`), durée? (s, défaut 900), raison? | `{ value: verrouillé, jusqua, raison }` | `security.session` | | `role-verifier` | session ou liste de rôles, rôle, hiérarchie JSON? | booléen + rôles effectifs (héritage `{"admin":["editeur"]}`, cycles tolérés) | `security.session` | | `audit-securite` | mode? (`ecrire` défaut, `lire`, `verifier`), événement, détails?, niveau? (`info`, `warn`, `alert`, `critical`) | écriture : `{ numero, empreinte }` ; lecture : N dernières entrées ; vérification : `{ value, entrees, premiereErreur }` | `security.audit` | | `masquer-donnee` | texte, types? (liste) | `{ value, masques, total }` — types : `jeton, secret, email, iban, nir, carte, ip, telephone` | `security.crypto` | ## Comportements à connaître - **Verrouillage ↔ sessions ↔ Passo** : un compte verrouillé voit ses sessions applicatives détruites, ne peut plus en créer, échoue à `role-verifier`, et `passo-authentifier` / `passo-mot-de-passe-changer` répondent par l'échec générique. - **Coffre** : fichier `/.berkios/vault.json` entièrement chiffré (AES-256-GCM). La clé maîtresse (≥ 20 caractères) vient de la variable d'environnement `BERKIOS_VAULT_KEY` du Bridge ; elle n'est jamais passée en argument de commande. Sans elle : `vault_locked`. Perdre la clé = perdre les secrets. 500 secrets et 8 Kio par secret au maximum. - **Audit** : `/.berkios/audit-securite.jsonl`, chaque entrée contient l'empreinte de la précédente ; `verifier` détecte toute modification ou suppression d'une entrée intermédiaire. Elle ne détecte pas la suppression des *dernières* entrées ni une réécriture complète de la chaîne par quelqu'un qui contrôle le fichier : pour cela, conserver l'empreinte de la dernière entrée ailleurs. Les détails sont masqués avant écriture (clés sensibles, e-mails, IBAN…). Plafond : 5 Mio. - **État en mémoire** : sessions, verrous, compteurs de limitation et secret CSRF sont propres au dossier de travail et **perdus au redémarrage du Bridge** (les jetons CSRF émis deviennent invalides). Le coffre et l'audit sont persistants. - **Épinglage TLS** : par défaut la chaîne doit être approuvée **et** l'empreinte correspondre. Avec `exiger-chaine = non`, seule l'empreinte compte (utile pour un certificat auto-signé épinglé). Sans empreinte, la commande valide seulement la chaîne et renvoie l'empreinte à épingler. Adresses privées refusées sauf `BERKIOS_SYSTEM_ALLOW_PRIVATE_NETWORK=1` ; la résolution DNS est contrôlée à la connexion. - **JWT** : HS256 uniquement ; `alg: none` et toute autre valeur sont refusés. Pas de liste de révocation : pour invalider un jeton avant son expiration, changer le secret ou utiliser des sessions. - Ne jamais journaliser clés, secrets, jetons ni sorties de `cle-signature-generer`. --- # BERKIOS Excel Engine (prototype initial) Source : https://docs.berkios.online/studio/excel-moteur/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online) Objectif : importer un classeur Excel existant et créer un fichier `.berkios.json` contenant les feuilles, cellules, formules traduites et diagnostics. ## Prérequis - Node.js >= 22.18 - Installer les dépendances : `npm install` dans ce dossier. ## Conversion ```bash node src/cli.mjs "C:/chemin/classeur.xlsx" node src/cli.mjs "C:/chemin/classeur.xlsm" "sortie.berkios.json" ``` Formats ciblés : `.xlsx`, `.xlsm`, `.xls`. Le format de fichier est accepté indépendamment de la version d'Excel ayant créé le classeur (Excel 2013 et versions ultérieures). Les fonctions récentes propres à Microsoft 365 peuvent toutefois nécessiter une implémentation dédiée. ## Contenu et limites actuelles - Importe les noms des feuilles, plages utilisées, cellules, valeurs, formules, formats numériques, cellules fusionnées et noms définis. - Traduit un premier ensemble de fonctions Excel (SUM, AVERAGE, IF, AND, ROUND, VLOOKUP, XLOOKUP, etc.) vers des noms d'expressions BERKIOS provisoires. - Ajoute des diagnostics lorsque les fonctions/références ne sont pas reconnues. - Détecte la présence d'un projet VBA binaire, mais **ne prétend pas encore décompiler/traduire automatiquement les modules VBA**. Le code VBA n'est jamais exécuté pendant l'import. - Les feuilles sont conservées comme données structurées (`excelWorkbook`) **et** converties en interfaces (voir « Génération des interfaces » ci-dessous). - Un import n'est pas une garantie de compatibilité parfaite. Toujours examiner `excelTranslation.diagnostics` et tester le résultat avant usage en production. ## Sécurité Les macros, liens externes et formules doivent être traités comme du contenu non fiable. Aucun code VBA n'est exécuté par le convertisseur. Toute future exécution de macros traduites devra passer par les permissions et capacités du moteur BERKIOS, avec confirmation pour les accès fichiers, réseau et système. ## Exécution autonome après conversion Une fois le fichier `.berkios.json` créé, l'application convertie ne nécessite pas Microsoft Excel ni l'installation d'Excel sur la machine cible. Le classeur est stocké comme données structurées dans le JSON; le runtime BERKIOS relit ces données et recalcule le sous-ensemble de formules pris en charge. La dépendance `xlsx` sert uniquement à importer le fichier source `.xlsx/.xlsm/.xls` et n'est pas utilisée par le runtime après conversion. API runtime (Node.js) : ```js import { loadBerkiosProject, readCell, writeCell, saveBerkiosProject } from './src/standalone-runtime.mjs'; const app = loadBerkiosProject('./gestion_stock.berkios.json'); console.log(readCell(app, 'Stock', 'B2')); writeCell(app, 'Stock', 'A2', 42); // recalcule les formules prises en charge saveBerkiosProject(app); // persiste les données dans le projet BERKIOS ``` Limites importantes : le runtime autonome est une première couche technique, pas encore une intégration complète à tous les contrôles visuels et événements du Studio. Les fonctions/formules non prises en charge sont diagnostiquées et ne doivent pas être considérées comme fidèlement exécutées. Les macros VBA ne sont pas exécutées automatiquement. Les formules nécessitant des services Excel, des compléments, des connexions externes ou des fonctionnalités propriétaires nécessitent une réimplémentation BERKIOS explicite. ## Traduction statique de modules VBA exportés (v0.7.147) Le traducteur reconnaît maintenant un sous-ensemble supplémentaire : procédures `Sub`/`Function`, événements courants (`Workbook_Open`, `Worksheet_Change`, `Worksheet_SelectionChange`, `*_Click`, `*_Change`), affectations `Range(...).Value`, `Cells(ligne,colonne).Value`, `MsgBox`, `Debug.Print`, conditions `If/ElseIf/Else` et boucles simples `For...To...Next`. Les boucles et les événements restent marqués pour revue, car une syntaxe traduite ne garantit pas une équivalence de comportement. Pour convertir les macros, exportez d'abord les modules VBA depuis l'éditeur VBA d'Excel vers des fichiers `.bas` ou `.cls`, puis fournissez-les à la commande d'import : ```bash node src/cli.mjs "C:/fichiers/gestion.xlsm" "gestion.berkios.json" --vba "C:/fichiers/Module1.bas" --vba "C:/fichiers/Feuil1.cls" ``` Les procédures et événements détectés sont enregistrés dans `excelTranslation.macros` et `events`; les appels inconnus et instructions sensibles produisent des diagnostics. Le moteur n'extrait pas automatiquement le code source depuis le projet VBA binaire et n'exécute jamais le VBA original. La traduction obtenue est une base à vérifier et non une garantie de conversion complète. ### Événements Excel ↔ composants BERKIOS (v0.7.171) `src/component-event-bridge.mjs` relie les événements importés (qui désignent un contrôle par son **nom** : `btnEnregistrer_Click`) aux composants générés (qui ont un **identifiant** : `if_frmclient__btn_enregistrer`). - `linkExcelEventsToComponents(project, interfaces)` : à l'import, chaque événement `ui.click` / `ui.change` reçoit `componentId` et `componentBinding` (`resolved`, `unresolved` ou `ambiguous`). Le nom de contrôle est déduit de `Bouton_Click` pour les modules VBA comme pour les UserForms ; `formName` restreint la recherche à l'interface du formulaire (`interface.sourceForm`). Rien n'est deviné : introuvable ou ambigu → diagnostic `EXCEL_EVENT_COMPONENT_*` et `requiresReview`. - `bindExcelEventToComponent(project, eventId, componentId, interfaces)` : association manuelle d'un cas non résolu. - `handleComponentEvent(project, interfaces, { componentId, event: 'click'|'change'|'input', value? }, options)` : point d'entrée pour une interaction sur un composant. `change` écrit la cellule liée (validation incluse), recalcule, puis déclenche `sheet.change` et `ui.change`. Retourne `changes` (propriétés de composants modifiées), `messages` (`ui-message`) et `pending` (événements non activés, non exécutés). - `describeExcelEventLinks(project)` : tableau de revue (cible résolue, actions valides, activable ou non). - Les liaisons cellule sont lues sous leurs deux formes : moteur `{sheet, cell}` ou Studio `{worksheet, address}` (feuille absente = feuille active ; plage `A1:B3` refusée). La forme Studio n'est jamais réécrite. Résoudre un événement **ne l'active pas** : il reste `needs_review` jusqu'à `enableExcelEvent`. ### Runtime des événements (v0.7.148) `src/event-runtime.mjs` route les événements vers une liste blanche d’actions Excel BERKIOS (`excel-read`, `excel-write`, `excel-recalculate`, `excel-save`). Les événements VBA restent à valider; aucun code VBA ou JavaScript n’est exécuté. Voir `tests/event-runtime.test.mjs`. ## Génération des interfaces (v0.7.150) Chaque feuille devient une **interface** du projet ; chaque UserForm exporté (`.frm`) devient une **interface modale**. Le rôle d'une feuille est déduit de sa structure (aucune macro n'est exécutée) : | Structure détectée | Rôle | Interface générée | |---|---|---| | Ligne d'en-têtes + lignes de données | `table` | Modèle de données **SQLite** (types déduits des noms/valeurs, clé primaire, `seed` des lignes existantes) + tableau lié (recherche, tri, édition) + formulaire de saisie (`data-create`) | | En-têtes dont ≥ 2 « Total… », ou nom `Rapport`/`Bilan`/`Synthèse`… | `report` | Critères de filtre, cartes KPI, tableau de détail rattaché au modèle le plus proche | | Paires libellé / formule | `dashboard` | Cartes KPI liées au modèle quand le calcul est exact (`COUNTA`, `SUM`, `AVERAGE`, `MIN`, `MAX` sur une colonne) | | Texte seul | `text` | Étiquettes (titre, sous-titres, paragraphes) | | En-têtes + cellules calculées | `grid` | Tableau en lecture seule | Autres déductions : valeurs de listes de choix lues dans les critères de `SUMIF`/`COUNTIF` (ex. `"DEPOT"`, `"RETRAIT"`), relations entre modèles (colonne `ID_Client` ↔ clé `ID_Client`), barre de navigation `open-interface` sur chaque page. ### UserForms ```bash node src/cli.mjs "gestion.xlsm" "gestion.berkios.json" --frm "frmMenu.frm" --frm "frmClient.frm" ``` Exporter chaque UserForm depuis l'éditeur VBA (clic droit → *Exporter un fichier…*). Contrôles convertis : Label, TextBox, ComboBox, ListBox, CheckBox, OptionButton, CommandButton, Frame (positions des contrôles imbriqués cumulées). Gestionnaires `xxx_Click` reconnus : `Unload Me`/`Me.Hide` → `close-interface`, `frmX.Show` → `open-interface`, écriture dans `Sheets("X")` d'une feuille convertie en modèle → `data-create` (champs appariés par nom de contrôle : `txtNom` → `nom`). Le reste est signalé dans `excelTranslation.diagnostics`. Les ressources `.frx` ne sont pas lues. ### Ce qui reste à vérifier après l'import - `excelTranslation.kpiMappings` : un KPI `needs_review` est affiché avec `⚠ à vérifier`. Les sommes **conditionnelles** (`SUMIF`) ne sont pas calculables par un KPI (pas de filtre) ; le filtre détecté est conservé dans le mapping. - `excelTranslation.assumptions` : choix proposés par défaut (ex. Sexe : M/F) absents du classeur. - Les règles métier écrites en VBA (numérotation, calcul de solde, contrôles) ne sont **pas** reprises. ## Formules recalculées par le runtime (v0.7.168) Le runtime autonome exécute localement, sans Excel, **98 fonctions** (priorités 1 et 2 : `SUMIF(S)`, `COUNTIF(S)`, `VLOOKUP`, `XLOOKUP`, `INDEX`, `MATCH`, `CONCATENATE`, `LEFT`/`RIGHT`/`MID`/`LEN`, `MOD`, `INT`, `SUBTOTAL`, `TODAY`, `NOW`, `DATE`, `YEAR`/`MONTH`/`DAY`, `TRIM`, `UPPER`, `LOWER`, `IFNA`, `IFERROR`… et bien d'autres). La liste complète, générée depuis le code, est dans `FONCTIONS_EXCEL.md`. **Source unique** : `src/function-registry.mjs` porte, pour chaque fonction, son nom Excel, son nom BERKIOS et son implémentation. Le traducteur (`translateFormula`), le moteur (`recalculateWorkbook`, `supportedRuntimeFunctions`) et le Studio la lisent : une fonction ne peut pas être « reconnue » sans être exécutable. `translateFormula(...).executable` indique si une formule entière est recalculable ; les fonctions Excel connues mais non exécutables (`FILTER`, `OFFSET`, `INDIRECT`, `LET`…) sont signalées par `FORMULA_FUNCTION_UNSUPPORTED` (`reason: known-not-executable`). Le moteur gère les références inter-feuilles (`Feuille!A1`, `'Nom feuille'!A1:B2`), les colonnes/lignes entières (`A:A`, `1:1`), les noms définis, les constantes matricielles, les opérations matricielles dans `SUMPRODUCT`, les valeurs d'erreur Excel et la détection des références circulaires (`FORMULA_CIRCULAR_REFERENCE`). Limites connues : - Pas de déversement matriciel : un résultat de plusieurs cellules n'est pas écrit dans la feuille (diagnostic `FORMULA_RUNTIME_UNSUPPORTED`, `reason: array-result`) ; il reste utilisable comme argument. - Classeurs liés : valeurs en lecture seule, sans noms définis externes ni références 3D externes (voir « Classeurs liés » ci-dessous) ; système de dates 1900 uniquement ; noms de mois et de jours de `TEXT` non pris en charge. - Les cellules en erreur sont stockées en texte (`calculatedValue: "#N/A"`) avec `calculationError`. - Une cellule non calculable garde sa valeur Excel importée et le statut `needs_review` ; `calculationDiagnostic` en donne la cause. ## Actions métier du runtime (v0.7.168) Le code VBA importé n'est **jamais exécuté**. Un bouton, un formulaire ou un événement n'a d'effet que par des actions déclaratives BERKIOS : `excel-read`, `excel-write`, `excel-recalculate`, `excel-save`, `ui-set-property`, `ui-message` et `run-procedure` (procédure du même module). Chaque action est validée avant exécution (`validateAction` : adresse de cellule valide, valeurs littérales uniquement), reste en `needs_review` jusqu'à `enableExcelEvent` / `enableExcelProcedure`, et une erreur sur une action n'interrompt pas les suivantes. Les appels de procédures sont bornés (profondeur 8, 1000 actions par déclenchement). `excelTranslation`/`project.procedures` listent les procédures non-événement extraites du VBA. ### Import complet d'un classeur : feuille de route et couverture (v0.7.198+) SheetJS ne lit ni les macros, ni les graphiques, ni les dessins, ni les contrôles ActiveX, ni les zones d'impression. L'import lit donc **directement le package OOXML** (`src/ooxml-reader.mjs`, sans dépendance) et suit une matrice de couverture à trois statuts : | Statut | Signification | |---|---| | `inventoried` | Détecté et décrit dans `project.excelPackage.inventory` ; **conservé intact** dans l'archive d'origine, pas encore reproduit. Un diagnostic `OOXML__NOT_REPRODUCED` le signale. | | `imported` | Converti en modèle BERKIOS (données exploitables par le Studio). | | `rendered` | Reproduit à l'écran / à l'impression. | `project.excelPackage.coverage` liste uniquement les familles présentes dans le classeur : `vba`, `charts`, `shapes`, `pictures`, `smartArt`, `activeX`, `formControls`, `printAreas`, `pageSetup`, `conditionalFormatting`, `dataValidations`, `sparklines`, `pivotTables`, `oleObjects`, `freezePanes`. **Archive d'origine.** Tant qu'une famille est `inventoried`, le convertisseur conserve le classeur source (`project.excelImport.original` : nom, taille, SHA-256, stockage). Option `preserveOriginal` : `auto` (défaut : copie « `.source.xlsm` » à côté du projet si des éléments ne sont pas reproduits), `sidecar`, `embed` (base64 dans le projet, 64 Mio max) ou `none`. En CLI : `--keep-original[=auto|sidecar|embed|none]`. **État actuel (étape 1/10) :** inventaire complet (VBA binaire repéré avec empreinte, graphiques avec séries, dessins avec ancrages, groupes imbriqués, images liées à leurs médias, ActiveX identifiés par classe, contrôles de formulaire avec cellule liée, zones/titres d'impression, mise en page, volets figés, formats conditionnels, validations, tableaux). Aucune famille n'est encore reproduite ; les `.xls` binaires ne sont pas inventoriés. ZIP64 refusé explicitement. ### Limite sur la fidélité visuelle des classeurs L'import conserve les données et plusieurs métadonnées Excel, mais le générateur actuel déduit un type d'interface (tableau, rapport, tableau de bord, grille ou texte) et reconstruit une interface BERKIOS. Il ne garantit pas une reproduction pixel à pixel de la feuille d'origine : tailles/positions exactes de chaque objet Excel, thèmes, dessins, graphiques, contrôles ActiveX, zones d'impression et comportements VBA complexes peuvent ne pas être reproduits. Ces éléments doivent être diagnostiqués séparément plutôt que présentés comme fidèlement importés. ## Classeurs liés (v0.7.169) Un classeur Excel qui lit un autre classeur (`=[1]Budget!B2`, `=SUM('[2]Stock 2026'!A:A)`) devient une application qui lit les **valeurs embarquées** de ce classeur, sans Excel et sans jamais suivre le chemin d'origine du lien. **Import.** Le cache de dernière mise à jour d'Excel (`xl/externalLinks`) est lu sans SheetJS et stocké dans `excelWorkbook.externalWorkbooks[]` (`index`, `fileName`, `target`, `source`, `sheets`). Pour des valeurs plus récentes que ce cache, fournissez le classeur lié : ```bash node src/cli.mjs "synthese.xlsx" "synthese.berkios.json" --linked "Budget.xlsx" --linked "Stock.xlsx" ``` Dans un bundle : `{ "role": "linked-workbook", "path": "Budget.xlsx" }` (répétable, facultatif). Le classeur lié est associé au lien par son nom de fichier. | `source` | Origine des valeurs | |---|---| | `excel-cache` | cache de la dernière mise à jour dans Excel (à vérifier : peut être périmé) | | `linked-file` | classeur lié fourni à l'import (`--linked`) | | `linked-project` | autre projet BERKIOS converti, recalculé à l'ouverture | | `manual` | valeurs fournies par l'application via `updateExternalLink` | **Diagnostics** (`excelTranslation.diagnostics`, bilan dans `excelTranslation.externalLinks`) : `EXTERNAL_LINK_CACHED` (valeurs du cache), `EXTERNAL_LINK_UNRESOLVED` (formule vers un classeur absent), `EXTERNAL_LINK_REFRESH_ERROR` (actualisation échouée dans Excel), `EXTERNAL_LINK_UNUSED_FILE`, `EXTERNAL_LINK_KIND_UNSUPPORTED` (DDE/OLE), `EXTERNAL_LINK_XLS_NOT_READ` (.xls : enregistrez en .xlsx). **Runtime** : ```js import { loadBerkiosProject, readCell, listExternalLinks, updateExternalLink, updateExternalLinkFromProject } from './src/standalone-runtime.mjs'; // Deux projets convertis qui se lisent mutuellement (équivalent de « Mettre à jour les liens ») : const app = loadBerkiosProject('synthese.berkios.json', { linkedProjects: { 'Budget.xlsx': 'budget.berkios.json' } }); updateExternalLink(app, 'Budget.xlsx', { Data: { A1: 200 } }); // valeurs fournies par l'application listExternalLinks(app); // origine et date de chaque lien ``` **Comportement** : classeur ou feuille liée absent → la formule passe en `needs_review` (`external-workbook-missing`, `external-sheet-missing`), ses dépendants gardent la valeur Excel d'origine ; une cellule absente du classeur lié vaut vide ; `[0]` désigne le classeur courant. **Limites** : lecture seule (aucune écriture vers un classeur lié) ; noms définis externes (`[1]!Nom`) et références 3D externes non exécutés ; liens DDE/OLE ignorés ; `.xls` : liens non lus ; pas de mise à jour automatique depuis le chemin d'origine (volontaire). ## BERKIOS Excel Cloud Engine (prototype — phase 1) The structural analyzer is available in `src/cloud/analyzer.mjs`. It creates a reviewable JSON inventory before any cloud backend is generated. See `CLOUD_ENGINE_PHASE1.md`. ```bash npm run cloud:analyze -- ../chemin/classeur.xlsm --out ./rapport-cloud.json ``` This is deliberately an analysis-only phase: no workbook mutation, VBA execution, PostgreSQL writes, or remote synchronization. ### Phase 3 — importation initiale `src/cloud/importer.mjs` copie les lignes Excel vers PostgreSQL (validation, doublons, relations, rapport, reprise, correspondance ligne Excel ↔ enregistrement). Voir `CLOUD_ENGINE_PHASE3.md`. ```bash npm run cloud:import -- ./classeur.xlsx --analysis ./a.json --plan ./p.json --dry-run ``` --- # Core : vos premiers pas Source : https://docs.berkios.online/core/premiers-pas/ · Section : Core · Documentation officielle BERKIOS (https://docs.berkios.online) BERKIOS Core est le langage typé de BERKIOS. Chaque fichier `.bks` commence par un nom de module, puis contient des fonctions. L'exécution démarre à la fonction `principale` (ou `main` en anglais). ## Votre premier programme Créez un fichier `bonjour.bks` : ```text module "Bonjour" fonction principale() -> Entier afficher "Bonjour BERKIOS !" retourner 0 ``` Lancez-le : ```bash berkios core bonjour.bks ``` Le compilateur vérifie d'abord les types, puis exécute le programme. ## Ce qu'il faut retenir - L'**indentation** (deux espaces) délimite les blocs : il n'y a pas d'accolades. - `afficher` écrit une valeur à l'écran. - `retourner 0` termine la fonction ; `0` signifie « tout s'est bien passé ». - Les types s'écrivent après deux-points : `nom: Texte`. Le type de retour suit la flèche `->`. ## Variables avec `soit` ```text module "Variables" fonction principale() -> Entier soit prix = 125.0 soit pourcentage = 15.0 soit remise = prix * pourcentage / 100 afficher remise afficher prix - remise retourner 0 ``` `soit` crée une variable. Son type est deviné à partir de la valeur, ou écrit explicitement : `soit total: Decimal = 0.0`. ## Conditions et boucles ```text module "Controle" fonction principale() -> Entier soit total = 40 si total > 30 afficher "Grand total" sinon afficher "Petit total" soit index = 0 tant que index < 3 afficher index index = index + 1 retourner 0 ``` - `si` / `sinon` : exécuter un bloc selon une condition. - `tant que` : répéter tant que la condition est vraie. - `pour élément dans liste` : parcourir une liste et agir sur chaque élément (par exemple l'afficher). ## Listes ```text module "Listes" fonction principale() -> Entier soit nombres = [10, 20, 30] afficher somme(nombres) retourner 0 ``` ## Gérer les erreurs `essayer` / `capturer` évite qu'une erreur arrête tout le programme : ```text module "Erreurs" fonction principale() -> Entier essayer soit quotient = diviser(10, 0) afficher quotient capturer erreur afficher "Erreur contrôlée :" afficher erreur retourner 0 ``` > **Écrire dans votre langue.** Le dépôt fournit le même programme complet en français, anglais, espagnol et swahili (`compiler/examples/core/multilingual/`). Les mots-clés français (`fonction`, `soit`, `retourner`) et anglais (`fn`, `let`, `return`) sont les plus courants. Gardez la même langue dans tout un fichier. Suite : [Fonctions et modules](https://docs.berkios.online/core/fonctions-et-modules/). --- # Core : fonctions et modules Source : https://docs.berkios.online/core/fonctions-et-modules/ · Section : Core · Documentation officielle BERKIOS (https://docs.berkios.online) ## Écrire une fonction Une fonction déclare ses paramètres et son type de retour : ```text fonction calculer_remise(prix: Decimal, pourcentage: Decimal) -> Decimal retourner prix * pourcentage / 100 ``` Appelez-la comme n'importe quelle valeur : `soit remise = calculer_remise(125.0, 15.0)`. ## Découper un programme en modules Quand un programme grandit, séparez-le en plusieurs fichiers. Voici deux fichiers dans le même dossier. **`maths-fr.bks`** ```text nocheck module "Mathématiques" fonction doubler(nombre: Decimal) -> Decimal retourner nombre * 2 fonction calculer_remise(prix: Decimal, pourcentage: Decimal) -> Decimal retourner prix * pourcentage / 100 ``` **`main-fr.bks`** ```text nocheck module "Application de vente" importer "maths-fr.bks" fonction principale() -> Entier soit prix = 125.0 soit pourcentage = 15.0 soit remise = calculer_remise(prix, pourcentage) soit total = prix - remise afficher "Remise :" afficher remise afficher "Total à payer :" afficher total afficher doubler(10) retourner 0 ``` ```bash berkios core main-fr.bks ``` Résultat : ```text Remise : 18.75 Total à payer : 106.25 20 ``` ## Règles des imports - `importer "fichier.bks"` est résolu **par rapport au fichier qui l'écrit**. - Les cycles d'import (A importe B qui importe A) sont détectés et refusés. - Alias selon la langue : `import` (anglais), `importar` (espagnol), `agiza` (swahili). ## Fonctions génériques Une fonction générique accepte plusieurs types. Le compilateur devine `T` à partir des arguments puis vérifie les types : ```text type Boite valeur: T fonction principale() -> Entier soit boite: Boite = Boite(42) afficher boite.valeur retourner boite.valeur ``` Suite : [Types, classes et héritage](https://docs.berkios.online/core/classes-et-types/). --- # Core : types, classes et héritage Source : https://docs.berkios.online/core/classes-et-types/ · Section : Core · Documentation officielle BERKIOS (https://docs.berkios.online) ## Définir un type de données Un `type` regroupe des champs : ```text module "Capteurs" type LectureCapteur capteur: Texte temperature: Décimal valide: Bool fonction principale() -> Entier soit lecture = LectureCapteur("T1", 21.4, true) afficher lecture.temperature retourner 0 ``` ## Les classes Une classe ajoute des **méthodes** qui agissent sur ses champs. Dans une méthode, `self` désigne l'objet courant. ```text module "Comptes" class Compte titulaire: Text solde: Int fn deposer(montant: Int) -> Int self.solde = self.solde + montant retourner self.solde fn retirer(montant: Int) -> Int self.solde = self.solde - montant retourner self.solde fn main() -> Int soit compte = Compte("Amina", 100) afficher compte.deposer(50) afficher compte.retirer(20) afficher compte.solde retourner 0 ``` Résultat : `150`, `130`, `130`. On crée un objet en appelant la classe avec la valeur de chaque champ, dans l'ordre : `Compte("Amina", 100)`. ## L'héritage `extends` permet à une classe de reprendre une autre classe et de redéfinir ses méthodes : ```text class Animal nom: Text fn parler() -> Text retourner "..." class Chien extends Animal race: Text fn parler() -> Text retourner "Wouf !" ``` ## Les interfaces Une interface décrit ce qu'une classe **doit** savoir faire, sans dire comment : ```text interface Rechargeable fn recharger(quantite: Int) -> Int class Batterie implements Rechargeable niveau: Int fn recharger(quantite: Int) -> Int self.niveau = self.niveau + quantite retourner self.niveau ``` ## Pour aller plus loin Le dépôt contient des exemples exécutables dans `compiler/examples/core/` : classes, héritage, interfaces, génériques, modules et valeurs typées. Exécutez-les avec `berkios core .bks`. --- # Code : votre premier fichier .bk Source : https://docs.berkios.online/code/premier-fichier/ · Section : Code (.bk) · Documentation officielle BERKIOS (https://docs.berkios.online) BERKIOS Code décrit une application dans un fichier texte lisible, presque en langage naturel. Le compilateur le transforme en projet que le Studio sait ouvrir. ## Créer un fichier ```bash berkios --lg --fr berkios nouveau main.bk ``` Vous obtenez un fichier de départ dans votre langue : ```text langue français application "Ma première application" version 1.0 type interface édition pro interface Accueil étiquette titre "Bonjour" taille du texte 26 gras bouton valider "Cliquer ici" quand on clique : afficher "Bravo !" ``` ## Voir le résultat ```bash berkios apercu main.bk ``` L'application s'ouvre dans le navigateur. Modifiez le fichier, enregistrez : la page se recharge. Les erreurs de syntaxe s'affichent à l'écran avec leur ligne. ## Anatomie d'un fichier | Élément | Rôle | |---|---| | `langue français` | Langue du fichier (une seule par fichier) | | `application "Nom"` | Nom, version, type et plateformes | | `interface Accueil` | Un écran : page, fenêtre modale ou panneau latéral | | `étiquette`, `bouton`, `champ`, `case à cocher`, `tableau`, `panneau` | Les six composants de base | | `quand on clique : …` | Ce qui se passe au clic | ## Vérifier et compiler ```bash berkios valider main.bk # vérifie sans rien écrire berkios compiler main.bk # produit main.berkios.json, ouvrable dans le Studio ``` Suite : [Interfaces et modèles de données](https://docs.berkios.online/code/interfaces-et-modeles/). --- # Code : interfaces et modèles de données Source : https://docs.berkios.online/code/interfaces-et-modeles/ · Section : Code (.bk) · Documentation officielle BERKIOS (https://docs.berkios.online) Cet exemple décrit une petite gestion de stock : un **modèle** (la forme des données), une interface avec un tableau, et un formulaire modal. ```text langue français application "Gestion de stock" version 1.0 description "Suivi simple des produits" type interface plateformes windows, macos, linux, android édition pro modèle Produit sku : texte, unique, obligatoire nom : texte, obligatoire quantité : nombre entier, minimum 0 prix : montant interface Accueil titre "Produits en stock" taille 1280 sur 720 fond #f8fafc panneau en-tête disposition ligne étiquette titre "Produits en stock" taille du texte 26 gras bouton ajouter "Ajouter un produit" quand on clique : ouvrir Formulaire produit tableau liste source : Produit colonnes : sku, nom, quantité, prix interface Formulaire produit affichage modale titre "Nouveau produit" champ sku "Référence" obligatoire champ nom "Nom du produit" obligatoire champ quantité "Quantité" format nombre minimum 0 bouton enregistrer "Enregistrer" quand on clique : envoyer le formulaire bouton annuler "Annuler" quand on clique : fermer ``` ## Comment ça marche - Le **modèle** déclare les champs et leurs règles : `obligatoire`, `unique`, `minimum`, types (`texte`, `nombre entier`, `montant`…). - Le **tableau** se lie au modèle avec `source : Produit`. - Un formulaire **valide** la ligne selon le modèle (obligatoire, minimum, unicité) avant de l'ajouter au tableau. - `quand on clique : ouvrir …` change d'interface ; `fermer` revient en arrière. ## Actions disponibles dans l'aperçu Ouvrir / fermer une interface, afficher un message, montrer / cacher / basculer un composant, envoyer ou vider le formulaire, appeler une API. ## Limites à connaître - Dans l'aperçu navigateur, les données restent dans le navigateur (`localStorage`). Le bouton « Réinitialiser les données » les efface. Ce n'est pas la persistance SQLite des applications générées. - Les actions Excel ne fonctionnent pas dans un navigateur. - Le rendu n'est pas garanti identique à celui de Flutter : testez toujours l'application générée. --- # Code : créer un outil en ligne de commande Source : https://docs.berkios.online/code/ligne-de-commande/ · Section : Code (.bk) · Documentation officielle BERKIOS (https://docs.berkios.online) BERKIOS Code ne sert pas qu'aux interfaces. Avec `type command`, vous créez un outil qui s'utilise dans un terminal. ```bash berkios nouveau outil.bk --type commande ``` Exemple en anglais : ```text language english application "Greeter" type command version 2.0 description "Greets people" command greet description "Greets someone" argument name : text, required option count : whole number, default 1 action repeat count times print "Hello " and name ``` ## L'exécuter ```bash berkios lancer greet.en.bk Alice --count 2 ``` ```text Hello Alice Hello Alice ``` ## L'exporter ```bash berkios exporter outil.bk -o outil.mjs node outil.mjs Alice ``` Le script exporté est autonome : il ne nécessite que Node.js. ## Traduire un programme Un fichier peut être traduit dans une autre langue sans le réécrire : ```bash berkios traduire main.bk --vers en -o main.en.bk ``` --- # Les modules BERKIOS : vue d'ensemble Source : https://docs.berkios.online/modules/apercu/ · Section : Modules · Documentation officielle BERKIOS (https://docs.berkios.online) Un **module** (ou **bibliothèque**) ajoute de nouvelles commandes au code de vos composants : générer un identifiant unique, calculer une date relative, fabriquer un PDF, appeler une API, tirer un nombre au hasard… Vous l'installez en quelques clics depuis le Studio, puis vous utilisez ses commandes comme celles de BERKIOS CODE. ## Installer un module 1. Ouvrez le Studio, puis **Code → Bibliothèques**. 2. Choisissez une bibliothèque dans le catalogue et installez-la. Le Studio vérifie l'**empreinte SHA-256** du fichier avant de l'enregistrer. 3. Cliquez sur **Ajouter au projet**. La définition est copiée **dans votre projet** : il reste ouvrable sans connexion, et l'application générée est autonome. 4. Utilisez les commandes dans le code d'un composant. Avant l'ajout, le Studio affiche les **permissions** demandées par la bibliothèque (réseau, fichiers, impression…). Une bibliothèque qui utilise une permission non déclarée est refusée. ## Utiliser une commande ```text quand clic uuid4 "$id" # génère un identifiant unique uuid-valide "$id" "$ok" # true dans-jours "Echeance" 30 # date d'aujourd'hui + 30 jours ``` - Une commande s'écrit par son **nom court** (`uuid4`) ou son **nom qualifié** (`uuid.uuid4`). - Si deux bibliothèques utilisent le même nom, ou si le nom existe déjà dans BERKIOS CODE, utilisez la forme qualifiée. - Une commande de bibliothèque commence une ligne : on ne l'imbrique pas après `si … alors` ou `repeter`. - La plupart des bibliothèques proposent leurs commandes en **français, anglais, espagnol et swahili**. ## Deux familles de modules | Famille | Principe | Exemples | |---|---|---| | **Bibliothèques `.bkl`** | Des macros écrites en BERKIOS CODE. Elles n'exécutent rien d'autre que ce que BERKIOS CODE sait déjà faire : l'aperçu et l'application finale se comportent de la même façon. | `datetime`, `uuid`, `randomy`, `golib`, `requeto`, `pdflab`, `video`, `mygame`, `easyapi` | | **Modules natifs** | Du code exécuté par le Bridge de BERKIOS, pour les fonctions qu'une macro ne peut pas faire (cryptographie, réseau, appareils). | [Passo](https://docs.berkios.online/modules/passo/), [Berkrypt](https://docs.berkios.online/modules/berkrypt/), [ftpLab](https://docs.berkios.online/modules/ftplab/), [KConnect](https://docs.berkios.online/modules/kconnect/), [KPartage](https://docs.berkios.online/modules/kpartage/) | ## Les bibliothèques fournies | Bibliothèque | Contenu | |---|---| | `systeme` | Copier une valeur, exporter un texte, sauvegarder et restaurer une valeur. | | [`datetime`](https://docs.berkios.online/modules/datetime/) | Date et heure, dates relatives, jours restants, durées lisibles, chronomètre (13 commandes). | | [`randomy`](https://docs.berkios.online/modules/randomy/) | Nombres aléatoires, dans l'esprit du module `random` de Python (30 commandes). | | [`uuid`](https://docs.berkios.online/modules/uuid/) | Identifiants uniques (12 commandes). | | [`golib`](https://docs.berkios.online/modules/golib/) | Chemins de fichiers, dans l'esprit de `pathlib` (37 commandes). | | [`requeto`](https://docs.berkios.online/modules/requeto/) | Requêtes HTTP GET avec extraction JSON et cache (8 commandes). | | [`pdflab`](https://docs.berkios.online/modules/pdflab/) | Génération de PDF (39 commandes). | | [`pdfreader`](https://docs.berkios.online/modules/pdfreader/) | Lecture de PDF. | | [`video`](https://docs.berkios.online/modules/video/) | Lecteur vidéo (24 commandes). | | [`mygame`](https://docs.berkios.online/modules/mygame/) | Jeux 2D : canevas, sprites, collisions, scores. | | [`easyapi`](https://docs.berkios.online/modules/easyapi/) | Créer des API REST en BERKIOS CODE. | | `fichiers` | Fichiers virtuels et réels dans le dossier de travail confiné. | ## Permissions Les permissions possibles pour une bibliothèque `.bkl` sont : `reseau`, `fichiers`, `presse-papiers`, `impression`, `audio` et `stockage`. Le Studio les **déduit** des commandes utilisées et refuse une bibliothèque qui n'en déclare pas assez. ## Limites actuelles - Les bibliothèques `.bkl` sont des macros : elles ne peuvent pas ajouter de code Dart ni de plugins. - Le catalogue n'est pas signé. L'empreinte SHA-256 protège contre un fichier modifié, pas contre un catalogue malveillant : installez uniquement des bibliothèques de sources de confiance. ## Créer votre propre bibliothèque Une bibliothèque est un simple fichier JSON. Le [format `.bkl`](https://docs.berkios.online/modules/format-bkl/) explique comment en écrire une. --- # Bibliothèques BERKIOS CODE (extensions) Source : https://docs.berkios.online/modules/format-bkl/ · Section : Modules · Documentation officielle BERKIOS (https://docs.berkios.online) Une bibliothèque ajoute des commandes au code des composants. C'est un **fichier JSON** (`.bkl`, format `berkios-library/1`) : ses commandes sont des **macros** écrites en BERKIOS CODE. À l'analyse du script, un appel de macro est remplacé par les commandes intégrées qu'elle contient. Rien n'est exécuté en dehors de ce que BERKIOS CODE sait déjà faire, donc l'aperçu du Studio et l'application Flutter se comportent de la même façon. ## Format ```json { "format": "berkios-library/1", "id": "systeme", "version": "1.0.0", "title": "Système", "description": "…", "author": "…", "license": "MIT", "permissions": ["presse-papiers", "fichiers", "stockage"], "commands": [{ "id": "exporter-texte", "names": ["exporter-texte", "export-text"], "usage": "exporter-texte \"nom.txt\" \"Source\"", "summary": "Enregistre la valeur d'un composant dans un fichier texte.", "minArgs": 2, "maxArgs": 2, "body": ["telecharger %1 %2"] }] } ``` - `%1`…`%9` = arguments de l'appel (avec leurs guillemets d'origine) ; `%*` = tous les arguments ; `%1` dans un texte entre guillemets est remplacé par la valeur de l'argument. - `permissions` : `reseau`, `fichiers`, `presse-papiers`, `impression`, `audio`, `stockage`. Le Studio **déduit** les permissions des commandes du corps et refuse la bibliothèque si l'une n'est pas déclarée. - Interdits dans un corps : en-têtes d'événement (`quand clic`, `toutes les 100 ms`, `quand touche …`) et appel d'une autre commande de bibliothèque (pas de récursion possible). - Dans un script : le nom court (`exporter-texte …`) ou qualifié (`systeme.exporter-texte …`). Un nom déjà pris par une commande intégrée n'est disponible que sous sa forme qualifiée ; deux bibliothèques qui partagent un nom le rendent ambigu (forme qualifiée obligatoire). - Une commande de bibliothèque s'utilise comme première commande d'une ligne ; elle ne peut pas être imbriquée après `si … alors` ou `repeter`. ## Cycle de vie 1. **Catalogue** : le Bridge lit `https://github.com/berkiosbuinu-server/berkios-code/releases/latest/download/index.json` (surchargeable par `BERKIOS_LIBRARY_CATALOG_URL`). Seules les adresses `https` sont acceptées. 2. **Installation** (Studio → *Code → Bibliothèques*) : le Bridge télécharge le `.bkl`, vérifie le **SHA-256** annoncé par le catalogue, valide la structure et l'enregistre dans `%LOCALAPPDATA%\BerkiosLibraries` (ou `~/.berkios/libraries`, surchargeable par `BERKIOS_LIBRARIES_HOME`). 3. **Activation** : « Ajouter au projet » copie la définition **dans le projet** (`libraries`). Le projet reste ouvrable sans connexion, et les commandes sont disponibles dans l'aperçu et la vérification du code. 4. **Génération** : le Bridge intègre les bibliothèques du projet au Dart généré (`setActiveLibraries(...)` au démarrage). L'application finale est autonome. ## Publier une bibliothèque Voir `libraries-repo/` (dépôt `berkios-code`) : `node scripts/build-release.mjs` construit `dist/index.json` et les `.bkl` ; un tag `v*` déclenche la release GitHub. ## Limites de la v1 - Macros uniquement : pas de bibliothèque native (Dart/plugins). `audio` et `imprimer` dans l'application Flutter restent à faire. - Le catalogue n'est pas signé : l'empreinte SHA-256 protège contre un fichier altéré, pas contre un catalogue malveillant. Une signature (clé publique intégrée au Bridge) est prévue. - Le Dart n'a pas été compilé dans l'environnement de développement (voir RELEASE_NOTES_v0.7.79). --- # Bibliothèque `datetime` (Date et heure) — v1.0.0 Source : https://docs.berkios.online/modules/datetime/ · Section : Modules · Documentation officielle BERKIOS (https://docs.berkios.online) 13 commandes pour BERKIOS CODE : dates relatives, jours restants, formats courts, durées lisibles et chronomètre. Chaque commande existe en **français, anglais, espagnol et swahili** ; la forme qualifiée `datetime.` fonctionne aussi. Permission demandée : `stockage` (uniquement pour le chronomètre). Conventions : une **cible** ou un **résultat** est le nom d'un composant ou d'une variable `$nom` ; une **date** s'écrit `AAAA-MM-JJ` (celle d'un champ date) ; `JJ/MM/AAAA` est aussi accepté en lecture. ## Date et heure du moment | Commande (fr · en · es · sw) | Syntaxe | Résultat | |---|---|---| | `date-et-heure` · `date-and-time` · `fecha-y-hora` · `tarehe-na-saa` | `date-et-heure "Cible"` | `24/10/2026 14:30` | | `heure-courte` · `short-time` · `hora-corta` · `saa-fupi` | `heure-courte "Cible"` | `14:30` | | `jour-actuel` · `current-weekday` · `dia-actual` · `siku-ya-sasa` | `jour-actuel "Cible"` | `samedi` | ## Formats de date | Commande | Syntaxe | Effet | |---|---|---| | `date-courte` · `short-date` · `fecha-corta` · `tarehe-fupi` | `date-courte "Cible"` | `2026-10-24` → `24/10/2026` (sur place) | | `date-iso` · `iso-date` · `fecha-iso` · `tarehe-iso` | `date-iso "Cible"` | `24/10/2026` → `2026-10-24` (sur place) | ## Dates relatives et écarts | Commande | Syntaxe | Effet | |---|---|---| | `dans-jours` · `in-days` · `en-dias` · `baada-ya-siku` | `dans-jours "Cible" 30` | aujourd'hui + 30 jours (négatif accepté) | | `dans-mois` · `in-months` · `en-meses` · `baada-ya-miezi` | `dans-mois "Cible" 3` | aujourd'hui + 3 mois (fin de mois respectée) | | `jours-restants` · `days-left` · `dias-restantes` · `siku-zilizobaki` | `jours-restants "Date" "Résultat"` | jours entre aujourd'hui et la date (négatif si passée) | | `jours-ecoules` · `days-since` · `dias-transcurridos` · `siku-zilizopita` | `jours-ecoules "Date" "Résultat"` | jours depuis la date (négatif si à venir) | | `est-passee` · `is-past` · `esta-pasada` · `imepita` | `est-passee "Date" "Résultat"` | `true` si la date est avant aujourd'hui, sinon `false` | ## Durées et chronomètre | Commande | Syntaxe | Effet | |---|---|---| | `formater-duree` · `format-duration` · `formatear-duracion` · `fomati-muda` | `formater-duree "Secondes" "Résultat"` | `3661` → `01:01:01` (heures > 24 permises ; décimales tronquées ; valeurs négatives non prises en charge) | | `chrono-demarrer` · `start-stopwatch` · `iniciar-cronometro` · `anza-kipima-muda` | `chrono-demarrer "clé"` | mémorise l'instant présent sous la clé | | `chrono-lire` · `read-stopwatch` · `leer-cronometro` · `soma-kipima-muda` | `chrono-lire "clé" "Résultat"` | secondes écoulées depuis `chrono-demarrer` ; erreur « Chronomètre non démarré. » sinon | ```text quand clic chrono-demarrer "essai" quand clic chrono-lire "essai" "$secondes" formater-duree "$secondes" "duree" ``` ## Bon à savoir - **Heure locale** : « aujourd'hui » et « maintenant » suivent l'horloge de l'appareil. - **Le chronomètre est mémorisé** (commande `stocker`) : dans l'application générée, il survit à la fermeture de l'application. Réutiliser la même clé le remplace. - **Variables réservées** : les commandes utilisent en interne des variables commençant par `$dt` (`$dtjour`, `$dtnow`…). Évitez ces noms dans vos scripts. - **Dans une ligne** : comme toute commande de bibliothèque, elles s'utilisent en début de ligne (pas après `si … alors`). --- # Bibliothèque `uuid` (identifiants uniques) — v1.0.0 Source : https://docs.berkios.online/modules/uuid/ · Section : Modules · Documentation officielle BERKIOS (https://docs.berkios.online) 12 commandes pour BERKIOS CODE qui reprennent l'esprit du module `uuid` de Python : génération d'UUID version 4, formes dérivées (hexadécimal, URN, court), UUID nul et maximal, validation, lecture de la version, normalisation et comparaison. Chaque commande existe sous son **nom Python/anglais**, en **français**, en **espagnol** et en **swahili** ; la forme qualifiée `uuid.` fonctionne aussi. Aucune permission n'est demandée. Les commandes sont de simples macros vers des commandes intégrées (`identifiant`, `generer-identifiant`, `uuid-reproductible`, `correspond`, `sous-texte`…). ## Exemple ```text quand clic uuid4 "$id" # 3f2b8c1e-9a4d-4e57-b1c6-0d2f7a9e5b34 uuid-valide "$id" "$ok" # true uuid-version "$id" "$v" # 4 uuid4-hex "$cle" # 32 caractères hexadécimaux, sans tirets uuid-court "$code" # 8 caractères, ex. 3f2b8c1e uuid-egal "$id" "$autre" "$meme" ``` ## Choisir la bonne commande - **Identifiant d'enregistrement, de ligne, de commande** : `uuid4`. - **Jeton ou clé qui doit rester imprévisible** : `uuid4-secure` (générateur sécurisé de l'hôte). - **Tests reproductibles** : `randomy.seed 42` puis `uuid4-seeded` → mêmes identifiants à chaque exécution. Jamais pour un secret. - **Code lisible** : `uuid-court` (8 caractères : plus pratique, mais risque de collision bien plus élevé qu'un UUID complet). ## Commandes | Noms (python/en · fr · es · sw) | Syntaxe | Effet | |---|---|---| | `uuid4 · nouvel-uuid · nuevo-uuid · uuid-mpya` | `uuid4 "Résultat"` | Génère un identifiant unique aléatoire (UUID version 4) comme uuid.uuid4() de Python, par exemple 3f2b8c1e-9a4d-4e57-b1c6-0d2f7a9e5b34. | | `uuid4-hex · uuid-hexa · uuid-hexadecimal · uuid-heksadesimali` | `uuid4-hex "Résultat"` | UUID v4 sans tirets : 32 caractères hexadécimaux (uuid.uuid4().hex). | | `uuid-urn · urn-uuid · urn-de-uuid · urn-ya-uuid` | `uuid-urn "Résultat"` | UUID v4 au format URN : urn:uuid:… (uuid.uuid4().urn). | | `uuid-short · uuid-court · uuid-corto · uuid-fupi` | `uuid-court "Résultat"` | Identifiant court : les 8 premiers caractères d'un UUID v4. Pratique pour un code lisible, mais moins unique qu'un UUID complet. | | `uuid4-secure · uuid-securise · uuid-seguro · uuid-salama` | `uuid4-secure "Résultat"` | UUID v4 issu du générateur sécurisé de l'hôte (generer-identifiant) : à préférer pour un jeton ou une clé qui doit rester imprévisible. | | `uuid4-seeded · uuid-graine · uuid-semilla · uuid-mbegu` | `uuid4-seeded "Résultat"` | UUID v4 tiré avec la graine courante (voir randomy.seed) : même graine, mêmes identifiants. Pour des tests reproductibles, jamais pour un secret. | | `uuid-nil · uuid-nul · uuid-nulo · uuid-tupu` | `uuid-nil "Résultat"` | L'UUID nul 00000000-0000-0000-0000-000000000000 (« aucun identifiant »). | | `uuid-max · uuid-maximal · uuid-maximo · uuid-upeo` | `uuid-max "Résultat"` | L'UUID maximal ffffffff-ffff-ffff-ffff-ffffffffffff. | | `is-uuid · uuid-valide · uuid-valido · uuid-halali` | `uuid-valide "Source" "Résultat"` | Écrit true si la source est un UUID de forme 8-4-4-4-12 chiffres hexadécimaux (majuscules ou minuscules), sinon false. | | `uuid-version · version-uuid · version-del-uuid · toleo-la-uuid` | `uuid-version "Source" "Résultat"` | Écrit la version de l'UUID (1 à 8 ; 4 pour un UUID aléatoire). Arrête le script si la source n'est pas un UUID valide. | | `uuid-normalize · uuid-normaliser · uuid-normalizar · uuid-sanifisha` | `uuid-normaliser "Cible"` | Met l'UUID de la cible en minuscules, sans espaces, accolades {…} ni préfixe urn:uuid:. | | `uuid-equal · uuid-egal · uuid-igual · uuid-sawa` | `uuid-egal "A" "B" "Résultat"` | Écrit true si deux UUID sont identiques, sans tenir compte de la casse, des accolades ni du préfixe urn:uuid:. | ## Limites - Seule la **version 4** (aléatoire) est générée. Les versions 1, 3, 5 et 7 de Python ne sont pas fournies : une bibliothèque de macros ne dispose ni de l'adresse MAC, ni de MD5/SHA-1, ni de l'horloge à la précision requise. - `uuid-valide` et `uuid-version` n'acceptent que la forme canonique 8-4-4-4-12 ; utilisez `uuid-normaliser` d'abord pour une valeur avec accolades ou préfixe `urn:uuid:`. Un UUID sans tirets (32 caractères) est refusé. - `uuid4-seeded` (commande intégrée `uuid-reproductible`) et `uuid4-secure` suivent la disponibilité de ces commandes intégrées : `uuid-reproductible` n'est pas encore porté dans le runtime Dart des applications Flutter ; `uuid4`, `uuid4-hex`, `uuid-urn`, `uuid-court` et les commandes de validation n'en dépendent pas. - Dans ce document, le nom `uuid` seul reste la commande intégrée `identifiant` : pour la bibliothèque, écrivez `uuid4` ou `uuid.uuid4`. Vérifié par `studio/tests/library-uuid.test.ts` (8 tests, exécution réelle des macros). --- # Bibliothèque `randomy` (clone de `random` de Python) — v1.0.0 Source : https://docs.berkios.online/modules/randomy/ · Section : Modules · Documentation officielle BERKIOS (https://docs.berkios.online) 30 commandes pour BERKIOS CODE qui reprennent le module `random` de Python : `seed`, `randint`, `randrange`, `choice`, `choices`, `sample`, `shuffle`, `uniform`, les lois de probabilité (`gauss`, `normalvariate`, `gammavariate`, `betavariate`, `binomialvariate`…), `getrandbits`, `randbytes`, `getstate` / `setstate`. Chaque commande existe sous son **nom Python**, en **français**, en **espagnol** et en **swahili** ; la forme qualifiée `randomy.` fonctionne aussi. Aucune permission n'est demandée. Les commandes sont de simples macros vers les 50 commandes intégrées de la catégorie **« Génération aléatoire »** (voir la leçon formation/08) : le moteur est dans `studio/src/model/random-engine.ts`. ## Même graine, mêmes tirages qu'en Python Le moteur est un Mersenne Twister MT19937 qui suit les algorithmes de CPython 3.12/3.13. Avec la même graine, les suites sont identiques : ```text quand clic randomy.seed 42 randomy.random "$a" # 0.6394267984578837, comme random.seed(42); random.random() seed 5 randint "$de" 1 6 # 5, 3, 6, 3, 6, 6… comme random.seed(5); [random.randint(1, 6) …] seed 9 shuffle "$liste" # mélange identique à random.shuffle après random.seed(9) ``` Vérifié contre CPython 3.13 (`studio/tests/random-commands.test.ts`, `library-randomy.test.ts`) pour : `random`, `getrandbits`, `randbytes`, `randint`, `randrange`, `choice`, `choices` (avec poids), `sample`, `shuffle`, `gauss`, `binomialvariate`, graines entières, négatives, très grandes et textuelles (SHA-512). ### Règles de graine - Une valeur **entière** (`seed 42`, `seed "42"`) est lue comme l'entier Python ; tout autre texte (`seed "bonjour"`) est lu comme une chaîne Python (version 2 de `random.seed`). Les deux n'ont pas la même suite, comme en Python. - Un nombre décimal (`seed 1.5`) est traité comme du texte (Python utiliserait `hash(1.5)`). Écart connu. - `seed` sans valeur prend de l'entropie du système. - Le générateur est **global** (comme l'instance cachée de `random`) : il est partagé par tous les composants d'une session d'aperçu et n'est pas enregistré dans le projet. Pour rejouer une suite plus tard, mémorisez `getstate` (avec `stocker`) puis `setstate`. ## Conventions BERKIOS - Le **résultat** est le premier argument : `randint "$r" 1 6` au lieu de `r = random.randint(1, 6)`. - Une **liste** s'écrit `a, b, c` (éléments séparés par des virgules) ; `choices` accepte des poids dans le même format : `choices "$r" "a, b, c" 5 "1, 2, 7"`. - Les erreurs correspondent aux `ValueError` de Python (intervalle vide, échantillon plus grand que la population, poids invalides…) et arrêtent le script avec un message. - **`random` est déjà une commande intégrée** de BERKIOS CODE (entier de 1 à 100). Pour le `random()` de Python, écrivez `randomy.random "$r"` ou son nom français `hasard`. ## Commandes | Noms (python · fr · es · sw) | Syntaxe | Effet | |---|---|---| | `seed · graine · semilla · mbegu` | `seed ["valeur"]` | Fixe la graine : une même graine (entier ou texte) redonne la même suite de tirages, comme random.seed de Python. Sans valeur, graine du système. | | `getstate · lire-etat · obtener-estado · pata-hali` | `getstate "Résultat"` | Écrit l'état complet du générateur (random.getstate) pour le restaurer avec setstate. | | `setstate · fixer-etat · fijar-estado · weka-hali` | `setstate "Etat"` | Restaure un état produit par getstate (random.setstate) : les tirages suivants sont rejoués à l'identique. | | `random · hasard · aleatorio · nasibu` | `randomy.random "Résultat"` | Nombre décimal dans [0, 1[ (random.random). « random » existe déjà dans BERKIOS CODE : écrivez randomy.random, ou utilisez hasard. | | `getrandbits · bits-hasard · bits-aleatorios · biti-nasibu` | `getrandbits "Résultat" k` | Entier de k bits aléatoires, 1 ≤ k ≤ 8192 (random.getrandbits). | | `randbytes · octets-hasard · bytes-aleatorios · baiti-nasibu` | `randbytes "Résultat" n` | n octets aléatoires écrits en hexadécimal (random.randbytes). | | `randint · entier-hasard · entero-aleatorio · kamili-nasibu` | `randint "Résultat" a b` | Entier de a à b, bornes incluses (random.randint). | | `randrange · plage-hasard · rango-aleatorio · masafa-nasibu` | `randrange "Résultat" fin \| "Résultat" début fin [pas]` | Entier pris dans range(début, fin, pas), fin exclue (random.randrange). | | `randbelow · sous-hasard · menor-aleatorio · chini-nasibu` | `randbelow "Résultat" n` | Entier de 0 à n − 1 (comme secrets.randbelow, mais reproductible avec seed). | | `choice · choix · elegir · chagua` | `choice "Résultat" "a, b, c"` | Un élément de la liste, au hasard (random.choice). | | `choices · choix-plusieurs · elegir-varios · chagua-nyingi` | `choices "Résultat" "a, b, c" k ["poids"]` | k éléments tirés avec remise, poids facultatifs (random.choices). | | `sample · echantillon · muestra · sampuli` | `sample "Résultat" "a, b, c" k` | k éléments distincts de la liste (random.sample). | | `shuffle · melanger · barajar · changanya` | `shuffle "Liste"` | Mélange la liste en place (random.shuffle). | | `uniform · uniforme · uniforme-aleatorio · sawia` | `uniform "Résultat" a b` | Nombre décimal entre a et b (random.uniform). | | `triangular · triangulaire · triangular-aleatorio · pembetatu` | `triangular "Résultat" [bas] [haut] [mode]` | Loi triangulaire (random.triangular). | | `gauss · gaussienne · gaussiana · gauss-nasibu` | `gauss "Résultat" [mu] [sigma]` | Loi normale par Box-Muller (random.gauss). | | `normalvariate · loi-normale · normal-aleatoria · kawaida-nasibu` | `normalvariate "Résultat" [mu] [sigma]` | Loi normale par Kinderman-Monahan (random.normalvariate). | | `lognormvariate · loi-lognormale · lognormal-aleatoria · lognormal-nasibu` | `lognormvariate "Résultat" mu sigma` | Loi log-normale (random.lognormvariate). | | `expovariate · loi-exponentielle · exponencial-aleatoria · kielelezo-nasibu` | `expovariate "Résultat" [lambda]` | Loi exponentielle (random.expovariate). | | `gammavariate · loi-gamma · gamma-aleatoria · gamma-nasibu` | `gammavariate "Résultat" alpha beta` | Loi gamma (random.gammavariate). | | `betavariate · loi-beta · beta-aleatoria · beta-nasibu` | `betavariate "Résultat" alpha beta` | Loi bêta (random.betavariate). | | `paretovariate · loi-pareto · pareto-aleatoria · pareto-nasibu` | `paretovariate "Résultat" alpha` | Loi de Pareto (random.paretovariate). | | `weibullvariate · loi-weibull · weibull-aleatoria · weibull-nasibu` | `weibullvariate "Résultat" alpha beta` | Loi de Weibull (random.weibullvariate). | | `vonmisesvariate · loi-vonmises · vonmises-aleatoria · vonmises-nasibu` | `vonmisesvariate "Résultat" mu kappa` | Loi de von Mises (random.vonmisesvariate). | | `binomialvariate · loi-binomiale · binomial-aleatoria · binomu-nasibu` | `binomialvariate "Résultat" [n] [p]` | Nombre de succès sur n essais (random.binomialvariate, Python 3.12). | | `token_hex · jeton-hex · token-hexadecimal · tokeni-hex` | `token_hex "Résultat" [octets]` | Jeton hexadécimal cryptographique (secrets.token_hex), non reproductible. | | `randlist · liste-hasard · lista-aleatoria · orodha-nasibu` | `randlist "Résultat" n a b` | Liste de n entiers entre a et b : [randint(a, b) for _ in range(n)]. | | `permutation · permuter · permutar · badilisha-mpangilio` | `permutation "Résultat" n` | Les entiers de 1 à n dans un ordre aléatoire : sample(range(1, n + 1), n). | | `roll · lancer · lanzar · rusha` | `roll "Résultat" "2d6+3"` | Lance des dés en notation NdF±M et écrit le total. | | `coinflip · pile-face · cara-o-cruz · sarafu` | `coinflip "Résultat"` | « pile » ou « face » : choice(["pile", "face"]). | ## Sécurité `random` de Python n'est pas cryptographique, et Randomy non plus : **ne l'utilisez pas pour des mots de passe ni des jetons**. `token_hex` est l'exception : il appelle le générateur cryptographique du système (comme le module `secrets`), jamais la graine. Même chose pour `entier-securise`, `jeton-aleatoire` et `mot-de-passe-aleatoire` parmi les commandes intégrées. ## Limites - Traductions espagnoles et swahilies écrites sans relecture par des locuteurs natifs : à relire avant diffusion large. - Les dernières décimales des lois continues peuvent différer d'un ulp de CPython selon la bibliothèque mathématique de la plateforme (les tests tolèrent 1e-12). - Ces commandes tournent dans l'**aperçu du Studio**. Le port Dart (application Flutter générée) n'est pas fait : voir `RELEASE_NOTES_v0.7.288_randomy_50_commandes_aleatoires.md`. - `binomialvariate` suppose Python ≥ 3.12 ; `gauss` et `expovariate` suivent la version 3.12 (le paramètre `lambd` d'`expovariate` est facultatif, valeur 1). --- # golib — gestion moderne des chemins (équivalent de `pathlib` de Python) Source : https://docs.berkios.online/modules/golib/ · Section : Modules · Documentation officielle BERKIOS (https://docs.berkios.online) Bibliothèque `golib` 1.0.0 : 37 commandes pour **lire, construire et comparer des chemins** de fichiers sans écrire de séparateurs à la main, avec les mêmes règles que `pathlib` (`PurePosixPath`, `PureWindowsPath`) et `os.path` de Python 3.12. Noms Python, français, espagnols et swahilis. Aucune permission : les commandes ne touchent pas au disque. ## Démarrage Ajoutez `golib` au projet (Studio → *Code → Bibliothèques*), puis dans le code d'un composant : ``` quand clic joinpath "$chemin" "/projets" "facture" "2026.pdf" # /projets/facture/2026.pdf name "$nom" "$chemin" # 2026.pdf with_suffix "$copie" "$chemin" ".bak" # /projets/facture/2026.bak relative_to "$rel" "$chemin" "/projets" # facture/2026.pdf splitext "$racine" "$ext" "$chemin" # /projets/facture/2026 et .pdf ``` Sans bibliothèque, les mêmes fonctions existent comme commandes intégrées de la catégorie **Chemins** (`chemin-assembler`, `chemin-element`, `chemin-avec-suffixe`, `chemin-relatif-a`, `chemin-scinder-ext`…), sans conflit avec `chemin-joindre`, `chemin-nom` et `chemin-dossier` de la bibliothèque `fichiers`. Les commandes de golib sont des macros vers ces commandes intégrées. ## Règles à connaître - **Résultat en premier** : `commande "$resultat" "chemin" …` (comme `randomy`). `splitext` et `split` écrivent deux résultats : `splitext "$racine" "$extension" "chemin"`. - **Style POSIX ou Windows, reconnu automatiquement** : un chemin avec lecteur (`C:`), un chemin UNC (`\\serveur\partage`) ou des antislash sans barre oblique est lu comme un chemin Windows, sinon comme un chemin POSIX. `set_style posix` / `set_style windows` force le style, `set_style auto` revient au défaut. - **Antislash doublés** : dans un texte BERKIOS CODE, `\\` désigne un antislash. Pour `C:\Users\ana`, écrivez `"C:\\Users\\ana"` (ou `"C:/Users/ana"`, lu lui aussi comme un chemin Windows grâce au lecteur). - **Calcul lexical** : `normpath`, `abspath`, `relpath`, `relative_to`… calculent sur le texte ; `..` n'est jamais résolu à travers un lien symbolique, aucun fichier n'est lu. - **Répertoire courant virtuel** : `abspath` et `relpath` partent de `getcwd` (`/` au départ) ; `chdir "/projets/app"` le change (sans disque). - **Listes** : `parts`, `parents`, `suffixes` écrivent leurs éléments séparés par `, `. - **Booléens** : `true` / `false`. - **Erreurs** : comme en Python (`ValueError`), l'erreur arrête le script avec un message en français : nom vide, suffixe sans point, chemin qui n'est pas sous la base, mélange absolu/relatif dans `commonpath`… ## Commandes | Syntaxe | Noms français · espagnol · swahili | Rôle | |---|---|---| | `name "Résultat" "Chemin"` | `nom` · `nombre` · `jina` | Dernier élément du chemin (Path.name) : « c.txt » pour a/b/c.txt ; vide pour la racine. | | `stem "Résultat" "Chemin"` | `radical` · `nombre-base` · `jina-msingi` | Nom sans son dernier suffixe (Path.stem) : « archive.tar » pour archive.tar.gz. | | `suffix "Résultat" "Chemin"` | `suffixe` · `sufijo` · `kiambishi` | Dernier suffixe avec son point (Path.suffix) : « .gz » ; vide pour .bashrc. | | `suffixes "Résultat" "Chemin"` | `tous-suffixes` · `sufijos` · `viambishi` | Tous les suffixes, séparés par des virgules (Path.suffixes) : « .tar, .gz ». | | `parent "Résultat" "Chemin"` | `dossier-parent` · `padre` · `mzazi` | Dossier parent (Path.parent) : a/b pour a/b/c ; « . » pour un nom seul. | | `parents "Résultat" "Chemin"` | `dossiers-parents` · `padres` · `wazazi` | Tous les ancêtres, du plus proche au plus lointain (Path.parents). | | `parts "Résultat" "Chemin"` | `parties` · `partes` · `sehemu` | Parties du chemin séparées par des virgules (Path.parts) ; l'ancre vient en premier. | | `part_at "Résultat" "Chemin" position` | `partie-numero` · `parte-numero` · `sehemu-namba` | Une partie du chemin (Path.parts[i]) : 1 = la première, -1 = la dernière. | | `drive "Résultat" "Chemin"` | `lecteur` · `unidad` · `diski` | Lecteur Windows (« C: » ou partage UNC) ; vide en POSIX (Path.drive). | | `root "Résultat" "Chemin"` | `racine-chemin` · `raiz-ruta` · `mzizi` | Racine du chemin (Path.root) : « / » ou « \ » ; vide pour un chemin relatif. | | `anchor "Résultat" "Chemin"` | `ancre` · `ancla` · `nanga` | Lecteur + racine (Path.anchor) : « C:\ », « / ». | | `depth "Résultat" "Chemin"` | `profondeur` · `profundidad` · `kina` | Nombre d'éléments du chemin sans l'ancre (a/b/c donne 3). | | `is_absolute "Résultat" "Chemin"` | `est-absolu` · `es-absoluta` · `ni-kamili` | true si le chemin est absolu (Path.is_absolute) ; sous Windows : lecteur ET racine. | | `is_reserved "Résultat" "Chemin"` | `est-reserve` · `es-reservada` · `imehifadhiwa` | true si le nom est réservé par Windows (NUL, CON, COM1…) ; toujours false en POSIX. | | `as_posix "Résultat" "Chemin"` | `en-posix` · `como-posix` · `kama-posix` | Chemin avec des / (Path.as_posix) : C:\a\b devient C:/a/b. | | `as_windows "Résultat" "Chemin"` | `en-windows` · `como-windows` · `kama-windows` | Chemin au format Windows (a/b devient a\b). | | `as_uri "Résultat" "Chemin"` | `en-uri` · `como-uri` · `kama-uri` | Adresse file:// d'un chemin absolu (Path.as_uri), encodée en UTF-8. | | `joinpath "Résultat" "a" "b" ["c" …]` | `joindre` · `unir-ruta` · `unganisha-njia` | Assemble jusqu'à 8 morceaux (Path.joinpath ou opérateur /) : un morceau absolu remplace ce qui précède. | | `with_name "Résultat" "Chemin" "nom.ext"` | `avec-nom` · `con-nombre` · `na-jina` | Remplace le dernier élément (Path.with_name). | | `with_stem "Résultat" "Chemin" "radical"` | `avec-radical` · `con-nombre-base` · `na-jina-msingi` | Remplace le nom en gardant l'extension (Path.with_stem). | | `with_suffix "Résultat" "Chemin" ".ext"` | `avec-suffixe` · `con-sufijo` · `na-kiambishi` | Remplace, ajoute ou retire (texte vide) le suffixe (Path.with_suffix). | | `relative_to "Résultat" "Chemin" "Base" [remonter]` | `relatif-a` · `relativa-a` · `jamaa-na` | Chemin relatif à Base (Path.relative_to) ; « remonter » (walk_up) autorise les « .. ». | | `is_relative_to "Résultat" "Chemin" "Base"` | `est-relatif-a` · `es-relativa-a` · `ni-jamaa-na` | true si le chemin est Base ou se trouve dessous (Path.is_relative_to). | | `match "Résultat" "Chemin" "*.txt"` | `motif-correspond` · `coincide` · `lingana` | Motif comparé depuis la droite (Path.match) : * ? [abc] [!abc]. | | `full_match "Résultat" "Chemin" "**/*.py"` | `motif-complet` · `coincide-total` · `lingana-kamili` | Motif sur le chemin entier (Path.full_match, Python 3.13) ; ** = zéro ou plusieurs éléments. | | `equals "Résultat" "A" "B"` | `egaux` · `iguales` · `sawa` | true si les deux chemins sont identiques (sans casse sous Windows). | | `normpath "Résultat" "Chemin"` | `normaliser` · `normalizar` · `sawazisha` | Réduit « . », « .. » et les séparateurs répétés (os.path.normpath). | | `abspath "Résultat" "Chemin" ["Base"]` | `rendre-absolu` · `ruta-absoluta` · `njia-kamili` | Chemin absolu normalisé (os.path.abspath) depuis Base ou le répertoire courant virtuel. | | `relpath "Résultat" "Chemin" ["Début"]` | `relatif-de` · `ruta-relativa` · `njia-jamaa` | Chemin relatif depuis Début (os.path.relpath). | | `commonpath "Résultat" "a" "b" ["c" …]` | `commun` · `ruta-comun` · `njia-ya-pamoja` | Plus long dossier commun de 2 à 8 chemins (os.path.commonpath). | | `splitext "$racine" "$extension" "Chemin"` | `scinder-ext` · `dividir-ext` · `gawa-kiambishi` | Sépare racine et extension (os.path.splitext). | | `split "$tete" "$queue" "Chemin"` | `scinder` · `dividir-ruta` · `gawa-njia` | Sépare dossier et dernier élément (os.path.split). | | `basename "Résultat" "Chemin"` | `queue` · `ultimo` · `wa-mwisho` | Dernier élément (os.path.basename) ; vide si le chemin finit par un séparateur. | | `dirname "Résultat" "Chemin"` | `tete` · `cabeza` · `kichwa` | Tout sauf le dernier élément (os.path.dirname). | | `set_style auto/posix/windows` | `style-chemin` · `estilo-ruta` · `mtindo-njia` | Choisit la lecture des chemins : auto (défaut), posix ou windows. | | `getcwd "Résultat"` | `dossier-courant` · `directorio-actual` · `saraka-ya-sasa` | Répertoire courant virtuel (os.getcwd) : « / » au départ. | | `chdir "Chemin"` | `aller-dans` · `ir-a` · `nenda` | Change le répertoire courant virtuel (os.chdir, sans disque). | Le nom Python est le premier nom de chaque commande ; le nom qualifié (`golib.name`) fonctionne toujours. ## Différences avec pathlib | pathlib | golib | |---|---| | objets `Path` | des textes (un chemin est toujours un texte) | | `p / "x"` | `joinpath "$r" "$p" "x"` | | `Path.exists()`, `read_text()`, `mkdir()`, `iterdir()`… | **absents** (golib ne touche pas au disque) : utilisez la bibliothèque `fichiers` avec le chemin calculé par golib | | `Path.cwd()`, `os.getcwd()` | `getcwd` : répertoire courant **virtuel** | | `Path.resolve()` | `abspath` (résolution lexicale ; pas de liens symboliques) | | `os.path.isabs` | `is_absolute` (règle de `Path.is_absolute` : sous Windows, lecteur **et** racine) | | `Path.match` | `match` (règle de Python 3.12 : `**` y vaut `*`) ; `full_match` suit Python 3.13 | | `Path.expanduser`, `os.path.expandvars` | absents (pas d'environnement) | | `Path.is_relative_to`, `relative_to(walk_up=True)` | `is_relative_to`, `relative_to … remonter` | | `Path.with_segments`, sous-classes | absents | ## Vérification - `studio/tests/path-engine.test.ts` compare le moteur (`studio/src/model/path-engine.ts`) à **CPython 3.12.3** sur 2 405 opérations et les propriétés de 73 chemins POSIX et Windows : mêmes résultats, y compris les cas limites (`//a`, `C:a`, `\\serveur\partage`, `.bashrc`, `a.`, `NUL.txt`, `..\x`, `.\C:x`). Les vecteurs sont générés par `python3 scripts/gen-path-reference.py`. - `studio/tests/library-golib.test.ts` : validité de la bibliothèque, aucun conflit de nom avec les commandes intégrées, résultats en 4 langues, chemins Windows, erreurs. - `full_match` suit Python 3.13 et n'a pas pu être comparé à CPython 3.13 (non disponible ici) : il est vérifié par des cas écrits à la main. ## Limites - **Le port Dart n'est pas fait** : comme Randomy, les commandes fonctionnent dans l'aperçu du Studio, pas encore dans l'application Flutter générée (Dart n'est pas compilable dans l'environnement de développement ; les tables `scripts/generate-dart-script-tables.mjs` n'ont pas été régénérées). - `joinpath` et `commonpath` acceptent 8 chemins au plus dans la bibliothèque (limite de 9 arguments des macros) ; les commandes intégrées `chemin-assembler` et `chemin-commun` n'ont pas cette limite. - Un texte sans lecteur ni antislash est lu en POSIX : pour des chemins Windows avec des `/` seulement (`a/b/c`), utilisez `set_style windows`. - Traductions espagnoles et swahilies non relues par des locuteurs natifs. - Les noms réservés Windows (`is_reserved`) suivent la liste de Python 3.12 (`CON`, `PRN`, `AUX`, `NUL`, `COM1-9`, `LPT1-9`, `CONIN$`, `CONOUT$` et leurs variantes exposants). --- # Bibliothèque `requeto` — requêtes HTTP — v1.0.0 Source : https://docs.berkios.online/modules/requeto/ · Section : Modules · Documentation officielle BERKIOS (https://docs.berkios.online) 8 commandes pour appeler une API HTTP(S) depuis BERKIOS CODE sans répéter les mêmes lignes : **adresse vérifiée**, **extraction JSON avec valeur par défaut**, **réponse JSON indentée**, **paramètres d'adresse encodés** et **cache temporisé**. Chaque commande existe en **français**, **anglais** et **espagnol**. Permissions demandées : `reseau` (commande intégrée `requete`) et `stockage` (cache : `stocker`, `lire`, `oublier`). Ce sont de simples macros vers les commandes intégrées `requete`, `extraire`, `valider-json`, `formater-json`, `encoder-url`, `stocker`… : le Studio et l'application Flutter se comportent donc de la même façon. ## Une requête en quatre lignes ```text quand clic set "$u" "https://jsonplaceholder.typicode.com/posts" parametre-url "$u" "userId" "Champ_utilisateur" # ignoré si le champ est vide obtenir "$u" "$reponse" champ-ou "$reponse" "0.title" "(aucun résultat)" "Titre" ``` `parametre-url` ajoute `?userId=1` (ou `&userId=1` s'il y a déjà des paramètres) ; nom et valeur sont encodés. Avec `obtenir-cache "$u" 60 "$reponse"`, la réponse à cette adresse est relue pendant 60 secondes sans nouvelle requête. ## Commandes | Noms (fr · en · es) | Syntaxe | Effet | |---|---|---| | `obtenir` · `get-url` · `obtener` | `obtenir "https://…" "Résultat"` | Requête GET : vérifie que l'adresse est http(s), puis écrit le corps de la réponse dans le résultat. L'adresse peut être un texte, un composant ou une $variable ; {variable} et {variable:url} y sont remplacés. | | `obtenir-json` · `get-json` · `obtener-json` | `obtenir-json "https://…" "chemin.dans.le.json" "Résultat"` | Requête GET puis extraction d'un champ du JSON reçu (« items.0.nom »). Texte vide si le champ est absent ; erreur si la réponse n'est pas du JSON. | | `obtenir-formate` · `get-pretty` · `obtener-formateado` | `obtenir-formate "https://…" "Résultat"` | Requête GET ; si la réponse est du JSON, elle est écrite indentée (lisible dans un champ de texte), sinon telle quelle. | | `champ-ou` · `field-or` · `campo-o` | `champ-ou "$reponse" "chemin" "valeur par défaut" "Résultat"` | Lit un champ d'un JSON déjà reçu (chemin à points, indices de tableau permis) ; écrit la valeur par défaut quand le champ est absent, null ou vide, ou quand la source n'est pas du JSON valide (sans erreur). | | `parametre-url` · `url-param` · `parametro-url` | `parametre-url "$url" "nom" "valeur"` | Ajoute « nom=valeur » (nom et valeur encodés) à l'adresse contenue dans la variable : « ? » si elle n'a pas encore de paramètres, « & » sinon. Si le nom ou la valeur est vide, l'adresse reste inchangée (filtre facultatif d'un formulaire). Peut être répété. | | `obtenir-cache` · `get-cached` · `obtener-cache` | `obtenir-cache "https://…" 60 "Résultat"` | GET avec cache : si la réponse mémorisée pour cette adresse a moins de N secondes, elle est relue sans requête ; sinon la requête est faite et mémorisée. Le cache est propre à chaque adresse (paramètres compris) ; N = 0 le désactive. | | `age-cache` · `cache-age` · `edad-cache` | `age-cache "https://…" "Résultat"` | Écrit l'âge en secondes de la réponse mémorisée par obtenir-cache pour cette adresse (0 = obtenue à l'instant), ou -1 s'il n'y en a pas. | | `vider-cache` · `clear-cache` · `vaciar-cache` | `vider-cache "https://…"` | Oublie la réponse mémorisée par obtenir-cache pour cette adresse : le prochain appel refera la requête. | L'adresse d'une commande `obtenir*` peut être un texte, un composant ou une `$variable`. Dans le texte, `{variable}` est remplacé par sa valeur et `{variable:url}` par sa valeur **encodée** (comme avec la commande intégrée `requete`). Pour assembler base et chemin, `parametre-url` se combine avec les commandes intégrées `joindre-url "Base" "Chemin" "Résultat"`, `extraire-parametre-url` et `valider-json`. ## Ce que fait la bibliothèque - **Adresse vérifiée** : `obtenir`, `obtenir-json`, `obtenir-formate` et `obtenir-cache` refusent, **avant toute requête**, une adresse qui n'est pas `http://` ou `https://` (`file:`, `ftp:`, `javascript:`, texte libre…) avec le message « Requeto : adresse http(s) invalide. ». - **Erreur réseau** : le script s'arrête sur la ligne en cause avec le message de l'hôte ; les lignes suivantes ne sont pas exécutées. - **`champ-ou`** : la valeur par défaut est écrite quand le champ est absent, `null` ou vide, ou quand la source n'est pas du JSON valide (page d'erreur HTML, texte…) — sans interrompre le script ; `0` et `false` sont de vraies valeurs et sont conservées. À l'inverse, `obtenir-json` s'arrête avec une erreur si la réponse n'est pas du JSON. - **`parametre-url`** : si le nom ou la valeur est vide, l'adresse reste inchangée — pratique pour des filtres facultatifs de formulaire. L'adresse ne doit pas déjà se terminer par `?` ou `&`. - **`obtenir-cache "adresse" N "Résultat"`** : mémorise la réponse et l'instant de la requête sous `requeto:` et `requeto::t` (commande intégrée `stocker`, qui persiste d'une session à l'autre quand l'hôte le permet). Si la réponse à **cette adresse** (paramètres compris) a moins de `N` secondes, elle est relue sans requête ; `N = 0` désactive le cache. Deux adresses différentes ne partagent jamais d'entrée. `age-cache "adresse" "Résultat"` donne l'âge de l'entrée (secondes, `-1` si absente) ; `vider-cache "adresse"` oublie l'entrée ; il n'existe pas de « tout vider » (BERKIOS CODE ne sait pas lister les clés mémorisées). - **`obtenir-formate`** : la réponse est indentée seulement si c'est du JSON valide, sinon elle est écrite telle quelle. ## Limites assumées - **GET uniquement.** La seule commande réseau de BERKIOS CODE est `requete`, qui fait un GET sans en-têtes ni corps. Requeto n'ajoute donc ni POST/PUT/PATCH/DELETE, ni en-têtes (`Authorization`, `X-API-Key`), ni lecture du **code HTTP** ou des en-têtes de réponse. Les commandes `http-post`, `http-put`… du registre système sont des commandes du Bridge, pas encore appelables depuis le code d'un composant. - **Pas de secret dans l'adresse.** Une clé passée en paramètre (`?api_key=…`) apparaît dans l'adresse, les journaux des serveurs et l'historique réseau ; n'y mettez que des clés publiques ou à portée limitée. - **Pas de nouvel essai automatique** : une erreur arrête le script, elle ne peut pas être interceptée. - **Navigateur** : dans le Studio web, l'API appelée doit autoriser CORS ; l'application Flutter n'a pas cette contrainte. - Le cache stocke la réponse brute : ne pas y mettre de données sensibles. - Tests : `studio/tests/library-requeto.test.ts` (réseau simulé). Aucun appel à une vraie API n'a été fait pendant le développement. --- # Bibliothèque `easyapi` — créer des API REST en BERKIOS CODE — v1.1.0 Source : https://docs.berkios.online/modules/easyapi/ · Section : Modules · Documentation officielle BERKIOS (https://docs.berkios.online) 27 commandes pour définir une **API REST** dans un script, la **tester sans réseau** (ou contre un vrai serveur), en tirer la description **OpenAPI 3.1** et **exporter un serveur Node.js autonome** (un seul fichier, aucune dépendance). Chaque commande existe en **anglais**, **français**, **espagnol** et **swahili** (noms swahili non relus par des locuteurs natifs). Permissions demandées : `fichiers` (pour `save-server` et `save-openapi`, qui utilisent `telecharger`) et `reseau` (pour `call-api` sur un serveur désigné par `set-server`). Ce sont de simples macros vers les 19 commandes intégrées de la catégorie **« API REST »** (`api-creer`, `api-ressource`, `api-route`… voir la leçon formation/08) : le moteur est dans le Studio (`studio/src/model/rest-api-engine.ts`), pas dans la bibliothèque. ## Une API en cinq lignes ```text quand clic easy-api "Boutique" "produits" "nom:texte*, prix:nombre, sku:texte*!" protect-api make-key "mobile" "ecriture" "$cle" # le secret s'affiche une seule fois call-api "$r" "POST" "/api/produits" '{"nom":"Stylo","sku":"A1","prix":2}' "$cle" status-code "$code" # 201 save-server "serveur.mjs" # télécharge le serveur à déployer ``` `easy-api` crée l'API **Boutique** et la ressource `produits` avec ses six routes : `GET /api/produits`, `POST /api/produits`, `GET|PUT|PATCH|DELETE /api/produits/:id`. ## Ce que fait le moteur - **Validation** à chaque écriture : types `texte`, `nombre`, `entier`, `booleen`, `date` (AAAA-MM-JJ), `email` ; `*` = obligatoire, `!` = unique. Champ inconnu, type faux ou doublon → `422` ou `409` avec le détail par champ. - **Liste** : `?limit=` (1–1000, 50 par défaut), `?offset=`, **`?after=` (pagination par curseur : la réponse porte `next_after` tant qu'il reste des pages)**, `?sort=champ` ou `?sort=-champ`, `?q=` (recherche dans les textes), `?champ=valeur` (filtre). Un filtre inconnu est une erreur `400`, pas ignoré. - **Routes personnalisées** : `route`, `get-route`, `post-route`, `put-route`, `patch-route`, `delete-route`. La réponse est du JSON si elle commence par `{` ou `[`, sinon du texte ; `{param}`, `{query.x}`, `{body.x}`, `{method}`, `{path}`, `{date}` sont remplacés à chaque requête. Dans une réponse JSON, les valeurs injectées restent des chaînes : aucune injection possible. - **Sécurité** : `protect-api` exige une clé (`X-API-Key` ou `Authorization: Bearer`) sur **toute** requête, même vers une route inconnue, sauf `/health`, `/openapi.json` et les routes marquées `public`. Rôles `lecture` (GET), `ecriture` (+ POST/PUT/PATCH/DELETE), `admin`. Les secrets ne sont **jamais** écrits dans la définition ni dans le serveur exporté. - **CORS** : seules les origines listées par `allow-origin` sont autorisées ; `*` doit être écrit explicitement. - **Débit** : `rate-limit N` → `429` avec `Retry-After` au-delà de N requêtes par minute et par client. - **Import en masse** : `POST /ressource/bulk` (tableau JSON ou `{ "data": [...] }`, 1 000 enregistrements au plus par requête) est **atomique** : tout est créé ou rien, avec l'indice de l'enregistrement fautif. `seed-data` accepte jusqu'à 100 000 enregistrements par appel. - Corps limité à 5 Mo, 1 000 000 d'enregistrements par ressource (`507` au-delà ; `EASYAPI_MAX_RECORDS` sur le serveur), 50 ressources, 200 routes, 20 clés ; en-têtes `Cache-Control: no-store` et `X-Content-Type-Options: nosniff`. ## Tester, documenter, déployer - `call-api "$r" "GET" "/api/produits"` appelle l'API **dans le Studio, sans réseau**, avec le **même routeur** que le serveur exporté ; `status-code` et `response-header` lisent le code et les en-têtes. - `set-server "https://api.monsite.com"` désigne un **vrai serveur** : `call-api` envoie alors de vraies requêtes HTTP (mêmes arguments, mêmes codes, `status-code` et `response-header` lisent la réponse du serveur). `set-server` sans argument revient à l'API d'essai : un même script sert à l'essai et à la production. Le navigateur du Studio impose le CORS : le serveur doit autoriser l'origine (`allow-origin`). - `openapi` / `save-openapi "openapi.json"` : description OpenAPI 3.1 (Swagger UI, Postman, générateurs de clients). Elle est aussi servie par le serveur sur `/api/openapi.json`. - `export-spec` / `import-spec` : sauvegarde et rechargement de la définition (sans données ni secrets). - `save-server "serveur.mjs"` (ou `server-code "$code"`) : serveur **Node.js 18+**, sans dépendance. ```text EASYAPI_KEYS="mobile:write:UnSecretLongEtAleatoire1234" PORT=3000 HOST=0.0.0.0 node serveur.mjs ``` | Variable | Rôle | |---|---| | `PORT` | port d'écoute (3000) | | `HOST` | interface (127.0.0.1 ; `0.0.0.0` dans un conteneur ou derrière un proxy) | | `DATA_FILE` | instantané JSON des données (`./donnees.json`) ; chaque modification est ajoutée au **journal** `DATA_FILE.journal` (écriture groupée toutes les 100 ms) puis fusionnée dans l'instantané au démarrage, à l'arrêt et quand le journal dépasse `EASYAPI_JOURNAL_MB` (64 par défaut) | | `EASYAPI_MAX_RECORDS` | enregistrements maximum par ressource (1 000 000) ; compter environ 1 Ko de mémoire par enregistrement | | `EASYAPI_KEYS` | clés `nom:role:secret` séparées par `;` (rôle `read`, `write` ou `admin`, secret de 16 caractères ou plus) | | `TRUST_PROXY=1` | lit l'adresse du client dans `X-Forwarded-For` (proxy de confiance seulement) | Après un arrêt brutal (kill, coupure), le journal est rejoué au redémarrage : on ne perd que les 100 dernières millisecondes. Une dernière ligne tronquée est ignorée ; une ligne corrompue au milieu du journal **empêche le démarrage** (rien n'est écrasé). Une API protégée **refuse de démarrer** sans clé. Placez toujours le serveur derrière **HTTPS** (Caddy, nginx…). ## Limites assumées - Les données d'essai du Studio vivent en mémoire pour la session d'aperçu et ne sont pas enregistrées dans le projet : la définition, elle, est le script (ou `export-spec`). `easy-api` / `new-api` repartent de zéro. - Pas de relations entre ressources ni de transactions (sauf le lot `/bulk`, atomique). **Gros volumes** : tout reste en mémoire (≈ 1 Ko par enregistrement, 1 000 000 au plus par ressource). Accès par id, unicité et filtres d'égalité (`?champ=valeur`) sont **indexés** ; le tri est mis en cache par champ ; la pagination par curseur (`after`) ne coûte pas plus cher à la page 10 000 qu'à la première. La recherche `?q=` parcourt les textes (linéaire) et un lot d'écritures simultanées reste sérialisé sur un seul processus. Au-delà du million, de plusieurs serveurs ou de besoins de requêtes complexes : une vraie base. - L'instantané est relu avec `JSON.parse` : un fichier de données de plusieurs centaines de Mo demande autant de mémoire à la lecture. - Pas de comptes utilisateurs : l'accès se règle par clés d'API. - Le Studio ne peut pas ouvrir de port réseau : on teste avec `call-api`, puis on déploie le serveur exporté. - **Flutter** : les 19 commandes `api-*` (donc toute la bibliothèque) existent dans l'application générée (`bridge/runtime/berkios_rest_api.dart`, moteur Dart pur) ; `set-server` + `call-api` y envoient de vraies requêtes HTTP (`dart:io`). Le moteur Dart est un **simulateur local en mémoire** : mêmes règles et mêmes messages, mais filtres d'égalité sans index. **Ce code Dart n'a pas été compilé** (ni Dart ni Flutter dans l'environnement de développement) : il est vérifié par des tests statiques et par le gabarit de serveur qu'il assemble ; à compiler au premier `flutter build`. ## Application client-serveur L'accueil du Studio propose la carte **Application client-serveur** : projet autonome (client multiplateforme) marqué `architecture: "client-serveur"`, relié à un serveur qui héberge données et API REST. Ajoutez EasyAPI pour écrire l'API en BERKIOS CODE, exportez le serveur, puis appelez-le depuis le client. ## Exemple complet `examples/application/api/client-serveur/` : une application de tâches (client BERKIOS avec easyapi, serveur Node exporté, clé d'API, import en masse, pagination par curseur). Essai sans serveur dans le Studio, puis contre `serveur.mjs`. Généré par `node scripts/build-api-client-serveur-example.mjs`. ## Commandes | Noms (en · fr · es · sw) | Syntaxe | Effet | |---|---|---| | `easy-api · api-rapide · api-facil · api-rahisi` | `easy-api "Boutique" "produits" "nom:texte*, prix:nombre"` | Crée en une ligne une API complète : son nom et une première ressource avec ses 6 routes REST (liste, lecture, création, remplacement, modification, suppression) et la validation des champs. | | `new-api · nouvelle-api · nueva-api · api-mpya` | `new-api "Nom" ["/prefixe"] ["1.0.0"]` | Commence une nouvelle API (efface la précédente) ; préfixe /api et version 1.0.0 par défaut. | | `resource · ressource · recurso · rasilimali` | `resource "produits" "nom:texte*, prix:nombre, sku:texte*!"` | Déclare une ressource REST : GET/POST /produits et GET/PUT/PATCH/DELETE /produits/:id. Types : texte, nombre, entier, booleen, date, email ; * obligatoire, ! unique. | | `route · chemin-api · ruta · njia` | `route "GET" "/salut/:nom" "Bonjour {nom}" [statut] [public]` | Ajoute une route personnalisée. Réponse JSON si le texte commence par { ou [, sinon texte brut ; {param}, {query.x}, {body.x} sont remplacés à chaque requête. | | `get-route · route-get · ruta-get · njia-get` | `get-route "/chemin" "réponse" [statut] [public]` | Raccourci de route pour la méthode GET : get-route "/chemin" "réponse" équivaut à route "GET" "/chemin" "réponse". | | `post-route · route-post · ruta-post · njia-post` | `post-route "/chemin" "réponse" [statut] [public]` | Raccourci de route pour la méthode POST : post-route "/chemin" "réponse" équivaut à route "POST" "/chemin" "réponse". | | `put-route · route-put · ruta-put · njia-put` | `put-route "/chemin" "réponse" [statut] [public]` | Raccourci de route pour la méthode PUT : put-route "/chemin" "réponse" équivaut à route "PUT" "/chemin" "réponse". | | `patch-route · route-patch · ruta-patch · njia-patch` | `patch-route "/chemin" "réponse" [statut] [public]` | Raccourci de route pour la méthode PATCH : patch-route "/chemin" "réponse" équivaut à route "PATCH" "/chemin" "réponse". | | `delete-route · route-delete · ruta-delete · njia-delete` | `delete-route "/chemin" "réponse" [statut] [public]` | Raccourci de route pour la méthode DELETE : delete-route "/chemin" "réponse" équivaut à route "DELETE" "/chemin" "réponse". | | `seed-data · donnees-api · datos-api · data-ya-api` | `seed-data "produits" '[{"nom":"Stylo","sku":"A1"}]'` | Insère des enregistrements de démonstration (tableau JSON) dans une ressource, validés comme par POST ; tout ou rien. | | `protect-api · securiser-api · proteger-api · linda-api` | `protect-api [oui\|non]` | Exige une clé d'API (X-API-Key ou Authorization: Bearer) pour toute requête, sauf /health, /openapi.json et les routes « public ». | | `make-key · creer-cle · crear-clave · tengeneza-ufunguo` | `make-key "mobile" "lecture\|ecriture\|admin" "Résultat"` | Crée une clé d'API et écrit son secret dans le résultat (à copier tout de suite : il n'est ni exporté ni relisible). | | `allow-origin · autoriser-origine · permitir-origen · ruhusu-asili` | `allow-origin "https://monsite.com, https://app.monsite.com"` | Autorise des origines de navigateur précises (CORS). Aucune origine par défaut ; « * » doit être écrit explicitement. | | `rate-limit · limiter-debit · limitar-tasa · punguza-kasi` | `rate-limit 120` | Limite le nombre de requêtes par minute et par client (0 = aucune) ; au-delà, la réponse est 429 avec Retry-After. | | `set-server · serveur-api · servidor-api · seva-ya-api` | `set-server "https://api.monsite.com"` | Désigne le serveur d'API réel : call-api envoie alors ses requêtes HTTP à ce serveur au lieu de l'API d'essai ; sans argument, retour à l'API locale. | | `call-api · appeler-api · llamar-api · piga-api` | `call-api "Résultat" "GET" "/api/produits" ["corps JSON"] ["cle"]` | Appelle l'API sans réseau (même routeur que le serveur exporté) et écrit le corps de la réponse ; le code HTTP se lit avec status-code. | | `status-code · code-http · codigo-http · msimbo-http` | `status-code "Résultat"` | Écrit le code HTTP de la dernière réponse de call-api (200, 201, 404, 422…). | | `response-header · entete-reponse · cabecera-respuesta · kichwa-jibu` | `response-header "Résultat" "Location"` | Écrit un en-tête de la dernière réponse de call-api (texte vide s'il est absent). | | `list-routes · lister-routes · listar-rutas · orodhesha-njia` | `list-routes "Résultat"` | Liste les routes de l'API (« METHODE /chemin »), séparées par des virgules. | | `openapi · documenter-api · documentar-api · andika-api` | `openapi "Résultat"` | Écrit la description OpenAPI 3.1 de l'API (JSON), utilisable avec Swagger UI, Postman ou un générateur de clients. | | `count-records · compter-enregistrements · contar-registros · hesabu-rekodi` | `count-records "Résultat" "produits"` | Nombre d'enregistrements d'une ressource dans les données d'essai. | | `clear-data · vider-donnees · vaciar-datos · futa-data` | `clear-data ["produits"]` | Vide les données d'essai d'une ressource (ou de toutes) sans toucher à la définition de l'API. | | `export-spec · exporter-definition · exportar-definicion · hamisha-ufafanuzi` | `export-spec "Résultat"` | Écrit la définition de l'API en JSON (sans données ni secrets) pour la sauvegarder ou la partager. | | `import-spec · importer-definition · importar-definicion · leta-ufafanuzi` | `import-spec "Source"` | Recharge une définition produite par export-spec (données d'essai remises à zéro ; clés à recréer). | | `server-code · code-serveur · codigo-servidor · msimbo-seva` | `server-code "Résultat"` | Écrit le code d'un serveur Node.js autonome pour cette API : un fichier, aucune dépendance, données JSON sur disque, clés lues dans EASYAPI_KEYS. | | `save-server · enregistrer-serveur · guardar-servidor · hifadhi-seva` | `save-server "serveur.mjs"` | Télécharge le serveur Node.js autonome de l'API dans un fichier. Lancez-le avec : node serveur.mjs | | `save-openapi · enregistrer-openapi · guardar-openapi · hifadhi-openapi` | `save-openapi "openapi.json"` | Télécharge la description OpenAPI 3.1 de l'API dans un fichier. | --- # Bibliothèque `pdflab` — générer des PDF par le code Source : https://docs.berkios.online/modules/pdflab/ · Section : Modules · Documentation officielle BERKIOS (https://docs.berkios.online) Clone de **ReportLab** (Python) en JavaScript pur, sans dépendance. Le moteur est dans `pdflab/` ; la bibliothèque BERKIOS `pdflab.bkl` (44 commandes, fr/en) l'expose aux composants via la commande native `pdf …`. ## Cycle d'un document 1. `pdf-nouveau` (réinitialise) — 2. réglages (`pdf-format`, `pdf-orientation`, `pdf-marges`, `pdf-auteur`, `pdf-entete`, `pdf-pied`, `pdf-numerotation`, `pdf-filigrane`, `pdf-proteger`, `pdf-police`, `pdf-couleur`, `pdf-nom`, `pdf-proteger`) — 3. contenu (`pdf-titre`, `pdf-sous-titre`, `pdf-section`, `pdf-texte`, `pdf-note`, `pdf-bloc-citation`, `pdf-puces`, `pdf-numerotee`, `pdf-tableau`, `pdf-total`, `pdf-fiche`, `pdf-image`, `pdf-graphique`, `pdf-code-barres`, `pdf-qr`, `pdf-champ`, `pdf-case`, `pdf-liste`, `pdf-code`, `pdf-espace`, `pdf-ligne`, `pdf-saut-page`, `pdf-sommaire`) — 4. sortie (`pdf-generer`, `pdf-pages`, `pdf-apercu`, `pdf-imprimer`, `pdf-telecharger`, `pdf-ouvrir`). Le texte accepte le mini-balisage de ReportLab : ``, ``, ``, ``, ``, `
`, entités HTML. Un tableau se saisit `A;B|1;2|3;4` (lignes séparées par `|`, colonnes par `;`). Les pieds et en-têtes acceptent `{page}`, `{pages}`, `{date}`, `{titre}`. ## Exemple ``` pdf-nouveau pdf-titre "Facture 2026-014" pdf-tableau "Désignation;Qté;Prix|Clavier;2;40|Souris;1;15" pdf-total "Total;;95" pdf-numerotation "Page {page} / {pages}" pdf-apercu ``` L'aperçu s'ouvre dans une fenêtre avec **Imprimer** et **Télécharger**. ## API JavaScript (navigateur ou Node) ```js import { SimpleDocTemplate, Paragraph, Table, getSampleStyleSheet, cm } from "pdflab/dist/pdflab.mjs"; const ss = getSampleStyleSheet(); const bytes = new SimpleDocTemplate("a.pdf").build([new Paragraph("Bonjour", ss.Title), new Table([["A","B"],["1","2"]])]); ``` Navigateur : `