Compare commits

..

No commits in common. "0.2.0a36" and "main" have entirely different histories.

8715 changed files with 26111 additions and 150141 deletions

View file

@ -1,295 +1,3 @@
## 0.2.0a36 (2025-10-29)
### Feat
- anchor in gitlab output_format
- can had comments with family/variable description in examples doc
- comment variables from a family
## 0.2.0a35 (2025-10-27)
### Feat
- tags documentation
### Fix
- add changelog support for github/gitlab format
- tests
## 0.2.0a34 (2025-10-22)
### Feat
- ca force true_color terminal when export to console
### Fix
- parse subtree for a dynamic
- adapt api for rougail-web-ui
- undocumented variable in dynamic
## 0.2.0a33 (2025-10-16)
### Feat
- can document a variable for a specified identifier
- can remove header when generate a table
- add html output
- changelog for variables
### Fix
- support rougail-web-ui
- black
- remove extra '*'
- always use name for informations key (sometime path was used)
- update tests
- translation for property is now in rougail
## 0.2.0a32 (2025-10-03)
### Fix
- property calculated with disabled variable
- better disabled support
## 0.2.0a31 (2025-10-02)
### Feat
- limit warning when asked
## 0.2.0a30 (2025-10-02)
### Feat
- better support variable calculation for property
## 0.2.0a29 (2025-10-02)
### Fix
- property for namespace
## 0.2.0a28 (2025-10-02)
### Feat
- add gitlab plugin
### Fix
- tests for formatter
- update translation
## 0.2.0a27 (2025-09-29)
### Fix
- doc network with CIDR format
- better doc for calculation with unknown variable
## 0.2.0a26 (2025-09-29)
### Feat
- default value for a calculated variable with an unknown optional variable
- add integer type which will replace number type
## 0.2.0a25 (2025-09-22)
### Feat
- adapt to tiramisu-web-ui
## 0.2.0a24 (2025-06-19)
### Feat
- could not change default value during annotator
## 0.2.0a23 (2025-06-18)
### Fix
- separation
## 0.2.0a22 (2025-06-18)
### Fix
- rougail separation
## 0.2.0a21 (2025-05-12)
### Fix
- update translation
- black
- doc example with leader example lower than leader default value
## 0.2.0a20 (2025-05-09)
### Fix
- undefined is a rougail object
## 0.2.0a19 (2025-05-05)
### Fix
- update translation
## 0.2.0a18 (2025-05-05)
### Fix
- doc default value with undocumented variable
## 0.2.0a17 (2025-05-05)
### Fix
- description for all calculations
- better documentation variable with variable in default attribut
## 0.2.0a16 (2025-04-30)
### Fix
- update translation
- remove negative_description support
- better documentation with hidden variable in property calculation
- use new information ymlfiles
- update tests
- better dynamic support
## 0.2.0a15 (2025-04-09)
### Fix
- version
## 0.2.0a14 (2025-04-07)
### Fix
- calculation for dynamic ans leadership variables
## 0.2.0a13 (2025-04-02)
### Fix
- error in disabled dynamic variable
## 0.2.0a12 (2025-04-01)
### Fix
- update tests
- groups.namespace could be unexistant
## 0.2.0a11 (2025-03-31)
### Fix
- doc a param with a set but with only one item
## 0.2.0a10 (2025-03-30)
### Feat
- document unix file name parameters
- better console output
- do not document reference to undocumented variable
### Fix
- doc for param
- support NamespaceCalculation
- convert <ENV> to &lt;ENV&gt; for github plugin
## 0.2.0a9 (2025-02-19)
### Fix
- support suffix (in version 1.0 format) in calculation
## 0.2.0a8 (2025-02-19)
### Fix
- key is the path
## 0.2.0a7 (2025-02-19)
### Fix
- with_family => without_family and with_example => example
## 0.2.0a6 (2025-02-17)
### Feat
- add with_family parameter
## 0.2.0a5 (2025-02-17)
### Fix
- do not add multiple attribute several time in json export
## 0.2.0a4 (2025-02-10)
### Feat
- output return status too
## 0.2.0a3 (2025-01-04)
### Fix
- detect_symlink => only_self
## 0.2.0a2 (2025-01-04)
### Feat
- create tests
### Fix
- do not document symlink
- remove prefix_path
## 0.2.0a1 (2024-11-28)
### Fix
- separation between run and print function
## 0.2.0a0 (2024-11-20)
### Feat
- personalize mode that we want disable documentation
- add console output
- better dynamique family support
- add json output
### Fix
- correction for properties in italic
## 0.1.1a0 (2024-11-08)
### Fix
- generate documentation with force_optional configuration
## 0.1.0 (2024-11-06)
## 0.1.0rc1 (2024-11-06)
### Fix

Binary file not shown.

View file

@ -5,8 +5,8 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2025-10-29 11:01+0100\n"
"PO-Revision-Date: 2025-10-29 11:02+0100\n"
"POT-Creation-Date: 2024-11-01 11:42+0100\n"
"PO-Revision-Date: 2024-11-01 11:42+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fr\n"
@ -14,431 +14,138 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"X-Generator: Poedit 3.7\n"
"X-Generator: Poedit 3.5\n"
#: src/rougail/output_doc/annotator.py:325
msgid "the value of the information \"{0}\" of the variable \"{1}\""
msgstr "la valeur de l'information \"{0}\" de la variable \"{1}\""
#: src/rougail/output_doc/annotator.py:328
msgid "the value of the global information \"{0}\""
msgstr "la valeur de l'information globale \"{0}\""
#: src/rougail/output_doc/annotator.py:335
msgid "when the identifier is \"{0}\""
msgstr "lorsque l'identifiant est \"{0}\""
#: src/rougail/output_doc/annotator.py:337
msgid "when the identifier is not \"{0}\""
msgstr "lorsque l'identifiant n'est pas \"{0}\""
#: src/rougail/output_doc/changelog.py:144
msgid "New variable"
msgstr "Nouvelle variable"
#: src/rougail/output_doc/changelog.py:146
msgid "New variables"
msgstr "Nouvelles variables"
#: src/rougail/output_doc/changelog.py:158
msgid "Modified variable"
msgstr "Variable modifiée"
#: src/rougail/output_doc/changelog.py:160
msgid "Modified variables"
msgstr "Variables modifiées"
#: src/rougail/output_doc/changelog.py:172
msgid "Deleted variable"
msgstr "Variable supprimée"
#: src/rougail/output_doc/changelog.py:174
msgid "Deleted variables"
msgstr "Variables supprimées"
#: src/rougail/output_doc/config.py:43
msgid "duplicated level rougail-doc for output \"{0}\": {1} and {2}"
msgstr "niveau dupliqué pour rougail-doc pour la sortie \"{0}\": {1} et {2}"
#: src/rougail/output_doc/config.py:75
msgid "Configuration rougail-doc"
msgstr "Configuration de rougail-doc"
#: src/rougail/output_doc/config.py:83
msgid "Starting title level"
msgstr "Niveau de titre de départ"
#: src/rougail/output_doc/config.py:88
msgid "Generated content"
msgstr "Contenu générer"
#: src/rougail/output_doc/config.py:97
msgid "Previous description file in JSON format"
msgstr "Précédent fichier de description au format JSON"
#: src/rougail/output_doc/config.py:105
msgid "Do not add families in documentation"
msgstr "Ne pas ajouter les familles dans la documentation"
#: src/rougail/output_doc/config.py:114
msgid "Document the variables from this family"
msgstr "Documente les variables depuis cette famille"
#: src/rougail/output_doc/config.py:118
msgid "Families or variables for this family are in an other file name"
msgstr ""
"Les familles ou variables pour cette famille sont dans un autre fichier"
#: src/rougail/output_doc/config.py:128
msgid "documentation must be splitted and in gitlab format"
msgstr "documentation doit être séparée et au format gitlab"
#: src/rougail/output_doc/config.py:131
msgid "Root family name"
msgstr "Nom de la famille racine"
#: src/rougail/output_doc/config.py:135
msgid "Name of the file"
msgstr "Nom du fichier"
#: src/rougail/output_doc/config.py:141
msgid "Disable documentation for variables with those modes"
msgstr "Désactiver la documentation des variables avec ces modes"
#: src/rougail/output_doc/config.py:149
msgid "disabled when there is no mode available"
msgstr "désactiver lorsqu'il n'y a pas de mode valable"
#: src/rougail/output_doc/config.py:155
msgid "verify if disable modes already exists"
msgstr "vérifier le mode existe déjà"
#: src/rougail/output_doc/config.py:157
msgid "Modify values to document leaderships and dynamics families"
msgstr "Valeurs modifiées pour documenter les familles leader ou dynamique"
#: src/rougail/output_doc/config.py:160
msgid "Add description of variables and families when generate examples"
msgstr ""
"Ajouter la description des variables et des familles lorsqu'on génère des "
"exemples"
#: src/rougail/output_doc/config.py:166
msgid "disabled when example in not in contents"
msgstr "désactiver lorsqu'il example n'est pas dans contents"
#: src/rougail/output_doc/config.py:169
msgid "Comment in examples starts at column"
msgstr "Commentaire dans les exemples commence à la colonne"
#: src/rougail/output_doc/config.py:177
msgid "Generate document in format"
msgstr "Générer le document au format"
#: src/rougail/output_doc/config.py:187
msgid ""
"json output_format is not compatible with \"changelog\" and \"example\" "
"contents"
msgstr ""
"le format de sortie json n'est pas compatible avec \"changelog\" et "
"example\" de la variable contents"
#: src/rougail/output_doc/config.py:196
msgid "Force true color terminal"
msgstr "Force les vrais couleurs dans le terminal"
#: src/rougail/output_doc/doc.py:358
msgid "This family contains lists of variable blocks"
msgstr "Cette famille contient des listes de bloc de variable"
#: src/rougail/output_doc/doc.py:368
msgid "This family builds families dynamically"
msgstr "Cette famille construit des familles dynamiquement"
#: src/rougail/output_doc/doc.py:382
msgid "Default"
msgstr "Défaut"
#: src/rougail/output_doc/doc.py:397
msgid "multiple"
msgstr "multiple"
#: src/rougail/output_doc/doc.py:405
msgid "Example"
msgstr "Exemple"
#: src/rougail/output_doc/doc.py:408
msgid "Examples"
msgstr "Exemples"
#: src/rougail/output_doc/doc.py:417
msgid "Tag"
msgstr "Étiquette"
#: src/rougail/output_doc/doc.py:420
msgid "Tags"
msgstr "Étiquettes"
#: src/rougail/output_doc/doc.py:449
msgid "No attribute \"description\" for \"{0}\" in {1}"
msgstr "Aucun attribut \"description\" pour \"{0}\" dans {1}"
#: src/rougail/output_doc/doc.py:587
msgid "text based with regular expressions \"{0}\""
msgstr "texte avec expression rationnelle \"{0}\""
#: src/rougail/output_doc/doc.py:591
msgid "Validator"
msgstr "Validateur"
#: src/rougail/output_doc/doc.py:594
msgid "Validators"
msgstr "Validateurs"
#: src/rougail/output_doc/doc.py:603
msgid "Choices"
msgstr "Choix"
#: src/rougail/output_doc/doc.py:706
msgid "the value of the identifier"
msgstr "la valeur de l'identifiant"
#: src/rougail/output_doc/doc.py:710
msgid "the value of the {0}"
msgstr "la valeur de l'{0}"
#: src/rougail/output_doc/doc.py:719
msgid "depends on a calculation"
msgstr "dépend d'un calcul"
#: src/rougail/output_doc/doc.py:725
msgid "\"{0}\" is a calculation for {1} but has no description in {2}"
msgstr "\"{0}\" est un calcul pour {1} mais n'a pas de description dans {2}"
#: src/rougail/output_doc/doc.py:753
msgid "the value of the variable \"{0}\""
msgstr "la valeur de la variable \"{0}\""
#: src/rougail/output_doc/doc.py:755
msgid "the value of the variable \"{0}\" if it is defined"
msgstr "la valeur de la variable \"{0}\" si elle est définie"
#: src/rougail/output_doc/doc.py:775
msgid "the value of an undocumented variable"
msgstr "la valeur d'une variable non documentée"
#: src/rougail/output_doc/doc.py:778
msgid "the values of undocumented variables"
msgstr "les valeurs de variables non documentées"
#: src/rougail/output_doc/doc.py:801
msgid "(from an undocumented variable)"
msgstr "(issue d'une variable non documentée)"
#: src/rougail/output_doc/doc.py:809
msgid "{0} (from an undocumented variable)"
msgstr "{0} (issue d'une variable non documentée)"
#: src/rougail/output_doc/doc.py:813 src/rougail/output_doc/doc.py:862
msgid "depends on an undocumented variable"
msgstr "dépends d'une variable non documentée"
#: src/rougail/output_doc/doc.py:884
msgid ""
"when the variable \"{{0}}\" is defined, accessible and hasn't the value "
"\"{0}\""
msgstr ""
"lorsque la variable \"{{0}}\" est définie, accessible et n'a pas la valeur "
"\"{0}\""
#: src/rougail/output_doc/doc.py:888
msgid "when the variable \"{{0}}\" is defined and hasn't the value \"{0}\""
msgstr "lorsque la variable \"{{0}}\" est définie et n'a pas la valeur \"{0}\""
#: src/rougail/output_doc/doc.py:892
msgid "when the variable \"{{0}}\" is accessible and hasn't the value \"{0}\""
msgstr ""
"lorsque la variable \"{{0}}\" est acessible et n'a pas la valeur \"{0}\""
#: src/rougail/output_doc/doc.py:894
msgid "when the variable \"{{0}}\" hasn't the value \"{0}\""
msgstr "lorsque la variable \"{{0}}\" n'a pas la valeur \"{0}\""
#: src/rougail/output_doc/doc.py:898
msgid ""
"when the variable \"{{0}}\" is defined, is accessible and has the value "
"\"{0}\""
msgstr ""
"lorsque la variable \"{{0}}\" est définie, accessible et a la valeur \"{0}\""
#: src/rougail/output_doc/doc.py:902
msgid "when the variable \"{{0}}\" is defined and has the value \"{0}\""
msgstr "lorsque la variable \"{{0}}\" est définie et a la valeur \"{0}\""
#: src/rougail/output_doc/doc.py:906
msgid "when the variable \"{{0}}\" is accessible and has the value \"{0}\""
msgstr "lorsque la variable \"{{0}}\" est accessible et a la valeur \"{0}\""
#: src/rougail/output_doc/doc.py:908
msgid "when the variable \"{{0}}\" has the value \"{0}\""
msgstr "lorsque la variable \"{{0}}\" a la valeur \"{0}\""
#: src/rougail/output_doc/example.py:38
msgid "Example with mandatory variables not filled in"
msgstr "Exemple avec des variables obligatoire non renseignée"
#: src/rougail/output_doc/example.py:43
msgid "Example with all variables modifiable"
msgstr "Exemple avec toutes les variables modifiable"
#: src/rougail/output_doc/output/console.py:165
#: src/rougail/output_doc/utils.py:820
msgid "Variable"
msgstr "Variable"
#: src/rougail/output_doc/output/console.py:166
#: src/rougail/output_doc/utils.py:820
msgid "Description"
msgstr "Description"
#: src/rougail/output_doc/output/gitlab.py:68
msgid "Informations"
msgstr "Informations"
#: src/rougail/output_doc/utils.py:44
#: src/rougail/output_doc/__init__.py:40
msgid "the domain name can starts by a dot"
msgstr "le nom de domaine peut commencer par un point"
msgstr "le nom de domaine peut commencé par un point"
#: src/rougail/output_doc/utils.py:45
#: src/rougail/output_doc/__init__.py:41
msgid "the domain name can be a hostname"
msgstr "le nom de domaine peut être un nom d'hôte"
#: src/rougail/output_doc/utils.py:46
#: src/rougail/output_doc/__init__.py:42
msgid "the domain name can be an IP"
msgstr "le nom de domaine peut être une IP"
#: src/rougail/output_doc/utils.py:47
#: src/rougail/output_doc/__init__.py:43
msgid "the domain name can be network in CIDR format"
msgstr "le nom de domaine peut être un réseau au format CIDR"
#: src/rougail/output_doc/utils.py:52 src/rougail/output_doc/utils.py:58
#: src/rougail/output_doc/__init__.py:48
msgid "the minimum value is {0}"
msgstr "le valeur minimal est {0}"
#: src/rougail/output_doc/utils.py:53 src/rougail/output_doc/utils.py:59
#: src/rougail/output_doc/__init__.py:49
msgid "the maximum value is {0}"
msgstr "le valeur maximal est {0}"
#: src/rougail/output_doc/utils.py:65
#: src/rougail/output_doc/__init__.py:55
msgid "IP must be in CIDR format"
msgstr "IP doit être au format CIDR"
#: src/rougail/output_doc/utils.py:66
#: src/rougail/output_doc/__init__.py:56
msgid "private IP are allowed"
msgstr "les IP privées sont autorisés"
#: src/rougail/output_doc/utils.py:67
#: src/rougail/output_doc/__init__.py:57
msgid "reserved IP are allowed"
msgstr "les IP réservés sont autorisés"
#: src/rougail/output_doc/utils.py:72
msgid "network must be in CIDR format"
msgstr "réseau doit être au format CIDR"
#: src/rougail/output_doc/utils.py:77
#: src/rougail/output_doc/__init__.py:62
msgid "the host name can be an IP"
msgstr "le nom d'hôte peut être une IP"
#: src/rougail/output_doc/utils.py:82
#: src/rougail/output_doc/__init__.py:67
msgid "the domain name in web address can be an IP"
msgstr "le nom de domaine dans l'adresse web peut être une IP"
#: src/rougail/output_doc/utils.py:83
#: src/rougail/output_doc/__init__.py:68
msgid "the domain name in web address can be only a hostname"
msgstr "le nom de domaine dans l'adresse web ne peut être qu'un nom d'hôte"
#: src/rougail/output_doc/utils.py:90
#: src/rougail/output_doc/__init__.py:75
msgid "can be range of port"
msgstr "peut être un range de port"
#: src/rougail/output_doc/utils.py:91
#: src/rougail/output_doc/__init__.py:76
msgid "can have the protocol"
msgstr "peut avoir un protocole"
#: src/rougail/output_doc/utils.py:92
#: src/rougail/output_doc/__init__.py:77
msgid "port 0 is allowed"
msgstr "le port 0 est autorisé"
#: src/rougail/output_doc/utils.py:93
msgid "well-known ports (1 to 1023) are allowed"
msgstr "les ports connus (de 1 à 1023) sont autorisés"
#: src/rougail/output_doc/__init__.py:78
msgid "ports 1 to 1023 are allowed"
msgstr "les ports entre 1 et 1023 sont autorisés"
#: src/rougail/output_doc/utils.py:94
msgid "registred ports (1024 to 49151) are allowed"
msgstr "les ports enregistrés (de 1024 à 49151) sont autorisés"
#: src/rougail/output_doc/__init__.py:79
msgid "ports 1024 to 49151 are allowed"
msgstr "les ports entre 1024 et 49151 sont autorisés"
#: src/rougail/output_doc/utils.py:95
msgid "private ports (greater than 49152) are allowed"
msgstr "les ports privés (supérieurs à 49152) sont autorisés"
#: src/rougail/output_doc/__init__.py:80
msgid "ports greater than 49152 are allowed"
msgstr "les ports supérieurs à 49152 sont autorisés"
#: src/rougail/output_doc/utils.py:100
msgid "minimum length for the secret is {0} characters"
msgstr "longueur minimum pour le secret est de {0} caractères"
#: src/rougail/output_doc/__init__.py:125
msgid "mandatory"
msgstr "obligatoire"
#: src/rougail/output_doc/utils.py:101
msgid "maximum length for the secret is {0} characters"
msgstr "longueur maximal pour le secret est de {0} caractères"
#: src/rougail/output_doc/__init__.py:126
msgid "hidden"
msgstr "caché"
#: src/rougail/output_doc/utils.py:102
msgid "forbidden characters: {0}"
msgstr "caractères interdits: {0}"
#: src/rougail/output_doc/__init__.py:127
msgid "disabled"
msgstr "désactivé"
#: src/rougail/output_doc/utils.py:107
msgid "this filename could be a relative path"
msgstr "ce nom de fichier peut être un chemin relative"
#: src/rougail/output_doc/__init__.py:128
msgid "unique"
msgstr "unique"
#: src/rougail/output_doc/utils.py:108
msgid "this file must exists"
msgstr "ce fichier doit exister"
#: src/rougail/output_doc/__init__.py:129
msgid "auto modified"
msgstr "auto modifiée"
#: src/rougail/output_doc/utils.py:109
msgid "file type allowed: {0}"
msgstr "type de fichier autorisé : {0}"
#: src/rougail/output_doc/utils.py:362
#: src/rougail/output_doc/__init__.py:163
msgid "Variables for \"{0}\""
msgstr "Variables pour \"{0}\""
#: src/rougail/output_doc/utils.py:392
msgid "Identifiers"
msgstr "Identifiants"
#: src/rougail/output_doc/__init__.py:180
msgid "Variables"
msgstr "Variables"
#: src/rougail/output_doc/utils.py:697 src/rougail/output_doc/utils.py:706
#: src/rougail/output_doc/utils.py:712 src/rougail/output_doc/utils.py:718
#: src/rougail/output_doc/utils.py:722
#: src/rougail/output_doc/__init__.py:187
msgid "Example with mandatory variables not filled in"
msgstr "Exemple avec des variables obligatoire non renseignée"
#: src/rougail/output_doc/__init__.py:493
msgid "(default)"
msgstr "(défaut)"
msgstr "(defaut)"
#: src/rougail/output_doc/utils.py:877
msgid "{0}: {1}"
msgstr "{0} : {1}"
#: src/rougail/output_doc/__init__.py:498
msgid "Choices"
msgstr "Choix"
#~ msgid "Generate example"
#~ msgstr "Génération de l'exemple"
#: src/rougail/output_doc/__init__.py:501
msgid "Default"
msgstr "Défaut"
#~ msgid "Add families in documentation"
#~ msgstr "Ajouter les familles dans la documentation"
#: src/rougail/output_doc/__init__.py:559
msgid "the value of the variable \"{0}\""
msgstr "la valeur de la variable \"{0}\""
#~ msgid "Display example in documentation"
#~ msgstr "Afficher un exemple dans la documentation"
#: src/rougail/output_doc/__init__.py:564
#: src/rougail/output_doc/__init__.py:566
msgid "value of the {0}"
msgstr "la valeur de {0}"
#~ msgid "Hide example in documentation"
#~ msgstr "Cacher l'exemple dans la documentation"
#: src/rougail/output_doc/__init__.py:638
#: src/rougail/output_doc/__init__.py:651
msgid "Example"
msgstr "Exemple"
#, fuzzy
#~| msgid ":"
#~ msgid ": "
#~ msgstr " : "
#~ msgid "when the variable \"{0}\" has the value \"True\""
#~ msgstr "lorsque la variable \"{0}\" a la valeur \"True\""
#: src/rougail/output_doc/__init__.py:649
msgid "Examples"
msgstr "Exemples"

