/* * CookieCode - apprendre l'algorithmique avec des recettes de cuisine. * Microlibrairie sans dépendance, compatible navigateur, CDN et Node/CommonJS. */ ((root, factory) => { if (typeof module === "object" && module.exports) { module.exports = factory(); } else { root.CookieCode = factory(); } })(typeof globalThis !== "undefined" ? globalThis : this, () => { var configuration = { sortie: "console", afficherNotions: true, }; function configurer(options) { options = options || {}; if (Object.hasOwn(options, "sortie")) { configuration.sortie = options.sortie; } if (Object.hasOwn(options, "afficherNotions")) { configuration.afficherNotions = Boolean(options.afficherNotions); } return CookieCode; } function texte(valeur, defaut) { if (valeur === undefined || valeur === null || valeur === "") { return defaut || ""; } return String(valeur); } function echapperHTML(valeur) { return texte(valeur) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } function creerElement(type, nom, quantite, unite, valeur) { if (!nom && nom !== 0) { throw new Error( "CookieCode : un nom est obligatoire pour creer un " + type + ".", ); } return { type: type, nom: texte(nom), quantite: quantite, unite: unite, valeur: valeur, }; } function ingredient(nom, quantite, unite) { return creerElement("ingredient", nom, quantite, unite); } function materiel(nom) { return creerElement("materiel", nom); } function constante(nom, valeur) { return creerElement("constante", nom, undefined, undefined, valeur); } function preparation(nom) { return { type: "preparation", nom: texte(nom, "preparation"), etat: {}, definir: function (cle, valeur) { this.etat[cle] = valeur; return this; }, est: function (valeur) { return ( this.etat.texture === valeur || this.etat.etat === valeur || this.etat[valeur] === true ); }, }; } function nomDe(element) { if (element && typeof element === "object" && element.nom !== undefined) { return texte(element.nom); } return texte(element); } function quantiteDe(element, quantite, unite) { var q = quantite !== undefined ? quantite : element?.quantite; var u = unite !== undefined ? unite : element?.unite; if (q === undefined || q === null || q === "") { return ""; } return texte(q) + (u ? " " + texte(u) : ""); } function formatElement(element, quantite, unite) { var quantiteTexte = quantiteDe(element, quantite, unite); var nom = nomDe(element); return quantiteTexte ? quantiteTexte + " de " + nom : nom; } function conditionLisible(condition) { if (typeof condition === "string") { return condition; } if (typeof condition === "boolean") { return condition ? "condition vraie" : "condition fausse"; } if (typeof condition === "function") { return "condition fournie"; } return "condition"; } function evaluerCondition(condition) { if (typeof condition === "function") { return Boolean(condition()); } if (typeof condition === "boolean") { return condition; } return true; } function creerEtape(texteEtape, notion, enfants) { return { texte: texteEtape, notion: notion, enfants: enfants || [], }; } function Recette(nom) { if (!nom && nom !== 0) { throw new Error("CookieCode : une recette doit avoir un nom."); } this.nom = texte(nom); this.etapes = []; this.notions = { programme: true, variables: [], constantes: [], fonctions: [], boucles: false, conditions: false, sequence: true, }; } Recette.prototype._noterFonction = function (nom) { if (this.notions.fonctions.indexOf(nom) === -1) { this.notions.fonctions.push(nom); } }; Recette.prototype._noterVariable = function (nom) { if (nom && this.notions.variables.indexOf(nom) === -1) { this.notions.variables.push(nom); } }; Recette.prototype._noterConstante = function (nom) { if (nom && this.notions.constantes.indexOf(nom) === -1) { this.notions.constantes.push(nom); } }; Recette.prototype._ajouterEtape = function (texteEtape, notion, enfants) { this.etapes.push(creerEtape(texteEtape, notion, enfants)); return this; }; Recette.prototype.prendre = function (nom, quantite, unite) { this._noterVariable(nomDe(nom)); this._noterFonction("prendre"); return this._ajouterEtape( "Prendre " + formatElement(nom, quantite, unite) + ".", "variable", ); }; Recette.prototype.utiliser = function (outil) { this._noterConstante(nomDe(outil)); this._noterFonction("utiliser"); return this._ajouterEtape("Utiliser " + nomDe(outil) + ".", "constante"); }; Recette.prototype.ajouter = function (element, quantite, unite) { this._noterFonction("ajouter"); if (element && element.type === "ingredient") { this._noterVariable(element.nom); } return this._ajouterEtape( "Ajouter " + formatElement(element, quantite, unite) + ".", "fonction", ); }; Recette.prototype.retirer = function (element) { this._noterFonction("retirer"); return this._ajouterEtape("Retirer " + nomDe(element) + ".", "fonction"); }; Recette.prototype.couper = function (element, forme) { this._noterFonction("couper"); return this._ajouterEtape( "Couper " + nomDe(element) + (forme ? " en " + texte(forme) : "") + ".", "fonction", ); }; Recette.prototype.melanger = function () { this._noterFonction("melanger"); return this._ajouterEtape("Melanger.", "fonction"); }; Recette.prototype.verser = function (contenu, contenant) { this._noterFonction("verser"); return this._ajouterEtape( "Verser " + nomDe(contenu) + (contenant ? " dans " + nomDe(contenant) : "") + ".", "fonction", ); }; Recette.prototype.chauffer = function (element, temperature) { this._noterFonction("chauffer"); return this._ajouterEtape( "Chauffer " + nomDe(element) + (temperature ? " a " + nomDe(temperature) : "") + ".", "fonction", ); }; Recette.prototype.cuire = function (duree, unite) { this._noterFonction("cuire"); return this._ajouterEtape( "Cuire" + (duree ? " pendant " + texte(duree) + (unite ? " " + texte(unite) : "") : "") + ".", "fonction", ); }; Recette.prototype.attendre = function (duree, unite) { this._noterFonction("attendre"); return this._ajouterEtape( "Attendre " + texte(duree) + (unite ? " " + texte(unite) : "") + ".", "fonction", ); }; Recette.prototype.repeter = function (nombre, action) { this.notions.boucles = true; this._noterFonction("repeter"); var bloc = new Recette("bloc repeter"); if (typeof action === "function") { action(bloc); } this._fusionnerNotions(bloc); return this._ajouterEtape( "Repeter " + texte(nombre) + " fois :", "boucle", bloc.etapes, ); }; Recette.prototype.si = function (condition, action, sinonAction) { this.notions.conditions = true; this._noterFonction("si"); var bloc = new Recette("bloc si"); var blocSinon = new Recette("bloc sinon"); var conditionVraie = evaluerCondition(condition); if (conditionVraie && typeof action === "function") { action(bloc); } if (!conditionVraie && typeof sinonAction === "function") { sinonAction(blocSinon); } this._fusionnerNotions(bloc); this._fusionnerNotions(blocSinon); var enfants = bloc.etapes; if (blocSinon.etapes.length > 0) { enfants = enfants.concat([ creerEtape("Sinon :", "condition", blocSinon.etapes), ]); } return this._ajouterEtape( "Si " + conditionLisible(condition) + " :", "condition", enfants, ); }; Recette.prototype.servir = function (element) { this._noterFonction("servir"); this._ajouterEtape( "Servir" + (element ? " " + nomDe(element) : "") + ".", "fonction", ); return this.afficher(); }; Recette.prototype.afficher = function () { var cible; if (configuration.sortie === "console" || !configuration.sortie) { if (typeof console !== "undefined" && console.log) { console.log(this.toText()); } return this; } if ( typeof configuration.sortie === "string" && typeof document !== "undefined" ) { cible = document.querySelector(configuration.sortie); if (cible) { cible.innerHTML = this.toHTML(); } } return this; }; Recette.prototype._fusionnerNotions = function (autreRecette) { autreRecette.notions.variables.forEach((nom) => { this._noterVariable(nom); }); autreRecette.notions.constantes.forEach((nom) => { this._noterConstante(nom); }); autreRecette.notions.fonctions.forEach((nom) => { this._noterFonction(nom); }); this.notions.boucles = this.notions.boucles || autreRecette.notions.boucles; this.notions.conditions = this.notions.conditions || autreRecette.notions.conditions; }; Recette.prototype._lignesEtapes = function (etapes, prefixe, indentation) { var lignes = []; etapes.forEach(function (etape, index) { var numero = prefixe ? prefixe + "." + (index + 1) : String(index + 1); lignes.push(indentation + numero + ". " + etape.texte); if (etape.enfants && etape.enfants.length > 0) { lignes = lignes.concat( this._lignesEtapes(etape.enfants, numero, indentation + " "), ); } }, this); return lignes; }; Recette.prototype._lignesNotions = function () { var lignes = [ "", "Notions utilisees :", "- Recette = programme", "- Sequence = les etapes sont executees dans l'ordre", ]; if (this.notions.variables.length > 0) { lignes.push( "- Ingredients = variables : " + this.notions.variables.join(", "), ); } if (this.notions.constantes.length > 0) { lignes.push( "- Materiel / valeurs fixes = constantes : " + this.notions.constantes.join(", "), ); } if (this.notions.fonctions.length > 0) { lignes.push( "- Actions = fonctions : " + this.notions.fonctions.join(", "), ); } if (this.notions.boucles) { lignes.push("- Repeter = boucle"); } if (this.notions.conditions) { lignes.push("- Si = condition"); } return lignes; }; Recette.prototype.toText = function () { var lignes = ["Recette : " + this.nom, "", "Etapes :"]; lignes = lignes.concat(this._lignesEtapes(this.etapes, "", "")); if (configuration.afficherNotions) { lignes = lignes.concat(this._lignesNotions()); } return lignes.join("\n"); }; Recette.prototype.toHTML = function () { var html = '"; return html; }; function etapesHTML(etapes) { var html = "