View file

@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2025-10-29 11:02+0100\n"
"POT-Creation-Date: 2024-11-01 11:42+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -15,395 +15,137 @@ msgstr ""
"Generated-By: pygettext.py 1.5\n"
#: src/rougail/output_doc/annotator.py:325
msgid "the value of the information \"{0}\" of the variable \"{1}\""
msgstr ""
#: src/rougail/output_doc/annotator.py:328
msgid "the value of the global information \"{0}\""
msgstr ""
#: src/rougail/output_doc/annotator.py:335
msgid "when the identifier is \"{0}\""
msgstr ""
#: src/rougail/output_doc/annotator.py:337
msgid "when the identifier is not \"{0}\""
msgstr ""
#: src/rougail/output_doc/changelog.py:144
msgid "New variable"
msgstr ""
#: src/rougail/output_doc/changelog.py:146
msgid "New variables"
msgstr ""
#: src/rougail/output_doc/changelog.py:158
msgid "Modified variable"
msgstr ""
#: src/rougail/output_doc/changelog.py:160
msgid "Modified variables"
msgstr ""
#: src/rougail/output_doc/changelog.py:172
msgid "Deleted variable"
msgstr ""
#: src/rougail/output_doc/changelog.py:174
msgid "Deleted variables"
msgstr ""
#: src/rougail/output_doc/config.py:43
msgid "duplicated level rougail-doc for output \"{0}\": {1} and {2}"
msgstr ""
#: src/rougail/output_doc/config.py:75
msgid "Configuration rougail-doc"
msgstr ""
#: src/rougail/output_doc/config.py:83
msgid "Starting title level"
msgstr ""
#: src/rougail/output_doc/config.py:88
msgid "Generated content"
msgstr ""
#: src/rougail/output_doc/config.py:97
msgid "Previous description file in JSON format"
msgstr ""
#: src/rougail/output_doc/config.py:105
msgid "Do not add families in documentation"
msgstr ""
#: src/rougail/output_doc/config.py:114
msgid "Document the variables from this family"
msgstr ""
#: src/rougail/output_doc/config.py:118
msgid "Families or variables for this family are in an other file name"
msgstr ""
#: src/rougail/output_doc/config.py:128
msgid "documentation must be splitted and in gitlab format"
msgstr ""
#: src/rougail/output_doc/config.py:131
msgid "Root family name"
msgstr ""
#: src/rougail/output_doc/config.py:135
msgid "Name of the file"
msgstr ""
#: src/rougail/output_doc/config.py:141
msgid "Disable documentation for variables with those modes"
msgstr ""
#: src/rougail/output_doc/config.py:149
msgid "disabled when there is no mode available"
msgstr ""
#: src/rougail/output_doc/config.py:155
msgid "verify if disable modes already exists"
msgstr ""
#: src/rougail/output_doc/config.py:157
msgid "Modify values to document leaderships and dynamics families"
msgstr ""
#: src/rougail/output_doc/config.py:160
msgid "Add description of variables and families when generate examples"
msgstr ""
#: src/rougail/output_doc/config.py:166
msgid "disabled when example in not in contents"
msgstr ""
#: src/rougail/output_doc/config.py:169
msgid "Comment in examples starts at column"
msgstr ""
#: src/rougail/output_doc/config.py:177
msgid "Generate document in format"
msgstr ""
#: src/rougail/output_doc/config.py:187
msgid "json output_format is not compatible with \"changelog\" and \"example\" contents"
msgstr ""
#: src/rougail/output_doc/config.py:196
msgid "Force true color terminal"
msgstr ""
#: src/rougail/output_doc/doc.py:358
msgid "This family contains lists of variable blocks"
msgstr ""
#: src/rougail/output_doc/doc.py:368
msgid "This family builds families dynamically"
msgstr ""
#: src/rougail/output_doc/doc.py:382
msgid "Default"
msgstr ""
#: src/rougail/output_doc/doc.py:397
msgid "multiple"
msgstr ""
#: src/rougail/output_doc/doc.py:405
msgid "Example"
msgstr ""
#: src/rougail/output_doc/doc.py:408
msgid "Examples"
msgstr ""
#: src/rougail/output_doc/doc.py:417
msgid "Tag"
msgstr ""
#: src/rougail/output_doc/doc.py:420
msgid "Tags"
msgstr ""
#: src/rougail/output_doc/doc.py:449
msgid "No attribute \"description\" for \"{0}\" in {1}"
msgstr ""
#: src/rougail/output_doc/doc.py:587
msgid "text based with regular expressions \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:591
msgid "Validator"
msgstr ""
#: src/rougail/output_doc/doc.py:594
msgid "Validators"
msgstr ""
#: src/rougail/output_doc/doc.py:603
msgid "Choices"
msgstr ""
#: src/rougail/output_doc/doc.py:706
msgid "the value of the identifier"
msgstr ""
#: src/rougail/output_doc/doc.py:710
msgid "the value of the {0}"
msgstr ""
#: src/rougail/output_doc/doc.py:719
msgid "depends on a calculation"
msgstr ""
#: src/rougail/output_doc/doc.py:725
msgid "\"{0}\" is a calculation for {1} but has no description in {2}"
msgstr ""
#: src/rougail/output_doc/doc.py:753
msgid "the value of the variable \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:755
msgid "the value of the variable \"{0}\" if it is defined"
msgstr ""
#: src/rougail/output_doc/doc.py:775
msgid "the value of an undocumented variable"
msgstr ""
#: src/rougail/output_doc/doc.py:778
msgid "the values of undocumented variables"
msgstr ""
#: src/rougail/output_doc/doc.py:801
msgid "(from an undocumented variable)"
msgstr ""
#: src/rougail/output_doc/doc.py:809
msgid "{0} (from an undocumented variable)"
msgstr ""
#: src/rougail/output_doc/doc.py:813 src/rougail/output_doc/doc.py:862
msgid "depends on an undocumented variable"
msgstr ""
#: src/rougail/output_doc/doc.py:884
msgid "when the variable \"{{0}}\" is defined, accessible and hasn't the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:888
msgid "when the variable \"{{0}}\" is defined and hasn't the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:892
msgid "when the variable \"{{0}}\" is accessible and hasn't the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:894
msgid "when the variable \"{{0}}\" hasn't the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:898
msgid "when the variable \"{{0}}\" is defined, is accessible and has the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:902
msgid "when the variable \"{{0}}\" is defined and has the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:906
msgid "when the variable \"{{0}}\" is accessible and has the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:908
msgid "when the variable \"{{0}}\" has the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/example.py:38
msgid "Example with mandatory variables not filled in"
msgstr ""
#: src/rougail/output_doc/example.py:43
msgid "Example with all variables modifiable"
msgstr ""
#: src/rougail/output_doc/output/console.py:165
#: src/rougail/output_doc/utils.py:820
msgid "Variable"
msgstr ""
#: src/rougail/output_doc/output/console.py:166
#: src/rougail/output_doc/utils.py:820
msgid "Description"
msgstr ""
#: src/rougail/output_doc/output/gitlab.py:68
msgid "Informations"
msgstr ""
#: src/rougail/output_doc/utils.py:44
#: src/rougail/output_doc/__init__.py:40
msgid "the domain name can starts by a dot"
msgstr ""
#: src/rougail/output_doc/utils.py:45
#: src/rougail/output_doc/__init__.py:41
msgid "the domain name can be a hostname"
msgstr ""
#: src/rougail/output_doc/utils.py:46
#: src/rougail/output_doc/__init__.py:42
msgid "the domain name can be an IP"
msgstr ""
#: src/rougail/output_doc/utils.py:47
#: src/rougail/output_doc/__init__.py:43
msgid "the domain name can be network in CIDR format"
msgstr ""
#: src/rougail/output_doc/utils.py:52 src/rougail/output_doc/utils.py:58
#: src/rougail/output_doc/__init__.py:48
msgid "the minimum value is {0}"
msgstr ""
#: src/rougail/output_doc/utils.py:53 src/rougail/output_doc/utils.py:59
#: src/rougail/output_doc/__init__.py:49
msgid "the maximum value is {0}"
msgstr ""
#: src/rougail/output_doc/utils.py:65
#: src/rougail/output_doc/__init__.py:55
msgid "IP must be in CIDR format"
msgstr ""
#: src/rougail/output_doc/utils.py:66
#: src/rougail/output_doc/__init__.py:56
msgid "private IP are allowed"
msgstr ""
#: src/rougail/output_doc/utils.py:67
#: src/rougail/output_doc/__init__.py:57
msgid "reserved IP are allowed"
msgstr ""
#: src/rougail/output_doc/utils.py:72
msgid "network must be in CIDR format"
msgstr ""
#: src/rougail/output_doc/utils.py:77
#: src/rougail/output_doc/__init__.py:62
msgid "the host name can be an IP"
msgstr ""
#: src/rougail/output_doc/utils.py:82
#: src/rougail/output_doc/__init__.py:67
msgid "the domain name in web address can be an IP"
msgstr ""
#: src/rougail/output_doc/utils.py:83
#: src/rougail/output_doc/__init__.py:68
msgid "the domain name in web address can be only a hostname"
msgstr ""
#: src/rougail/output_doc/utils.py:90
#: src/rougail/output_doc/__init__.py:75
msgid "can be range of port"
msgstr ""
#: src/rougail/output_doc/utils.py:91
#: src/rougail/output_doc/__init__.py:76
msgid "can have the protocol"
msgstr ""
#: src/rougail/output_doc/utils.py:92
#: src/rougail/output_doc/__init__.py:77
msgid "port 0 is allowed"
msgstr ""
#: src/rougail/output_doc/utils.py:93
msgid "well-known ports (1 to 1023) are allowed"
#: src/rougail/output_doc/__init__.py:78
msgid "ports 1 to 1023 are allowed"
msgstr ""
#: src/rougail/output_doc/utils.py:94
msgid "registred ports (1024 to 49151) are allowed"
#: src/rougail/output_doc/__init__.py:79
msgid "ports 1024 to 49151 are allowed"
msgstr ""
#: src/rougail/output_doc/utils.py:95
msgid "private ports (greater than 49152) are allowed"
#: src/rougail/output_doc/__init__.py:80
msgid "ports greater than 49152 are allowed"
msgstr ""
#: src/rougail/output_doc/utils.py:100
msgid "minimum length for the secret is {0} characters"
#: src/rougail/output_doc/__init__.py:125
msgid "mandatory"
msgstr ""
#: src/rougail/output_doc/utils.py:101
msgid "maximum length for the secret is {0} characters"
#: src/rougail/output_doc/__init__.py:126
msgid "hidden"
msgstr ""
#: src/rougail/output_doc/utils.py:102
msgid "forbidden characters: {0}"
#: src/rougail/output_doc/__init__.py:127
msgid "disabled"
msgstr ""
#: src/rougail/output_doc/utils.py:107
msgid "this filename could be a relative path"
#: src/rougail/output_doc/__init__.py:128
msgid "unique"
msgstr ""
#: src/rougail/output_doc/utils.py:108
msgid "this file must exists"
#: src/rougail/output_doc/__init__.py:129
msgid "auto modified"
msgstr ""
#: src/rougail/output_doc/utils.py:109
msgid "file type allowed: {0}"
msgstr ""
#: src/rougail/output_doc/utils.py:362
#: src/rougail/output_doc/__init__.py:163
msgid "Variables for \"{0}\""
msgstr ""
#: src/rougail/output_doc/utils.py:392
msgid "Identifiers"
#: src/rougail/output_doc/__init__.py:180
msgid "Variables"
msgstr ""
#: src/rougail/output_doc/utils.py:697 src/rougail/output_doc/utils.py:706
#: src/rougail/output_doc/utils.py:712 src/rougail/output_doc/utils.py:718
#: src/rougail/output_doc/utils.py:722
#: src/rougail/output_doc/__init__.py:187
msgid "Example with mandatory variables not filled in"
msgstr ""
#: src/rougail/output_doc/__init__.py:493
msgid "(default)"
msgstr ""
#: src/rougail/output_doc/utils.py:877
msgid "{0}: {1}"
#: src/rougail/output_doc/__init__.py:498
msgid "Choices"
msgstr ""
#: src/rougail/output_doc/__init__.py:501
msgid "Default"
msgstr ""
#: src/rougail/output_doc/__init__.py:559
msgid "the value of the variable \"{0}\""
msgstr ""
#: src/rougail/output_doc/__init__.py:564
#: src/rougail/output_doc/__init__.py:566
msgid "value of the {0}"
msgstr ""
#: src/rougail/output_doc/__init__.py:638
#: src/rougail/output_doc/__init__.py:651
msgid "Example"
msgstr ""
#: src/rougail/output_doc/__init__.py:649
msgid "Examples"
msgstr ""

View file

@ -4,7 +4,7 @@ requires = ["flit_core >=3.8.0,<4"]
[project]
name = "rougail.output_doc"
version = "0.2.0a36"
version = "0.1.0"
authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}]
readme = "README.md"
description = "Rougail output doc"
@ -13,10 +13,11 @@ license = {file = "LICENSE"}
classifiers = [
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
"Programming Language :: Python",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
"Natural Language :: English",
@ -24,9 +25,8 @@ classifiers = [
]
dependencies = [
"rougail-base > 1.1,<2",
"rougail ~= 1.1,<2",
"tabulate ~= 0.9.0",
"rich ~= 13.9.3",
]
[project.urls]
@ -37,9 +37,5 @@ name = "cz_conventional_commits"
tag_format = "$version"
version_scheme = "pep440"
version_provider = "pep621"
version_files = [
"src/rougail/output_doc/__version__.py",
"pyproject.toml:version"
]
update_changelog_on_bump = true
#update_changelog_on_bump = true
changelog_merge_prerelease = true

View file

@ -1,6 +1,7 @@
#!/usr/bin/env python3
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
Copyright (C) 2024
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
@ -15,9 +16,671 @@ details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
# FIXME si plusieurs example dont le 1er est none tester les autres : tests/dictionaries/00_8test_none
from tiramisu import Calculation
from tiramisu.error import display_list
import tabulate as tabulate_module
from tabulate import tabulate
from warnings import warn
from typing import Optional
from .doc import RougailOutputDoc
from .__version__ import __version__
from rougail.error import display_xmlfiles
from rougail import RougailConfig, Rougail, CONVERT_OPTION
from rougail.object_model import PROPERTY_ATTRIBUTE
from .config import OutPuts
from .i18n import _
ENTER = "\n\n"
DocTypes = {
"domainname": {
"params": {
"allow_startswith_dot": _("the domain name can starts by a dot"),
"allow_without_dot": _("the domain name can be a hostname"),
"allow_ip": _("the domain name can be an IP"),
"allow_cidr_network": _("the domain name can be network in CIDR format"),
},
},
"number": {
"params": {
"min_number": _("the minimum value is {0}"),
"max_number": _("the maximum value is {0}"),
},
},
"ip": {
"msg": "IP",
"params": {
"cidr": _("IP must be in CIDR format"),
"private_only": _("private IP are allowed"),
"allow_reserved": _("reserved IP are allowed"),
},
},
"hostname": {
"params": {
"allow_ip": _("the host name can be an IP"),
},
},
"web_address": {
"params": {
"allow_ip": _("the domain name in web address can be an IP"),
"allow_without_dot": _(
"the domain name in web address can be only a hostname"
),
},
},
"port": {
"params": {
"allow_range": _("can be range of port"),
"allow_protocol": _("can have the protocol"),
"allow_zero": _("port 0 is allowed"),
"allow_wellknown": _("ports 1 to 1023 are allowed"),
"allow_registred": _("ports 1024 to 49151 are allowed"),
"allow_private": _("ports greater than 49152 are allowed"),
},
},
}
ROUGAIL_VARIABLE_TYPE = (
"https://rougail.readthedocs.io/en/latest/variable.html#variables-types"
)
class RougailOutputDoc:
def __init__(
self,
*,
config: "Config" = None,
rougailconfig: RougailConfig = None,
**kwarg,
):
if rougailconfig is None:
rougailconfig = RougailConfig
if rougailconfig["step.output"] != "doc":
rougailconfig["step.output"] = "doc"
if rougailconfig["step.output"] != "doc":
raise Exception("doc is not set as step.output")
self.rougailconfig = rougailconfig
outputs = OutPuts().get()
output = self.rougailconfig["doc.output_format"]
if output not in outputs:
raise Exception(
f'cannot find output "{output}", available outputs: {list(outputs)}'
)
if config is None:
rougail = Rougail(self.rougailconfig)
rougail.converted.plugins.append("output_doc")
config = rougail.get_config()
self.conf = config
self.conf.property.setdefault(frozenset({"advanced"}), "read_write", "append")
self.conf.property.read_write()
self.conf.property.remove("cache")
self.dynamic_paths = {}
self.formater = outputs[output]()
self.level = self.rougailconfig["doc.title_level"]
# self.property_to_string = [('mandatory', 'obligatoire'), ('hidden', 'cachée'), ('disabled', 'désactivée'), ('unique', 'unique'), ('force_store_value', 'modifié automatiquement')]
self.property_to_string = [
("mandatory", _("mandatory")),
("hidden", _("hidden")),
("disabled", _("disabled")),
("unique", _("unique")),
("force_store_value", _("auto modified")),
]
def run(self):
print(self.gen_doc())
def gen_doc(self):
tabulate_module.PRESERVE_WHITESPACE = True
examples_mini = {}
examples_all = {}
return_string = self.formater.header()
if self.rougailconfig["main_namespace"]:
for namespace in self.conf.unrestraint.list():
name = namespace.name()
examples_mini[name] = {}
examples_all[name] = {}
doc = (
self._display_doc(
self.display_families(
namespace,
self.level + 1,
examples_mini[name],
examples_all[name],
),
[],
)
+ "\n"
)
if not examples_mini[name]:
del examples_mini[name]
if not examples_all[name]:
del examples_all[name]
else:
return_string += self.formater.title(
_('Variables for "{0}"').format(namespace.name()), self.level
)
return_string += doc
else:
doc = (
self._display_doc(
self.display_families(
self.conf.unrestraint,
self.level + 1,
examples_mini,
examples_all,
),
[],
)
+ "\n"
)
if examples_all:
return_string += self.formater.title(_("Variables"), self.level)
return_string += doc
if not examples_all:
return ""
if self.rougailconfig["doc.with_example"]:
if examples_mini:
return_string += self.formater.title(
_("Example with mandatory variables not filled in"), self.level
)
return_string += self.formater.yaml(examples_mini)
if examples_all:
return_string += self.formater.title(
"Example with all variables modifiable", self.level
)
return_string += self.formater.yaml(examples_all)
return return_string
def _display_doc(self, variables, add_paths):
return_string = ""
for variable in variables:
typ = variable["type"]
path = variable["path"]
if path in add_paths:
continue
if typ == "family":
return_string += variable["title"]
return_string += self._display_doc(variable["objects"], add_paths)
else:
for idx, path in enumerate(variable["paths"]):
if path in self.dynamic_paths:
paths_msg = display_list(
[
self.formater.bold(path_)
for path_ in self.dynamic_paths[path]["paths"]
],
separator="or",
)
variable["objects"][idx][0] = variable["objects"][idx][
0
].replace("{{ ROUGAIL_PATH }}", paths_msg)
identifiers = self.dynamic_paths[path]["identifiers"]
description = variable["objects"][idx][1][0]
if "{{ identifier }}" in description:
if description.endswith("."):
description = description[:-1]
comment_msg = self.to_phrase(
display_list(
[
description.replace(
"{{ identifier }}",
self.formater.italic(identifier),
)
for identifier in identifiers
],
separator="or",
add_quote=True,
)
)
variable["objects"][idx][1][0] = comment_msg
variable["objects"][idx][1] = self.formater.join(
variable["objects"][idx][1]
)
return_string += (
self.formater.table(
tabulate(
variable["objects"],
headers=self.formater.table_header(
["Variable", "Description"]
),
tablefmt=self.formater.name,
)
)
+ "\n\n"
)
add_paths.append(path)
return return_string
def is_hidden(self, child):
properties = child.property.get(uncalculated=True)
for hidden_property in ["hidden", "disabled", "advanced"]:
if hidden_property in properties:
return True
return False
def display_families(
self,
family,
level,
examples_mini,
examples_all,
):
variables = []
for child in family.list():
if self.is_hidden(child):
continue
if not child.isoptiondescription():
if child.isfollower() and child.index() != 0:
# only add to example
self.display_variable(
child,
examples_mini,
examples_all,
)
continue
path = child.path(uncalculated=True)
if child.isdynamic():
self.dynamic_paths.setdefault(
path, {"paths": [], "identifiers": []}
)["paths"].append(child.path())
self.dynamic_paths[path]["identifiers"].append(
child.identifiers()[-1]
)
if not variables or variables[-1]["type"] != "variables":
variables.append(
{
"type": "variables",
"objects": [],
"path": path,
"paths": [],
}
)
variables[-1]["objects"].append(
self.display_variable(
child,
examples_mini,
examples_all,
)
)
variables[-1]["paths"].append(path)
else:
name = child.name()
if child.isleadership():
examples_mini[name] = []
examples_all[name] = []
else:
examples_mini[name] = {}
examples_all[name] = {}
variables.append(
{
"type": "family",
"title": self.display_family(
child,
level,
),
"path": child.path(uncalculated=True),
"objects": self.display_families(
child,
level + 1,
examples_mini[name],
examples_all[name],
),
}
)
if not examples_mini[name]:
del examples_mini[name]
if not examples_all[name]:
del examples_all[name]
return variables
def display_family(
self,
family,
level,
):
if family.name() != family.description(uncalculated=True):
title = f"{family.description(uncalculated=True)}"
else:
warning = f'No attribute "description" for family "{family.path()}" in {display_xmlfiles(family.information.get("dictionaries"))}'
warn(warning)
title = f"{family.path()}"
isdynamic = family.isdynamic(only_self=True)
if isdynamic:
identifiers = family.identifiers(only_self=True)
if "{{ identifier }}" in title:
title = display_list(
[
title.replace(
"{{ identifier }}", self.formater.italic(identifier)
)
for identifier in identifiers
],
separator="or",
add_quote=True,
)
msg = self.formater.title(title, level)
subparameter = []
self.manage_properties(family, subparameter)
if subparameter:
msg += self.subparameter_to_string(subparameter) + ENTER
comment = []
self.subparameter_to_parameter(subparameter, comment)
if comment:
msg += "\n".join(comment) + ENTER
help = self.to_phrase(family.information.get("help", ""))
if help:
msg += "\n" + help + ENTER
if family.isleadership():
# help = "Cette famille contient des listes de bloc de variables."
help = "This family contains lists of variable blocks."
msg += "\n" + help + ENTER
if isdynamic:
identifiers = family.identifiers(only_self=True, uncalculated=True)
if isinstance(identifiers, Calculation):
identifiers = self.to_string(family, "dynamic")
if isinstance(identifiers, list):
for idx, val in enumerate(identifiers):
if not isinstance(val, Calculation):
continue
identifiers[idx] = self.to_string(family, "dynamic", f"_{idx}")
identifiers = self.formater.list(identifiers)
# help = f"Cette famille construit des familles dynamiquement.\n\n{self.formater.bold('Identifiers')}: {identifiers}"
help = f"This family builds families dynamically.\n\n{self.formater.bold('Identifiers')}: {identifiers}"
msg += "\n" + help + ENTER
return msg
def manage_properties(
self,
variable,
subparameter,
):
properties = variable.property.get(uncalculated=True)
for mode in self.rougailconfig["modes_level"]:
if mode in properties:
subparameter.append((self.formater.prop(mode), None, None))
break
for prop, msg in self.property_to_string:
if prop in properties:
subparameter.append((self.formater.prop(msg), None, None))
elif variable.information.get(f"{prop}_calculation", False):
subparameter.append(
(self.formater.prop(msg), msg, self.to_string(variable, prop))
)
def subparameter_to_string(
self,
subparameter,
):
subparameter_str = ""
for param in subparameter:
if param[1]:
subparameter_str += f"_{param[0]}_ "
else:
subparameter_str += f"{param[0]} "
return subparameter_str[:-1]
def subparameter_to_parameter(
self,
subparameter,
comment,
):
for param in subparameter:
if not param[1]:
continue
msg = param[2]
comment.append(f"{self.formater.bold(param[1].capitalize())}: {msg}")
def to_phrase(self, msg):
if not msg:
return ""
msg = str(msg).strip()
if not msg.endswith("."):
msg += "."
return msg[0].upper() + msg[1:]
def display_variable(
self,
variable,
examples_mini,
examples_all,
):
if variable.isdynamic():
parameter = ["{{ ROUGAIL_PATH }}"]
else:
parameter = [f"{self.formater.bold(variable.path())}"]
subparameter = []
description = variable.description(uncalculated=True)
comment = [self.to_phrase(description)]
help_ = self.to_phrase(variable.information.get("help", ""))
if help_:
comment.append(help_)
self.type_to_string(
variable,
subparameter,
comment,
)
self.manage_properties(
variable,
subparameter,
)
if variable.ismulti():
multi = not variable.isfollower() or variable.issubmulti()
else:
multi = False
if multi:
subparameter.append((self.formater.prop("multiple"), None, None))
if subparameter:
parameter.append(self.subparameter_to_string(subparameter))
if variable.name() == description:
warning = f'No attribute "description" for variable "{variable.path()}" in {display_xmlfiles(variable.information.get("dictionaries"))}'
warn(warning)
default = self.get_default(
variable,
comment,
)
default_in_choices = False
if variable.information.get("type") == "choice":
choices = variable.value.list(uncalculated=True)
if isinstance(choices, Calculation):
choices = self.to_string(variable, "choice")
if isinstance(choices, list):
for idx, val in enumerate(choices):
if not isinstance(val, Calculation):
if default is not None and val == default:
choices[idx] = str(val) + "" + _("(default)")
default_in_choices = True
continue
choices[idx] = self.to_string(variable, "choice", f"_{idx}")
choices = self.formater.list(choices)
comment.append(f'{self.formater.bold(_("Choices"))}: {choices}')
# choice
if default is not None and not default_in_choices:
comment.append(f"{self.formater.bold(_('Default'))}: {default}")
self.manage_exemples(
multi,
variable,
examples_all,
examples_mini,
comment,
)
self.subparameter_to_parameter(subparameter, comment)
self.formater.columns(parameter, comment)
return [self.formater.join(parameter), comment]
def get_default(
self,
variable,
comment,
):
if variable.information.get("fake_default", False):
default = None
else:
default = variable.value.get(uncalculated=True)
if default in [None, []]:
return
if isinstance(default, Calculation):
default = self.to_string(variable, "default")
if isinstance(default, list):
for idx, val in enumerate(default):
if not isinstance(val, Calculation):
continue
default[idx] = self.to_string(variable, "default", f"_{idx}")
default = self.formater.list(default)
return default
def to_string(
self,
variable,
prop,
identifier="",
):
calculation_type = variable.information.get(
f"{prop}_calculation_type{identifier}", None
)
if not calculation_type:
raise Exception(
f"cannot find {prop}_calculation_type{identifier} information, do you have declare doc has a plugins?"
)
calculation = variable.information.get(f"{prop}_calculation{identifier}")
if calculation_type == "jinja":
if calculation is not True:
values = self.formater.to_string(calculation)
else:
values = "depends on a calculation"
warning = f'"{prop}" is a calculation for {variable.path()} but has no description in {display_xmlfiles(variable.information.get("dictionaries"))}'
warn(warning)
elif calculation_type == "variable":
if prop in PROPERTY_ATTRIBUTE:
values = self.formater.to_string(calculation)
else:
values = _('the value of the variable "{0}"').format(calculation)
elif calculation_type == "identifier":
if prop in PROPERTY_ATTRIBUTE:
values = self.formater.to_string(calculation)
else:
values = _("value of the {0}").format(calculation_type)
else:
values = _("value of the {0}").format(calculation_type)
if not values.endswith("."):
values += "."
return values
def type_to_string(
self,
variable,
subparameter,
comment,
):
variable_type = variable.information.get("type")
doc_type = DocTypes.get(variable_type, {"params": {}})
subparameter.append(
(
self.formater.link(
doc_type.get("msg", variable_type), ROUGAIL_VARIABLE_TYPE
),
None,
)
)
option = variable.get()
validators = []
for param, msg in doc_type["params"].items():
value = option.impl_get_extra(f"_{param}")
if value is None:
value = option.impl_get_extra(param)
if value is not None and value is not False:
validators.append(msg.format(value))
valids = [
name
for name in variable.information.list()
if name.startswith("validators_calculation_type_")
]
if valids:
for idx in range(len(valids)):
validators.append(
self.to_string(
variable,
"validators",
f"_{idx}",
)
)
if validators:
if len(validators) == 1:
comment.append(f'{self.formater.bold("Validator")}: ' + validators[0])
else:
comment.append(
f'{self.formater.bold("Validators")}:'
+ self.formater.list(validators)
)
def manage_exemples(
self,
multi,
variable,
examples_all,
examples_mini,
comment,
):
example_mini = None
example_all = None
example = variable.information.get("examples", None)
if example is None:
example = variable.information.get("test", None)
default = variable.value.get()
if isinstance(example, tuple):
example = list(example)
mandatory = "mandatory" in variable.property.get(uncalculated=True)
if example:
if not multi:
example = example[0]
title = _("Example")
if mandatory:
example_mini = example
example_all = example
else:
if mandatory:
example_mini = "\n - example"
example_all = example
len_test = len(example)
example = self.formater.list(example)
if len_test > 1:
title = _("Examples")
else:
title = _("Example")
comment.append(f"{self.formater.bold(title)}: {example}")
elif default not in [None, []]:
example_all = default
else:
example = CONVERT_OPTION.get(variable.information.get("type"), {}).get(
"example", None
)
if example is None:
example = "xxx"
if multi:
example = [example]
if mandatory:
example_mini = example
example_all = example
if variable.isleader():
if example_mini is not None:
for mini in example_mini:
examples_mini.append({variable.name(): mini})
if example_all is not None:
for mall in example_all:
examples_all.append({variable.name(): mall})
elif variable.isfollower():
if example_mini is not None:
for idx in range(0, len(examples_mini)):
examples_mini[idx][variable.name()] = example_mini
if example_all is not None:
for idx in range(0, len(examples_all)):
examples_all[idx][variable.name()] = example_all
else:
if example_mini is not None:
examples_mini[variable.name()] = example_mini
examples_all[variable.name()] = example_all
RougailOutput = RougailOutputDoc

View file

@ -1 +0,0 @@
__version__ = "0.2.0a36"

View file

@ -1,6 +1,7 @@
"""
"""Annotate for documentation
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
Copyright (C) 2024
distribued with GPL-2 or later license
@ -19,13 +20,12 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from typing import Union
from rougail.utils import undefined, PROPERTY_ATTRIBUTE
from tiramisu import undefined
from rougail.annotator.variable import Walk
from rougail.output_doc.i18n import _
from rougail.convert.object_model import (
from rougail.i18n import _
from rougail.error import DictConsistencyError
from rougail.object_model import (
Calculation,
JinjaCalculation,
VariableCalculation,
@ -34,8 +34,8 @@ from rougail.convert.object_model import (
IdentifierPropertyCalculation,
InformationCalculation,
IndexCalculation,
NamespaceCalculation,
CONVERT_OPTION,
PROPERTY_ATTRIBUTE,
)
@ -47,140 +47,113 @@ class Annotator(Walk):
def __init__(
self,
objectspace,
*args, # pylint: disable=unused-argument
*args,
) -> None:
if not objectspace.paths:
return
self.objectspace = objectspace
self.change_default_value = self.objectspace.rougailconfig[
"doc.change_default_value"
]
self.populate_family()
self.populate_variable()
def populate_family(self) -> None:
"""Set doc, path, ... to family"""
for family in self.get_families():
self.add_informations_from_properties(family)
if family.type == "dynamic":
self.force_default_value_in_suffix_variable(family)
self.calculation_to_information(
family.path,
"dynamic",
family.dynamic,
family.version,
)
path = family.path
if path in self.objectspace.forced_descriptions:
self.objectspace.informations.add(
path,
"forced_description",
True,
)
def force_default_value_in_suffix_variable(self, family) -> None:
if not self.change_default_value:
return
if not isinstance(family.dynamic, list):
self._force_default_value_in_suffix_variable(family, family.dynamic)
else:
for value in family.dynamic:
self._force_default_value_in_suffix_variable(
family, value, return_a_list=False
)
def _force_default_value_in_suffix_variable(
self,
family,
value,
*,
return_a_list=True,
) -> None:
"""For dynamic we must have values to document it"""
if not isinstance(value, Calculation):
return
value_added = False
if isinstance(value, (VariableCalculation, VariablePropertyCalculation)):
variable = self.objectspace.paths.get_with_dynamic(
value.variable,
family.path,
value.version,
value.namespace,
value.xmlfiles,
)[0]
if variable and not variable.default:
values = self.add_examples_values(variable)
value_added = True
if not value_added:
default_values = ["example"]
if not return_a_list:
default_values = default_values[0]
value.default_values = default_values
def add_examples_values(self, variable) -> list:
"""Check examples or test information to define examples values in a variable"""
def get_examples_values(self, variable):
values = self.objectspace.informations.get(variable.path).get("examples", None)
if not values:
values = self.objectspace.informations.get(variable.path).get("test", None)
if isinstance(values, tuple):
values = list(values)
if values:
variable.default = list(values)
else:
variable.default = [CONVERT_OPTION[variable.type]["example"]]
self.objectspace.informations.add(
variable.path, "default_value_makes_sense", False
)
return values
def add_default_value(
self,
family,
value,
*,
inside_list=False,
) -> None:
if isinstance(value, Calculation):
default_values = "example"
if not inside_list:
default_values = [default_values]
if isinstance(value, (VariableCalculation, VariablePropertyCalculation)):
variable, identifier = self.objectspace.paths.get_with_dynamic(
value.variable,
value.path_prefix,
family.path,
value.version,
value.namespace,
value.xmlfiles,
)
values = self.get_examples_values(variable)
if values:
if inside_list:
default_values = list(values)
else:
default_values = values
value.default_values = default_values
def populate_family(self) -> None:
"""Set doc, path, ... to family"""
for family in self.get_families():
self.objectspace.informations.add(
family.path, "dictionaries", family.xmlfiles
)
self.convert_variable_property(family)
if family.type != "dynamic":
continue
if not isinstance(family.dynamic, list):
self.add_default_value(family, family.dynamic)
else:
for value in family.dynamic:
self.add_default_value(family, value, inside_list=True)
self.calculation_to_information(
family.path,
"dynamic",
family.dynamic,
family.version,
)
def populate_variable(self) -> None:
"""convert variables"""
for variable in self.get_variables():
if variable.type == "symlink":
continue
path = variable.path
if variable.type == "choice":
self.calculation_to_information(
path,
variable.path,
"choice",
variable.choices,
variable.version,
)
default = variable.default
if default is None and path in self.objectspace.default_multi:
default = self.objectspace.default_multi[path]
self.calculation_to_information(
path,
variable.path,
"default",
default,
variable.default,
variable.version,
)
self.calculation_to_information(
path,
variable.path,
"validators",
variable.validators,
variable.version,
)
if (
self.change_default_value
and path in self.objectspace.leaders
and not default
):
self.add_examples_values(variable)
self.add_informations_from_properties(variable)
if path in self.objectspace.forced_descriptions:
self.objectspace.informations.add(
path,
"forced_description",
True,
)
if variable.path in self.objectspace.leaders and not variable.default:
values = self.get_examples_values(variable)
if values:
variable.default = list(values)
else:
variable.default = [CONVERT_OPTION[variable.type]["example"]]
self.objectspace.informations.add(variable.path, "fake_default", True)
self.objectspace.informations.add(
variable.path, "dictionaries", variable.xmlfiles
)
self.convert_variable_property(variable)
def add_informations_from_properties(
def convert_variable_property(
self,
variable: dict,
) -> None:
"""convert properties"""
for prop in PROPERTY_ATTRIBUTE:
for prop in ["hidden", "disabled", "mandatory"]:
prop_value = getattr(variable, prop, None)
if not prop_value:
continue
@ -190,8 +163,6 @@ class Annotator(Walk):
prop_value,
variable.version,
)
if isinstance(prop_value, Calculation):
prop_value.default_values = False
def calculation_to_information(
self,
@ -200,151 +171,76 @@ class Annotator(Walk):
values,
version: str,
):
"""tranform calculation to an information"""
one_is_calculation = False
if not isinstance(values, list):
if not isinstance(values, Calculation):
return
one_is_calculation = True
datas = self.calculation_to_string(path, prop, values, version)
else:
datas = []
self._calculation_to_information(
path,
prop,
values,
version,
)
if isinstance(values, list):
for idx, val in enumerate(values):
data = self.calculation_to_string(path, prop, val, version)
if data is None:
continue
if "type" in data or "description" in data:
one_is_calculation = True
datas.append(data)
if one_is_calculation:
self.objectspace.informations.add(
path,
f"{prop}_calculation",
datas,
)
self._calculation_to_information(
path,
prop,
val,
version,
identifier=f"_{idx}",
)
def calculation_to_string(
def _calculation_to_information(
self,
path: str,
prop: str,
values,
version: str,
*,
identifier: str = "",
):
if not isinstance(values, Calculation):
return {"value": values}
if values.description:
return {"description": values.description}
return
values_calculation = True
if isinstance(values, JinjaCalculation):
if values.description:
value = values.description
else:
value = True
return {
"type": "jinja",
"value": value,
}
if isinstance(values, (VariableCalculation, VariablePropertyCalculation)):
variable_path = self.get_path_from_variable(values, version, values.path)
value = self.calculation_to_information_variable(
variable_path, values, prop, version, path
)
if value is None:
return
return {
"type": "variable",
"value": value,
"ori_path": variable_path,
"optional": values.optional,
"propertyerror": values.propertyerror,
}
if isinstance(values, InformationCalculation):
return {
"type": "information",
"value": self.calculation_to_information_information(
values, version, path
),
}
if isinstance(values, (IdentifierCalculation, IdentifierPropertyCalculation)):
return {
"type": "identifier",
"value": self.calculation_to_information_identifier(
values, prop, version
),
}
if isinstance(values, IndexCalculation):
return {
"type": "index",
"value": True,
}
if isinstance(values, NamespaceCalculation):
return {
"type": "namespace",
"value": True,
}
raise Exception(f'unknown calculation {type(values)} "{values}"')
def calculation_to_information_variable(
self, variable_path: str, values, prop: str, version: str, path: str
) -> str:
# is optional
variable = self.objectspace.paths.get_with_dynamic(
variable_path,
values_calculation = values.description
values_calculation_type = "jinja"
elif isinstance(values, (VariableCalculation, VariablePropertyCalculation)):
values_calculation = values.variable
paths = self.objectspace.paths
if version != "1.0" and paths.regexp_relative.search(values_calculation):
calculation_path = paths.get_full_path(
values_calculation,
path,
)
if prop in PROPERTY_ATTRIBUTE:
if values.when is not undefined:
values_calculation = f'when the variable "{calculation_path}" has the value "{values.when}"'
elif values.when_not is not undefined:
values_calculation = f'when the variable "{calculation_path}" hasn\'t the value "{values.when_not}"'
else:
values_calculation = f'when the variable "{calculation_path}" has the value "True"'
else:
values_calculation = calculation_path
values_calculation_type = "variable"
elif isinstance(values, InformationCalculation):
values_calculation_type = "information"
elif isinstance(values, (IdentifierCalculation, IdentifierPropertyCalculation)):
if version != "1.0" and prop in PROPERTY_ATTRIBUTE:
if values.when is not undefined:
values_calculation = f'when the identifier is "{values.when}"'
elif values.when_not is not undefined:
values_calculation = (
f'when the identifier is not "{values.when_not}"'
)
values_calculation_type = "identifier"
elif isinstance(values, IndexCalculation):
values_calculation_type = "index"
self.objectspace.informations.add(
path,
values.version,
values.namespace,
values.xmlfiles,
)[0]
if isinstance(values, VariableCalculation) and values.optional and not variable:
return None
if variable:
variable_path = variable.path
if prop in PROPERTY_ATTRIBUTE:
# get comparative value
if values.when_not is not undefined:
value = values.when_not
condition = "when_not"
elif values.when is not undefined:
value = values.when
condition = "when"
else:
value = True
condition = "when"
# set message
values_calculation = (variable_path, value, condition)
else:
values_calculation = variable_path
return values_calculation
def calculation_to_information_information(
self, values, version: str, path: str
) -> Union[str, bool]:
if values.variable:
variable_path = self.get_path_from_variable(values, version, path)
return _('the value of the information "{0}" of the variable "{1}"').format(
values.information, variable_path
)
return _('the value of the global information "{0}"').format(values.information)
def calculation_to_information_identifier(
self, values, prop: str, version: str
) -> Union[str, bool]:
if version != "1.0" and prop in PROPERTY_ATTRIBUTE:
if values.when is not undefined:
return _('when the identifier is "{0}"').format(values.when)
if values.when_not is not undefined:
return _('when the identifier is not "{0}"').format(values.when_not)
return True
def get_path_from_variable(self, values, version: str, path: str) -> str:
variable_path = values.variable
paths = self.objectspace.paths
if version != "1.0" and paths.regexp_relative.search(variable_path):
variable_path = paths.get_full_path(
variable_path,
path,
)
elif version == "1.0" and "{{ suffix }}" in variable_path:
variable_path = variable_path.replace("{{ suffix }}", "{{ identifier }}")
return variable_path
f"{prop}_calculation_type{identifier}",
values_calculation_type,
)
self.objectspace.informations.add(
path,
f"{prop}_calculation{identifier}",
values_calculation,
)

View file

@ -1,184 +0,0 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2025
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from pathlib import Path
from json import loads
from .config import OutPuts
from .i18n import _
from .utils import calc_path
class Changelog: # pylint: disable=no-member,too-few-public-methods
"""Build changelog"""
def gen_doc_changelog(self):
"""Return changelog"""
with Path(self.previous_json_file).open() as outfh:
previous_doc = loads(outfh.read())
self.load()
self._added_variables = []
self._modified_variables = []
self._removed_variables = []
if self.root:
for family in self.root.split('.'):
if family in previous_doc:
previous_doc = previous_doc[family]['children']
else:
previous_doc = {}
break
self.parser(previous_doc, self.informations)
return self.display()
def parser(self, previous_families, new_families):
def add(new):
self.formatter.variable_to_string(new, self._added_variables)
def remove(previous):
self._removed_variables.append(previous)
done = []
for element in list(previous_families) + list(new_families):
if element in done:
continue
done.append(element)
previous = previous_families.get(element)
new = new_families.get(element)
if not previous:
if new["type"] == "variable":
add(new)
else:
self.parser({}, new["children"])
elif not new:
if previous["type"] == "variable":
if "identifiers" in previous:
for identifiers in previous["identifiers"]:
remove(calc_path(previous["path"], self.formatter, identifiers))
else:
remove(calc_path(previous["path"], self.formatter))
else:
self.parser(previous["children"], {})
elif previous["type"] != new["type"]:
if previous["type"] == "variable":
if "identifiers" in previous:
for identifiers in previous["identifiers"]:
remove(calc_path(previous["path"], self.formatter, identifiers))
else:
remove(calc_path(previous["path"], self.formatter))
self.parser({}, new["children"])
else:
add(new)
self.parser(previous["children"], {})
elif previous["type"] != "variable":
self.parser(previous["children"], new["children"])
else:
modified_attributes = {}
for prop in set(previous) | set(new):
prop_previous = previous.get(prop, [])
prop_new = new.get(prop, [])
if prop_previous != prop_new:
name = None
if (
isinstance(prop_previous, dict)
and "values" in prop_previous
):
name = prop_previous["name"]
local_prop_previous = prop_previous = prop_previous[
"values"
]
if not isinstance(prop_previous, list):
if prop == "default":
local_prop_previous = [prop_previous]
else:
local_prop_previous = prop_previous = [
prop_previous
]
else:
local_prop_previous = prop_previous
if isinstance(prop_new, dict) and "values" in prop_new:
name = prop_new["name"]
prop_new = prop_new["values"]
if not isinstance(prop_new, list):
prop_new = [prop_new]
if isinstance(prop_new, list):
prop_new = prop_new.copy()
else:
prop_new = [prop_new]
if isinstance(prop_previous, list):
prop_previous = [
p for p in prop_previous if p not in prop_new
]
elif prop_previous in prop_new:
prop_new.remove(prop_previous)
prop_previous = []
prop_new = [p for p in prop_new if p not in local_prop_previous]
if prop_previous not in [None, []] or prop_new not in [
None,
[],
]:
modified_attributes[prop] = (name, prop_previous, prop_new)
if not modified_attributes:
continue
self.formatter.variable_to_string(
new, self._modified_variables, modified_attributes
)
def display(self) -> str:
msg = ""
if self._added_variables:
if len(self._added_variables) == 1:
title = _("New variable")
else:
title = _("New variables")
msg += self.formatter.run(
[
self.formatter.title(title, self.level),
self.formatter.table(self._added_variables),
self.formatter.end_family(self.level)
],
self.level,
dico_is_already_treated=True,
)
if self._modified_variables:
if len(self._modified_variables) == 1:
title = _("Modified variable")
else:
title = _("Modified variables")
msg += self.formatter.run(
[
self.formatter.title(title, self.level),
self.formatter.table(self._modified_variables),
self.formatter.end_family(self.level)
],
self.level,
dico_is_already_treated=True,
)
if self._removed_variables:
if len(self._removed_variables) == 1:
title = _("Deleted variable")
else:
title = _("Deleted variables")
msg += self.formatter.run(
[
self.formatter.title(title, self.level),
self.formatter.list(self._removed_variables, inside_table=False),
self.formatter.end_family(self.level)
],
self.level,
dico_is_already_treated=True,
)
return msg

View file

@ -2,7 +2,7 @@
Config file for Rougail-doc
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
Copyright (C) 2024
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
@ -20,31 +20,27 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
from pathlib import Path
from rougail.utils import load_modules
from .i18n import _
OUTPUTS = None
def get_outputs() -> None:
"""Load all outputs"""
module_name = "rougail.output_doc.output"
module_name = "rougail.doc.output"
outputs = {}
for path in (Path(__file__).parent / "output").iterdir():
name = path.name
if not name.endswith(".py") or name.endswith("__.py"):
continue
module = load_modules(module_name + "." + name[:-3], str(path))
if "Formatter" not in dir(module):
module = load_modules(module_name + "." + name, str(path))
if "Formater" not in dir(module):
continue
level = module.Formatter.level
level = module.Formater.level
if level in outputs:
raise ImportError(
_('duplicated level rougail-doc for output "{0}": {1} and {2}').format(
level, module.Formatter.name, outputs[level].name
)
raise Exception(
f'duplicated level rougail-doc for output "{level}": {module.Formater.name} and {outputs[level].name}'
)
outputs[module.Formatter.level] = module.Formatter
outputs[module.Formater.level] = module.Formater
return {outputs[level].name: outputs[level] for level in sorted(outputs)}
@ -59,143 +55,43 @@ class OutPuts: # pylint: disable=R0903
OUTPUTS = get_outputs()
def get(self) -> dict:
"""Get all outputs"""
return OUTPUTS
def get_rougail_config(
*,
backward_compatibility=True, # pylint: disable=unused-argument
backward_compatibility=True,
) -> dict:
"""Get documentation for output_doc modules"""
outputs = list(OutPuts().get())
output_format_default = outputs[0]
rougail_options = f"""
rougail_options = """
doc:
description: {_('Configuration rougail-doc')}
description: Configuration rougail-doc
disabled:
type: jinja
jinja: |
{{% if step.output is propertyerror or step.output != 'doc' %}}
{% if step.output != 'doc' %}
disabled
{{% endif %}}
{% endif %}
title_level:
description: {_('Starting title level')}
description: Start title level
alternative_name: dt
default: 1
contents:
description: {_('Generated content')}
choices:
- variables
- example
- changelog
default:
- variables
previous_json_file:
description: {_('Previous description file in JSON format')}
disabled:
jinja: |-
{{{{ "changelog" not in _.contents }}}}
return_type: boolean
description: changelog is not selected
without_family:
description: {_('Do not add families in documentation')}
with_example:
description: Display example in documentation
negative_description: Hide example in documentation
alternative_name: de
default: false
disabled:
jinja: |-
{{{{ "variables" not in _.contents and _.output_format != "json" }}}}
return_type: boolean
description: variables is not selected
root:
description: {_('Document the variables from this family')}
mandatory: false
other_root_filenames:
description: {_("Families or variables for this family are in an other file name")}
type: leadership
disabled:
jinja: |-
{{% if not _.root %}}
Documents are not splitted
{{% endif %}}
{{% if _.output_format != 'gitlab' %}}
anchor is available only for gitlab output_format
{{% endif %}}
description: {_('documentation must be splitted and in gitlab format')}
root_path:
description: {_("Root family name")}
mandatory: false
filename:
description: {_("Name of the file")}
type: unix_filename
params:
allow_relative: true
disabled_modes:
description: {_('Disable documentation for variables with those modes')}
multi: true
mandatory: false
disabled:
jinja: |
{{% if not modes_level %}}
there is no mode
{{% endif %}}
description: {_('disabled when there is no mode available')}
validators:
- jinja: |
{{% if _.disabled_modes not in modes_level %}}
this mode is not available
{{% endif %}}
description: {_('verify if disable modes already exists')}
change_default_value: true # {_('Modify values to document leaderships and dynamics families')}
comment_examples:
description: {_('Add description of variables and families when generate examples')}
default: false
disabled:
jinja: |-
{{{{ "example" not in _.contents }}}}
return_type: boolean
description: {_('disabled when example in not in contents')}
comment_examples_column:
description: {_('Comment in examples starts at column')}
default: 30
disabled:
variable: _.comment_examples
propertyerror: false
when: false
output_format:
description: {_('Generate document in format')}
description: Generate document in format
alternative_name: do
default: output_format_default
validators:
- jinja: |-
{{% if _.output_format == 'json' %}}
{{% if "changelog" in _.contents or "example" in _.contents %}}
cannot add to contents "{{{{ _.contents }}}}" with output_format "json"
{{% endif %}}
{{% endif %}}
description: {_('json output_format is not compatible with "changelog" and "example" contents')}
choices:
""".replace(
"output_format_default", output_format_default
)
for output in outputs:
rougail_options += f" - {output}\n"
rougail_options += f"""
force_true_color_terminal:
description: {_('Force true color terminal')}
default: false
"""
return {
"name": "doc",
"process": "output",

View file

@ -1,956 +0,0 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from warnings import warn
from typing import Optional
from itertools import chain
from re import compile
from tiramisu import Calculation, groups
from tiramisu.error import ConfigError, display_list, PropertiesOptionError
from rougail.tiramisu import display_xmlfiles, normalize_family
from rougail.utils import undefined, get_properties_to_string, PROPERTY_ATTRIBUTE
from rougail.error import VariableCalculationDependencyError, RougailWarning
from .config import OutPuts
from .i18n import _
from .utils import DocTypes, dump, to_phrase, calc_path
from .example import Examples
from .changelog import Changelog
HIDDEN_PROPERTIES = [
"hidden",
"disabled",
]
class RougailOutputDoc(Examples, Changelog):
"""Rougail Output Doc:
Generate documentation from rougail description files
"""
def __init__(
self,
config: "Config",
*,
rougailconfig: "RougailConfig" = None,
**kwarg,
):
# Import here to avoid circular import
from rougail.tiramisu import CONVERT_OPTION
self.convert_option = CONVERT_OPTION
if rougailconfig is None:
from rougail import RougailConfig
rougailconfig = RougailConfig
if rougailconfig["step.output"] != "doc":
rougailconfig["step.output"] = "doc"
if rougailconfig["step.output"] != "doc":
raise Exception("doc is not set as step.output")
outputs = OutPuts().get()
output_format = rougailconfig["doc.output_format"]
if output_format not in outputs:
raise Exception(
f'cannot find output "{output_format}", available outputs: {list(outputs)}'
)
self.conf = config
self.modes_level = rougailconfig["modes_level"]
if self.modes_level:
self.disabled_modes = rougailconfig["doc.disabled_modes"]
if self.disabled_modes:
self.conf.property.setdefault(
frozenset(self.disabled_modes), "read_write", "append"
)
else:
self.disabled_modes = []
self.conf.property.read_write()
# self.conf.property.remove("cache")
self.output_format = output_format
self.level = rougailconfig["doc.title_level"]
self.contents = rougailconfig["doc.contents"]
self.root = rougailconfig["doc.root"]
if self.root:
try:
self.other_root_filenames = rougailconfig["doc.other_root_filenames"]
except PropertiesOptionError:
self.other_root_filenames = None
else:
self.other_root_filenames = None
self.example = "example" in self.contents
if self.example:
self.comment_examples = rougailconfig["doc.comment_examples"]
if self.comment_examples:
self.comment_examples_column = rougailconfig["doc.comment_examples_column"]
if "variables" in self.contents:
self.with_family = not rougailconfig["doc.without_family"]
else:
self.with_family = True
if "changelog" in self.contents:
self.previous_json_file = rougailconfig["doc.previous_json_file"]
if output_format == 'console':
self.force_true_color_terminal = rougailconfig["doc.force_true_color_terminal"]
else:
self.force_true_color_terminal = None
self.formatter = outputs[output_format](self)
self.informations = None
try:
groups.namespace
self.support_namespace = True
except AttributeError:
self.support_namespace = False
self.property_to_string = get_properties_to_string()
super().__init__()
def run(self) -> str:
"""Print documentation in stdout"""
self.load()
return_string = ""
if "variables" in self.contents:
return_string += self.formatter.run(self.informations, self.level)
if "example" in self.contents:
return_string += self.gen_doc_examples()
if "changelog" in self.contents:
return_string += self.gen_doc_changelog()
return True, return_string
def print(self) -> None:
ret, data = self.run()
print(data)
return ret
def load(self):
self.dynamic_paths = {}
config = self.conf.unrestraint
if self.root:
config = config.option(self.root)
self.populate_dynamics(config=config)
informations = self.parse_families(config)
if informations is None:
informations = {}
self.informations = informations
def populate_dynamics(self, *, config=None, reload=False):
if config is None:
config = self.conf.unrestraint
self._populate_dynamics(config, reload)
def _populate_dynamics(self, family, reload, uncalculated=False) -> None:
def populate(child, uncalculated):
if child.isoptiondescription():
type_ = "family"
else:
type_ = "variable"
if child.isdynamic():
self.populate_dynamic(child, type_, reload, uncalculated)
if child.isoptiondescription():
self._populate_dynamics(child, reload, uncalculated)
for child in family.list(uncalculated=uncalculated):
populate(child, uncalculated)
if not uncalculated:
for child in family.list(uncalculated=True):
if child.isdynamic() and child.path(uncalculated=True) not in self.dynamic_paths:
populate(family, uncalculated=True)
def populate_dynamic(self, obj, type_, reload, uncalculated) -> None:
path = obj.path(uncalculated=True)
if path not in self.dynamic_paths:
new_name = True
description = obj.description(uncalculated=True)
name = obj.name(uncalculated=True)
self.dynamic_paths[path] = {
"names": [],
"identifiers": [],
"path": path,
}
if not obj.information.get("forced_description", False):
self.dynamic_paths[path]["description"] = self._convert_description(
description, type_, its_a_path=False
)
elif obj.isoptiondescription():
self.dynamic_paths[path]["description"] = self._convert_description(
description, type_, its_a_path=True
)
if uncalculated:
return
dynamic_obj = self.dynamic_paths[path]
if reload and obj.identifiers() in dynamic_obj["identifiers"]:
return
dynamic_obj["names"].append(obj.name())
dynamic_obj["identifiers"].append(obj.identifiers())
def parse_families(self, family) -> dict:
informations = {}
leader = None
for child in family.list():
if self.is_inaccessible_user_data(child):
continue
if child.type(only_self=True) == "symlink":
continue
if not child.isoptiondescription():
leader = self.parse_variable(child, leader, informations)
else:
self.parse_family(child, informations)
return informations
def is_inaccessible_user_data(self, child):
"""If family is not accessible in read_write mode (to load user_data),
do not comment this family
"""
properties = child.property.get(uncalculated=True)
for hidden_property in HIDDEN_PROPERTIES:
if hidden_property in properties:
return True
calculation = child.information.get(f"{hidden_property}_calculation", None)
if calculation and calculation.get("type") == "variable":
variable_path, value, condition = calculation["value"]
variable = self.conf.forcepermissive.option(variable_path)
try:
variable.value.get()
except AttributeError:
variable = None
if variable and self.is_inaccessible_user_data(variable):
try:
variable_value = self._get_unmodified_default_value(variable)
except VariableCalculationDependencyError:
pass
else:
if (condition == "when" and value == variable_value) or (condition == "when_not" and value != variable_value):
return True
if not child.isoptiondescription():
for hidden_property in self.disabled_modes:
if hidden_property in properties:
return True
return False
def parse_family(self, family, informations: dict, *, force_injection=False) -> None:
path = family.path(uncalculated=True)
name = family.name(uncalculated=True)
sub_informations = self.parse_families(family)
if not force_injection and not sub_informations:
return
# if self.with_family:
family_informations = self._populate_family(
family,
path,
)
if family_informations is not False:
informations[name] = {
"type": self._get_family_type(family),
"informations": family_informations,
"children": sub_informations,
}
def parse_variable(
self,
variable,
leader: dict,
informations: dict,
*,
only_one=False,
) -> Optional[dict]:
path = variable.path(uncalculated=True)
name = variable.name(uncalculated=True)
potential_leader = None
if variable.isdynamic():
# information is already set
potential_leader = self._parse_variable_dynamic(
variable, leader, name, path, informations, only_one
)
elif variable.isfollower() and variable.index():
self._parse_variable_follower_with_index(
variable, leader, name, informations
)
else:
potential_leader = self.parse_variable_normal(
variable, leader, name, path, informations
)
if potential_leader:
leader = potential_leader
return leader
def parse_variable_normal(
self, variable, leader, name: str, path: str, informations: dict
) -> Optional[dict]:
if variable.isdynamic():
sub_informations = self.dynamic_paths[path]
elif variable.isfollower() and path in informations: # variable.index():
sub_informations = informations[name]
else:
sub_informations = {}
if not self._populate_variable(
variable,
sub_informations,
):
return None
if self.example:
self._add_examples(variable, sub_informations, leader)
informations[name] = sub_informations
if variable.isleader():
return sub_informations
return None
def _parse_variable_follower_with_index(
self, variable, leader: dict, name: str, informations: dict
) -> None:
if not self.example or (variable.index() + 1) > len(leader["example"][-1]):
return
informations[name]["example"][-1][variable.index()] = self._get_example(
variable, informations[name], None
)
def _parse_variable_dynamic(
self, variable, leader, name, path, informations, only_one
) -> None:
# if path not in self.dynamic_paths:
# self.populate_dynamic(variable, path)
dynamic_variable = self.dynamic_paths[path]
if (not only_one or path in informations) and "type" in dynamic_variable:
if self.example:
dynamic_variable["example"].append(
self._get_example(variable, dynamic_variable, leader)
)
if variable.isleader():
return dynamic_variable
if not only_one:
return None
return self.parse_variable_normal(variable, leader, name, path, informations)
def _get_family_type(self, family) -> str:
if self.support_namespace and family.group_type() is groups.namespace:
return "namespace"
if family.isleadership():
return "leadership"
if family.isdynamic(only_self=True):
return "dynamic"
return "family"
def _populate_family(
self,
family,
path: str,
) -> dict:
if family.isdynamic():
informations = self.dynamic_paths[path]
else:
informations = {}
if not self._populate(family, informations, "family"):
return False
if family.isleadership():
informations.setdefault("help", []).append(
_("This family contains lists of variable blocks")
)
if family.isdynamic(only_self=True):
identifiers = self._to_string(family, "dynamic", do_not_raise=True)
if identifiers is None:
identifiers = family.identifiers(only_self=True)
if not isinstance(identifiers, list):
identifiers = [identifiers]
informations["identifier"] = identifiers
informations.setdefault("help", []).append(
_("This family builds families dynamically")
)
return informations
def _populate_variable(
self,
variable,
informations: dict,
):
informations["type"] = "variable"
default = self._get_default(
variable,
)
if default is not None:
informations["default"] = {"name": _("Default"), "values": default}
self._parse_type(
variable,
informations,
)
if not self._populate(variable, informations, "variable"):
return False
if variable.ismulti():
multi = not variable.isfollower() or variable.issubmulti()
else:
multi = False
if multi:
informations["properties"].append(
{
"type": "multiple",
"name": _("multiple"),
}
)
examples = variable.information.get("examples", None)
if examples is None:
examples = variable.information.get("test", None)
if examples is not None:
if len(examples) == 1:
name = _("Example")
values = examples[0]
else:
name = _("Examples")
values = list(examples)
informations["examples"] = {
"name": name,
"values": values
}
tags = variable.information.get("tags", None)
if tags:
if len(tags) == 1:
name = _("Tag")
values = tags[0]
else:
name = _("Tags")
values = list(tags)
informations["tags"] = {
"name": name,
"values": values,
}
return True
def _populate(
self,
child,
informations: dict,
type_: str,
):
need_disabled, properties = self._parse_properties(child)
if not need_disabled:
return False
name = child.name(uncalculated=True)
if child.information.get("forced_description", False):
if (
not child.isoptiondescription()
or not self.support_namespace
or child.group_type() is not groups.namespace
):
if (
child.isoptiondescription()
or not child.isfollower()
or not child.index()
):
warning = _('No attribute "description" for "{0}" in {1}').format(
child.path(uncalculated=True),
display_xmlfiles(child.information.get("ymlfiles")),
)
warn(
warning,
RougailWarning,
)
if child.isoptiondescription():
description = self._convert_description(
child.description(uncalculated=True), type_, its_a_path=True
)
else:
description = None
else:
description = self._convert_description(
child.description(uncalculated=True), type_, its_a_path=False
)
if not child.isdynamic():
informations["path"] = child.path(uncalculated=True)
informations["names"] = [child.name()]
if description is not None:
informations["description"] = description
help_ = child.information.get("help", None)
if help_:
informations["help"] = [to_phrase(help_)]
if "properties" in informations:
informations["properties"].extend(properties)
else:
informations["properties"] = properties
return True
def _convert_description(self, description, type_, its_a_path=False):
if not its_a_path:
description = to_phrase(description, type_)
return description
def _add_examples(self, variable, informations: dict, leader) -> None:
if not variable.index():
example = self._get_example(variable, informations, leader)
informations["example"] = [example]
informations["mandatory_without_value"] = "mandatory" in variable.property.get(
uncalculated=True
) and (
not variable.information.get("default_value_makes_sense", True)
or variable.value.get(uncalculated=True) in [None, []]
)
def _get_example(self, variable, informations: dict, leader):
example = informations.get("examples", {}).get("values")
if example is not None:
if isinstance(example, tuple):
example = list(example)
for prop in informations["properties"]:
if prop["type"] == "multiple":
if not isinstance(example, list):
example = [example]
break
else:
if isinstance(example, list):
index = variable.index()
if index is None or len(example) - 1 >= index:
index = 0
example = example[index]
else:
if variable.information.get("fake_default", False):
default = None
else:
try:
default = variable.value.get()
except ConfigError:
default = None
if default not in [None, []]:
example = default
else:
example = self.get_type_default_value(
variable, informations["properties"]
)
if leader is not None and variable.isfollower():
example = [example] + [undefined] * (len(leader["example"][-1]) - 1)
return example
def get_type_default_value(self, variable, properties):
example = self.convert_option.get(variable.information.get("type"), {}).get(
"example", None
)
if example is None:
example = "xxx"
for prop in properties:
if prop["type"] == "multiple":
multi = True
break
else:
multi = False
if multi:
example = [example]
return example
def _parse_type(
self,
child,
informations,
):
variable_type = child.information.get("type")
doc_type = DocTypes.get(variable_type, {"params": {}})
informations["properties"] = [
{
"type": "type",
"name": doc_type.get("msg", variable_type),
}
]
# extra parameters for types
option = child.get()
validators = []
for param, msg in doc_type["params"].items():
value = option.impl_get_extra(f"_{param}")
if value is None:
value = option.impl_get_extra(param)
if value is not None and value is not False:
if isinstance(value, set):
value = list(value)
if isinstance(value, list):
value = display_list(value, add_quote=True)
validators.append(msg.format(value))
# get validation information from annotator
for name in child.information.list():
if not name.startswith("validators_calculation"):
continue
validators.extend(
self._to_string(
child,
"validators",
)
)
break
if child.information.get("type") == "regexp":
validators.append(
_('text based with regular expressions "{0}"').format(child.pattern())
)
if validators:
if len(validators) == 1:
key = _("Validator")
validators = validators[0]
else:
key = _("Validators")
informations["validators"] = {"name": key, "values": validators}
if child.information.get("type") == "choice":
choices = self._to_string(child, "choice", do_not_raise=True)
if choices is None:
choices = child.value.list()
for idx, val in enumerate(choices):
if isinstance(val, Calculation):
choices[idx] = self._to_string(child, "choice", f"_{idx}")
informations["choices"] = {"name": _("Choices"), "values": choices}
def _parse_properties(
self,
child,
):
informations = []
properties = child.property.get(uncalculated=True)
for mode in self.modes_level:
if mode not in properties:
continue
informations.append(
{
"type": "mode",
"name": mode,
}
)
break
for prop, translated_prop in self.property_to_string:
if prop in properties:
prop_obj = {
"type": "property",
"name": translated_prop,
}
elif child.information.get(f"{prop}_calculation", False):
annotation = self._to_string(child, prop)
if annotation is None or isinstance(annotation, bool):
if annotation is None and prop in HIDDEN_PROPERTIES:
return False, {}
if not annotation:
continue
prop_obj = {
"type": "property",
"name": translated_prop,
}
else:
prop_obj = {
"type": "property",
"name": translated_prop,
"annotation": annotation,
}
else:
# this property is not in the variable so, do not comment it
continue
informations.append(prop_obj)
return True, informations
def _get_default(
self,
variable,
):
default = self._to_string(variable, "default", do_not_raise=True)
if default is not None:
if default == []:
default = None
return default
if variable.information.get("default_value_makes_sense", True):
default_ = variable.value.get(uncalculated=True)
if not isinstance(default_, Calculation):
default = default_
if default == []:
default = None
return default
def _to_string(
self,
child,
prop,
do_not_raise=False,
):
calculation = child.information.get(f"{prop}_calculation", None)
if not calculation:
if do_not_raise:
return None
raise Exception(
f'cannot find "{prop}_calculation" information, '
"do you have declare doc has a plugins?"
)
if isinstance(calculation, list):
values = []
for cal in calculation:
value = self._calculation_to_string(child, cal, prop, inside_list=True)
if value is not None:
values.append(value)
return values
return self._calculation_to_string(child, calculation, prop)
def _calculation_to_string(self, child, calculation, prop, inside_list=False):
if "description" in calculation:
values = calculation["description"]
# if not values.endswith("."):
# values += "."
return values
if "type" not in calculation:
return calculation["value"]
if calculation["type"] == "jinja":
values = self._calculation_jinja_to_string(child, calculation, prop)
elif calculation["type"] == "variable":
values = self._calculation_variable_to_string(child, calculation, prop)
elif calculation["type"] == "identifier":
if prop in PROPERTY_ATTRIBUTE:
values = calculation["value"]
else:
values = _("the value of the identifier")
elif calculation["type"] == "information":
values = calculation["value"]
else:
values = _("the value of the {0}").format(calculation["type"])
# if not inside_list and isinstance(values, str) and not values.endswith("."):
# values += "."
return values
def _calculation_jinja_to_string(self, child, calculation, prop):
if calculation["value"] is not True:
values = calculation["value"]
else:
values = _("depends on a calculation")
if (
child.isoptiondescription()
or not child.isfollower()
or not child.index()
):
warning = _(
'"{0}" is a calculation for {1} but has no description in {2}'
).format(
prop,
child.path(),
display_xmlfiles(child.information.get("ymlfiles")),
)
warn(
warning,
RougailWarning,
)
return values
def _calculation_variable_to_string(self, child, calculation, prop):
if prop in PROPERTY_ATTRIBUTE:
values = self._calculation_variable_to_string_known_property(child, calculation, prop)
else:
if calculation["optional"]:
path = calculation["value"]
if "{{ identifier }}" in path:
if path not in self.dynamic_paths:
return None
else:
try:
self.conf.forcepermissive.option(path).get()
except AttributeError:
return None
if not calculation["optional"]:
true_msg = _('the value of the variable "{0}"')
else:
true_msg = _('the value of the variable "{0}" if it is defined')
if "{{ identifier }}" in calculation["ori_path"]:
values = []
all_is_undocumented = False
for cpath, description, identifiers in self.get_annotation_variable(calculation["value"], calculation["ori_path"]):
if cpath:
all_is_undocumented = False
path_obj = {
"path": cpath,
}
if identifiers:
path_obj["identifiers"] = identifiers
values.append({
"message": true_msg,
"path": path_obj,
"description": description,
})
else:
if all_is_undocumented is None:
all_is_undocumented = True
values.append(_("the value of an undocumented variable"))
if all_is_undocumented:
if len(values) > 1:
values = _("the values of undocumented variables")
else:
values = values[0]
else:
# FIXME A MUTUALISER AUSSI
variable_path = calculation["ori_path"]
variable = self.conf.forcepermissive.option(variable_path)
try:
isfollower = variable.isfollower()
except AttributeError as err:
pass
else:
if not isfollower and self.is_inaccessible_user_data(variable):
try:
uncalculated = variable.value.get(uncalculated=True)
except PropertiesOptionError:
true_msg = None
else:
if uncalculated and not isinstance(
uncalculated, Calculation
):
if isinstance(uncalculated, list):
true_msg = {
"submessage": _(
"(from an undocumented variable)"
),
"values": uncalculated,
}
else:
if not isinstance(uncalculated, str):
uncalculated = dump(uncalculated)
true_msg = _(
"{0} (from an undocumented variable)"
).format(uncalculated)
else:
true_msg = _("depends on an undocumented variable")
if true_msg:
if isinstance(true_msg, dict):
values = true_msg
else:
description = self._convert_description(self.conf.option(calculation["ori_path"]).description(uncalculated=True), "description", its_a_path=False)
values = {
"message": true_msg,
"path": {
"path": calculation["ori_path"],
},
"description": description,
}
else:
values = None
return values
def _calculation_variable_to_string_known_property(self, child, calculation, prop):
variable_path, value, condition = calculation["value"]
if isinstance(value, str):
str_value = value
else:
str_value = dump(value)
values = []
if "{{ identifier }}" in calculation["ori_path"] or "{{ identifier }}" in variable_path:
variables = self.get_annotation_variable(variable_path, calculation["ori_path"])
else:
option = self.conf.option(variable_path)
try:
is_inaccessible = self.is_inaccessible_user_data(option)
except AttributeError as err:
if err.code != "option-not-found":
raise err from err
is_inaccessible = True
if is_inaccessible:
variables = [[None, None, None]]
else:
description = self._convert_description(option.description(uncalculated=True), "description", its_a_path=False)
variables = [[variable_path, description, None]]
for cpath, description, identifiers in variables:
if not cpath:
variable = self.conf.forcepermissive.option(variable_path)
try:
variable_value = self._get_unmodified_default_value(variable)
except PropertiesOptionError as err:
if calculation["propertyerror"]:
raise err from err
variable_value = value
except VariableCalculationDependencyError:
values.append(_("depends on an undocumented variable"))
continue
except AttributeError as err:
if err.code != "option-not-found" or not calculation.get("optional", False):
raise err from err
return calculation.get("default", False)
if (
condition == "when"
and value == variable_value
or condition == "when_not"
and value != variable_value
):
if prop in HIDDEN_PROPERTIES:
return False
# always "prop"
return True
# never "prop"
return False
else:
if condition == "when_not":
if calculation["optional"]:
if not calculation["propertyerror"]:
msg = _(
'when the variable "{{0}}" is defined, accessible and hasn\'t the value "{0}"'
)
else:
msg = _(
'when the variable "{{0}}" is defined and hasn\'t the value "{0}"'
)
elif not calculation["propertyerror"]:
msg = _('when the variable "{{0}}" is accessible and hasn\'t the value "{0}"')
else:
msg = _('when the variable "{{0}}" hasn\'t the value "{0}"')
else:
if calculation["optional"]:
if not calculation["propertyerror"]:
msg = _(
'when the variable "{{0}}" is defined, is accessible and has the value "{0}"'
)
else:
msg = _(
'when the variable "{{0}}" is defined and has the value "{0}"'
)
elif not calculation["propertyerror"]:
msg = _('when the variable "{{0}}" is accessible and has the value "{0}"')
else:
msg = _('when the variable "{{0}}" has the value "{0}"')
path_obj = {
"path": variable_path,
}
if identifiers:
path_obj["identifiers"] = identifiers
values.append({
"message": msg.format(str_value),
"path": path_obj,
"description": description,
})
if len(values) == 1:
return values[0]
return values
def get_annotation_variable(self, current_path, ori_path):
if current_path == ori_path:
regexp = None
else:
regexp = compile(
"^"
+ ori_path.replace("{{ identifier }}", "(.*)")
+ "$"
)
information = self.dynamic_paths[current_path]
path = information["path"]
for identifiers in information["identifiers"]:
cpath = calc_path(path, identifiers=identifiers)
if regexp and not regexp.search(cpath):
continue
if self.is_inaccessible_user_data(self.conf.option(cpath)):
yield None, None, None
else:
description = self._convert_description(self.conf.option(path).description(uncalculated=True), "description", its_a_path=False)
if "{{ identifier }}" in path:
yield path, description, identifiers.copy()
else:
yield path, description, None
def _get_unmodified_default_value(self, child):
calculation = child.information.get(f"default_calculation", None)
if not calculation:
return child.value.get()
if calculation["type"] == "variable":
variable = self.conf.forcepermissive.option(calculation["value"])
if variable and self.is_inaccessible_user_data(variable):
return self._get_unmodified_default_value(variable)
raise VariableCalculationDependencyError()

View file

@ -1,214 +0,0 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from typing import Optional
from ruamel.yaml import CommentedMap
from .utils import _, calc_path
class Examples: # pylint: disable=no-member,too-few-public-methods
"""Build examples"""
def __init__(self):
self.examples = None
self.examples_mandatories = None
def gen_doc_examples(self):
"""Return examples"""
self._build_examples()
return_string = ""
if self.examples_mandatories:
return_string += self.formatter.title(
_("Example with mandatory variables not filled in"), self.level
)
return_string += self.formatter.yaml(self.examples_mandatories)
if self.examples:
return_string += self.formatter.title(
_("Example with all variables modifiable"), self.level
)
return_string += self.formatter.yaml(self.examples)
return return_string
def _build_examples(self):
examples, examples_mandatories = self._parse_examples(
self.informations
)
if self.root and examples:
for sub in self.root.split('.'):
examples = {sub: examples}
if examples_mandatories:
examples_mandatories = {sub: examples_mandatories}
self.examples = examples
self.examples_mandatories = examples_mandatories
def _parse_examples(self, dico, dyn_parent: Optional[str] = None) -> tuple:
if self.comment_examples:
examples = CommentedMap()
examples_mandatories = CommentedMap()
else:
examples = {}
examples_mandatories = {}
for value in dico.values():
if value["type"] == "variable":
parse = self._parse_examples_variable
else:
parse = self._parse_examples_family
parse(
value, dyn_parent, examples, examples_mandatories
)
return examples, examples_mandatories
def _parse_examples_variable(
self,
variable,
dyn_parent: Optional[str],
examples: dict,
examples_mandatories: dict,
) -> None:
paths = []
ori_path = variable["path"]
if "identifiers" in variable:
for idx, identifiers in enumerate(variable["identifiers"]):
paths.append(calc_path(ori_path, identifiers=identifiers))
else:
paths.append(ori_path)
for idx, path in enumerate(paths):
path = calc_path(path)
if dyn_parent is not None and not path.startswith(dyn_parent):
continue
if len(variable["names"]) == 1:
name = variable["names"][0]
else:
name = variable["names"][idx]
value = variable["example"][idx]
examples[name] = value
if self.comment_examples and "description" in variable:
description = variable["description"]
if description.endswith('.'):
description = description[:-1]
examples.yaml_add_eol_comment(description, name, column=self.comment_examples_column)
if variable["mandatory_without_value"]:
examples_mandatories[name] = value
if self.comment_examples and "description" in variable:
description = variable["description"]
if description.endswith('.'):
description = description[:-1]
examples_mandatories.yaml_add_eol_comment(description, name, column=self.comment_examples_column)
break
def _parse_examples_family(
self,
family,
dyn_parent: Optional[str],
examples: dict,
examples_mandatories: dict,
) -> None:
def _set_example(idx, identifiers):
path = calc_path(ori_path, identifiers=identifiers)
if dyn_parent is not None and not path.startswith(dyn_parent):
return
if len(family["informations"]["names"]) == 1:
name = family["informations"]["names"][0]
else:
name = family["informations"]["names"][idx]
if family["type"] == "leadership":
func = self._parse_examples_leadership
else:
func = self._parse_examples
ret_e, ret_m = func(
family["children"],
path + "." if family["type"] == "dynamic" else dyn_parent,
)
if ret_m:
examples_mandatories[name] = ret_m
if self.comment_examples and "description" in family["informations"]:
description = family["informations"]["description"]
if description.endswith('.'):
description = description[:-1]
examples_mandatories.yaml_add_eol_comment(description, name, column=self.comment_examples_column)
if ret_e:
examples[name] = ret_e
if self.comment_examples and "description" in family["informations"]:
description = family["informations"]["description"]
if description.endswith('.'):
description = description[:-1]
examples.yaml_add_eol_comment(description, name, column=self.comment_examples_column)
ori_path = family["informations"]["path"]
if "identifiers" in family["informations"]:
for idx, identifiers in enumerate(family["informations"]["identifiers"]):
_set_example(idx, identifiers)
else:
_set_example(0, None)
def _parse_examples_leadership(
self, leadership, dyn_parent: Optional[str] = None
) -> tuple:
examples = []
examples_mandatories = []
leader = next(iter(leadership.values()))
paths = []
ori_path = leader["path"]
if "identifiers" in leader:
for idx, identifiers in enumerate(leader["identifiers"]):
paths.append(calc_path(ori_path, identifiers=identifiers))
else:
paths.append(ori_path)
for path_idx, path in enumerate(paths):
path = calc_path(path)
if dyn_parent is not None and not path.startswith(dyn_parent):
continue
for leader_idx in range(len(leader["example"][path_idx])):
if self.comment_examples:
followers = CommentedMap()
else:
followers = {}
for follower in leadership.values():
if len(follower["names"]) == 1:
name = follower["names"][0]
else:
name = follower["names"][path_idx]
followers[name] = follower["example"][path_idx][leader_idx]
if self.comment_examples and "description" in follower:
description = follower["description"]
if description.endswith('.'):
description = description[:-1]
followers.yaml_add_eol_comment(description, name, column=self.comment_examples_column)
examples.append(followers)
if leader["mandatory_without_value"]:
if self.comment_examples:
followers = CommentedMap()
else:
followers = {}
for follower in leadership.values():
if not follower["mandatory_without_value"]:
continue
if len(follower["names"]) == 1:
name = follower["names"][0]
else:
name = follower["names"][path_idx]
followers[name] = follower["example"][path_idx][leader_idx]
if self.comment_examples and "description" in follower:
description = follower["description"]
if description.endswith('.'):
description = description[:-1]
followers.yaml_add_eol_comment(description, name, column=self.comment_examples_column)
examples_mandatories.append(followers)
break
return examples, examples_mandatories

View file

@ -1,6 +1,6 @@
"""Internationalisation utilities
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
Copyright (C) 2024
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
@ -19,8 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
from gettext import translation
from pathlib import Path
t = translation(
"rougail_output_doc", str(Path(__file__).parent / "locale"), fallback=True
)
t = translation("rougail_output_doc", str(Path(__file__).parent / "locale"), fallback=True)
_ = t.gettext

View file

@ -1,6 +1,6 @@
"""Loads output
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
Copyright (C) 2024
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the

View file

@ -1,6 +1,6 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
Copyright (C) 2024
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
@ -16,36 +16,86 @@ You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from io import BytesIO
from typing import List
from ..utils import CommonFormatter, dump
from itertools import chain
from ruamel.yaml import YAML
class Formatter(CommonFormatter):
"""The asciidoc formatter"""
class Formater:
name = "asciidoc"
_table_name = "asciidoc"
level = 40
def __init__(self):
self._yaml = YAML()
self._yaml.indent(mapping=2, sequence=4, offset=2)
def header(self):
return ""
def title(
self,
title: str,
level: int,
) -> str:
"""Display family name as a title"""
char = "="
return f"{char * (level + 1)} {title}\n\n"
def yaml(self, dump: dict) -> str:
return f"[,yaml]\n----\n{self.dump(dump)}\n----\n"
def table(self, table: str) -> str:
# add 'a' option in cols to display list
stable = table.split("\n", 1)
return stable[0].replace("<", "a") + "\n" + stable[1]
def link(
self,
comment: str,
link: str,
) -> str:
return f"`{link}[{comment}]`"
def prop(
self,
prop: str,
) -> str:
return f"`{prop}`"
def list(
self,
choices: list,
) -> str:
prefix = "\n\n* "
char = "\n* "
return prefix + char.join([self.dump(choice) for choice in choices])
def is_list(
self,
txt: str,
) -> str:
return txt.startswith("* ")
def columns(
self,
col1: List[str],
col2: List[str],
) -> None:
self.max_line = 0
for params in chain(col1, col2):
for param in params.split("\n"):
self.max_line = max(self.max_line, len(param))
self.max_line += 1
def join(
self,
lst: List[str],
) -> str:
"""Display line in table from a list"""
string = ""
previous = ""
for line in lst:
if string:
if self.is_list(previous.split("\n", 1)[-1]):
if self.is_list(previous.split("\n")[-1]):
string += "\n\n"
else:
string += " +\n"
@ -54,84 +104,36 @@ class Formatter(CommonFormatter):
previous = line
return "\n" + string
def to_string(
self,
text: str,
) -> str:
return text
def table_header(
self,
lst,
):
return lst[0] + " " * (self.max_line - len(lst[0])), lst[1] + " " * (
self.max_line - len(lst[1])
)
def bold(
self,
msg: str,
) -> str:
"""Set a text to bold"""
return f"**{msg}**"
def italic(
self,
msg: str,
) -> str:
"""Set a text to italic"""
return f"__{msg}__"
return f"_{msg}_"
def delete(
self,
msg: str,
) -> str:
"""Set a text to deleted"""
return f"+++{msg}+++"
def underline(
self,
msg: str,
) -> str:
"""Set a text to underline"""
return f"#{msg}#"
def stripped(
self,
text: str,
) -> str:
"""Return stripped text (as help)"""
return text.strip()
def list(
self,
choices: list,
inside_table: bool=True,
) -> str:
"""Display a liste of element"""
prefix = "\n\n* "
char = "\n* "
return prefix + char.join([dump(choice) for choice in choices])
def prop(
self,
prop: str,
italic: bool,
) -> str:
"""Display property"""
if italic:
prop = self.italic(prop)
return f"`{prop}`"
def yaml(self, _dump: dict) -> str:
"""Dump yaml part of documentation"""
return f"[,yaml]\n----\n---\n{dump(_dump)}\n----\n"
def table(self, datas: list, with_header: bool = True) -> str:
"""Transform list to a table in string format
we change the first line because we want that col has the same width
"""
table = super().table(datas, with_header)
stable = table.split("\n", 1)
return '[cols="1a,1a"]\n' + stable[1]
def link(
self,
comment: str,
link: str,
) -> str:
"""Add a link"""
return f"`{link}[{comment}]`"
def is_list(
self,
txt: str,
) -> str:
"""verify if a text is a list"""
return txt.strip().startswith("* ")
def dump(self, dico):
with BytesIO() as ymlfh:
self._yaml.dump(dico, ymlfh)
ret = ymlfh.getvalue().decode("utf-8").strip()
if ret.endswith("..."):
ret = ret[:-3].strip()
return ret

View file

@ -1,169 +0,0 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from typing import List
from ..i18n import _
from ..utils import dump, CommonFormatter, ENTER
class Formatter(CommonFormatter):
"""The markdown (for github) formatter"""
name = "console"
level = 10
enter_table = "\n"
titles_color = {
"title1": "bright_cyan underline bold",
"title2": "bright_green underline bold",
"title3": "green1 underline bold",
"title4": "green3 underline bold",
"title5": "dark_green underline bold",
}
def __init__(self, doc) -> None:
from rich.table import Table
from rich.theme import Theme
from rich.console import Console
self.rich_table = Table
self.rich_console = Console
if doc.force_true_color_terminal:
self.force_terminal = 'xterm-256color'
else:
self.force_terminal = None
self.custom_theme = Theme(self.titles_color)
self.max_line = 0
super().__init__(doc)
def run(self, dico: dict, level: int, *, dico_is_already_treated=False) -> str:
if not dico_is_already_treated:
dico = self.dict_to_dict(dico, level)
console = self.rich_console(theme=self.custom_theme, force_terminal=self.force_terminal)
with console.capture() as capture:
for data in dico:
console.print(data)
return capture.get()
def title(
self,
title: str,
level: int,
) -> str:
"""Display family name as a title"""
space = " " * (2 * (level - 1))
return f"{ENTER}{space}[title{level}]{title}[/title{level}]{ENTER}"
def join(
self,
lst: List[str],
) -> str:
"""Display line in table from a list"""
return self.enter_table.join(lst)
def bold(
self,
msg: str,
) -> str:
"""Set a text to bold"""
return f"[bold]{msg}[/bold]"
def italic(
self,
msg: str,
) -> str:
"""Set a text to italic"""
return f"[italic]{msg}[/italic]"
def delete(
self,
msg: str,
) -> str:
"""Set a text to delete"""
return f"[strike]{msg}[/strike]"
def underline(
self,
msg: str,
) -> str:
"""Set a text to underline"""
return f"[underline]{msg}[/underline]"
def stripped(
self,
text: str,
) -> str:
"""Return stripped text (as help)"""
return text
def list(
self,
choices: list,
inside_table: bool=True,
) -> str:
"""Display a liste of element"""
char = f"{self.enter_table}- "
ret = ""
for choice in choices:
if not isinstance(choice, str):
choice = dump(choice)
ret += char + choice
return ret
def prop(
self,
prop: str,
italic: bool,
) -> str:
"""Display property"""
prop = f"[reverse][bold] {prop} [/bold][/reverse]"
if italic:
prop = self.italic(prop)
return prop
def yaml(self, _dump):
"""Dump yaml part of documentation"""
return f"```yaml\n---\n{dump(_dump)}\n```\n"
def link(
self,
comment: str,
link: str,
) -> str:
"""Add a link"""
return self.prop(comment, False)
# return f"{comment} ({link})"
def columns(
self,
col: List[str],
) -> None:
"""count columns length"""
for line in col:
for l in line.split(self.enter_table):
self.max_line = max(self.max_line, len(l) + 1)
def table(self, datas: list, with_header: bool = True) -> str:
"""Transform list to a table in string format"""
table = self.rich_table(show_lines=True)
if with_header:
table.add_column(_("Variable"), width=self.max_line)
table.add_column(_("Description"), width=self.max_line)
for data in datas:
table.add_row(str(data[0]), data[1])
return table

View file

@ -1,6 +1,6 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
Copyright (C) 2024
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
@ -16,131 +16,112 @@ You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from io import BytesIO
from typing import List
from html import escape
from ..utils import dump, CommonFormatter
from itertools import chain
from ruamel.yaml import YAML
class Formatter(CommonFormatter):
"""The markdown (for github) formatter"""
class Formater:
name = "github"
_table_name = "github"
level = 50
enter_table = "<br/>"
def __init__(self, doc, **kwarg) -> None:
self.max_line_variable = 0
self.max_line_description = 0
super().__init__(doc)
def __init__(self):
self._yaml = YAML()
self._yaml.indent(mapping=2, sequence=4, offset=2)
self.header_setted = False
def header(self):
if self.header_setted:
return ""
self.header_setted = True
return "---\ngitea: none\ninclude_toc: true\n---\n"
def title(
self,
title: str,
level: int,
) -> str:
"""Display family name as a title"""
char = "#"
return f"{char * level} {title}\n\n"
def join(
self,
lst: List[str],
) -> str:
"""Display line in table from a list"""
return self.enter_table.join(lst)
def yaml(self, dump):
return f"```yaml\n---\n{self.dump(dump)}\n```\n"
def bold(
self,
msg: str,
) -> str:
"""Set a text to bold"""
return f"**{msg}**"
def italic(
self,
msg: str,
) -> str:
"""Set a text to italic"""
return f"*{msg}*"
def delete(
self,
msg: str,
) -> str:
"""Set a text to deleted"""
return f"~~{msg}~~"
def underline(
self,
msg: str,
) -> str:
"""Set a text to underline"""
return f"<ins>{msg}</ins>"
def stripped(
self,
text: str,
) -> str:
"""Return stripped text (as help)"""
return text.strip().replace("\n", self.enter_table)
def list(
self,
choices: list,
inside_table: bool=True,
):
"""Display a liste of element"""
if inside_table:
char = f"{self.enter_table}- "
else:
char = "\n- "
ret = ""
for choice in choices:
if not isinstance(choice, str):
choice = dump(choice)
ret += char + choice
return ret
def prop(
self,
prop: str,
italic: bool,
) -> str:
"""Display property"""
prop = f"`{prop}`"
if italic:
prop = self.italic(prop)
return prop
def table_header(self, lst):
"""Manage the header of a table"""
return lst[0] + "&nbsp;" * (self.max_line_variable - len(lst[0])), lst[
1
] + "&nbsp;" * (self.max_line_description - len(lst[1]))
def yaml(self, _dump):
"""Dump yaml part of documentation"""
return f"```yaml\n---\n{dump(_dump)}\n```\n"
def table(self, table):
return table
def link(
self,
comment: str,
link: str,
) -> str:
"""Add a link"""
return f"[`{comment}`]({link})"
def prop(
self,
prop: str,
) -> str:
return f"`{prop}`"
def list(
self,
choices,
):
prefix = "<br/>- "
char = "<br/>- "
return prefix + char.join([self.dump(choice) for choice in choices])
def is_list(
self,
txt: str,
) -> str:
return txt.startswith("* ")
def columns(
self,
col: List[str],
col1: List[str],
col2: List[str],
) -> None:
"""count columns length"""
for line in col:
for l in line.split(self.enter_table):
self.max_line_variable = max(self.max_line_variable, len(l) + 1)
self.max_line_description = self.max_line_variable
self.max_line = 0
for params in chain(col1, col2):
for param in params.split("\n"):
self.max_line = max(self.max_line, len(param))
self.max_line += 1
def to_phrase(self, text: str) -> str:
return escape(text)
def join(
self,
lst: List[str],
) -> str:
return "<br/>".join(lst)
def to_string(
self,
text: str,
) -> str:
return text.strip().replace("\n", "<br/>")
def table_header(self, lst):
return lst[0] + "&nbsp;" * (self.max_line - len(lst[0])), lst[1] + "&nbsp;" * (
self.max_line - len(lst[1])
)
def bold(
self,
msg: str,
) -> str:
return f"**{msg}**"
def italic(
self,
msg: str,
) -> str:
return f"*{msg}*"
def dump(self, dico):
with BytesIO() as ymlfh:
self._yaml.dump(dico, ymlfh)
ret = ymlfh.getvalue().decode("utf-8").strip()
if ret.endswith("..."):
ret = ret[:-3].strip()
return ret

View file

@ -1,81 +0,0 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2025
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from typing import List, Optional
from .github import Formatter as GithubFormatter
from ..i18n import _
class Formatter(GithubFormatter):
name = "gitlab"
level = 51
def namespace_to_title(self, informations: dict, level: int) -> str:
"""manage namespace family"""
return self.title(
self.get_description("family", informations, {}, None),
level,
)
def title(self, title: str, level: int) -> str:
# self.max_line_variable = 0
return "<details><summary>" + title + "</summary>\n\n"
def end_family(self, level):
return "</details>\n\n"
def anchor(self,
path: str,
true_path: str,
) -> str:
return f'<a id="{true_path}" name="{true_path}">{path}</a>'
def link_variable(self,
path: str,
description: str,
filename: Optional[str],
) -> str:
if filename:
link = f'{filename}#{path}'
else:
link = f'#{path}'
return self.link(description, link)
def columns(
self,
col: List[str],
) -> None:
pass
def family_informations(self) -> str:
return f">>> [!note] {_('Informations')}\n"
def end_family_informations(self) -> str:
return f"\n>>>\n"
def after_family_paths(self) -> str:
return "<br>"
def after_family_properties(self) -> str:
return ""
def table_header(self, lst):
"""Manage the header of a table"""
return lst

View file

@ -1,136 +0,0 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2025
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from typing import List
from html import escape
from ..utils import CommonFormatter, dump
class Formatter(CommonFormatter):
"""The asciidoc formatter"""
name = "html"
_table_name = "unsafehtml"
level = 45
def title(
self,
title: str,
level: int,
) -> str:
"""Display family name as a title"""
return f"<h{level}>{title}</h{level}>\n\n"
def join(
self,
lst: List[str],
) -> str:
"""Display line in table from a list"""
string = ""
previous = ""
for line in lst:
if string:
# if self.is_list(previous.split("\n", 1)[-1]):
# string += "<br/><br/>"
# else:
string += "<br/>"
string += line
previous = line
return string
def bold(
self,
msg: str,
) -> str:
"""Set a text to bold"""
return f"<b>{msg}</b>"
def italic(
self,
msg: str,
) -> str:
"""Set a text to italic"""
return f"<i>{msg}</i>"
def delete(
self,
msg: str,
) -> str:
"""Set a text to deleted"""
return f"<del>{msg}</del>"
def underline(
self,
msg: str,
) -> str:
"""Set a text to underline"""
return f"<ins>{msg}</ins>"
def stripped(
self,
text: str,
) -> str:
"""Return stripped text (as help)"""
return text.strip()
def list(
self,
choices: list,
inside_table: bool=True,
) -> str:
"""Display a liste of element"""
prefix = "<ul>"
char = "\n"
return (
"<ul>"
+ char.join(["<li>" + dump(choice) + "</li>" for choice in choices])
+ "</ul>"
)
def prop(
self,
prop: str,
italic: bool,
) -> str:
"""Display property"""
if italic:
prop = self.italic(prop)
return f"<mark>{prop}</mark>"
def yaml(self, _dump: dict) -> str:
"""Dump yaml part of documentation"""
return f"<pre>{dump(_dump)}</pre>"
def link(
self,
comment: str,
link: str,
) -> str:
"""Add a link"""
return self.prop(f"<a href='{link}'>{comment}</a>", False)
def is_list(
self,
txt: str,
) -> str:
"""verify if a text is a list"""
return txt.strip().startswith("<ul>")
def to_phrase(self, text: str) -> str:
return escape(text)

View file

@ -1,34 +0,0 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from json import dumps
from typing import Any
class Formatter:
"""Just return internal structure to json"""
name = "json"
level = 90
def __init__(self, doc):
pass
def run(self, dico: dict, *args) -> str: # pylint: disable=unused-argument
"""Transform to string"""
return dumps(dico, ensure_ascii=False, indent=2)

View file

@ -1,898 +0,0 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from typing import Tuple, List, Optional
from io import BytesIO
from ruamel.yaml import YAML
import tabulate as tabulate_module
from tiramisu.error import display_list
from tabulate import tabulate
from rougail.tiramisu import normalize_family
from tiramisu import undefined
from .i18n import _
ROUGAIL_VARIABLE_TYPE = (
"https://rougail.readthedocs.io/en/latest/variable.html#variables-types"
)
ENTER = "\n\n"
DocTypes = {
"domainname": {
"params": {
"allow_startswith_dot": _("the domain name can starts by a dot"),
"allow_without_dot": _("the domain name can be a hostname"),
"allow_ip": _("the domain name can be an IP"),
"allow_cidr_network": _("the domain name can be network in CIDR format"),
},
},
"number": {
"params": {
"min_number": _("the minimum value is {0}"),
"max_number": _("the maximum value is {0}"),
},
},
"integer": {
"params": {
"min_integer": _("the minimum value is {0}"),
"max_integer": _("the maximum value is {0}"),
},
},
"ip": {
"msg": "IP",
"params": {
"cidr": _("IP must be in CIDR format"),
"private_only": _("private IP are allowed"),
"allow_reserved": _("reserved IP are allowed"),
},
},
"network": {
"params": {
"cidr": _("network must be in CIDR format"),
},
},
"hostname": {
"params": {
"allow_ip": _("the host name can be an IP"),
},
},
"web_address": {
"params": {
"allow_ip": _("the domain name in web address can be an IP"),
"allow_without_dot": _(
"the domain name in web address can be only a hostname"
),
},
},
"port": {
"params": {
"allow_range": _("can be range of port"),
"allow_protocol": _("can have the protocol"),
"allow_zero": _("port 0 is allowed"),
"allow_wellknown": _("well-known ports (1 to 1023) are allowed"),
"allow_registred": _("registred ports (1024 to 49151) are allowed"),
"allow_private": _("private ports (greater than 49152) are allowed"),
},
},
"secret": {
"params": {
"min_len": _("minimum length for the secret is {0} characters"),
"max_len": _("maximum length for the secret is {0} characters"),
"forbidden_char": _("forbidden characters: {0}"),
},
},
"unix_filename": {
"params": {
"allow_relative": _("this filename could be a relative path"),
"test_existence": _("this file must exists"),
"types": _("file type allowed: {0}"),
},
},
}
_yaml = YAML()
_yaml.indent(mapping=2, sequence=4, offset=2)
def dump(informations):
"""Dump variable, means transform bool, ... to yaml string"""
with BytesIO() as ymlfh:
_yaml.dump(informations, ymlfh)
ret = ymlfh.getvalue().decode("utf-8").strip()
if ret.endswith("..."):
ret = ret[:-3].strip()
return ret
def to_phrase(msg, type_="variable"):
"""Add maj for the first character and ends with dot"""
if not msg:
# replace None to empty string
return ""
msg = str(msg).strip()
# a phrase must ends with a dot
if type_ == "variable":
if not msg.endswith("."):
msg += "."
elif type_ in ["family", "description"]:
if msg.endswith("."):
msg = msg[:-1]
else:
raise Exception("unknown type")
# and start with a maj
return msg[0].upper() + msg[1:]
class CommonFormatter:
"""Class with common function for formatter"""
enter_table = "\n"
# tabulate module name
name = None
def __init__(self, doc, **kwarg):
tabulate_module.PRESERVE_WHITESPACE = True
self.header_setted = False
self.with_family = doc.with_family
self.other_root_filenames = doc.other_root_filenames
if doc.other_root_filenames:
self.other_root_filenames = dict(zip(doc.other_root_filenames["root_path"], self.other_root_filenames["filename"]))
# Class you needs implement to your Formatter
def title(
self,
title: str,
level: int,
) -> str:
"""Display family name as a title"""
raise NotImplementedError()
def join(
self,
lst: List[str],
) -> str:
"""Display line in table from a list"""
raise NotImplementedError()
def bold(
self,
msg: str,
) -> str:
"""Set a text to bold"""
raise NotImplementedError()
def underline(
self,
msg: str,
) -> str:
"""Set a text to underline"""
raise NotImplementedError()
def anchor(self,
path: str,
true_path: str,
) -> str:
"""Set a text to a link anchor"""
return path
def link_variable(self,
path: str,
description: str,
filename: Optional[str],
) -> str:
"""Set a text link to variable anchor"""
return path
def stripped(
self,
text: str,
) -> str:
"""Return stripped text (as help)"""
raise NotImplementedError()
def list(
self,
choices: list,
inside_table: bool=True,
) -> str:
"""Display a liste of element"""
raise NotImplementedError()
def prop(
self,
prop: str,
italic: bool,
) -> str:
"""Display property"""
raise NotImplementedError()
def link(
self,
comment: str,
link: str,
) -> str:
"""Add a link"""
raise NotImplementedError()
##################
def family_informations(self) -> str:
return ""
def end_family_informations(self) -> str:
return ""
def display_paths(
self,
informations: dict,
modified_attributes: dict,
force_identifiers: Optional[str],
*,
is_variable=False
) -> str:
ret_paths = []
path = informations["path"]
if "identifiers" in modified_attributes:
name, previous, new = modified_attributes["identifiers"]
ret_paths.extend(
[
self.bold(self.delete(calc_path(path, self, identifier)))
for identifier in previous
]
)
else:
new = []
if "identifiers" in informations:
for idx, identifier in enumerate(informations["identifiers"]):
if force_identifiers and identifier != force_identifiers:
continue
path_ = calc_path(path, self, identifier)
if not idx:
path_ = self.anchor(path_, path)
if identifier in new:
path_ = self.underline(path_)
ret_paths.append(self.bold(path_))
else:
ret_paths.append(self.bold(self.anchor(path, path)))
return ret_paths
def after_family_paths(self) -> str:
return ENTER
def after_family_properties(self) -> str:
return ENTER
def table_header(
self,
lst: list,
) -> tuple:
"""Manage the header of a table"""
return lst
def run(
self, informations: dict, level: int, *, dico_is_already_treated=False
) -> str:
"""Transform to string"""
if informations:
return self._run(informations, level, dico_is_already_treated)
return ""
def _run(self, dico: dict, level: int, dico_is_already_treated: bool) -> str:
"""Parse the dict to transform to dict"""
if dico_is_already_treated:
return "".join(dico)
return "".join([msg for msg in self.dict_to_dict(dico, level, init=True)])
def dict_to_dict(
self,
dico: dict,
level: int,
*,
ori_table_datas: list = None,
init: bool = False,
) -> str:
"""Parse the dict to transform to dict"""
msg = []
if ori_table_datas is not None:
table_datas = ori_table_datas
else:
table_datas = []
ori_level = None
for value in dico.values():
if value["type"] == "variable":
self.variable_to_string(value, table_datas)
else:
if self.with_family:
if value["type"] == "namespace":
if ori_level is None:
ori_level = level
level += 1
informations = value["informations"]
msg.append(self.namespace_to_title(informations, ori_level))
msg.append(self.family_informations())
msg.extend(self.display_paths(informations, {}, None))
msg.append(self.after_family_paths())
msg.append(
self.property_to_string(informations, {}, {})[1] + ENTER
)
msg.append(self.end_family_informations())
msg.extend(self.dict_to_dict(value["children"], level))
msg.append(self.end_namespace(ori_level))
else:
if table_datas:
msg.append(self.table(table_datas))
table_datas = []
msg.extend(self.family_to_string(value["informations"], level))
msg.extend(self.dict_to_dict(value["children"], level + 1))
msg.append(self.end_family(level))
else:
self.dict_to_dict(
value["children"], level + 1, ori_table_datas=table_datas
)
if (init or ori_table_datas is None) and table_datas:
msg.append(self.table(table_datas))
return msg
# FAMILY
def namespace_to_title(self, informations: dict, level: int) -> str:
"""manage namespace family"""
return self.title(
_('Variables for "{0}"').format(
self.get_description("family", informations, {}, None)
),
level,
)
def end_namespace(self, level: int) -> str:
return self.end_family(level)
def family_to_string(self, informations: dict, level: int) -> str:
"""manage other family type"""
msg = [self.title(self.get_description("family", informations, {}, None), level)]
helps = informations.get("help")
if helps:
for help_ in helps:
msg.append(self.display_family_help(help_.strip()))
msg.append(self.family_informations())
msg.append(
self.join(self.display_paths(informations, {}, None)) + self.after_family_paths()
)
calculated_properties = []
msg.append(
self.property_to_string(informations, calculated_properties, {})[1] + ENTER
)
if calculated_properties:
msg.append(
self.join(calculated_properties) + self.after_family_properties()
)
if "identifier" in informations:
msg.append(
self.section(_("Identifiers"), informations["identifier"])
+ self.after_family_properties()
)
msg.append(self.end_family_informations())
return msg
def end_family(self, level: int) -> str:
return ""
def convert_list_to_string(
self, attribute: str, informations: dict, modified_attributes: dict
) -> str():
datas = []
if attribute in modified_attributes:
name, previous, new = modified_attributes[attribute]
for data in previous:
datas.append(self.delete(self.to_phrase(data)))
else:
new = []
if attribute in informations:
for data in informations[attribute]:
if isinstance(data, dict):
if attribute.endswith("s"):
attr = attribute[:-1]
else:
attr = attribute
data = data[attr].replace(
"{{ identifier }}", self.italic(data["identifier"])
)
data = self.to_phrase(data)
if data in new:
data = self.underline(data)
datas.append(data)
return self.stripped(self.join(datas))
def get_description(
self, type_: str, informations: dict, modified_attributes: dict, force_identifiers: Optional[str]
) -> str():
def _get_description(description, identifiers, delete=False, new=[]):
if "{{ identifier }}" in description:
if type_ == "variable":
identifiers_text = display_list(
[self.italic(i[-1]) for i in identifiers if not force_identifiers or i == force_identifiers], separator="or"
)
description = description.replace(
"{{ identifier }}", identifiers_text
)
else:
d = []
for i in identifiers:
if force_identifiers and i != force_identifiers:
continue
new_description = description.replace(
"{{ identifier }}", self.italic(i[-1])
)
if new_description not in d:
d.append(self.to_phrase(new_description))
description = display_list(d, separator="or")
else:
description = self.to_phrase(description)
if description in new:
description = self.underline(description)
if delete:
description = self.delete(description)
return description
if "description" in modified_attributes:
name, previous, new = modified_attributes["description"]
modified_description = _get_description(
previous, modified_attributes.get("identifiers", []), delete=True
)
else:
modified_description = None
new = []
description = _get_description(
informations["description"], informations.get("identifiers"), new=new
)
if modified_description:
if description:
description = self.join([modified_description, description])
else:
description = modified_description
if not description:
return None
return self.stripped(description)
# VARIABLE
def variable_to_string(
self, informations: dict, table_datas: list, modified_attributes: dict = {}, force_identifiers: Optional[str]=None
) -> None:
"""Manage variable"""
calculated_properties = []
multi, first_column = self.variable_first_column(
informations, calculated_properties, modified_attributes, force_identifiers
)
table_datas.append(
[
self.join(first_column),
self.join(
self.variable_second_column(
informations,
calculated_properties,
modified_attributes,
multi,
force_identifiers,
)
),
]
)
def variable_first_column(
self,
informations: dict,
calculated_properties: list,
modified_attributes: Optional[dict],
force_identifiers: Optional[str],
) -> list:
"""Collect string for the first column"""
multi, properties = self.property_to_string(
informations, calculated_properties, modified_attributes
)
first_col = [
self.join(self.display_paths(informations, modified_attributes, force_identifiers, is_variable=True)),
properties,
]
self.columns(first_col)
return multi, first_col
def variable_second_column(
self,
informations: dict,
calculated_properties: list,
modified_attributes: dict,
multi: bool,
force_identifiers: Optional[str],
) -> list:
"""Collect string for the second column"""
second_col = []
#
if "description" in informations:
description = self.get_description(
"variable", informations, modified_attributes, force_identifiers,
)
second_col.append(description)
#
help_ = self.convert_list_to_string("help", informations, modified_attributes)
if help_:
second_col.append(help_)
#
validators = self.convert_section_to_string(
"validators", informations, modified_attributes, multi=True
)
if validators:
second_col.append(validators)
default_is_already_set, choices = self.convert_choices_to_string(
informations, modified_attributes
)
if choices:
second_col.append(choices)
if not default_is_already_set and "default" in informations:
self.convert_section_to_string(
"default", informations, modified_attributes, multi=multi
)
second_col.append(
self.convert_section_to_string(
"default", informations, modified_attributes, multi=multi
)
)
examples = self.convert_section_to_string(
"examples", informations, modified_attributes, multi=True
)
if examples:
second_col.append(examples)
tags = self.convert_section_to_string(
"tags", informations, modified_attributes, multi=True
)
if tags:
second_col.append(tags)
second_col.extend(calculated_properties)
self.columns(second_col)
return second_col
def convert_section_to_string(
self, attribute: str, informations: dict, modified_attributes: dict, multi: bool
) -> str():
values = []
submessage = ""
if modified_attributes and attribute in modified_attributes:
name, previous, new = modified_attributes[attribute]
# if "identifiers" in modified_attributes:
# iname, iprevious, inew = modified_attributes["identifiers"]
# identifiers = iprevious.copy()
# for identifier in informations.get("identifiers", []):
# if identifier not in inew:
# identifiers.append(identifier)
#
# else:
# identifiers = informations.get("identifiers", [])
if isinstance(previous, list):
for p in previous:
submessage, m = self.message_to_string(p, submessage)
values.append(self.delete(m))
else:
submessage, old_values = self.message_to_string(previous, submessage)
values.append(self.delete(old_values))
else:
new = []
if attribute in informations:
old = informations[attribute]
name = old["name"]
if isinstance(old["values"], list):
for value in old["values"]:
submessage, old_value = self.message_to_string(value, submessage)
if value in new:
old_value = self.underline(old_value)
values.append(old_value)
if multi:
values = self.list(values)
else:
values = self.join(values)
elif values:
old_values = old["values"]
submessage, old_values = self.message_to_string(old_values, submessage)
if old["values"] in new:
old_values = self.underline(old_values)
values.append(old_values)
values = self.join(values)
else:
submessage, values = self.message_to_string(old["values"], submessage)
if old["values"] in new:
values = self.underline(values)
if values != []:
return self.section(name, values, submessage=submessage)
def convert_choices_to_string(
self, informations: dict, modified_attributes: dict
) -> str():
default_is_already_set = False
if "choices" in informations:
choices = informations["choices"]
choices_values = choices["values"]
if not isinstance(choices_values, list):
choices_values = [choices_values]
default_is_a_list = False
else:
default_is_a_list = True
for idx, choice in enumerate(choices_values.copy()):
if isinstance(choice, dict):
choices_values[idx] = self.message_to_string(choice, None)[1]
if "default" in modified_attributes:
name, old_default, new_default = modified_attributes["default"]
if not old_default:
old_default = [None]
if not isinstance(old_default, list):
old_default = [old_default]
for value in old_default.copy():
if (
isinstance(value, str)
and value.endswith(".")
and value not in choices_values
):
old_default.remove(value)
old_default.append(value[:-1])
else:
old_default = new_default = []
# check if all default values are in choices (could be from a calculation)
if "default" in informations:
default = informations["default"]["values"]
else:
default = []
if not isinstance(default, list):
default = [default]
for idx, value in enumerate(default.copy()):
if isinstance(value, dict):
default[idx] = self.message_to_string(value, None)[1]
default_value_not_in_choices = set(default) - set(choices_values)
if default_value_not_in_choices:
default_is_changed = False
for val in default_value_not_in_choices.copy():
if (
isinstance(val, str)
and val.endswith(".")
and val[:-1] in choices_values
):
default.remove(val)
default.append(val[:-1])
default_is_changed = True
if val in new_default:
new_default.remove(val)
new_default.append(val[:-1])
if default_is_changed:
default_value_not_in_choices = set(default) - set(choices_values)
if default_value_not_in_choices:
old_default = []
new_default = []
default = []
else:
default_is_already_set = True
if "choices" in modified_attributes:
name, previous, new = modified_attributes["choices"]
for choice in reversed(previous):
if isinstance(choice, dict):
choice = self.message_to_string(choice, None)[1]
if choice in old_default:
choices_values.insert(
0, self.delete(dump(choice) + "" + _("(default)"))
)
else:
choices_values.insert(0, self.delete(dump(choice)))
else:
new = []
for idx, val in enumerate(choices_values):
if val in old_default:
choices_values[idx] = (
dump(val) + " " + self.delete("" + _("(default)"))
)
elif val in default:
if val in new_default:
if val in new:
choices_values[idx] = self.underline(
dump(val) + " " + self.bold("" + _("(default)"))
)
else:
choices_values[idx] = (
dump(val)
+ " "
+ self.underline(self.bold("" + _("(default)")))
)
else:
choices_values[idx] = (
dump(val) + " " + self.bold("" + _("(default)"))
)
elif val in new:
choices_values[idx] = self.underline(dump(val))
# if old value and new value is a list, display a list
if not default_is_a_list and len(choices_values) == 1:
choices_values = choices_values[0]
return default_is_already_set, self.section(choices["name"], choices_values)
return default_is_already_set, None
# OTHERs
def to_phrase(self, text: str) -> str:
return text
def display_family_help(self, help_):
return self.to_phrase(help_) + ENTER
def property_to_string(
self,
informations: dict,
calculated_properties: list,
modified_attributes: dict,
) -> str:
"""Transform properties to string"""
properties = []
local_calculated_properties = {}
multi = False
if "properties" in modified_attributes:
previous, new = self.get_modified_properties(
*modified_attributes["properties"][1:]
)
for p, annotation in previous.items():
if p not in new:
properties.append(self.prop(self.delete(p), italic=False))
if annotation is not None:
local_calculated_properties[p] = [self.delete(annotation)]
else:
previous = new = []
for prop in informations.get("properties", []):
if prop["type"] == "type":
properties.append(self.link(prop["name"], ROUGAIL_VARIABLE_TYPE))
else:
if prop["type"] == "multiple":
multi = True
prop_name = prop["name"]
if "annotation" in prop:
italic = True
prop_annotation = prop["annotation"]
if prop_name in new and (
prop_name not in previous
or new[prop_name] != previous[prop_name]
):
prop_annotation = self.underline(prop_annotation)
local_calculated_properties.setdefault(prop["name"], []).append(
prop_annotation
)
else:
italic = False
if prop_name not in previous and prop_name in new:
prop_name = self.underline(prop_name)
properties.append(self.prop(prop_name, italic=italic))
if local_calculated_properties:
for (
calculated_property_name,
calculated_property,
) in local_calculated_properties.items():
if len(calculated_property) > 1:
calculated_property = self.join(calculated_property)
else:
calculated_property = calculated_property[0]
calculated_properties.append(
self.section(
calculated_property_name.capitalize(), calculated_property
)
)
if not properties:
return multi, ""
return multi, " ".join(properties)
def get_modified_properties(
self, previous: List[dict], new: List[dict]
) -> Tuple[dict, dict]:
def modified_properties_parser(dico):
return {d["name"]: d.get("annotation") for d in dico}
return modified_properties_parser(previous), modified_properties_parser(new)
def columns(
self,
col: List[str], # pylint: disable=unused-argument
) -> None:
"""Manage column"""
return
def table(self, datas: list, with_header: bool = True) -> str:
"""Transform list to a table in string format"""
if with_header:
headers = self.table_header([_("Variable"), _("Description")])
else:
headers = ()
msg = (
tabulate(
datas,
headers=headers,
tablefmt=self._table_name,
)
+ "\n\n"
)
datas.clear()
return msg
def message_to_string(self, msg, ret, identifiers=[]):
if isinstance(msg, dict):
if "submessage" in msg:
ret += msg["submessage"]
msg = msg["values"]
elif "message" in msg:
filename = None
if self.other_root_filenames:
path = msg["path"]["path"]
for root in self.other_root_filenames:
if path == root or path.startswith(f'{root}.'):
filename = self.other_root_filenames[root]
break
path = self.link_variable(calc_path(msg["path"], self, identifiers), msg["description"], filename=filename)
msg = msg["message"].format(path)
return ret, msg
def section(
self,
name: str,
msg: str,
submessage: str = "",
) -> str:
"""Return something like Name: msg"""
submessage, msg = self.message_to_string(msg, submessage)
if isinstance(msg, list):
if len(msg) == 1:
submessage, elt = self.message_to_string(msg[0], submessage)
if isinstance(elt, list):
submessage += self.list(elt)
else:
submessage += elt
else:
lst = []
for p in msg:
submessage, elt = self.message_to_string(p, submessage)
lst.append(elt)
submessage += self.list(lst)
msg = ""
if not isinstance(msg, str):
submessage += dump(msg)
else:
submessage += msg
return _("{0}: {1}").format(self.bold(name), submessage)
def calc_path(path, formatter=None, identifiers: List[str] = None) -> str:
def _path_with_identifier(path, identifier):
identifier = normalize_family(str(identifier))
if formatter:
identifier = formatter.italic(identifier)
return path.replace("{{ identifier }}", identifier, 1)
if isinstance(path, dict):
path_ = path["path"]
if "identifiers" in path:
for identifier in path["identifiers"]:
path_ = _path_with_identifier(path_, identifier)
elif identifiers:
path_ = path
for identifier in identifiers:
path_ = _path_with_identifier(path_, identifier)
else:
path_ = path
return path_

View file

@ -1,41 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
family: # a family
var2:
description: a second variable
test:
- string6
subfamily: # a sub family
variable: # third variable
- variable: ___.var1
- variable: __.var2
var3: # a third variable
family2: # a family
var2:
description: a variable2
default:
variable: __.family.var2
var3:
description: a third variable
test:
- string5
default: string4
subfamily: # a sub family
variable: # fourth variable
- variable: ___.var1
- variable: ___.family.var2
- variable: __.var3
...

View file

@ -1,21 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
family: # a family
var2:
description: a second variable
test:
- string6
subfamily: # a sub family
variable: # third variable
- variable: ___.var1
- variable: __.var2
var3: # a third variable
...

View file

@ -1,30 +0,0 @@
== New variables
[cols="1a,1a"]
|====
| Variable | Description
|
**family2.var2** +
`https://rougail.readthedocs.io/en/latest/variable.html#variables-types[string]` `standard` `mandatory` |
A variable2. +
**Default**: the value of the variable "family.var2"
|
**family2.var3** +
`https://rougail.readthedocs.io/en/latest/variable.html#variables-types[string]` `standard` `mandatory` |
A third variable. +
**Default**: string4 +
**Example**: string5
|
**family2.subfamily.variable** +
`https://rougail.readthedocs.io/en/latest/variable.html#variables-types[string]` `standard` `mandatory` `unique` `multiple` |
Fourth variable. +
**Default**:
* the value of the variable "var1"
* the value of the variable "family.var2"
* the value of the variable "family2.var3"
|====

View file

@ -1,10 +0,0 @@
<details><summary>New variables</summary>
| Variable | Description |
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **<a id="family2.var2" name="family2.var2">family2.var2</a>**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `standard` `mandatory` | A variable2.<br/>**Default**: the value of the variable "[`A second variable`](#family.var2)" |
| **<a id="family2.var3" name="family2.var3">family2.var3</a>**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `standard` `mandatory` | A third variable.<br/>**Default**: string4<br/>**Example**: string5 |
| **<a id="family2.subfamily.variable" name="family2.subfamily.variable">family2.subfamily.variable</a>**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `standard` `mandatory` `unique` `multiple` | Fourth variable.<br/>**Default**: <br/>- the value of the variable "[`First variable`](#var1)"<br/>- the value of the variable "[`A second variable`](#family.var2)"<br/>- the value of the variable "[`A third variable`](#family2.var3)" |
</details>

View file

@ -1,15 +0,0 @@
<h1>New variables</h1>
<table>
<thead>
<tr><th>Variable </th><th>Description </th></tr>
</thead>
<tbody>
<tr><td><b>family2.var2</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>string</a></mark> <mark>standard</mark> <mark>mandatory</mark> </td><td>A variable2.<br/><b>Default</b>: the value of the variable "family.var2" </td></tr>
<tr><td><b>family2.var3</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>string</a></mark> <mark>standard</mark> <mark>mandatory</mark> </td><td>A third variable.<br/><b>Default</b>: string4<br/><b>Example</b>: string5</td></tr>
<tr><td><b>family2.subfamily.variable</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>string</a></mark> <mark>standard</mark> <mark>mandatory</mark> <mark>unique</mark> <mark>multiple</mark></td><td>Fourth variable.<br/><b>Default</b>: <ul><li>the value of the variable "var1"</li>
<li>the value of the variable "family.var2"</li>
<li>the value of the variable "family2.var3"</li></ul> </td></tr>
</tbody>
</table>

View file

@ -1,8 +0,0 @@
# New variables
| Variable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **family2.var2**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `standard` `mandatory` | A variable2.<br/>**Default**: the value of the variable "family.var2" |
| **family2.var3**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `standard` `mandatory` | A third variable.<br/>**Default**: string4<br/>**Example**: string5 |
| **family2.subfamily.variable**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `standard` `mandatory` `unique` `multiple` | Fourth variable.<br/>**Default**: <br/>- the value of the variable "var1"<br/>- the value of the variable "family.var2"<br/>- the value of the variable "family2.var3" |

View file

@ -1,25 +0,0 @@
New variables
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 Variable  ┃ Description  ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
family2.var2 │ A variable2. │
 string   standard   mandatory  │ Default: the value of the variable │
│ │ "family.var2"
├───────────────────────────────────────┼──────────────────────────────────────┤
family2.var3 │ A third variable. │
 string   standard   mandatory  │ Default: string4 │
│ │ Example: string5 │
├───────────────────────────────────────┼──────────────────────────────────────┤
family2.subfamily.variable │ Fourth variable. │
 string   standard   mandatory    │ Default: │
unique   multiple  │ - the value of the variable "var1"
│ │ - the value of the variable │
│ │ "family.var2"
│ │ - the value of the variable │
│ │ "family2.var3"
└───────────────────────────────────────┴──────────────────────────────────────┘

View file

@ -1,8 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
variable_to_family: # a variable that became a family
...

View file

@ -1,11 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
variable_to_family: # a variable that became a family
var:
description: a second variable
...

View file

@ -1,17 +0,0 @@
== New variable
[cols="1a,1a"]
|====
| Variable | Description
|
**variable_to_family** +
`https://rougail.readthedocs.io/en/latest/variable.html#variables-types[string]` `basic` `mandatory` |
A variable that became a family.
|====
== Deleted variable
* variable_to_family.var

View file

@ -1,13 +0,0 @@
<details><summary>New variable</summary>
| Variable | Description |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------|
| **<a id="variable_to_family" name="variable_to_family">variable_to_family</a>**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | A variable that became a family. |
</details>
<details><summary>Deleted variable</summary>
- variable_to_family.var</details>

View file

@ -1,14 +0,0 @@
<h1>New variable</h1>
<table>
<thead>
<tr><th>Variable </th><th>Description </th></tr>
</thead>
<tbody>
<tr><td><b>variable_to_family</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>string</a></mark> <mark>basic</mark> <mark>mandatory</mark></td><td>A variable that became a family.</td></tr>
</tbody>
</table>
<h1>Deleted variable</h1>
<ul><li>variable_to_family.var</li></ul>

View file

@ -1,10 +0,0 @@
# New variable
| Variable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **variable_to_family**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | A variable that became a family. |
# Deleted variable
- variable_to_family.var

View file

@ -1,20 +0,0 @@
New variable
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 Variable  ┃ Description  ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
variable_to_family │ A variable that became a family. │
 string   basic   mandatory  │ │
└───────────────────────────────────────┴──────────────────────────────────────┘
Deleted variable
- variable_to_family.var

View file

@ -1,41 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
family: # a family
var2:
description: a second variable
test:
- string6
subfamily: # a sub family
variable: # third variable
- variable: ___.var1
- variable: __.var2
var3: # a third variable
family2: # a family
var2:
description: a variable2
default:
variable: __.family.var2
var3:
description: a third variable
test:
- string5
default: string4
subfamily: # a sub family
variable: # fourth variable
- variable: ___.var1
- variable: ___.family.var2
- variable: __.var3
...

View file

@ -1,39 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
family: # a family
var2:
description: a second variable
test:
- string6
subfamily: # a sub family
variable: # third variable
- variable: ___.var1
- variable: __.var2
family2: # a family
var2:
description: a variable2
default:
variable: __.family.var2
var3:
description: a third variable
test:
- string5
default: string4
subfamily: # a sub family
variable: # fourth variable
- variable: ___.var1
- variable: ___.family.var2
- variable: __.var3
...

View file

@ -1,12 +0,0 @@
== New variable
[cols="1a,1a"]
|====
| Variable | Description
|
**family.var3** +
`https://rougail.readthedocs.io/en/latest/variable.html#variables-types[string]` `basic` `mandatory` |
A third variable.
|====

View file

@ -1,8 +0,0 @@
<details><summary>New variable</summary>
| Variable | Description |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|
| **<a id="family.var3" name="family.var3">family.var3</a>**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | A third variable. |
</details>

View file

@ -1,11 +0,0 @@
<h1>New variable</h1>
<table>
<thead>
<tr><th>Variable </th><th>Description </th></tr>
</thead>
<tbody>
<tr><td><b>family.var3</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>string</a></mark> <mark>basic</mark> <mark>mandatory</mark></td><td>A third variable.</td></tr>
</tbody>
</table>

View file

@ -1,6 +0,0 @@
# New variable
| Variable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **family.var3**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | A third variable. |

View file

@ -1,12 +0,0 @@
New variable
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 Variable  ┃ Description  ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
family.var3 │ A third variable. │
 string   basic   mandatory  │ │
└───────────────────────────────────────┴──────────────────────────────────────┘

View file

@ -1,11 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
variable_to_family: # a variable that became a family
var:
description: a second variable
...

View file

@ -1,8 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
variable_to_family: # a variable that became a family
...

View file

@ -1,17 +0,0 @@
== New variable
[cols="1a,1a"]
|====
| Variable | Description
|
**variable_to_family.var** +
`https://rougail.readthedocs.io/en/latest/variable.html#variables-types[string]` `basic` `mandatory` |
A second variable.
|====
== Deleted variable
* variable_to_family

View file

@ -1,13 +0,0 @@
<details><summary>New variable</summary>
| Variable | Description |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------|
| **<a id="variable_to_family.var" name="variable_to_family.var">variable_to_family.var</a>**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | A second variable. |
</details>
<details><summary>Deleted variable</summary>
- variable_to_family</details>

View file

@ -1,14 +0,0 @@
<h1>New variable</h1>
<table>
<thead>
<tr><th>Variable </th><th>Description </th></tr>
</thead>
<tbody>
<tr><td><b>variable_to_family.var</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>string</a></mark> <mark>basic</mark> <mark>mandatory</mark></td><td>A second variable.</td></tr>
</tbody>
</table>
<h1>Deleted variable</h1>
<ul><li>variable_to_family</li></ul>

View file

@ -1,10 +0,0 @@
# New variable
| Variable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **variable_to_family.var**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | A second variable. |
# Deleted variable
- variable_to_family

View file

@ -1,20 +0,0 @@
New variable
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 Variable  ┃ Description  ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
variable_to_family.var │ A second variable. │
 string   basic   mandatory  │ │
└───────────────────────────────────────┴──────────────────────────────────────┘
Deleted variable
- variable_to_family

View file

@ -1,43 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
family: # a family
var2:
description: a second variable
test:
- string6
subfamily: # a sub family
variable: # third variable
- variable: ___.var1
- variable: __.var2
var3: # a third variable
family2: # a family
var2:
description: a variable2
default:
variable: __.family.var2
var3:
description: a third variable
test:
- string5
default: string4
subfamily: # a sub family
variable: # fourth variable
- variable: ___.var1
- variable: ___.family.var2
- variable: __.var3
var4: # a fourth variable
...

View file

@ -1,39 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
family: # a family
var2:
description: a second variable
test:
- string6
subfamily: # a sub family
variable: # third variable
- variable: ___.var1
- variable: __.var2
family2: # a family
var2:
description: a variable2
default:
variable: __.family.var2
var3:
description: a third variable
test:
- string5
default: string4
subfamily: # a sub family
variable: # fourth variable
- variable: ___.var1
- variable: ___.family.var2
- variable: __.var3
...

View file

@ -1,17 +0,0 @@
== New variables
[cols="1a,1a"]
|====
| Variable | Description
|
**family.var3** +
`https://rougail.readthedocs.io/en/latest/variable.html#variables-types[string]` `basic` `mandatory` |
A third variable.
|
**family2.var4** +
`https://rougail.readthedocs.io/en/latest/variable.html#variables-types[string]` `basic` `mandatory` |
A fourth variable.
|====

View file

@ -1,9 +0,0 @@
<details><summary>New variables</summary>
| Variable | Description |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------|
| **<a id="family.var3" name="family.var3">family.var3</a>**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | A third variable. |
| **<a id="family2.var4" name="family2.var4">family2.var4</a>**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | A fourth variable. |
</details>

View file

@ -1,12 +0,0 @@
<h1>New variables</h1>
<table>
<thead>
<tr><th>Variable </th><th>Description </th></tr>
</thead>
<tbody>
<tr><td><b>family.var3</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>string</a></mark> <mark>basic</mark> <mark>mandatory</mark> </td><td>A third variable. </td></tr>
<tr><td><b>family2.var4</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>string</a></mark> <mark>basic</mark> <mark>mandatory</mark></td><td>A fourth variable.</td></tr>
</tbody>
</table>

View file

@ -1,7 +0,0 @@
# New variables
| Variable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **family.var3**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | A third variable. |
| **family2.var4**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | A fourth variable. |

View file

@ -1,15 +0,0 @@
New variables
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 Variable  ┃ Description  ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
family.var3 │ A third variable. │
 string   basic   mandatory  │ │
├───────────────────────────────────────┼──────────────────────────────────────┤
family2.var4 │ A fourth variable. │
 string   basic   mandatory  │ │
└───────────────────────────────────────┴──────────────────────────────────────┘

View file

@ -1,21 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
family: # a family
var2:
description: a second variable
test:
- string6
subfamily: # a sub family
variable: # third variable
- variable: ___.var1
- variable: __.var2
var3: # a third variable
...

View file

@ -1,41 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
family: # a family
var2:
description: a second variable
test:
- string6
subfamily: # a sub family
variable: # third variable
- variable: ___.var1
- variable: __.var2
var3: # a third variable
family2: # a family
var2:
description: a variable2
default:
variable: __.family.var2
var3:
description: a third variable
test:
- string5
default: string4
subfamily: # a sub family
variable: # fourth variable
- variable: ___.var1
- variable: ___.family.var2
- variable: __.var3
...

View file

@ -1,7 +0,0 @@
== Deleted variables
* family2.var2
* family2.var3
* family2.subfamily.variable

View file

@ -1,7 +0,0 @@
<details><summary>Deleted variables</summary>
- family2.var2
- family2.var3
- family2.subfamily.variable</details>

View file

@ -1,5 +0,0 @@
<h1>Deleted variables</h1>
<ul><li>family2.var2</li>
<li>family2.var3</li>
<li>family2.subfamily.variable</li></ul>

View file

@ -1,6 +0,0 @@
# Deleted variables
- family2.var2
- family2.var3
- family2.subfamily.variable

View file

@ -1,10 +0,0 @@
Deleted variables
- family2.var2
- family2.var3
- family2.subfamily.variable

View file

@ -1,39 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
family: # a family
var2:
description: a second variable
test:
- string6
subfamily: # a sub family
variable: # third variable
- variable: ___.var1
- variable: __.var2
family2: # a family
var2:
description: a variable2
default:
variable: __.family.var2
var3:
description: a third variable
test:
- string5
default: string4
subfamily: # a sub family
variable: # fourth variable
- variable: ___.var1
- variable: ___.family.var2
- variable: __.var3
...

View file

@ -1,41 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
family: # a family
var2:
description: a second variable
test:
- string6
subfamily: # a sub family
variable: # third variable
- variable: ___.var1
- variable: __.var2
var3: # a third variable
family2: # a family
var2:
description: a variable2
default:
variable: __.family.var2
var3:
description: a third variable
test:
- string5
default: string4
subfamily: # a sub family
variable: # fourth variable
- variable: ___.var1
- variable: ___.family.var2
- variable: __.var3
...

View file

@ -1,5 +0,0 @@
== Deleted variable
* family.var3

View file

@ -1,5 +0,0 @@
<details><summary>Deleted variable</summary>
- family.var3</details>

View file

@ -1,3 +0,0 @@
<h1>Deleted variable</h1>
<ul><li>family.var3</li></ul>

View file

@ -1,4 +0,0 @@
# Deleted variable
- family.var3

View file

@ -1,8 +0,0 @@
Deleted variable
- family.var3

View file

@ -1,39 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
family: # a family
var2:
description: a second variable
test:
- string6
subfamily: # a sub family
variable: # third variable
- variable: ___.var1
- variable: __.var2
family2: # a family
var2:
description: a variable2
default:
variable: __.family.var2
var3:
description: a third variable
test:
- string5
default: string4
subfamily: # a sub family
variable: # fourth variable
- variable: ___.var1
- variable: ___.family.var2
- variable: __.var3
...

View file

@ -1,43 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
family: # a family
var2:
description: a second variable
test:
- string6
subfamily: # a sub family
variable: # third variable
- variable: ___.var1
- variable: __.var2
var3: # a third variable
family2: # a family
var2:
description: a variable2
default:
variable: __.family.var2
var3:
description: a third variable
test:
- string5
default: string4
subfamily: # a sub family
variable: # fourth variable
- variable: ___.var1
- variable: ___.family.var2
- variable: __.var3
var4: # a fourth variable
...

View file

@ -1,6 +0,0 @@
== Deleted variables
* family.var3
* family2.var4

View file

@ -1,6 +0,0 @@
<details><summary>Deleted variables</summary>
- family.var3
- family2.var4</details>

View file

@ -1,4 +0,0 @@
<h1>Deleted variables</h1>
<ul><li>family.var3</li>
<li>family2.var4</li></ul>

View file

@ -1,5 +0,0 @@
# Deleted variables
- family.var3
- family2.var4

View file

@ -1,9 +0,0 @@
Deleted variables
- family.var3
- family2.var4

View file

@ -1,6 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # new description
...

View file

@ -1,6 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # first variable
...

View file

@ -1,13 +0,0 @@
== Modified variable
[cols="1a,1a"]
|====
| Variable | Description
|
**var1** +
`https://rougail.readthedocs.io/en/latest/variable.html#variables-types[string]` `basic` `mandatory` |
+++First variable.+++ +
#New description.#
|====

View file

@ -1,8 +0,0 @@
<details><summary>Modified variable</summary>
| Variable | Description |
|--------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------|
| **<a id="var1" name="var1">var1</a>**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | ~~First variable.~~<br/><ins>New description.</ins> |
</details>

View file

@ -1,11 +0,0 @@
<h1>Modified variable</h1>
<table>
<thead>
<tr><th>Variable </th><th>Description </th></tr>
</thead>
<tbody>
<tr><td><b>var1</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>string</a></mark> <mark>basic</mark> <mark>mandatory</mark></td><td><del>First variable.</del><br/><ins>New description.</ins></td></tr>
</tbody>
</table>

View file

@ -1,6 +0,0 @@
# Modified variable
| Variable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **var1**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | ~~First variable.~~<br/><ins>New description.</ins> |

View file

@ -1,12 +0,0 @@
Modified variable
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 Variable  ┃ Description  ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
var1 │ First variable. │
 string   basic   mandatory  │ New description. │
└───────────────────────────────────────┴──────────────────────────────────────┘

View file

@ -1,8 +0,0 @@
%YAML 1.2
---
version: 1.1
var1:
description: first variable
help: modified help
...

View file

@ -1,8 +0,0 @@
%YAML 1.2
---
version: 1.1
var1:
description: first variable
help: first help
...

View file

@ -1,14 +0,0 @@
== Modified variable
[cols="1a,1a"]
|====
| Variable | Description
|
**var1** +
`https://rougail.readthedocs.io/en/latest/variable.html#variables-types[string]` `basic` `mandatory` |
First variable. +
+++First help.+++ +
#Modified help.#
|====

View file

@ -1,8 +0,0 @@
<details><summary>Modified variable</summary>
| Variable | Description |
|--------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------|
| **<a id="var1" name="var1">var1</a>**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | First variable.<br/>~~First help.~~<br/><ins>Modified help.</ins> |
</details>

View file

@ -1,11 +0,0 @@
<h1>Modified variable</h1>
<table>
<thead>
<tr><th>Variable </th><th>Description </th></tr>
</thead>
<tbody>
<tr><td><b>var1</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>string</a></mark> <mark>basic</mark> <mark>mandatory</mark></td><td>First variable.<br/><del>First help.</del><br/><ins>Modified help.</ins></td></tr>
</tbody>
</table>

View file

@ -1,6 +0,0 @@
# Modified variable
| Variable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **var1**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | First variable.<br/>~~First help.~~<br/><ins>Modified help.</ins> |

View file

@ -1,13 +0,0 @@
Modified variable
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 Variable  ┃ Description  ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
var1 │ First variable. │
 string   basic   mandatory  │ First help. │
│ │ Modified help. │
└───────────────────────────────────────┴──────────────────────────────────────┘

View file

@ -1,13 +0,0 @@
%YAML 1.2
---
version: 1.1
var1:
description: first variable
validators:
- jinja: |
{% if _.var1 == "not valid2" %}
not valid2
{% endif %}
description: '"not valid2" is not allowed'
...

View file

@ -1,13 +0,0 @@
%YAML 1.2
---
version: 1.1
var1:
description: first variable
validators:
- jinja: |
{% if _.var1 == "not valid1" %}
not valid1
{% endif %}
description: '"not valid1" is not allowed'
...

View file

@ -1,15 +0,0 @@
== Modified variable
[cols="1a,1a"]
|====
| Variable | Description
|
**var1** +
`https://rougail.readthedocs.io/en/latest/variable.html#variables-types[string]` `basic` `mandatory` |
First variable. +
**Validator**:
+++"not valid1" is not allowed+++ +
#"not valid2" is not allowed#
|====

View file

@ -1,8 +0,0 @@
<details><summary>Modified variable</summary>
| Variable | Description |
|--------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|
| **<a id="var1" name="var1">var1</a>**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | First variable.<br/>**Validator**: ~~"not valid1" is not allowed~~<br/><ins>"not valid2" is not allowed</ins> |
</details>

View file

@ -1,11 +0,0 @@
<h1>Modified variable</h1>
<table>
<thead>
<tr><th>Variable </th><th>Description </th></tr>
</thead>
<tbody>
<tr><td><b>var1</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>string</a></mark> <mark>basic</mark> <mark>mandatory</mark></td><td>First variable.<br/><b>Validator</b>: <del>"not valid1" is not allowed</del><br/><ins>"not valid2" is not allowed</ins></td></tr>
</tbody>
</table>

View file

@ -1,6 +0,0 @@
# Modified variable
| Variable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **var1**<br/>[`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `basic` `mandatory` | First variable.<br/>**Validator**: ~~"not valid1" is not allowed~~<br/><ins>"not valid2" is not allowed</ins> |

View file

@ -1,14 +0,0 @@
Modified variable
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 Variable  ┃ Description  ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
var1 │ First variable. │
 string   basic   mandatory  │ Validator: "not valid1" is not  │
│ │ allowed │
│ │ "not valid2" is not allowed │
└───────────────────────────────────────┴──────────────────────────────────────┘

View file

@ -1,18 +0,0 @@
%YAML 1.2
---
version: 1.1
var1:
description: first variable
validators:
- jinja: |
{% if _.var1 == "not valid1" %}
not valid1
{% endif %}
description: '"not valid1" is not allowed'
- jinja: |
{% if _.var1 == "not valid3" %}
not valid3
{% endif %}
description: '"not valid3" is not allowed'
...

Some files were not shown because too many files have changed in this diff Show more