Compare commits

...

132 commits

Author SHA1 Message Date
948e0b49ed feat: personalise column number 2025-12-02 13:39:44 +01:00
3cde479202 fix: better commandline doc + params description is now in rougail 2025-11-29 07:59:33 +01:00
77e311dedf feat: document commandline and environment variable 2025-11-27 22:17:17 +01:00
2b9c251780 bump: version 0.2.0a38 → 0.2.0a39 2025-11-21 08:15:09 +01:00
0b7f1fe087 feat: change path in description 2025-11-21 08:15:00 +01:00
e48c55a8f2 fix: dynamic variables with identifier in description 2025-11-17 15:46:24 +01:00
103adeddf4 feat: add anchor to markdown format and remove unsupported character in anchor id 2025-11-17 09:50:28 +01:00
4bf2f778ac fix: gitlab id in anchor with dynamic variables 2025-11-16 21:22:18 +01:00
d0915ff83d feat: use blockquote for family description 2025-11-15 10:37:15 +01:00
4f475be53e bump: version 0.2.0a37 → 0.2.0a38 2025-11-12 19:26:53 +01:00
a400088e2d feat: better enter support 2025-11-10 14:01:45 +01:00
4b215ce407 bump: version 0.2.0a36 → 0.2.0a37 2025-11-06 06:27:47 +01:00
64f448c141 feat: delete/underline is inside tag for some format 2025-11-05 21:43:10 +01:00
d8a0e22de9 feat: can reload formatter 2025-11-03 09:03:59 +01:00
8afb61c5ad feat: can document part by part with reloading structure 2025-10-30 21:14:34 +01:00
c754f5c654 bump: version 0.2.0a35 → 0.2.0a36 2025-10-29 11:12:09 +01:00
bd1d85442e feat: anchor in gitlab output_format 2025-10-29 11:03:16 +01:00
ecf3570b79 feat: can had comments with family/variable description in examples doc 2025-10-28 06:22:50 +01:00
9d8be3880a feat: comment variables from a family 2025-10-27 21:59:39 +01:00
2961a61aa6 bump: version 0.2.0a34 → 0.2.0a35 2025-10-27 14:25:26 +01:00
ce96cad54d fix: add changelog support for github/gitlab format 2025-10-27 14:25:07 +01:00
9bbb60c460 feat: tags documentation 2025-10-26 17:12:17 +01:00
72fa10208e fix: tests 2025-10-26 15:22:17 +01:00
a913be6b52 bump: version 0.2.0a33 → 0.2.0a34 2025-10-22 17:02:38 +02:00
bd44db892c feat: ca force true_color terminal when export to console 2025-10-22 17:01:57 +02:00
afb85063ac fix: parse subtree for a dynamic 2025-10-18 11:27:22 +02:00
a0843e08ca fix: adapt api for rougail-web-ui 2025-10-18 06:40:23 +02:00
c1ab106ba5 fix: undocumented variable in dynamic 2025-10-16 20:58:39 +02:00
cb770dd8d7 bump: version 0.2.0a32 → 0.2.0a33 2025-10-16 08:21:49 +02:00
fc4c2221d1 fix: support rougail-web-ui 2025-10-16 08:19:35 +02:00
a92f447478 feat: can document a variable for a specified identifier 2025-10-15 10:05:21 +02:00
b4ce22a0af fix: black 2025-10-15 09:44:22 +02:00
6dd6df77a1 fix: remove extra '*' 2025-10-14 21:58:01 +02:00
bebea05e7c feat: can remove header when generate a table 2025-10-14 16:48:39 +02:00
e97f4b4ca6 fix: always use name for informations key (sometime path was used) 2025-10-14 16:09:33 +02:00
a79a420ba5 feat: add html output 2025-10-14 13:50:02 +02:00
641ab723e0 feat: changelog for variables 2025-10-14 12:58:39 +02:00
da1519071e fix: update tests 2025-10-07 21:00:28 +02:00
622764bf53 fix: translation for property is now in rougail 2025-10-05 21:28:58 +02:00
856811805c bump: version 0.2.0a31 → 0.2.0a32 2025-10-03 08:22:36 +02:00
38fa8447eb fix: property calculated with disabled variable 2025-10-03 08:22:14 +02:00
c5134247a0 fix: better disabled support 2025-10-03 06:44:25 +02:00
a5dc507c65 bump: version 0.2.0a30 → 0.2.0a31 2025-10-02 22:43:42 +02:00
550996f22a feat: limit warning when asked 2025-10-02 22:43:25 +02:00
5652757787 bump: version 0.2.0a29 → 0.2.0a30 2025-10-02 22:23:04 +02:00
a307cb1c66 feat: better support variable calculation for property 2025-10-02 22:20:33 +02:00
1cbe8377e0 bump: version 0.2.0a28 → 0.2.0a29 2025-10-02 22:20:19 +02:00
3af6ee631c fix: property for namespace 2025-10-02 22:20:09 +02:00
d022e44e1d bump: version 0.2.0a27 → 0.2.0a28 2025-10-02 22:19:44 +02:00
9a0219ce55 feat: add gitlab plugin 2025-10-02 22:19:22 +02:00
17b589c268 fix: tests for formatter 2025-09-30 21:57:05 +02:00
53e1261812 fix: update translation 2025-09-30 06:15:00 +02:00
ef0aca7e55 bump: version 0.2.0a26 → 0.2.0a27 2025-09-29 21:26:25 +02:00
86dce82a57 fix: doc network with CIDR format 2025-09-29 21:26:12 +02:00
777346d070 fix: better doc for calculation with unknown variable 2025-09-29 21:18:55 +02:00
213c25c8f6 bump: version 0.2.0a25 → 0.2.0a26 2025-09-29 11:00:30 +02:00
242b6505ce feat: default value for a calculated variable with an unknown optional variable 2025-09-28 15:53:31 +02:00
f5dc501bf9 feat: add integer type which will replace number type 2025-09-23 22:09:33 +02:00
154238c46e bump: version 0.2.0a24 → 0.2.0a25 2025-09-22 09:43:08 +02:00
1fe10dbe20 feat: adapt to tiramisu-web-ui 2025-09-22 09:42:46 +02:00
2652fc9db6 bump: version 0.2.0a23 → 0.2.0a24 2025-06-19 07:28:10 +03:00
2a7f78103b feat: could not change default value during annotator 2025-06-19 07:27:59 +03:00
02778fe53b bump: version 0.2.0a22 → 0.2.0a23 2025-06-18 16:52:35 +03:00
1718a76ce9 fix: separation 2025-06-18 16:50:11 +03:00
a8c682d76c bump: version 0.2.0a21 → 0.2.0a22 2025-06-18 07:57:53 +03:00
706ddd369e fix: rougail separation 2025-06-18 07:42:33 +03:00
25dc2874b2 bump: version 0.2.0a20 → 0.2.0a21 2025-05-12 09:11:19 +02:00
3dfc3ab166 fix: update translation 2025-05-12 08:39:38 +02:00
263dae2b2c fix: black 2025-05-11 19:13:12 +02:00
561d117d4d fix: doc example with leader example lower than leader default value 2025-05-11 14:44:46 +02:00
8f2c4b0011 bump: version 0.2.0a19 → 0.2.0a20 2025-05-09 08:22:34 +02:00
94c7922782 fix: undefined is a rougail object 2025-05-09 07:45:10 +02:00
c9a0f2d1ec bump: version 0.2.0a18 → 0.2.0a19 2025-05-05 10:08:56 +02:00
5e325f744d fix: update translation 2025-05-05 10:08:45 +02:00
f911425e1a bump: version 0.2.0a17 → 0.2.0a18 2025-05-05 10:03:59 +02:00
b60792314e fix: doc default value with undocumented variable 2025-05-05 10:03:44 +02:00
2886cf0348 bump: version 0.2.0a16 → 0.2.0a17 2025-05-05 08:52:28 +02:00
f0f3fc899d fix: description for all calculations 2025-05-04 14:29:51 +02:00
96866e99a4 fix: better documentation variable with variable in default attribut 2025-05-02 21:57:35 +02:00
d8e52e26fd bump: version 0.2.0a15 → 0.2.0a16 2025-04-30 09:04:41 +02:00
07027690a7 fix: update translation 2025-04-29 23:06:35 +02:00
19767f346d fix: remove negative_description support 2025-04-29 22:51:36 +02:00
726c64e23d fix: better documentation with hidden variable in property calculation 2025-04-29 08:32:53 +02:00
abbeb78dbb fix: use new information ymlfiles 2025-04-28 16:49:41 +02:00
aaf3f95126 fix: update tests 2025-04-27 10:24:10 +02:00
aeff3e8b7c fix: better dynamic support 2025-04-25 14:17:07 +02:00
0f96fa0123 bump: version 0.2.0a14 → 0.2.0a15 2025-04-09 21:34:24 +02:00
d69d0cc8e8 fix: version 2025-04-09 21:34:21 +02:00
81ff417107 bump: version 0.2.0a13 → 0.2.0a14 2025-04-07 08:42:04 +02:00
a7ede66aa7 fix: calculation for dynamic ans leadership variables 2025-04-05 11:23:47 +02:00
b4dfa14602 bump: version 0.2.0a12 → 0.2.0a13 2025-04-02 21:16:40 +02:00
a2e1d7746e fix: error in disabled dynamic variable 2025-04-02 21:15:33 +02:00
b8f3e71314 bump: version 0.2.0a11 → 0.2.0a12 2025-04-01 22:19:42 +02:00
bb5caa5388 fix: update tests 2025-04-01 22:02:44 +02:00
fd8a2843ba fix: groups.namespace could be unexistant 2025-04-01 19:42:45 +02:00
8e5cc2622e bump: version 0.2.0a10 → 0.2.0a11 2025-03-31 10:25:17 +02:00
22e839027d fix: doc a param with a set but with only one item 2025-03-31 10:25:08 +02:00
fcac55ae92 bump: version 0.2.0a9 → 0.2.0a10 2025-03-30 19:48:00 +02:00
d3b1462db5 feat: document unix file name parameters 2025-03-30 19:47:56 +02:00
737ddc0f43 feat: better console output 2025-03-29 15:10:03 +01:00
5c9c102245 fix: doc for param 2025-03-29 14:38:47 +01:00
fd54b9ca00 fix: support NamespaceCalculation 2025-03-29 14:37:14 +01:00
83614a2a5e fix: convert <ENV> to &lt;ENV&gt; for github plugin 2025-03-29 14:35:32 +01:00
8e6200b321 feat: do not document reference to undocumented variable 2025-03-02 13:38:14 +01:00
1364083ffb bump: version 0.2.0a8 → 0.2.0a9 2025-02-19 16:43:55 +01:00
604cfa0a1d fix: support suffix (in version 1.0 format) in calculation 2025-02-19 16:43:37 +01:00
97a8653b28 bump: version 0.2.0a7 → 0.2.0a8 2025-02-19 12:49:32 +01:00
76d7c968fe fix: key is the path 2025-02-19 12:49:21 +01:00
693050b195 bump: version 0.2.0a6 → 0.2.0a7 2025-02-19 08:39:59 +01:00
d927f60769 fix: with_family => without_family and with_example => example 2025-02-19 08:39:44 +01:00
53de7569ee bump: version 0.2.0a5 → 0.2.0a6 2025-02-17 20:54:12 +01:00
3f3f6aa495 feat: add with_family parameter 2025-02-17 20:53:58 +01:00
affd645ebd bump: version 0.2.0a4 → 0.2.0a5 2025-02-17 09:49:59 +01:00
7f003a574b fix: do not add multiple attribute several time in json export 2025-02-17 09:49:51 +01:00
495336c146 bump: version 0.2.0a3 → 0.2.0a4 2025-02-10 09:52:15 +01:00
60b4a06807 feat: output return status too 2025-02-10 09:52:12 +01:00
88aca6b0ea bump: version 0.2.0a2 → 0.2.0a3 2025-01-04 18:00:49 +01:00
1903ee8031 fix: detect_symlink => only_self 2025-01-04 18:00:38 +01:00
135936782f bump: version 0.2.0a1 → 0.2.0a2 2025-01-04 11:55:02 +01:00
705239141e fix: do not document symlink 2025-01-04 11:54:20 +01:00
673e89e5e1 fix: remove prefix_path 2025-01-04 11:52:09 +01:00
cac294b800 feat: create tests 2024-12-07 10:53:41 +01:00
58ee0f3106 bump: version 0.2.0a0 → 0.2.0a1 2024-11-28 21:37:17 +01:00
e6a38423ef fix: separation between run and print function 2024-11-28 21:36:45 +01:00
1f37457b9f bump: version 0.1.1a0 → 0.2.0a0 2024-11-20 22:01:04 +01:00
9f5d0e2497 feat: personalize mode that we want disable documentation 2024-11-20 21:59:21 +01:00
af652eda76 feat: add console output 2024-11-20 21:13:42 +01:00
3d4b7b945c feat: better dynamique family support 2024-11-20 21:10:14 +01:00
3cc85d7ba5 feat: add json output 2024-11-09 15:10:25 +01:00
12622032a8 fix: correction for properties in italic 2024-11-09 07:40:08 +01:00
d805cbf565 bump: version 0.1.0 → 0.1.1a0 2024-11-08 08:14:35 +01:00
46eeb49c5f fix: generate documentation with force_optional configuration 2024-11-08 07:39:32 +01:00
17291 changed files with 277479 additions and 26153 deletions

View file

@ -1,3 +1,322 @@
## 0.2.0a39 (2025-11-21)
### Feat
- change path in description
- add anchor to markdown format and remove unsupported character in anchor id
- use blockquote for family description
### Fix
- dynamic variables with identifier in description
- gitlab id in anchor with dynamic variables
## 0.2.0a38 (2025-11-10)
### Feat
- better enter support
## 0.2.0a37 (2025-11-06)
### Feat
- delete/underline is inside tag for some format
- can reload formatter
- can document part by part with reloading structure
## 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

81
README.fr.md Normal file
View file

@ -0,0 +1,81 @@
---
gitea: none
include_toc: true
---
[🇬🇧 (EN)](README.md) - [🇫🇷 (FR)](README.fr.md)
## Générer la documentation depuis les fichiers de structure
> **🛈 Informations**
>
> Les fichiers de structure contiennent toutes les informations relatif aux variables. Cette sortie génère la documentation pour tout ou partie de ces variables.\
> **Chemin** : doc\
> *`désactivé`*\
> **Désactivé** : si doc n'est pas spécifié dans "[Sélection pour sortie](#step.output)"
| Variable | Description | Valeur par défaut | Type | Contrôle des accès | Validateur |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------|-------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
| **<a id="doc.output_format" name="doc.output_format">doc.output_format</a>**<br/>**Ligne de commande** : -do, --doc.output_format<br/>**Variable d'environnement** : ROUGAILCLI_DOC.OUTPUT_FORMAT | Le format de sortie de la documentation générée. | console | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | | **Choix** : <br/>&nbsp;console<br/>&nbsp;asciidoc<br/>&nbsp;html<br/>&nbsp;github<br/>&nbsp;gitlab<br/>&nbsp;json |
| **<a id="doc.tabular_template" name="doc.tabular_template">doc.tabular_template</a>**<br/>**Ligne de commande** : -dm, --doc.tabular_template<br/>**Variable d'environnement** : ROUGAILCLI_DOC.TABULAR_TEMPLATE | Génère la documentation avec ce modèle de tableau.<br/>Les variables sont documentées avec une vue tableau. Une sélection de modèle vous permet de choisir le contenu de chaque colonne. | two_columns | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | *`désactivé`*<br/>**Désactivé** : "[Le format de sortie de la documentation générée](#doc.output_format)" en json n\'est pas compatible avec cette variable<br/> | **Choix** : <br/>&nbsp;two_columns<br/>&nbsp;three_columns<br/>&nbsp;four_columns<br/>&nbsp;five_columns<br/>&nbsp;six_columns |
| **<a id="doc.contents" name="doc.contents">doc.contents</a>**<br/>**Ligne de commande** : -dc, --doc.contents<br/>**Variable d'environnement** : ROUGAILCLI_DOC.CONTENTS | Contenu généré.<br/>Vous pouvez générer trois type de documentation. Toutes les variables (&quot;variables&quot;), un exemple de fichier au format YAML (&quot;example&quot;) ou le journal des changements (&quot;changelog&quot;). | •&nbsp;variables | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` `obligatoire` | *`cachée`*<br/>**Cachée** : "[Le format de sortie de la documentation générée](#doc.output_format)" en json n'est pas compatible avec "[Contenu généré](#doc.contents)" changelog or example<br/> | `unique`<br/>**Choix** : <br/>&nbsp;variables<br/>&nbsp;example<br/>&nbsp;changelog |
| **<a id="doc.title_level" name="doc.title_level">doc.title_level</a>**<br/>**Ligne de commande** : -dt, --doc.title_level<br/>**Variable d'environnement** : ROUGAILCLI_DOC.TITLE_LEVEL | Niveau de titre de départ. | 1 | [`integer`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | | |
| **<a id="doc.default_values" name="doc.default_values">doc.default_values</a>**<br/>**Ligne de commande** : <br/>&nbsp;--doc.default_values<br/>&nbsp;--doc.no-default_values<br/>**Variable d'environnement** : ROUGAILCLI_DOC.DEFAULT_VALUES | Modifier les valeurs pour documenter toutes les variables.<br/>Pour documenter les variables des leadership ou des familles dynamiques, il est parfois nécessaire de générer des valeurs, qui peuvent modifier les valeurs de la configuration. Soyez vigilent si vous réutilisez cette configuration. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | | |
| **<a id="doc.true_color" name="doc.true_color">doc.true_color</a>**<br/>**Ligne de commande** : <br/>&nbsp;--doc.true_color<br/>&nbsp;--doc.no-true_color<br/>**Variable d'environnement** : ROUGAILCLI_DOC.TRUE_COLOR | Afficher la documentation dans la console en permanence avec un terminal en couleurs réelles. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | *`désactivé`*<br/>**Désactivé** : lorsque la variable "[Le format de sortie de la documentation générée](#doc.output_format)" n'a pas la valeur "console" | |
| **<a id="doc.root" name="doc.root">doc.root</a>**<br/>**Ligne de commande** : -dr, --doc.root<br/>**Variable d'environnement** : ROUGAILCLI_DOC.ROOT | Documenter les variables enfants de cette famille.<br/>Par défaut, toute les variables accessibles sont incluent dans la documentation. Il est possible de définir une famille a partir de laquelle la documentation doit être générée. | | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | | |
### Les variables pour cette famille sont documentés dans un autre fichier
> **🛈 Informations**
>
> Si vous séparez les variables dans différents fichiers, le lien entre les variables va être cassé. Dans ce cas, vous devez définit différents nom de fichiers pour les fichiers contenant ces variables.\
> Cette famille contient des listes de bloc de variable.\
> **Chemin** : doc.other_root_filenames\
> *`désactivé`*\
> **Désactivé** : lorsque la variable "[Documenter les variables enfants de cette famille](#doc.root)" a la valeur "null"
| Variable | Description | Type | Validateur |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------|---------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
| **<a id="doc.other_root_filenames.root_path" name="doc.other_root_filenames.root_path">doc.other_root_filenames.root_path</a>**<br/>**Ligne de commande** : --doc.other_root_filenames.root_path<br/>**Variable d'environnement** : ROUGAILCLI_DOC.OTHER_ROOT_FILENAMES.ROOT_PATH | Ce fichier contient les variables enfants de la famille. | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `unique` |
| **<a id="doc.other_root_filenames.filename" name="doc.other_root_filenames.filename">doc.other_root_filenames.filename</a>**<br/>**Ligne de commande** : --doc.other_root_filenames.filename<br/>**Variable d'environnement** : ROUGAILCLI_DOC.OTHER_ROOT_FILENAMES.FILENAME | Nom du fichier. | [`UNIX filename`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | •&nbsp;this filename could be a relative path<br/>&nbsp;file type allowed: "file". |
### Documentation des variables et journal de changements
> **🛈 Informations**
>
> **Chemin** : doc.tabulars\
> *`désactivé`*\
> **Désactivé** : si "[Le format de sortie de la documentation générée](#doc.output_format)" en json ou si "[Contenu généré](#doc.contents)" n'est pas variables ou changelog
| Variable | Description | Valeur par défaut | Type | Contrôle des accès | Validateur |
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|---------------------|---------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------|
| **<a id="doc.tabulars.without_family" name="doc.tabulars.without_family">doc.tabulars.without_family</a>**<br/>**Ligne de commande** : <br/>&nbsp;-df, --doc.tabulars.without_family<br/>&nbsp;-ndf, --doc.tabulars.no-without_family<br/>**Variable d'environnement** : ROUGAILCLI_DOC.TABULARS.WITHOUT_FAMILY | Ne pas ajouter les familles dans la documentation. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | | |
| **<a id="doc.tabulars.with_commandline" name="doc.tabulars.with_commandline">doc.tabulars.with_commandline</a>**<br/>**Ligne de commande** : <br/>&nbsp;-dw, --doc.tabulars.with_commandline<br/>&nbsp;-ndw, --doc.tabulars.no-with_commandline<br/>**Variable d'environnement** : ROUGAILCLI_DOC.TABULARS.WITH_COMMANDLINE | Ajoute les informations de la ligne de commande dans la documentation. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | | |
| **<a id="doc.tabulars.with_environment" name="doc.tabulars.with_environment">doc.tabulars.with_environment</a>**<br/>**Ligne de commande** : <br/>&nbsp;-de, --doc.tabulars.with_environment<br/>&nbsp;-nde, --doc.tabulars.no-with_environment<br/>**Variable d'environnement** : ROUGAILCLI_DOC.TABULARS.WITH_ENVIRONMENT | Ajoute les informations de variable d&#x27;environnement dans la documentation. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | | |
| **<a id="doc.tabulars.environment_prefix" name="doc.tabulars.environment_prefix">doc.tabulars.environment_prefix</a>**<br/>**Ligne de commande** : -dv, --doc.tabulars.environment_prefix<br/>**Variable d'environnement** : ROUGAILCLI_DOC.TABULARS.ENVIRONMENT_PREFIX | Préfixe du nom des variables d&#x27;environnement. | ROUGAIL | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | *`désactivé`*<br/>**Désactivé** : si "main_namespace" n'est pas défini ou "[Ajoute les informations de variable d&#x27;environnement dans la documentation](#doc.tabulars.with_environment)" est false | Doit seulement utilise des caractères en majuscule. |
### Documentation du journal des changements
> **🛈 Informations**
>
> **Chemin** : doc.changelog\
> *`désactivé`*\
> **Désactivé** : changelog n'est pas défini dans "[Contenu généré](#doc.contents)"
| Variable | Description | Type |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
| **<a id="doc.changelog.previous_json_file" name="doc.changelog.previous_json_file">doc.changelog.previous_json_file</a>**<br/>**Ligne de commande** : -dp, --doc.changelog.previous_json_file<br/>**Variable d'environnement** : ROUGAILCLI_DOC.CHANGELOG.PREVIOUS_JSON_FILE | Précédent fichier de description au format JSON.<br/>Pour générer le journal des changements, vous devez comparer l&#x27;ancienne liste des variables (au format json) avec les variables courantes. | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` |
### Configuration des exemples
> **🛈 Informations**
>
> **Chemin** : doc.examples\
> *`désactivé`*\
> **Désactivé** : si example n'est pas défini dans "[Contenu généré](#doc.contents)"
| Variable | Description | Valeur par défaut | Type | Contrôle des accès |
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|---------------------|---------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **<a id="doc.examples.comment" name="doc.examples.comment">doc.examples.comment</a>**<br/>**Ligne de commande** : <br/>&nbsp;-dx, --doc.examples.comment<br/>&nbsp;-ndx, --doc.examples.no-comment<br/>**Variable d'environnement** : ROUGAILCLI_DOC.EXAMPLES.COMMENT | Ajouter la description des variables et des familles lorsqu&#x27;on génère des exemples. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | |
| **<a id="doc.examples.comment_column" name="doc.examples.comment_column">doc.examples.comment_column</a>**<br/>**Ligne de commande** : --doc.examples.comment_column<br/>**Variable d'environnement** : ROUGAILCLI_DOC.EXAMPLES.COMMENT_COLUMN | Commentaire dans les exemples commence à la colonne. | 30 | [`integer`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | *`désactivé`*<br/>**Désactivé** : lorsque la variable "[Ajouter la description des variables et des familles lorsqu&#x27;on génère des exemples](#doc.examples.comment)" a la valeur "false" |

View file

@ -1,2 +1,81 @@
# rougaildoc
---
gitea: none
include_toc: true
---
[🇬🇧 (EN)](README.md) - [🇫🇷 (FR)](README.fr.md)
## Generate documentation from structural files
> **🛈 Informations**
>
> The structural files contain all the information related to the variables. This output generates the documentation for all or some of these variables.\
> **Path**: doc\
> *`disabled`*\
> **Disabled**: if doc is not set in "[Select for output](#step.output)"
| Variable | Description | Default value | Type | Access control | Validator |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|-----------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
| **<a id="doc.output_format" name="doc.output_format">doc.output_format</a>**<br/>**Command line**: -do, --doc.output_format<br/>**Environment variable**: ROUGAILCLI_DOC.OUTPUT_FORMAT | The output format of the generated documentation. | console | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | | **Choices**: <br/>&nbsp;console<br/>&nbsp;asciidoc<br/>&nbsp;html<br/>&nbsp;github<br/>&nbsp;gitlab<br/>&nbsp;json |
| **<a id="doc.tabular_template" name="doc.tabular_template">doc.tabular_template</a>**<br/>**Command line**: -dm, --doc.tabular_template<br/>**Environment variable**: ROUGAILCLI_DOC.TABULAR_TEMPLATE | Generate document with this tabular model.<br/>The variables are documented with a tabular view. A template selection allows you to choose the content of each column. | two_columns | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | *`disabled`*<br/>**Disabled**: "[The output format of the generated documentation](#doc.output_format)" in json is not compatible with this variable<br/> | **Choices**: <br/>&nbsp;two_columns<br/>&nbsp;three_columns<br/>&nbsp;four_columns<br/>&nbsp;five_columns<br/>&nbsp;six_columns |
| **<a id="doc.contents" name="doc.contents">doc.contents</a>**<br/>**Command line**: -dc, --doc.contents<br/>**Environment variable**: ROUGAILCLI_DOC.CONTENTS | Generated content.<br/>You can generate three type of document. All variables (&quot;variables&quot;), an example file in YAML format (&quot;example&quot;) or change log (&quot;changelog&quot;). | •&nbsp;variables | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` `mandatory` | *`hidden`*<br/>**Hidden**: "[The output format of the generated documentation](#doc.output_format)" in json is not compatible with changelog or example "[Generated content](#doc.contents)"<br/> | `unique`<br/>**Choices**: <br/>&nbsp;variables<br/>&nbsp;example<br/>&nbsp;changelog |
| **<a id="doc.title_level" name="doc.title_level">doc.title_level</a>**<br/>**Command line**: -dt, --doc.title_level<br/>**Environment variable**: ROUGAILCLI_DOC.TITLE_LEVEL | Starting title level. | 1 | [`integer`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | | |
| **<a id="doc.default_values" name="doc.default_values">doc.default_values</a>**<br/>**Command line**: <br/>&nbsp;--doc.default_values<br/>&nbsp;--doc.no-default_values<br/>**Environment variable**: ROUGAILCLI_DOC.DEFAULT_VALUES | Modify values to document all variables.<br/>To document leadership or dynamic family variables, it is sometimes necessary to generate values, which can change the values in the configuration. Be careful if you reuse this configuration. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | | |
| **<a id="doc.true_color" name="doc.true_color">doc.true_color</a>**<br/>**Command line**: <br/>&nbsp;--doc.true_color<br/>&nbsp;--doc.no-true_color<br/>**Environment variable**: ROUGAILCLI_DOC.TRUE_COLOR | Display documentation in console always with true color terminal. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | *`disabled`*<br/>**Disabled**: when the variable "[The output format of the generated documentation](#doc.output_format)" hasn't the value "console" | |
| **<a id="doc.root" name="doc.root">doc.root</a>**<br/>**Command line**: -dr, --doc.root<br/>**Environment variable**: ROUGAILCLI_DOC.ROOT | Document the child variables of the family.<br/>By default, all accessible variables are included in the documentation. It is possible to define the family from which the documentation should be generated. | | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | | |
### The variables in this family are documented in another file
> **🛈 Informations**
>
> If you separate the variables into different files, the links between the variables will break. Therefore, you must define different filenames for the files containing these variables.\
> This family contains lists of variable blocks.\
> **Path**: doc.other_root_filenames\
> *`disabled`*\
> **Disabled**: when the variable "[Document the child variables of the family](#doc.root)" has the value "null"
| Variable | Description | Type | Validator |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------|-------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
| **<a id="doc.other_root_filenames.root_path" name="doc.other_root_filenames.root_path">doc.other_root_filenames.root_path</a>**<br/>**Command line**: --doc.other_root_filenames.root_path<br/>**Environment variable**: ROUGAILCLI_DOC.OTHER_ROOT_FILENAMES.ROOT_PATH | This file contains child variables of the family. | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `unique` |
| **<a id="doc.other_root_filenames.filename" name="doc.other_root_filenames.filename">doc.other_root_filenames.filename</a>**<br/>**Command line**: --doc.other_root_filenames.filename<br/>**Environment variable**: ROUGAILCLI_DOC.OTHER_ROOT_FILENAMES.FILENAME | Name of the file. | [`UNIX filename`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | •&nbsp;this filename could be a relative path<br/>&nbsp;file type allowed: "file". |
### Variables and changelog documentation
> **🛈 Informations**
>
> **Path**: doc.tabulars\
> *`disabled`*\
> **Disabled**: if "[The output format of the generated documentation](#doc.output_format)" is json or "[Generated content](#doc.contents)" hasn't variables or changelog
| Variable | Description | Default value | Type | Access control | Validator |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------|-----------------|-------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------|
| **<a id="doc.tabulars.without_family" name="doc.tabulars.without_family">doc.tabulars.without_family</a>**<br/>**Command line**: <br/>&nbsp;-df, --doc.tabulars.without_family<br/>&nbsp;-ndf, --doc.tabulars.no-without_family<br/>**Environment variable**: ROUGAILCLI_DOC.TABULARS.WITHOUT_FAMILY | Do not add families in documentation. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | | |
| **<a id="doc.tabulars.with_commandline" name="doc.tabulars.with_commandline">doc.tabulars.with_commandline</a>**<br/>**Command line**: <br/>&nbsp;-dw, --doc.tabulars.with_commandline<br/>&nbsp;-ndw, --doc.tabulars.no-with_commandline<br/>**Environment variable**: ROUGAILCLI_DOC.TABULARS.WITH_COMMANDLINE | Add command line informations in documentation. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | | |
| **<a id="doc.tabulars.with_environment" name="doc.tabulars.with_environment">doc.tabulars.with_environment</a>**<br/>**Command line**: <br/>&nbsp;-de, --doc.tabulars.with_environment<br/>&nbsp;-nde, --doc.tabulars.no-with_environment<br/>**Environment variable**: ROUGAILCLI_DOC.TABULARS.WITH_ENVIRONMENT | Add environment variable informations in documentation. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | | |
| **<a id="doc.tabulars.environment_prefix" name="doc.tabulars.environment_prefix">doc.tabulars.environment_prefix</a>**<br/>**Command line**: -dv, --doc.tabulars.environment_prefix<br/>**Environment variable**: ROUGAILCLI_DOC.TABULARS.ENVIRONMENT_PREFIX | Environment variables prefix name. | ROUGAIL | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | *`disabled`*<br/>**Disabled**: if "main_namespace" is not set or "[Add environment variable informations in documentation](#doc.tabulars.with_environment)" is false | Should only use uppercase characters. |
### Changelog documentation
> **🛈 Informations**
>
> **Path**: doc.changelog\
> *`disabled`*\
> **Disabled**: if changelog in not in "[Generated content](#doc.contents)"
| Variable | Description | Type |
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|
| **<a id="doc.changelog.previous_json_file" name="doc.changelog.previous_json_file">doc.changelog.previous_json_file</a>**<br/>**Command line**: -dp, --doc.changelog.previous_json_file<br/>**Environment variable**: ROUGAILCLI_DOC.CHANGELOG.PREVIOUS_JSON_FILE | Previous description file in JSON format.<br/>To generate the changelog, you need to compare the old list of variables (in json format) with the current variables. | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` |
### Examples configuration
> **🛈 Informations**
>
> **Path**: doc.examples\
> *`disabled`*\
> **Disabled**: if example is not in "[Generated content](#doc.contents)"
| Variable | Description | Default value | Type | Access control |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------|-----------------|-------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **<a id="doc.examples.comment" name="doc.examples.comment">doc.examples.comment</a>**<br/>**Command line**: <br/>&nbsp;-dx, --doc.examples.comment<br/>&nbsp;-ndx, --doc.examples.no-comment<br/>**Environment variable**: ROUGAILCLI_DOC.EXAMPLES.COMMENT | Add description of variables and families when generate examples. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | |
| **<a id="doc.examples.comment_column" name="doc.examples.comment_column">doc.examples.comment_column</a>**<br/>**Command line**: --doc.examples.comment_column<br/>**Environment variable**: ROUGAILCLI_DOC.EXAMPLES.COMMENT_COLUMN | Comment in examples starts at column. | 30 | [`integer`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | *`disabled`*<br/>**Disabled**: when the variable "[Add description of variables and families when generate examples](#doc.examples.comment)" has the value "false" |

View file

@ -5,8 +5,8 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2024-11-01 11:42+0100\n"
"PO-Revision-Date: 2024-11-01 11:42+0100\n"
"POT-Creation-Date: 2025-12-02 12:49+0100\n"
"PO-Revision-Date: 2025-12-02 12:53+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fr\n"
@ -14,138 +14,566 @@ 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.5\n"
"X-Generator: Poedit 3.8\n"
#: src/rougail/output_doc/__init__.py:40
msgid "the domain name can starts by a dot"
msgstr "le nom de domaine peut commencé par un point"
#: src/rougail/output_doc/annotator.py:350
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/__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/annotator.py:353
msgid "the value of the global information \"{0}\""
msgstr "la valeur de l'information globale \"{0}\""
#: 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/annotator.py:360
msgid "when the identifier is \"{0}\""
msgstr "lorsque l'identifiant est \"{0}\""
#: 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/annotator.py:362
msgid "when the identifier is not \"{0}\""
msgstr "lorsque l'identifiant n'est pas \"{0}\""
#: src/rougail/output_doc/__init__.py:48
msgid "the minimum value is {0}"
msgstr "le valeur minimal est {0}"
#: src/rougail/output_doc/changelog.py:147
msgid "New variable"
msgstr "Nouvelle variable"
#: src/rougail/output_doc/__init__.py:49
msgid "the maximum value is {0}"
msgstr "le valeur maximal est {0}"
#: src/rougail/output_doc/changelog.py:149
msgid "New variables"
msgstr "Nouvelles variables"
#: 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/changelog.py:163
msgid "Modified variable"
msgstr "Variable modifiée"
#: src/rougail/output_doc/__init__.py:56
msgid "private IP are allowed"
msgstr "les IP privées sont autorisés"
#: src/rougail/output_doc/changelog.py:165
msgid "Modified variables"
msgstr "Variables modifiées"
#: 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/changelog.py:179
msgid "Deleted variable"
msgstr "Variable supprimée"
#: 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/changelog.py:181
msgid "Deleted variables"
msgstr "Variables supprimées"
#: 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/config.py:54
msgid "duplicated level rougail-output-doc for {0} \"{1}\": {2} and {3}"
msgstr "niveau dupliqué pour rougail-doc pour {0} \"{1}\": {2} et {3}"
#: 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/config.py:60
msgid "duplicated name \"{0}\" in rougail-output-doc"
msgstr "nom dupliqué \"{0}\" dans rougail-output-doc"
#: src/rougail/output_doc/__init__.py:75
msgid "can be range of port"
msgstr "peut être un range de port"
#: src/rougail/output_doc/config.py:123
msgid "Generate documentation from structural files"
msgstr "Générer la documentation depuis les fichiers de structure"
#: src/rougail/output_doc/__init__.py:76
msgid "can have the protocol"
msgstr "peut avoir un protocole"
#: src/rougail/output_doc/config.py:124
msgid ""
"The structural files contain all the information related to the variables. "
"This output generates the documentation for all or some of these variables."
msgstr ""
"Les fichiers de structure contiennent toutes les informations relatif aux "
"variables. Cette sortie génère la documentation pour tout ou partie de ces "
"variables."
#: src/rougail/output_doc/__init__.py:77
msgid "port 0 is allowed"
msgstr "le port 0 est autorisé"
#: src/rougail/output_doc/config.py:133
msgid "if doc is not set in \"step.output\""
msgstr "si doc n'est pas spécifié dans \"step.output\""
#: 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/config.py:136
msgid "The output format of the generated documentation"
msgstr "Le format de sortie de la documentation générée"
#: 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/config.py:145
msgid "Generate document with this tabular model"
msgstr "Génère la documentation avec ce modèle de tableau"
#: 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/config.py:146
msgid ""
"The variables are documented with a tabular view. A template selection "
"allows you to choose the content of each column."
msgstr ""
"Les variables sont documentées avec une vue tableau. Une sélection de modèle "
"vous permet de choisir le contenu de chaque colonne."
#: src/rougail/output_doc/__init__.py:125
msgid "mandatory"
msgstr "obligatoire"
#: src/rougail/output_doc/config.py:153
msgid "\"_.output_format\" in json is not compatible with this variable"
msgstr "\"_.output_format\" en json n\\'est pas compatible avec cette variable"
#: src/rougail/output_doc/__init__.py:126
msgid "hidden"
msgstr "caché"
#: src/rougail/output_doc/config.py:160
msgid "Generated content"
msgstr "Contenu généré"
#: src/rougail/output_doc/__init__.py:127
msgid "disabled"
msgstr "désactivé"
#: src/rougail/output_doc/config.py:161
msgid ""
"You can generate three type of document. All variables (\"variables\"), an "
"example file in YAML format (\"example\") or change log (\"changelog\")."
msgstr ""
"Vous pouvez générer trois type de documentation. Toutes les variables "
"(\"variables\"), un exemple de fichier au format YAML (\"example\") ou le "
"journal des changements (\"changelog\")."
#: src/rougail/output_doc/__init__.py:128
msgid "unique"
msgstr "unique"
#: src/rougail/output_doc/config.py:173
msgid ""
"\"_.output_format\" in json is not compatible with changelog or example "
"\"_.contents\""
msgstr ""
"\"_.output_format\" en json n'est pas compatible avec \"_.contents\" "
"changelog or example"
#: src/rougail/output_doc/__init__.py:129
msgid "auto modified"
msgstr "auto modifiée"
#: src/rougail/output_doc/config.py:176
msgid "Starting title level"
msgstr "Niveau de titre de départ"
#: src/rougail/output_doc/__init__.py:163
msgid "Variables for \"{0}\""
msgstr "Variables pour \"{0}\""
#: src/rougail/output_doc/config.py:181
msgid "Modify values to document all variables"
msgstr "Modifier les valeurs pour documenter toutes les variables"
#: src/rougail/output_doc/__init__.py:180
msgid "Variables"
msgstr "Variables"
#: src/rougail/output_doc/config.py:182
msgid ""
"To document leadership or dynamic family variables, it is sometimes "
"necessary to generate values, which can change the values in the "
"configuration. Be careful if you reuse this configuration."
msgstr ""
"Pour documenter les variables des leadership ou des familles dynamiques, il "
"est parfois nécessaire de générer des valeurs, qui peuvent modifier les "
"valeurs de la configuration. Soyez vigilent si vous réutilisez cette "
"configuration."
#: 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/config.py:186
msgid "Display documentation in console always with true color terminal"
msgstr ""
"Afficher la documentation dans la console en permanence avec un terminal en "
"couleurs réelles"
#: src/rougail/output_doc/__init__.py:493
msgid "(default)"
msgstr "(defaut)"
#: src/rougail/output_doc/config.py:193
msgid "Document the child variables of the family"
msgstr "Documenter les variables enfants de cette famille"
#: src/rougail/output_doc/__init__.py:498
msgid "Choices"
msgstr "Choix"
#: src/rougail/output_doc/config.py:194
msgid ""
"By default, all accessible variables are included in the documentation. It "
"is possible to define the family from which the documentation should be "
"generated."
msgstr ""
"Par défaut, toute les variables accessibles sont incluent dans la "
"documentation. Il est possible de définir une famille a partir de laquelle "
"la documentation doit être générée."
#: src/rougail/output_doc/__init__.py:501
#: src/rougail/output_doc/config.py:199
msgid "The variables in this family are documented in another file"
msgstr "Les variables pour cette famille sont documentés dans un autre fichier"
#: src/rougail/output_doc/config.py:200
msgid ""
"If you separate the variables into different files, the links between the "
"variables will break. Therefore, you must define different filenames for the "
"files containing these variables."
msgstr ""
"Si vous séparez les variables dans différents fichiers, le lien entre les "
"variables va être cassé. Dans ce cas, vous devez définit différents nom de "
"fichiers pour les fichiers contenant ces variables."
#: src/rougail/output_doc/config.py:207
msgid "This file contains child variables of the family"
msgstr "Ce fichier contient les variables enfants de la famille"
#: src/rougail/output_doc/config.py:211
msgid "Name of the file"
msgstr "Nom du fichier"
#: src/rougail/output_doc/config.py:219
msgid "Variables and changelog documentation"
msgstr "Documentation des variables et journal de changements"
#: src/rougail/output_doc/config.py:224
msgid ""
"if \"_.output_format\" is json or \"_.contents\" hasn't variables or "
"changelog"
msgstr ""
"si \"_.output_format\" en json ou si \"_.contents\" n'est pas variables ou "
"changelog"
#: src/rougail/output_doc/config.py:227
msgid "Do not add families in documentation"
msgstr "Ne pas ajouter les familles dans la documentation"
#: src/rougail/output_doc/config.py:232
msgid "Add command line informations in documentation"
msgstr "Ajoute les informations de la ligne de commande dans la documentation"
#: src/rougail/output_doc/config.py:237
msgid "Add environment variable informations in documentation"
msgstr ""
"Ajoute les informations de variable d'environnement dans la documentation"
#: src/rougail/output_doc/config.py:242
msgid "Environment variables prefix name"
msgstr "Préfixe du nom des variables d'environnement"
#: src/rougail/output_doc/config.py:249
msgid "should only use uppercase characters"
msgstr "doit seulement utilise des caractères en majuscule"
#: src/rougail/output_doc/config.py:254
msgid "if \"main_namespace\" is not set or \"_.with_environment\" is false"
msgstr ""
"si \"main_namespace\" n'est pas défini ou \"_.with_environment\" est false"
#: src/rougail/output_doc/config.py:257
msgid "Changelog documentation"
msgstr "Documentation du journal des changements"
#: src/rougail/output_doc/config.py:262
msgid "if changelog in not in \"_.contents\""
msgstr "changelog n'est pas défini dans \"_.contents\""
#: src/rougail/output_doc/config.py:265
msgid "Previous description file in JSON format"
msgstr "Précédent fichier de description au format JSON"
#: src/rougail/output_doc/config.py:266
msgid ""
"To generate the changelog, you need to compare the old list of variables (in "
"json format) with the current variables."
msgstr ""
"Pour générer le journal des changements, vous devez comparer l'ancienne "
"liste des variables (au format json) avec les variables courantes."
#: src/rougail/output_doc/config.py:270
msgid "Examples configuration"
msgstr "Configuration des exemples"
#: src/rougail/output_doc/config.py:275
msgid "if example is not in \"_.contents\""
msgstr "si example n'est pas défini dans \"_.contents\""
#: src/rougail/output_doc/config.py:278
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:283
msgid "Comment in examples starts at column"
msgstr "Commentaire dans les exemples commence à la colonne"
#: src/rougail/output_doc/doc.py:329
msgid "This family contains lists of variable blocks"
msgstr "Cette famille contient des listes de bloc de variable"
#: src/rougail/output_doc/doc.py:339
msgid "This family builds families dynamically"
msgstr "Cette famille construit des familles dynamiquement"
#: src/rougail/output_doc/doc.py:353
msgid "Default"
msgstr "Défaut"
#: src/rougail/output_doc/__init__.py:559
msgid "the value of the variable \"{0}\""
msgstr "la valeur de la variable \"{0}\""
#: src/rougail/output_doc/__init__.py:564
#: src/rougail/output_doc/__init__.py:566
msgid "value of the {0}"
msgstr "la valeur de {0}"
#: src/rougail/output_doc/__init__.py:638
#: src/rougail/output_doc/__init__.py:651
#: src/rougail/output_doc/doc.py:371
msgid "Example"
msgstr "Exemple"
#: src/rougail/output_doc/__init__.py:649
#: src/rougail/output_doc/doc.py:374
msgid "Examples"
msgstr "Exemples"
#: src/rougail/output_doc/doc.py:383
msgid "Tag"
msgstr "Étiquette"
#: src/rougail/output_doc/doc.py:386
msgid "Tags"
msgstr "Étiquettes"
#: src/rougail/output_doc/doc.py:418
msgid "No attribute \"description\" for \"{0}\" in {1}"
msgstr "Aucun attribut \"description\" pour \"{0}\" dans {1}"
#: src/rougail/output_doc/doc.py:553
msgid "text based with regular expressions \"{0}\""
msgstr "texte avec expression rationnelle \"{0}\""
#: src/rougail/output_doc/doc.py:557
#: src/rougail/output_doc/tabular/six_columns.py:65
msgid "Validator"
msgstr "Validateur"
#: src/rougail/output_doc/doc.py:560
msgid "Validators"
msgstr "Validateurs"
#: src/rougail/output_doc/doc.py:569
msgid "Choices"
msgstr "Choix"
#: src/rougail/output_doc/doc.py:672
msgid "the value of the identifier"
msgstr "la valeur de l'identifiant"
#: src/rougail/output_doc/doc.py:676
msgid "the value of the {0}"
msgstr "la valeur de l'{0}"
#: src/rougail/output_doc/doc.py:685
msgid "depends on a calculation"
msgstr "dépend d'un calcul"
#: src/rougail/output_doc/doc.py:691
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:719
msgid "the value of the variable \"{0}\""
msgstr "la valeur de la variable \"{0}\""
#: src/rougail/output_doc/doc.py:721
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:741
msgid "the value of an undocumented variable"
msgstr "la valeur d'une variable non documentée"
#: src/rougail/output_doc/doc.py:744
msgid "the values of undocumented variables"
msgstr "les valeurs de variables non documentées"
#: src/rougail/output_doc/doc.py:767
msgid "(from an undocumented variable)"
msgstr "(issue d'une variable non documentée)"
#: src/rougail/output_doc/doc.py:775
msgid "{0} (from an undocumented variable)"
msgstr "{0} (issue d'une variable non documentée)"
#: src/rougail/output_doc/doc.py:779 src/rougail/output_doc/doc.py:831
msgid "depends on an undocumented variable"
msgstr "dépends d'une variable non documentée"
#: src/rougail/output_doc/doc.py:853
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:857
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:861
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:863
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:867
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:871
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:875
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:877
msgid "when the variable \"{{0}}\" has the value \"{0}\""
msgstr "lorsque la variable \"{{0}}\" a la valeur \"{0}\""
#: src/rougail/output_doc/example.py:45
msgid "Example with mandatory variables not filled in"
msgstr "Exemple avec des variables obligatoire non renseignée"
#: src/rougail/output_doc/example.py:52
msgid "Example with all variables modifiable"
msgstr "Exemple avec toutes les variables modifiable"
#: src/rougail/output_doc/output/asciidoc.py:156
#: src/rougail/output_doc/output/console.py:199
#: src/rougail/output_doc/output/github.py:196
#: src/rougail/output_doc/output/gitlab.py:44
msgid "Informations"
msgstr "Informations"
#: src/rougail/output_doc/tabular/five_columns.py:59
msgid "Access control"
msgstr "Contrôle des accès"
#: src/rougail/output_doc/tabular/four_columns.py:53
msgid "Type"
msgstr "Type"
#: src/rougail/output_doc/tabular/three_columns.py:46
msgid "Default value"
msgstr "Valeur par défaut"
#: src/rougail/output_doc/tabular/two_columns.py:45
msgid "Variable"
msgstr "Variable"
#: src/rougail/output_doc/tabular/two_columns.py:47
msgid "Description"
msgstr "Description"
#: src/rougail/output_doc/utils.py:152
msgid "Command line"
msgstr "Ligne de commande"
#: src/rougail/output_doc/utils.py:159
msgid "Environment variable"
msgstr "Variable d'environnement"
#: src/rougail/output_doc/utils.py:458
msgid "Path"
msgstr "Chemin"
#: src/rougail/output_doc/utils.py:468
msgid "Identifiers"
msgstr "Identifiants"
#: src/rougail/output_doc/utils.py:684 src/rougail/output_doc/utils.py:693
#: src/rougail/output_doc/utils.py:699 src/rougail/output_doc/utils.py:705
#: src/rougail/output_doc/utils.py:709
msgid "(default)"
msgstr "(défaut)"
#: src/rougail/output_doc/utils.py:960
msgid "{0}: {1}"
msgstr "{0} : {1}"
#~ msgid "variables is not selected in \"_.contents\""
#~ msgstr "variables n'est pas sélectionné dans \"_.contents\""
#~ msgid "Name of the default environment prefix"
#~ msgstr "Nom du préfixe d'environnement par défaut"
#~ msgid "documentation must be splitted"
#~ msgstr "documentation doit être séparée"
#~ msgid "Root family name"
#~ msgstr "Nom de la famille racine"
#~ msgid "disabled when there is no mode available"
#~ msgstr "désactiver lorsqu'il n'y a pas de mode valable"
#~ msgid "verify if disable modes already exists"
#~ msgstr "vérifier si le mode existe déjà"
#~ msgid "Modify values to document leaderships and dynamics families"
#~ msgstr "Valeurs modifiées pour documenter les familles leader ou dynamique"
#~ msgid "Force true color terminal"
#~ msgstr "Force les vrais couleurs dans le terminal"
#~ msgid "multiple"
#~ msgstr "multiple"
#~ msgid "the domain name can starts by a dot"
#~ msgstr "le nom de domaine peut commencer par un point"
#~ msgid "the domain name can be a hostname"
#~ msgstr "le nom de domaine peut être un nom d'hôte"
#~ msgid "the domain name can be an IP"
#~ msgstr "le nom de domaine peut être une IP"
#~ msgid "the domain name can be network in CIDR format"
#~ msgstr "le nom de domaine peut être un réseau au format CIDR"
#~ msgid "the minimum value is {0}"
#~ msgstr "le valeur minimal est {0}"
#~ msgid "the maximum value is {0}"
#~ msgstr "le valeur maximal est {0}"
#~ msgid "IP must be in CIDR format"
#~ msgstr "IP doit être au format CIDR"
#~ msgid "private IP are allowed"
#~ msgstr "les IP privées sont autorisés"
#~ msgid "reserved IP are allowed"
#~ msgstr "les IP réservés sont autorisés"
#~ msgid "network must be in CIDR format"
#~ msgstr "réseau doit être au format CIDR"
#~ msgid "the host name can be an IP"
#~ msgstr "le nom d'hôte peut être une IP"
#~ msgid "the domain name in web address can be an IP"
#~ msgstr "le nom de domaine dans l'adresse web peut être une IP"
#~ 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"
#~ msgid "can be range of port"
#~ msgstr "peut être un range de port"
#~ msgid "can have the protocol"
#~ msgstr "peut avoir un protocole"
#~ msgid "port 0 is allowed"
#~ msgstr "le port 0 est autorisé"
#~ msgid "well-known ports (1 to 1023) are allowed"
#~ msgstr "les ports connus (de 1 à 1023) sont autorisés"
#~ msgid "registred ports (1024 to 49151) are allowed"
#~ msgstr "les ports enregistrés (de 1024 à 49151) sont autorisés"
#~ msgid "private ports (greater than 49152) are allowed"
#~ msgstr "les ports privés (supérieurs à 49152) sont autorisés"
#~ msgid "minimum length for the secret is {0} characters"
#~ msgstr "longueur minimum pour le secret est de {0} caractères"
#~ msgid "maximum length for the secret is {0} characters"
#~ msgstr "longueur maximal pour le secret est de {0} caractères"
#~ msgid "forbidden characters: {0}"
#~ msgstr "caractères interdits: {0}"
#~ msgid "this filename could be a relative path"
#~ msgstr "ce nom de fichier peut être un chemin relative"
#~ msgid "this file must exists"
#~ msgstr "ce fichier doit exister"
#~ msgid "file type allowed: {0}"
#~ msgstr "type de fichier autorisé : {0}"
#~ msgid "Configuration rougail-doc"
#~ msgstr "Configuration de rougail-doc"
#~ msgid "Variables for \"{0}\""
#~ msgstr "Variables pour \"{0}\""
#~ msgid "Generate example"
#~ msgstr "Génération de l'exemple"
#~ msgid "Display example in documentation"
#~ msgstr "Afficher un exemple dans la documentation"
#~ msgid "Hide example in documentation"
#~ msgstr "Cacher l'exemple dans la documentation"
#, fuzzy
#~| msgid ":"
#~ msgid ": "
#~ msgstr " : "
#~ msgid "when the variable \"{0}\" has the value \"True\""
#~ msgstr "lorsque la variable \"{0}\" a la valeur \"True\""

View file

@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2024-11-01 11:42+0100\n"
"POT-Creation-Date: 2025-12-02 12:54+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,137 +15,381 @@ msgstr ""
"Generated-By: pygettext.py 1.5\n"
#: src/rougail/output_doc/__init__.py:40
msgid "the domain name can starts by a dot"
#: src/rougail/output_doc/annotator.py:350
msgid "the value of the information \"{0}\" of the variable \"{1}\""
msgstr ""
#: src/rougail/output_doc/__init__.py:41
msgid "the domain name can be a hostname"
#: src/rougail/output_doc/annotator.py:353
msgid "the value of the global information \"{0}\""
msgstr ""
#: src/rougail/output_doc/__init__.py:42
msgid "the domain name can be an IP"
#: src/rougail/output_doc/annotator.py:360
msgid "when the identifier is \"{0}\""
msgstr ""
#: src/rougail/output_doc/__init__.py:43
msgid "the domain name can be network in CIDR format"
#: src/rougail/output_doc/annotator.py:362
msgid "when the identifier is not \"{0}\""
msgstr ""
#: src/rougail/output_doc/__init__.py:48
msgid "the minimum value is {0}"
#: src/rougail/output_doc/changelog.py:147
msgid "New variable"
msgstr ""
#: src/rougail/output_doc/__init__.py:49
msgid "the maximum value is {0}"
#: src/rougail/output_doc/changelog.py:149
msgid "New variables"
msgstr ""
#: src/rougail/output_doc/__init__.py:55
msgid "IP must be in CIDR format"
#: src/rougail/output_doc/changelog.py:163
msgid "Modified variable"
msgstr ""
#: src/rougail/output_doc/__init__.py:56
msgid "private IP are allowed"
#: src/rougail/output_doc/changelog.py:165
msgid "Modified variables"
msgstr ""
#: src/rougail/output_doc/__init__.py:57
msgid "reserved IP are allowed"
#: src/rougail/output_doc/changelog.py:179
msgid "Deleted variable"
msgstr ""
#: src/rougail/output_doc/__init__.py:62
msgid "the host name can be an IP"
#: src/rougail/output_doc/changelog.py:181
msgid "Deleted variables"
msgstr ""
#: src/rougail/output_doc/__init__.py:67
msgid "the domain name in web address can be an IP"
#: src/rougail/output_doc/config.py:54
msgid "duplicated level rougail-output-doc for {0} \"{1}\": {2} and {3}"
msgstr ""
#: src/rougail/output_doc/__init__.py:68
msgid "the domain name in web address can be only a hostname"
#: src/rougail/output_doc/config.py:60
msgid "duplicated name \"{0}\" in rougail-output-doc"
msgstr ""
#: src/rougail/output_doc/__init__.py:75
msgid "can be range of port"
#: src/rougail/output_doc/config.py:123
msgid "Generate documentation from structural files"
msgstr ""
#: src/rougail/output_doc/__init__.py:76
msgid "can have the protocol"
#: src/rougail/output_doc/config.py:124
msgid "The structural files contain all the information related to the variables. This output generates the documentation for all or some of these variables."
msgstr ""
#: src/rougail/output_doc/__init__.py:77
msgid "port 0 is allowed"
#: src/rougail/output_doc/config.py:133
msgid "if doc is not set in \"step.output\""
msgstr ""
#: src/rougail/output_doc/__init__.py:78
msgid "ports 1 to 1023 are allowed"
#: src/rougail/output_doc/config.py:136
msgid "The output format of the generated documentation"
msgstr ""
#: src/rougail/output_doc/__init__.py:79
msgid "ports 1024 to 49151 are allowed"
#: src/rougail/output_doc/config.py:145
msgid "Generate document with this tabular model"
msgstr ""
#: src/rougail/output_doc/__init__.py:80
msgid "ports greater than 49152 are allowed"
#: src/rougail/output_doc/config.py:146
msgid "The variables are documented with a tabular view. A template selection allows you to choose the content of each column."
msgstr ""
#: src/rougail/output_doc/__init__.py:125
msgid "mandatory"
#: src/rougail/output_doc/config.py:153
msgid "\"_.output_format\" in json is not compatible with this variable"
msgstr ""
#: src/rougail/output_doc/__init__.py:126
msgid "hidden"
#: src/rougail/output_doc/config.py:160
msgid "Generated content"
msgstr ""
#: src/rougail/output_doc/__init__.py:127
msgid "disabled"
#: src/rougail/output_doc/config.py:161
msgid "You can generate three type of document. All variables (\"variables\"), an example file in YAML format (\"example\") or change log (\"changelog\")."
msgstr ""
#: src/rougail/output_doc/__init__.py:128
msgid "unique"
#: src/rougail/output_doc/config.py:173
msgid "\"_.output_format\" in json is not compatible with changelog or example \"_.contents\""
msgstr ""
#: src/rougail/output_doc/__init__.py:129
msgid "auto modified"
#: src/rougail/output_doc/config.py:176
msgid "Starting title level"
msgstr ""
#: src/rougail/output_doc/__init__.py:163
msgid "Variables for \"{0}\""
#: src/rougail/output_doc/config.py:181
msgid "Modify values to document all variables"
msgstr ""
#: src/rougail/output_doc/__init__.py:180
msgid "Variables"
#: src/rougail/output_doc/config.py:182
msgid "To document leadership or dynamic family variables, it is sometimes necessary to generate values, which can change the values in the configuration. Be careful if you reuse this configuration."
msgstr ""
#: src/rougail/output_doc/__init__.py:187
msgid "Example with mandatory variables not filled in"
#: src/rougail/output_doc/config.py:186
msgid "Display documentation in console always with true color terminal"
msgstr ""
#: src/rougail/output_doc/__init__.py:493
msgid "(default)"
#: src/rougail/output_doc/config.py:193
msgid "Document the child variables of the family"
msgstr ""
#: src/rougail/output_doc/__init__.py:498
msgid "Choices"
#: src/rougail/output_doc/config.py:194
msgid "By default, all accessible variables are included in the documentation. It is possible to define the family from which the documentation should be generated."
msgstr ""
#: src/rougail/output_doc/__init__.py:501
#: src/rougail/output_doc/config.py:199
msgid "The variables in this family are documented in another file"
msgstr ""
#: src/rougail/output_doc/config.py:200
msgid "If you separate the variables into different files, the links between the variables will break. Therefore, you must define different filenames for the files containing these variables."
msgstr ""
#: src/rougail/output_doc/config.py:207
msgid "This file contains child variables of the family"
msgstr ""
#: src/rougail/output_doc/config.py:211
msgid "Name of the file"
msgstr ""
#: src/rougail/output_doc/config.py:219
msgid "Variables and changelog documentation"
msgstr ""
#: src/rougail/output_doc/config.py:224
msgid "if \"_.output_format\" is json or \"_.contents\" hasn't variables or changelog"
msgstr ""
#: src/rougail/output_doc/config.py:227
msgid "Do not add families in documentation"
msgstr ""
#: src/rougail/output_doc/config.py:232
msgid "Add command line informations in documentation"
msgstr ""
#: src/rougail/output_doc/config.py:237
msgid "Add environment variable informations in documentation"
msgstr ""
#: src/rougail/output_doc/config.py:242
msgid "Environment variables prefix name"
msgstr ""
#: src/rougail/output_doc/config.py:249
msgid "should only use uppercase characters"
msgstr ""
#: src/rougail/output_doc/config.py:254
msgid "if \"main_namespace\" is not set or \"_.with_environment\" is false"
msgstr ""
#: src/rougail/output_doc/config.py:257
msgid "Changelog documentation"
msgstr ""
#: src/rougail/output_doc/config.py:262
msgid "if changelog in not in \"_.contents\""
msgstr ""
#: src/rougail/output_doc/config.py:265
msgid "Previous description file in JSON format"
msgstr ""
#: src/rougail/output_doc/config.py:266
msgid "To generate the changelog, you need to compare the old list of variables (in json format) with the current variables."
msgstr ""
#: src/rougail/output_doc/config.py:270
msgid "Examples configuration"
msgstr ""
#: src/rougail/output_doc/config.py:275
msgid "if example is not in \"_.contents\""
msgstr ""
#: src/rougail/output_doc/config.py:278
msgid "Add description of variables and families when generate examples"
msgstr ""
#: src/rougail/output_doc/config.py:283
msgid "Comment in examples starts at column"
msgstr ""
#: src/rougail/output_doc/doc.py:329
msgid "This family contains lists of variable blocks"
msgstr ""
#: src/rougail/output_doc/doc.py:339
msgid "This family builds families dynamically"
msgstr ""
#: src/rougail/output_doc/doc.py:353
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
#: src/rougail/output_doc/doc.py:371
msgid "Example"
msgstr ""
#: src/rougail/output_doc/__init__.py:649
#: src/rougail/output_doc/doc.py:374
msgid "Examples"
msgstr ""
#: src/rougail/output_doc/doc.py:383
msgid "Tag"
msgstr ""
#: src/rougail/output_doc/doc.py:386
msgid "Tags"
msgstr ""
#: src/rougail/output_doc/doc.py:418
msgid "No attribute \"description\" for \"{0}\" in {1}"
msgstr ""
#: src/rougail/output_doc/doc.py:553
msgid "text based with regular expressions \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:557
#: src/rougail/output_doc/tabular/six_columns.py:65
msgid "Validator"
msgstr ""
#: src/rougail/output_doc/doc.py:560
msgid "Validators"
msgstr ""
#: src/rougail/output_doc/doc.py:569
msgid "Choices"
msgstr ""
#: src/rougail/output_doc/doc.py:672
msgid "the value of the identifier"
msgstr ""
#: src/rougail/output_doc/doc.py:676
msgid "the value of the {0}"
msgstr ""
#: src/rougail/output_doc/doc.py:685
msgid "depends on a calculation"
msgstr ""
#: src/rougail/output_doc/doc.py:691
msgid "\"{0}\" is a calculation for {1} but has no description in {2}"
msgstr ""
#: src/rougail/output_doc/doc.py:719
msgid "the value of the variable \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:721
msgid "the value of the variable \"{0}\" if it is defined"
msgstr ""
#: src/rougail/output_doc/doc.py:741
msgid "the value of an undocumented variable"
msgstr ""
#: src/rougail/output_doc/doc.py:744
msgid "the values of undocumented variables"
msgstr ""
#: src/rougail/output_doc/doc.py:767
msgid "(from an undocumented variable)"
msgstr ""
#: src/rougail/output_doc/doc.py:775
msgid "{0} (from an undocumented variable)"
msgstr ""
#: src/rougail/output_doc/doc.py:779 src/rougail/output_doc/doc.py:831
msgid "depends on an undocumented variable"
msgstr ""
#: src/rougail/output_doc/doc.py:853
msgid "when the variable \"{{0}}\" is defined, accessible and hasn't the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:857
msgid "when the variable \"{{0}}\" is defined and hasn't the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:861
msgid "when the variable \"{{0}}\" is accessible and hasn't the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:863
msgid "when the variable \"{{0}}\" hasn't the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:867
msgid "when the variable \"{{0}}\" is defined, is accessible and has the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:871
msgid "when the variable \"{{0}}\" is defined and has the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:875
msgid "when the variable \"{{0}}\" is accessible and has the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/doc.py:877
msgid "when the variable \"{{0}}\" has the value \"{0}\""
msgstr ""
#: src/rougail/output_doc/example.py:45
msgid "Example with mandatory variables not filled in"
msgstr ""
#: src/rougail/output_doc/example.py:52
msgid "Example with all variables modifiable"
msgstr ""
#: src/rougail/output_doc/output/asciidoc.py:156
#: src/rougail/output_doc/output/console.py:199
#: src/rougail/output_doc/output/github.py:196
#: src/rougail/output_doc/output/gitlab.py:44
msgid "Informations"
msgstr ""
#: src/rougail/output_doc/tabular/five_columns.py:59
msgid "Access control"
msgstr ""
#: src/rougail/output_doc/tabular/four_columns.py:53
msgid "Type"
msgstr ""
#: src/rougail/output_doc/tabular/three_columns.py:46
msgid "Default value"
msgstr ""
#: src/rougail/output_doc/tabular/two_columns.py:45
msgid "Variable"
msgstr ""
#: src/rougail/output_doc/tabular/two_columns.py:47
msgid "Description"
msgstr ""
#: src/rougail/output_doc/utils.py:152
msgid "Command line"
msgstr ""
#: src/rougail/output_doc/utils.py:159
msgid "Environment variable"
msgstr ""
#: src/rougail/output_doc/utils.py:458
msgid "Path"
msgstr ""
#: src/rougail/output_doc/utils.py:468
msgid "Identifiers"
msgstr ""
#: src/rougail/output_doc/utils.py:684 src/rougail/output_doc/utils.py:693
#: src/rougail/output_doc/utils.py:699 src/rougail/output_doc/utils.py:705
#: src/rougail/output_doc/utils.py:709
msgid "(default)"
msgstr ""
#: src/rougail/output_doc/utils.py:960
msgid "{0}: {1}"
msgstr ""

View file

@ -4,7 +4,7 @@ requires = ["flit_core >=3.8.0,<4"]
[project]
name = "rougail.output_doc"
version = "0.1.0"
version = "0.2.0a39"
authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}]
readme = "README.md"
description = "Rougail output doc"
@ -13,11 +13,10 @@ 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",
@ -25,8 +24,9 @@ classifiers = [
]
dependencies = [
"rougail ~= 1.1,<2",
"rougail-base > 1.1,<2",
"tabulate ~= 0.9.0",
"rich ~= 13.9.3",
]
[project.urls]
@ -37,5 +37,9 @@ name = "cz_conventional_commits"
tag_format = "$version"
version_scheme = "pep440"
version_provider = "pep621"
#update_changelog_on_bump = true
version_files = [
"src/rougail/output_doc/__version__.py",
"pyproject.toml:version"
]
update_changelog_on_bump = true
changelog_merge_prerelease = true

View file

@ -1,7 +1,6 @@
#!/usr/bin/env python3
"""
Silique (https://www.silique.fr)
Copyright (C) 2024
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
@ -16,671 +15,9 @@ 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 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
from .doc import RougailOutputDoc
from .__version__ import __version__
RougailOutput = RougailOutputDoc

View file

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

View file

@ -1,7 +1,6 @@
"""Annotate for documentation
"""
Silique (https://www.silique.fr)
Copyright (C) 2024
Copyright (C) 2024-2025
distribued with GPL-2 or later license
@ -20,12 +19,14 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from tiramisu import undefined
from typing import Union
from re import compile
from rougail.utils import undefined, PROPERTY_ATTRIBUTE
from rougail.annotator.variable import Walk
from rougail.i18n import _
from rougail.error import DictConsistencyError
from rougail.object_model import (
from rougail.output_doc.i18n import _
from rougail.convert.object_model import (
Calculation,
JinjaCalculation,
VariableCalculation,
@ -34,8 +35,8 @@ from rougail.object_model import (
IdentifierPropertyCalculation,
InformationCalculation,
IndexCalculation,
NamespaceCalculation,
CONVERT_OPTION,
PROPERTY_ATTRIBUTE,
)
@ -47,113 +48,141 @@ class Annotator(Walk):
def __init__(
self,
objectspace,
*args,
*args, # pylint: disable=unused-argument
) -> None:
if not objectspace.paths:
return
self.objectspace = objectspace
self.default_values = self.objectspace.rougailconfig[
"doc.default_values"
]
self.regexp_description_get_paths = None
self.populate_family()
self.populate_variable()
def get_examples_values(self, 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.default_values:
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"""
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(
variable.path,
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(
variable.path,
path,
"default",
variable.default,
default,
variable.version,
)
self.calculation_to_information(
variable.path,
path,
"validators",
variable.validators,
variable.version,
)
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)
if (
self.default_values
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,
)
def convert_variable_property(
def add_informations_from_properties(
self,
variable: dict,
) -> None:
"""convert properties"""
for prop in ["hidden", "disabled", "mandatory"]:
for prop in PROPERTY_ATTRIBUTE:
prop_value = getattr(variable, prop, None)
if not prop_value:
continue
@ -163,6 +192,8 @@ class Annotator(Walk):
prop_value,
variable.version,
)
if isinstance(prop_value, Calculation):
prop_value.default_values = False
def calculation_to_information(
self,
@ -171,76 +202,174 @@ class Annotator(Walk):
values,
version: str,
):
self._calculation_to_information(
path,
prop,
values,
version,
)
if isinstance(values, list):
"""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 = []
for idx, val in enumerate(values):
self._calculation_to_information(
path,
prop,
val,
version,
identifier=f"_{idx}",
)
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,
)
def _calculation_to_information(
def calculation_to_string(
self,
path: str,
prop: str,
values,
version: str,
*,
identifier: str = "",
):
if not isinstance(values, Calculation):
return
values_calculation = True
return {"value": values}
if values.description:
if not self.regexp_description_get_paths:
self.regexp_description_get_paths = compile('"(.*?)"')
index = 0
description = values.description
variables = []
for r_path in self.regexp_description_get_paths.findall(description):
variable, identifiers = self.objectspace.paths.get_with_dynamic(
r_path,
path,
values.version,
values.namespace,
values.xmlfiles,
)
if variable:
description = description.replace(f'"{r_path}"', f'"{{{index}}}"')
v = {"path": variable.path, "description": variable.description}
if identifiers:
v["identifiers"] = identifiers
variables.append(v)
index += 1
ret = {"description": description}
if variables:
ret["variables"] = variables
return ret
if isinstance(values, JinjaCalculation):
if values.description:
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(
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,
path,
f"{prop}_calculation_type{identifier}",
values_calculation_type,
)
self.objectspace.informations.add(
path,
f"{prop}_calculation{identifier}",
values_calculation,
)
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

View file

@ -0,0 +1,191 @@
"""
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"""
self.level = self.rougailconfig["doc.title_level"]
self.previous_json_file = self.rougailconfig["doc.changelog.previous_json_file"]
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 = []
root = self.rougailconfig["doc.root"]
if root:
informations = self.informations
for family in root.split('.'):
informations = informations[family]["children"]
if previous_doc and family in previous_doc:
previous_doc = previous_doc[family]['children']
else:
previous_doc = {}
else:
informations = self.informations
self.formatter.options()
self.parser(previous_doc, informations)
return self.display()
def parser(self, previous_families, new_families):
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":
self._added_variables.append(new)
else:
self.parser({}, new["children"])
elif not new:
if previous["type"] == "variable":
if "identifiers" in previous:
for identifiers in previous["identifiers"]:
self._removed_variables.append(calc_path(previous["path"], self.formatter, identifiers))
else:
self._removed_variables.append(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"]:
self._removed_variables.append(calc_path(previous["path"], self.formatter, identifiers))
else:
self._removed_variables.append(calc_path(previous["path"], self.formatter))
self.parser({}, new["children"])
else:
self._added_variables.append(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
]
elif isinstance(prop_previous, list):
local_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 = []
else:
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._modified_variables.append((new, modified_attributes))
def display(self) -> str:
msg = ""
if self._added_variables:
if len(self._added_variables) == 1:
title = _("New variable")
else:
title = _("New variables")
for add in self._added_variables:
self.formatter.variable_to_string(add)
msg += self.formatter._run(
[
self.formatter.title(title, self.level),
self.formatter.tabular(),
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")
for mod, modified_attributes in self._modified_variables:
self.formatter.variable_to_string(mod, modified_attributes)
msg += self.formatter._run(
[
self.formatter.title(title, self.level),
self.formatter.tabular(),
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_tabular=False),
self.formatter.end_family(self.level)
],
self.level,
dico_is_already_treated=True,
)
return msg

View file

@ -1,8 +1,6 @@
"""
Config file for Rougail-doc
Silique (https://www.silique.fr)
Copyright (C) 2024
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
@ -20,27 +18,51 @@ 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 _
ROUGAIL_VARIABLE_TYPE = (
"https://rougail.readthedocs.io/en/latest/variable.html#variables-types"
)
OUTPUTS = None
TABULARS = None
def get_outputs() -> None:
module_name = "rougail.doc.output"
def get_outputs_or_tabulars(type_) -> None:
"""Load all outputs or tabulars"""
module_name = f"rougail.output_doc.{type_}"
outputs = {}
for path in (Path(__file__).parent / "output").iterdir():
names = []
for path in (Path(__file__).parent / type_).iterdir():
name = path.name
if not name.endswith(".py") or name.endswith("__.py"):
continue
module = load_modules(module_name + "." + name, str(path))
if "Formater" not in dir(module):
continue
level = module.Formater.level
module = load_modules(module_name + "." + name[:-3], str(path))
if type_ == "output":
if "Formatter" not in dir(module):
continue
obj_class = module.Formatter
elif type_ == "tabular":
if "Tabular" not in dir(module):
continue
obj_class = module.Tabular
level = obj_class.level
if level in outputs:
raise Exception(
f'duplicated level rougail-doc for output "{level}": {module.Formater.name} and {outputs[level].name}'
raise ImportError(
_('duplicated level rougail-output-doc for {0} "{1}": {2} and {3}').format(
type_, level, obj_class.name, outputs[level].name
)
)
outputs[module.Formater.level] = module.Formater
if obj_class.name in names:
raise ImportError(
_('duplicated name "{0}" in rougail-output-doc').format(
obj_class.name
)
)
names.append(obj_class.name)
outputs[level] = obj_class
return {outputs[level].name: outputs[level] for level in sorted(outputs)}
@ -52,46 +74,220 @@ class OutPuts: # pylint: disable=R0903
) -> None:
global OUTPUTS
if OUTPUTS is None:
OUTPUTS = get_outputs()
OUTPUTS = get_outputs_or_tabulars("output")
def get(self) -> dict:
"""Get all outputs"""
return OUTPUTS
class Tabulars: # pylint: disable=R0903
"""Transformations applied on a object instance"""
def __init__(
self,
) -> None:
global TABULARS
if TABULARS is None:
TABULARS = get_outputs_or_tabulars("tabular")
def get(self) -> dict:
"""Get all tabulars"""
return TABULARS
def get_rougail_config(
*,
backward_compatibility=True,
backward_compatibility=True, # pylint: disable=unused-argument
) -> dict:
"""Get documentation for output_doc modules"""
outputs = list(OutPuts().get())
output_format_default = outputs[0]
rougail_options = """
tabulars = list(Tabulars().get())
tabular_default = tabulars[0]
rougail_options = f"""
cli:
read_write:
redefine: true
exists: true
default:
jinja: |-
{{% if __.step.output is not propertyerror and "doc" in __.step.output %}}
true
{{% else %}}
false
{{% endif %}}
doc:
description: Configuration rougail-doc
description: {_('Generate documentation from structural files')}
help: {_('The structural files contain all the information related to the variables. This output generates the documentation for all or some of these variables.')}
disabled:
type: jinja
jinja: |
{% if step.output != 'doc' %}
disabled
{% endif %}
title_level:
description: Start title level
alternative_name: dt
default: 1
with_example:
description: Display example in documentation
negative_description: Hide example in documentation
alternative_name: de
default: false
jinja: |-
{{% if step.output is propertyerror or step.output != 'doc' %}}
true
{{% else %}}
false
{{% endif %}}
return_type: boolean
description: {_('if doc is not set in "step.output"')}
output_format:
description: Generate document in format
description: {_('The output format of the generated documentation')}
alternative_name: do
default: output_format_default
default: { output_format_default }
choices:
""".replace(
"output_format_default", output_format_default
)
"""
for output in outputs:
rougail_options += f" - {output}\n"
rougail_options += f"""
tabular_template:
description: {_('Generate document with this tabular model')}
help: {_("The variables are documented with a tabular view. A template selection allows you to choose the content of each column.")}
alternative_name: dm
default: { tabular_default }
disabled:
jinja: |-
{{{{ _.output_format == 'json' }}}}
return_type: boolean
description: >
{_('"_.output_format" in json is not compatible with this variable')}
choices:
"""
for tabular in tabulars:
rougail_options += f" - {tabular}\n"
rougail_options += f"""
contents:
description: {_('Generated content')}
help: {_('You can generate three type of document. All variables ("variables"), an example file in YAML format ("example") or change log ("changelog").')}
alternative_name: dc
choices:
- variables
- example
- changelog
default:
- variables
hidden:
jinja: |-
{{{{ _.output_format == 'json' }}}}
return_type: boolean
description: >
{_('"_.output_format" in json is not compatible with changelog or example "_.contents"')}
title_level:
description: {_('Starting title level')}
alternative_name: dt
default: 1
default_values:
description: {_('Modify values to document all variables')}
help: {_('To document leadership or dynamic family variables, it is sometimes necessary to generate values, which can change the values in the configuration. Be careful if you reuse this configuration.')}
default: true
true_color:
description: {_('Display documentation in console always with true color terminal')}
default: false
disabled:
variable: _.output_format
when_not: console
root:
description: {_('Document the child variables of the family')}
help: {_('By default, all accessible variables are included in the documentation. It is possible to define the family from which the documentation should be generated.')}
alternative_name: dr
mandatory: false
other_root_filenames:
description: {_("The variables in this family are documented in another file")}
help: {_("If you separate the variables into different files, the links between the variables will break. Therefore, you must define different filenames for the files containing these variables.")}
type: leadership
disabled:
variable: _.root
when: null
root_path:
description: {_("This file contains child variables of the family")}
mandatory: false
filename:
description: {_("Name of the file")}
type: unix_filename
params:
allow_relative: true
types:
- file
tabulars:
description: {_('Variables and changelog documentation')}
disabled:
jinja: |-
{{{{ step.output is propertyerror or "doc" not in step.output or _.output_format == "json" or ("variables" not in _.contents and "changelog" not in _.contents) }}}}
return_type: boolean
description: {_('if "_.output_format" is json or "_.contents" hasn\'t variables or changelog')}
without_family:
description: {_('Do not add families in documentation')}
default: false
alternative_name: df
with_commandline:
description: {_('Add command line informations in documentation')}
alternative_name: dw
default: false
with_environment:
description: {_('Add environment variable informations in documentation')}
alternative_name: de
default: false
environment_prefix:
description: {_("Environment variables prefix name")}
alternative_name: dv
default: ROUGAIL
validators:
- jinja: |-
{{{{ (_.environment_prefix | upper) != _.environment_prefix }}}}
return_type: boolean
description: {_("should only use uppercase characters")}
disabled:
jinja: |-
{{{{ ___.main_namespace is not defined or ___.main_namespace == none or _.with_environment is false }}}}
return_type: boolean
description: {_('if "main_namespace" is not set or "_.with_environment" is false')}
changelog:
description: {_('Changelog documentation')}
disabled:
jinja: |-
{{{{ step.output is propertyerror or "doc" not in step.output or _.output_format == "json" or "changelog" not in _.contents }}}}
return_type: boolean
description: {_('if changelog in not in "_.contents"')}
previous_json_file:
description: {_('Previous description file in JSON format')}
help: {_('To generate the changelog, you need to compare the old list of variables (in json format) with the current variables.')}
alternative_name: dp
examples:
description: {_('Examples configuration')}
disabled:
jinja: |-
{{{{ step.output is propertyerror or "doc" not in step.output or "example" not in _.contents }}}}
return_type: boolean
description: {_('if example is not in "_.contents"')}
comment:
description: {_('Add description of variables and families when generate examples')}
alternative_name: dx
default: false
comment_column:
description: {_('Comment in examples starts at column')}
default: 30
disabled:
variable: _.comment
when: false
"""
return {
"name": "doc",
"process": "output",
@ -100,5 +296,4 @@ doc:
"level": 50,
}
__all__ = ("OutPuts", "get_rougail_config")

View file

@ -0,0 +1,925 @@
"""
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 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,
**kwargs,
):
# 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")
self.outputs = OutPuts().get()
self.conf = config
self.modes_level = rougailconfig["modes_level"]
self.disabled_modes = []
if self.modes_level:
for mode in self.modes_level:
for prop in self.conf.property.get():
if mode != prop:
continue
self.disabled_modes.append(prop)
# self.conf.property.read_write()
# # self.conf.property.remove("cache")
self.rougailconfig = rougailconfig
self.informations = None
try:
groups.namespace
self.support_namespace = True
except AttributeError:
self.support_namespace = False
self.property_to_string = get_properties_to_string()
self.formatter = None
super().__init__()
def run(self) -> str:
"""Print documentation in stdout"""
self.load()
self.load_formatter()
return_string = ""
contents = self.rougailconfig["doc.contents"]
if "variables" in contents:
return_string += self.formatter.run(self.informations)
if "example" in contents:
return_string += self.gen_doc_examples()
if "changelog" in contents:
return_string += self.gen_doc_changelog()
return True, return_string
def load_formatter(self) -> str:
output_format = self.rougailconfig["doc.output_format"]
self.formatter = self.outputs[output_format](self.rougailconfig, support_namespace=self.support_namespace)
def print(self) -> None:
ret, data = self.run()
print(data)
return ret
def load(self):
self.dynamic_paths = {}
config = self.conf.unrestraint
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
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 (variable.index() + 1) > len(leader["gen_examples"][-1]):
return
informations[name]["gen_examples"][-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:
dynamic_variable["gen_examples"].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["multiple"] = True
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,
}
alternative_name = variable.information.get("alternative_name", None)
if alternative_name:
informations["alternative_name"] = alternative_name
return True
def _populate(
self,
child,
informations: dict,
type_: str,
):
need_disabled, properties = self._parse_properties(child, informations)
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
properties = child.property.get(uncalculated=True)
for mode in self.modes_level:
if mode not in properties:
continue
informations["mode"] = mode
break
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["gen_examples"] = [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)
if informations.get("multiple"):
if not isinstance(example, list):
example = [example]
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
)
if leader is not None and variable.isfollower():
example = [example] + [undefined] * (len(leader["gen_examples"][-1]) - 1)
return example
def get_type_default_value(self, variable, informations):
example = self.convert_option.get(variable.information.get("type"), {}).get(
"example", None
)
if example is None:
example = "xxx"
if informations.get("multiple"):
example = [example]
return example
def _parse_type(
self,
child,
informations,
):
variable_type = child.information.get("type")
doc_type = self.convert_option.get(variable_type, {"params": {}})
informations["variable_type"] = doc_type.get("msg", variable_type)
# extra parameters for types
option = child.get()
validators = []
if "params" in doc_type:
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)
if "doc" in msg:
validators.append(msg['doc'].format(value))
else:
validators.append(msg['description'].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 variable_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 variable_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,
child_informations,
):
informations = []
properties = child.property.get(uncalculated=True)
for prop, translated_prop in self.property_to_string:
if "not_for_commandline" in properties:
child_informations["not_for_commandline"] = True
continue
if prop in properties:
prop_obj = {
"type": "property",
"name": translated_prop,
"ori_name": prop,
"access_control": prop in HIDDEN_PROPERTIES,
}
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,
"ori_name": prop,
"access_control": prop in HIDDEN_PROPERTIES,
}
else:
prop_obj = {
"type": "property",
"name": translated_prop,
"ori_name": prop,
"access_control": prop in HIDDEN_PROPERTIES,
"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 calculation
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.unrestraint.option(variable_path)
try:
isfollower = variable.isfollower()
except AttributeError:
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:
try:
description = self._convert_description(self.conf.option(calculation["ori_path"]).description(uncalculated=True), "description", its_a_path=False)
except AttributeError:
description = calculation["ori_path"]
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

@ -0,0 +1,238 @@
"""
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"""
root = self.rougailconfig["doc.root"]
self.comment_examples = self.rougailconfig["doc.examples.comment"]
self.level = self.rougailconfig["doc.title_level"]
if self.comment_examples:
self.comment_examples_column = self.rougailconfig["doc.examples.comment_column"]
self._build_examples(root)
return_string = ""
datas = []
if self.examples_mandatories:
datas.extend([
self.formatter.title(
_("Example with mandatory variables not filled in"), self.level
),
self.formatter.yaml(self.examples_mandatories),
self.formatter.end_family(self.level),
])
if self.examples:
datas.extend([self.formatter.title(
_("Example with all variables modifiable"), self.level
),
self.formatter.yaml(self.examples),
self.formatter.end_family(self.level),
])
return self.formatter.compute(datas)
def _build_examples(self, root):
examples, examples_mandatories = self._parse_examples(
self.informations
)
if root and examples:
sub_examples = examples
sub_examples_mandatories = examples_mandatories
new_examples_mandatories = examples_mandatories = {}
new_examples = examples = {}
for sub in root.split('.'):
new_examples[sub] = {}
new_examples = new_examples[sub]
sub_examples = sub_examples[sub]
if examples_mandatories and sub in sub_examples_mandatories:
new_examples_mandatories[sub] = {}
new_examples_mandatories = new_examples_mandatories[sub]
sub_examples_mandatories = sub_examples_mandatories[sub]
else:
new_examples_mandatories = {}
sub_examples_mandatories = {}
new_examples.update(sub_examples)
new_examples_mandatories.update(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["gen_examples"][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["gen_examples"][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["gen_examples"][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["gen_examples"][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
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
@ -19,6 +19,8 @@ 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
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

View file

@ -1,6 +1,6 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024
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
@ -16,124 +16,148 @@ 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 itertools import chain
from ruamel.yaml import YAML
from ..utils import CommonFormatter, dump
from ..i18n import _
class Formater:
class Formatter(CommonFormatter):
"""The asciidoc formatter"""
name = "asciidoc"
_tabular_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 tabular from a list"""
string = ""
previous = ""
for line in lst:
if string:
if self.is_list(previous.split("\n")[-1]):
if self.is_list(previous.split("\n", 1)[-1]):
string += "\n\n"
else:
string += " +\n"
string += line
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])
)
return string
def bold(
self,
msg: str,
) -> str:
"""Set a text to bold"""
return f"**{msg}**"
def italic(
self,
msg: str,
) -> str:
return f"_{msg}_"
"""Set a text to italic"""
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
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_tabular: bool=True,
type_: str="variable",
with_enter: bool = True,
) -> str:
"""Display a liste of element"""
char = "\n* "
if with_enter:
prefix = "\n\n* "
else:
prefix = char
return prefix + char.join([dump(choice) for choice in choices])
def prop(
self,
prop: str,
italic: bool,
delete: bool,
underline: bool,
) -> str:
"""Display property"""
if italic:
prop = self.italic(prop)
if delete:
prop = self.delete(prop)
if underline:
prop = self.underline(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 tabular(self, with_header: bool = True) -> str:
"""Transform list to a tabular in string format
we change the first line because we want that col has the same width
"""
tabular = super().tabular(with_header)
stable = tabular.split("\n", 1)
return '[cols="1a,1a"]\n' + stable[1]
def link(
self,
comment: str,
link: str,
underline: bool,
) -> str:
"""Add a link"""
if underline:
link = self.underline(link)
return f"`{link}[{comment}]`"
def is_list(
self,
txt: str,
) -> str:
"""verify if a text is a list"""
return txt.strip().startswith("* ")
def family_informations(self) -> str:
info = self.bold(f"🛈 {_('Informations')}")
return f"====\n{info}\n\n"
def end_family_informations(self) -> str:
return f"\n====\n"
def family_informations_ends_line(self) -> str:
return " +\n"

View file

@ -0,0 +1,210 @@
"""
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
class Formatter(CommonFormatter):
"""The console formatter"""
name = "console"
level = 10
enter_tabular = "\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, rougailconfig, **kwargs) -> None:
from rich.table import Table
from rich.theme import Theme
from rich.console import Console
from rich.syntax import Syntax
self.rich_table = Table
self.rich_console = Console
self.rich_syntaxt = Syntax
self.custom_theme = Theme(self.titles_color)
self.max_line = 0
super().__init__(rougailconfig, **kwargs)
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, init=True)
return self.compute(dico)
def compute(self, dico):
if self.rougailconfig["doc.true_color"]:
force_terminal = 'xterm-256color'
else:
force_terminal = None
console = self.rich_console(theme=self.custom_theme, force_terminal=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"{space}[title{level}]{title}[/title{level}]\n"
def join(
self,
lst: List[str],
) -> str:
"""Display line in tabular from a list"""
return self.enter_tabular.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_tabular: bool=True,
type_: str="variable",
with_enter: bool = True,
) -> str:
"""Display a liste of element"""
if type_ == "variable":
if with_enter:
char = first_char = f"{self.enter_tabular}"
else:
first_char = ""
char = f"{self.enter_tabular}{first_char}"
else:
char = first_char = f"\n{self.family_informations_starts_line()}"
ret = ""
for idx, choice in enumerate(choices):
if not isinstance(choice, str):
choice = dump(choice)
if not idx:
c = first_char
else:
c = char
ret += c + choice
return ret
def prop(
self,
prop: str,
italic: bool,
delete: bool,
underline: bool,
) -> str:
"""Display property"""
if italic:
prop = self.italic(prop)
if delete:
prop = self.delete(prop)
if underline:
prop = self.underline(prop)
prop = f"[reverse][bold] {prop} [/bold][/reverse]"
return prop
def yaml(self, _dump):
"""Dump yaml part of documentation"""
return self.rich_syntaxt(f'---\n{dump(_dump)}', 'yaml')
def link(
self,
comment: str,
link: str,
underline: bool,
) -> str:
"""Add a link"""
return self.prop(comment, False, False, underline)
# 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_tabular):
self.max_line = max(self.max_line, len(l) + 1)
def tabular(self, with_header: bool = True) -> str:
"""Transform list to a tabular in string format"""
tabular = self.rich_table(show_lines=True)
if with_header:
for column in self.tabular_datas.headers():
tabular.add_column(column, width=self.max_line)
for data in self.tabular_datas.get():
tabular.add_row(*data)
return tabular
def family_informations(self) -> str:
info = "[blue]" + self.bold(f"🛈 {_('Informations')}") + "[/blue]"
starts_line = self.family_informations_starts_line()
return starts_line + info + "\n" + starts_line
def family_informations_starts_line(self) -> str:
return "[blue]▌ [/blue]"
def family_informations_ends_line(self) -> str:
return "\n"
def end_family_informations(self) -> str:
return "\n"

View file

@ -1,6 +1,6 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024
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
@ -16,112 +16,199 @@ 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 itertools import chain
from ruamel.yaml import YAML
from typing import List, Optional
from html import escape
from ..utils import dump, CommonFormatter
from ..i18n import _
class Formater:
def to_id(path):
# https://www.w3.org/TR/html4/types.html#type-name
return ''.join(e if e in ["-", "_", ":", "."] or e.isalnum() else ":" for e in path )
class Formatter(CommonFormatter):
"""The markdown (for github) formatter"""
name = "github"
_tabular_name = "github"
level = 50
enter_tabular = "<br/>"
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 __init__(self, rougailconfig, **kwarg) -> None:
self.max_line_variable = 0
self.max_line_description = 0
super().__init__(rougailconfig, **kwarg)
def title(
self,
title: str,
level: int,
) -> str:
"""Display family name as a title"""
char = "#"
return f"{char * level} {title}\n\n"
def yaml(self, dump):
return f"```yaml\n---\n{self.dump(dump)}\n```\n"
def table(self, table):
return table
def link(
self,
comment: str,
link: str,
) -> str:
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,
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:
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])
)
"""Display line in tabular from a list"""
return self.enter_tabular.join([l.replace("\n", self.enter_tabular) for l in lst])
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 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()
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_tabular)
def list(
self,
choices: list,
*,
inside_tabular: bool=True,
type_: str="variable",
with_enter: bool = True,
):
"""Display a liste of element"""
if type_ == 'variable':
if inside_tabular:
if with_enter:
char = first_char = f"{self.enter_tabular}•&nbsp;"
else:
first_char = f"•&nbsp;"
char = f"{self.enter_tabular}{first_char}"
else:
first_char = char = "\n- "
else:
char = first_char = f"\n{self.family_informations_starts_line()}- "
ret = ""
for idx, choice in enumerate(choices):
if not isinstance(choice, str):
choice = dump(choice)
if not idx:
c = first_char
else:
c = char
ret += c + choice
return ret
def prop(
self,
prop: str,
italic: bool,
delete: bool,
underline: bool,
) -> str:
"""Display property"""
prop = f"`{prop}`"
if italic:
prop = self.italic(prop)
if delete:
prop = self.delete(prop)
if underline:
prop = self.underline(prop)
return prop
def tabular_header(self, lst):
"""Manage the header of a tabular"""
return lst
return [l + "&nbsp;" * (self.max_line_variable - len(l)) for l in lst]
def yaml(self, _dump):
"""Dump yaml part of documentation"""
return f"```yaml\n---\n{dump(_dump)}\n```\n"
def link_variable(self,
path: str,
true_path: str,
description: str,
filename: Optional[str],
) -> str:
name = to_id(true_path)
if filename:
link = f'{filename}#{name}'
else:
link = f'#{name}'
return f"[{description}]({link})"
def anchor(self,
path: str,
true_path: str,
) -> str:
name = to_id(true_path)
return f'<a id="{name}" name="{name}">{path}</a>'
def link(
self,
comment: str,
link: str,
underline: bool,
) -> str:
"""Add a link"""
comment = self.prop(comment, False, False, underline)
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_tabular):
self.max_line_variable = max(self.max_line_variable, len(l) + 1)
self.max_line_description = self.max_line_variable
def to_phrase(self, text: str) -> str:
return escape(text)
def family_informations(self) -> str:
info = self.bold(f"🛈 {_('Informations')}") #
starts_line = self.family_informations_starts_line()
return starts_line + info + "\n" + starts_line + "\n"
def family_informations_starts_line(self) -> str:
return "> "
def family_informations_ends_line(self) -> str:
return "\\\n"
#
# def family_to_string(self, *args, **kwargs) -> List[str]:
# lst = super().family_to_string(*args, **kwargs)
# if self.name != 'github':
# return lst
# # remove the title
# ret = lst.pop(0)
# if lst:
# ret = "\n> ".join([l.strip() for l in lst]).strip() + "\n\n"
# return [ret]

View file

@ -0,0 +1,48 @@
"""
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 .github import Formatter as GithubFormatter
from ..i18n import _
class Formatter(GithubFormatter):
name = "gitlab"
level = 51
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 columns(
self,
col: List[str],
) -> None:
pass
def family_informations(self) -> str:
return f"> [!note] 🛈 {_('Informations')}\n"
def table_header(self, lst):
"""Manage the header of a table"""
return lst

View file

@ -0,0 +1,146 @@
"""
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"
_tabular_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 tabular 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_tabular: bool=True,
type_: str="variable",
with_enter: 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,
delete: bool,
underline: bool,
) -> str:
"""Display property"""
if italic:
prop = self.italic(prop)
if delete:
prop = self.delete(prop)
if underline:
prop = self.underline(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,
underline: bool,
) -> str:
"""Add a link"""
return self.prop(f"<a href='{link}'>{comment}</a>", False, False, underline)
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

@ -0,0 +1,40 @@
"""
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, rougailconfig, **kwargs):
self.rougailconfig = rougailconfig
def run(self, informations: dict, *args) -> str: # pylint: disable=unused-argument
"""Transform to string"""
root = self.rougailconfig["doc.root"]
if root:
current = informations
for path in root.split('.'):
current = current[path]["children"]
informations = current
return dumps(informations, ensure_ascii=False, indent=2)

View file

@ -0,0 +1,17 @@
"""Loads output
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/>.
"""

View file

@ -0,0 +1,78 @@
"""
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 ..i18n import _
from ..config import ROUGAIL_VARIABLE_TYPE
from .four_columns import Tabular as FourTabular
class Tabular(FourTabular):
"""The five columns tabular"""
name = "five_columns"
level = 60
def clear(self):
super().clear()
self.five_column = False
def _add(self) -> tuple:
first_column = self.add_first_column()
second_column = self.get_column(self.description, self.help_, self.validators, self.choices, self.examples, self.tags)
if second_column:
self.second_column = True
third_column = self.get_column(self.default)
if third_column:
self.third_column = True
types = self.formatter.property_to_string(
self.informations, self.calculated_properties, self.modified_attributes, contents=["type"],
)
four_column = self.get_column(types)
if four_column:
self.four_column = True
mode = self.formatter.property_to_string(
self.informations, self.calculated_properties, self.modified_attributes, contents=["mode", "access_control"],
)
five_column = self.get_column(mode, *self.calculated_properties)
if five_column:
self.five_column = True
return first_column, second_column, third_column, four_column, five_column
def headers(self) -> tuple:
header = super().headers()
if self.five_column:
header.append(_("Access control"))
return header
def get_columns(self):
for column in self.columns:
ret = [column[0]]
if self.second_column:
ret.append(column[1])
if self.third_column:
ret.append(column[2])
if self.four_column:
ret.append(column[3])
if self.five_column:
ret.append(column[4])
yield ret
def set_properties(self):
self.properties = self.formatter.property_to_string(
self.informations, self.calculated_properties, self.modified_attributes, contents=["properties", "validator"],
)

View file

@ -0,0 +1,70 @@
"""
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 ..i18n import _
from ..config import ROUGAIL_VARIABLE_TYPE
from .three_columns import Tabular as ThreeTabular
class Tabular(ThreeTabular):
"""The four columns tabular"""
name = "four_columns"
level = 50
def clear(self):
super().clear()
self.four_column = False
def _add(self) -> tuple:
first_column = self.add_first_column()
second_column = self.get_column(self.description, self.help_, self.validators, self.choices, self.examples, self.tags, *self.calculated_properties)
if second_column:
self.second_column = True
third_column = self.get_column(self.default)
if third_column:
self.third_column = True
types = self.formatter.property_to_string(
self.informations, self.calculated_properties, self.modified_attributes, contents="type",
)
four_column = self.get_column(types)
if four_column:
self.four_column = True
return first_column, second_column, third_column, four_column
def headers(self) -> tuple:
header = super().headers()
if self.four_column:
header.append(_("Type"))
return header
def get_columns(self):
for column in self.columns:
ret = [column[0]]
if self.second_column:
ret.append(column[1])
if self.third_column:
ret.append(column[2])
if self.four_column:
ret.append(column[3])
yield ret
def set_properties(self):
self.properties = self.formatter.property_to_string(
self.informations, self.calculated_properties, self.modified_attributes, contents=["properties", "mode", "access_control", "validator"],
)

View file

@ -0,0 +1,91 @@
"""
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 ..i18n import _
from ..config import ROUGAIL_VARIABLE_TYPE
from .five_columns import Tabular as FiveTabular
class Tabular(FiveTabular):
"""The six columns tabular"""
name = "six_columns"
level = 70
def clear(self):
super().clear()
self.six_column = False
def _add(self) -> tuple:
first_column = self.add_first_column()
second_column = self.get_column(self.description, self.help_, self.examples, self.tags)
if second_column:
self.second_column = True
third_column = self.get_column(self.default)
if third_column:
self.third_column = True
types = self.formatter.property_to_string(
self.informations, self.calculated_properties, self.modified_attributes, contents=["type"],
)
four_column = self.get_column(types)
if four_column:
self.four_column = True
mode = self.formatter.property_to_string(
self.informations, self.calculated_properties, self.modified_attributes, contents=["mode", "access_control"],
)
five_column = self.get_column(mode, *self.calculated_properties)
if five_column:
self.five_column = True
validators = self.formatter.property_to_string(
self.informations, self.calculated_properties, self.modified_attributes, contents=["validator"],
)
six_column = self.get_column(validators, self.validators, self.choices)
if six_column:
self.six_column = True
return first_column, second_column, third_column, four_column, five_column, six_column
def headers(self) -> tuple:
header = super().headers()
if self.six_column:
header.append(_("Validator"))
return header
def get_columns(self):
for column in self.columns:
ret = [column[0]]
if self.second_column:
ret.append(column[1])
if self.third_column:
ret.append(column[2])
if self.four_column:
ret.append(column[3])
if self.five_column:
ret.append(column[4])
if self.six_column:
ret.append(column[5])
yield ret
def set_properties(self):
self.properties = self.formatter.property_to_string(
self.informations, self.calculated_properties, self.modified_attributes, contents=["properties"],
)
def set_validators(self):
self.validators = self.formatter.convert_section_to_string(
"validators", self.informations, self.modified_attributes, multi=True, section_name=False, with_to_phrase=True,
)

View file

@ -0,0 +1,69 @@
"""
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 ..i18n import _
from .two_columns import Tabular as TwoTabular
class Tabular(TwoTabular):
"""The three columns tabular"""
name = "three_columns"
level = 30
def clear(self):
super().clear()
self.third_column = False
def _add(self) -> tuple:
first_column = self.add_first_column()
second_column = self.get_column(self.description, self.help_, self.validators, self.choices, self.examples, self.tags, *self.calculated_properties)
if second_column:
self.second_column = True
third_column = self.get_column(self.default)
if third_column:
self.third_column = True
return first_column, second_column, third_column
def headers(self) -> tuple:
headers = super().headers()
if self.third_column:
headers.append(_("Default value"))
return headers
def get_columns(self):
for column in self.columns:
ret = [column[0]]
if self.second_column:
ret.append(column[1])
if self.third_column:
ret.append(column[2])
yield ret
def set_default(self):
if "default" in self.informations:
self.default = self.formatter.convert_section_to_string(
"default", self.informations, self.modified_attributes, multi=self.multi, section_name=False
)
else:
self.default = None
def set_choices(self):
self.default_is_already_set, self.choices = self.formatter.convert_choices_to_string(
self.informations, self.modified_attributes, with_default=False
)

View file

@ -0,0 +1,55 @@
"""
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 ..i18n import _
from ..utils import CommonTabular
class Tabular(CommonTabular):
"""The two columns tabular"""
name = "two_columns"
level = 10
def clear(self):
super().clear()
self.second_column = False
def _add(self) -> tuple:
first_column = self.add_first_column()
default = self.default if not self.default_is_already_set else None
second_column = self.get_column(self.description, self.help_, self.validators, self.choices, default, self.examples, self.tags, *self.calculated_properties)
if second_column:
self.second_column = True
return first_column, second_column
def add_first_column(self) -> str:
return self.get_column(self.paths, self.properties, self.commandlines, self.environments)
def headers(self) -> tuple:
headers = [_("Variable")]
if self.second_column:
headers.append(_("Description"))
return headers
def get_columns(self):
for column in self.columns:
ret = [column[0]]
if self.second_column:
ret.append(column[1])
yield ret

View file

@ -0,0 +1,984 @@
"""
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 tabulate import tabulate
from rougail.tiramisu import normalize_family
from tiramisu import undefined
from tiramisu.error import PropertiesOptionError, display_list
try:
from tiramisu_cmdline_parser.api import gen_argument_name
except:
gen_argument_name = None
from .i18n import _
from .config import Tabulars, ROUGAIL_VARIABLE_TYPE
ENTER = "\n\n"
_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 CommonTabular:
"""Class with common function for tabular"""
def __init__(self, formatter: "CommonFormatter") -> None:
self.formatter = formatter
self.clear()
def clear(self):
self.columns = []
def get(self):
columns = list(self.get_columns())
self.clear()
return columns
def add(self, informations: dict, modified_attributes: dict, force_identifiers: Optional[str]) -> tuple:
self.informations = informations
self.modified_attributes = modified_attributes
self.force_identifiers = force_identifiers
self.calculated_properties = []
self.set_description()
self.set_type()
self.set_choices()
self.set_properties()
self.set_default()
self.set_examples()
self.set_paths()
self.set_commandline()
self.set_environment()
self.set_validators()
self.set_tags()
self.columns.append(self._add())
def set_description(self):
if "description" in self.informations:
self.description = self.formatter.get_description(
"variable", self.informations, self.modified_attributes, self.force_identifiers,
)
else:
self.description = None
self.help_ = self.formatter.convert_list_to_string("help", self.informations, self.modified_attributes)
def set_choices(self):
self.default_is_already_set, self.choices = self.formatter.convert_choices_to_string(
self.informations, self.modified_attributes
)
def set_type(self):
self.multi = self.informations.get("multiple", True)
self.type = self.informations["variable_type"]
def set_default(self):
if "default" in self.informations:
self.default = self.formatter.convert_section_to_string(
"default", self.informations, self.modified_attributes, multi=self.multi
)
else:
self.default = None
def set_examples(self):
self.examples = self.formatter.convert_section_to_string(
"examples", self.informations, self.modified_attributes, multi=True
)
def set_paths(self):
self.paths = self.formatter.join(self.formatter.display_paths(self.informations, self.modified_attributes, self.force_identifiers, is_variable=True))
def set_commandline(self):
if self.formatter.with_commandline and not self.informations.get('not_for_commandline', False):
commandlines = self.formatter.display_paths(self.informations, self.modified_attributes, self.force_identifiers, is_variable=True, is_bold=False, variable_prefix="--", with_anchor=False)
if self.type == 'boolean':
for path in self.formatter.display_paths(self.informations, self.modified_attributes, self.force_identifiers, is_variable=True, is_bold=False, is_upper=False, with_anchor=False, variable_prefix="--"):
commandlines.append("--" + gen_argument_name(path[2:], False, True, False))
if "alternative_name" in self.informations:
alternative_name = self.informations["alternative_name"]
commandlines[0] = f"-{alternative_name}, {commandlines[0]}"
if self.type == 'boolean':
commandlines[1] = "-" + gen_argument_name(alternative_name, True, True, False) + f", {commandlines[1]}"
self.commandlines = self.formatter.section(_("Command line"), commandlines)
else:
self.commandlines = None
def set_environment(self):
if self.formatter.with_environment:
environments = self.formatter.display_paths(self.informations, self.modified_attributes, self.force_identifiers, is_variable=True, is_bold=False, is_upper=True, variable_prefix=self.formatter.prefix, with_anchor=False)
self.environments = self.formatter.section(_("Environment variable"), environments)
else:
self.environments = None
def set_properties(self):
self.properties = self.formatter.property_to_string(
self.informations, self.calculated_properties, self.modified_attributes,
)
def set_validators(self):
self.validators = self.formatter.convert_section_to_string(
"validators", self.informations, self.modified_attributes, multi=True
)
def set_tags(self):
self.tags = self.formatter.convert_section_to_string(
"tags", self.informations, self.modified_attributes, multi=True
)
def get_column(self, *args):
contents = [arg for arg in args if arg]
self.formatter.columns(contents)
return self.formatter.join(contents)
class CommonFormatter:
"""Class with common function for formatter"""
enter_tabular = "\n"
# tabulate module name
name = None
def __init__(self, rougailconfig, support_namespace, **kwargs):
tabulate_module.PRESERVE_WHITESPACE = True
self.header_setted = False
self.rougailconfig = rougailconfig
self.support_namespace = support_namespace
def run(
self, informations: dict, *, dico_is_already_treated=False
) -> str:
"""Transform to string"""
if informations:
level = self.rougailconfig["doc.title_level"]
self.options()
if self.root:
current = informations
for path in self.root.split('.'):
info = current[path]['informations']
current = current[path]["children"]
informations = {"informations": info, "children": current}
return self._run(informations, level, dico_is_already_treated)
return ""
def options(self):
self.with_commandline = self.rougailconfig["doc.tabulars.with_commandline"]
self.with_environment = self.rougailconfig["doc.tabulars.with_environment"]
if self.with_environment and not gen_argument_name:
raise Exception('please install tiramisu_cmdline_parser')
if not self.rougailconfig["main_namespace"] and self.with_environment:
if self.support_namespace:
self.prefix = ""
else:
self.prefix = self.rougailconfig["doc.tabulars.environment_prefix"] + "_"
self.with_family = not self.rougailconfig["doc.tabulars.without_family"]
self.root = self.rougailconfig["doc.root"]
self.other_root_filenames = None
if self.root:
try:
other_root_filenames = self.rougailconfig["doc.other_root_filenames"]
except PropertiesOptionError:
pass
else:
if other_root_filenames:
self.other_root_filenames = dict(zip(other_root_filenames["root_path"], other_root_filenames["filename"]))
tabular_template = self.rougailconfig["doc.tabular_template"]
self.tabular_datas = Tabulars().get()[tabular_template](self)
def compute(self, data):
return "".join([d for d in data if d])
# 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 tabular 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,
true_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_tabular: bool=True,
type_: str="variable",
with_enter: bool = False,
) -> str:
"""Display a liste of element"""
raise NotImplementedError()
def prop(
self,
prop: str,
italic: bool,
delete: bool,
underline: bool,
) -> str:
"""Display property"""
raise NotImplementedError()
def link(
self,
comment: str,
link: str,
underline: bool,
) -> str:
"""Add a link"""
raise NotImplementedError()
##################
def family_informations(self) -> str:
return ""
def end_family_informations(self) -> str:
return ENTER
def display_paths(
self,
informations: dict,
modified_attributes: dict,
force_identifiers: Optional[str],
*,
is_variable=False,
variable_prefix: str="",
is_bold: bool=True,
is_upper: bool=False,
with_anchor: bool=True,
) -> str:
if with_anchor:
anchor = self.anchor
else:
def anchor(path, true_path):
return path
ret_paths = []
path = informations["path"]
if is_bold:
bold = self.bold
else:
def bold(value):
return value
if is_upper:
def upper(value):
return value.upper()
else:
def upper(value):
return value
if "identifiers" in modified_attributes:
name, previous, new = modified_attributes["identifiers"]
ret_paths.extend(
[
bold(self.delete(upper(variable_prefix + 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 variable_prefix:
path_ = variable_prefix + upper(path_)
if not idx:
path_ = anchor(path_, path)
if identifier in new:
path_ = self.underline(path_)
ret_paths.append(bold(path_))
else:
ret_paths.append(bold(anchor(variable_prefix + upper(path), path)))
return ret_paths
def tabular_header(
self,
lst: list,
) -> tuple:
"""Manage the header of a tabular"""
return lst
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,
*,
init: bool = False,
) -> str:
"""Parse the dict to transform to dict"""
msg = []
if init and self.root:
if self.with_family:
msg.extend(self.family_to_string(dico["informations"], level, False))
level += 1
dico = dico["children"]
for value in dico.values():
if value["type"] == "variable":
self.variable_to_string(value)
elif self.with_family:
if init and value["type"] == "namespace":
namespace = True
else:
namespace = False
if self.tabular_datas.columns:
msg.append(self.tabular())
msg.extend(self.family_to_string(value["informations"], level, namespace))
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,
)
if self.tabular_datas.columns and (init or self.with_family):
msg.append(self.tabular())
return msg
# FAMILY
def namespace_to_title(self, informations: dict, level: int) -> str:
"""manage namespace family"""
return self.title(
self.get_description("family", informations, {}, None),
level,
)
def family_to_string(self, informations: dict, level: int, namespace: bool) -> str:
"""manage other family type"""
if namespace:
ret = [self.namespace_to_title(informations, level)]
else:
ret = [self.title(self.get_description("family", informations, {}, None), level)]
# ret.append(self.anchor("", informations["path"]) + ENTER)
fam_info = self.family_informations()
if fam_info:
ret.append(fam_info)
msg = []
helps = informations.get("help")
if helps:
for help_ in helps:
msg.append(to_phrase(help_.strip()))
msg.append(self.section(_("Path"), self.display_paths(informations, {}, None, with_anchor=False, is_bold=False), type_="family"))
calculated_properties = []
property_str = self.property_to_string(informations, calculated_properties, {})
if property_str:
msg.append(property_str)
if calculated_properties:
msg.append(self.join(calculated_properties)
)
if "identifier" in informations:
msg.append(
self.section(_("Identifiers"), informations["identifier"], type_="family")
)
starts_line = self.family_informations_starts_line()
ret.append(self.family_informations_ends_line().join([starts_line + m for m in msg]) + self.end_family_informations())
return ret
def family_informations_starts_line(self) -> str:
return ""
def family_informations_ends_line(self) -> str:
return ENTER
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 identifiers and "{{ 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"]
if previous:
modified_description = _get_description(
previous[0], modified_attributes.get("identifiers", []), delete=True
)
else:
modified_description = None
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, modified_attributes: dict = {}, force_identifiers: Optional[str]=None
) -> None:
"""Manage variable"""
self.tabular_datas.add(informations, modified_attributes, force_identifiers)
def convert_section_to_string(
self, attribute: str, informations: dict, modified_attributes: dict, multi: bool, *, section_name: bool = True, with_to_phrase = False
) -> str():
values = []
submessage = ""
if modified_attributes and attribute in modified_attributes:
name, previous, new = modified_attributes[attribute]
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, with_enter=section_name)
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, section_name=section_name, with_to_phrase=with_to_phrase)
def convert_choices_to_string(
self, informations: dict, modified_attributes: dict, with_default: bool = True,
) -> 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 = [None]
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 with_default and 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 with_default and val in old_default:
choices_values[idx] = (
dump(val) + " " + self.delete("" + _("(default)"))
)
elif with_default and 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 property_to_string(
self,
informations: dict,
calculated_properties: list,
modified_attributes: dict,
contents: list = ["type", "properties", "mode", "access_control", "validator"]
) -> str:
"""Transform properties to string"""
properties = []
modified_properties = []
if "type" in contents:
if "type" in modified_attributes:
properties.append(self.prop(modified_attributes["type"], italic=False, delete=True, underline=False))
if "multi" in modified_attributes:
properties.append(self.prop("multiple", italic=False, delete=True, underline=False))
if "properties" not in contents and "properties" in modified_attributes:
for prop in modified_attributes["properties"]:
if prop["ori_name"] == "mandatory":
properties.append(self.prop(prop["ori_name"], italic=False, delete=True, underline=False))
break
if "mode" in contents and "mode" in modified_attributes:
properties.append(self.prop(modified_attributes["mode"], italic=False, delete=True, underline=False))
if "properties" in modified_attributes:
if "properties" in contents:
for props in modified_attributes["properties"]:
if not props:
continue
for prop in props:
if prop.get("access_control"):
if "access_control" in contents:
modified_properties.append(prop)
elif prop["ori_name"] != "unique" or "unique" in contents:
modified_properties.append(prop)
elif "access_control" in contents:
for prop in modified_attributes["properties"]:
if prop.get("access_control"):
modified_properties.append(prop)
elif "validator" in contents:
for prop in modified_attributes["properties"]:
if prop["name"] == "unique":
modified_properties.append(prop)
local_calculated_properties = {}
if "properties" in contents and "properties" in modified_attributes:
previous, new = self.get_modified_properties(
*modified_attributes["properties"][1:]
)
for p, data in previous.items():
if "type" not in contents and data[0] == "mandatory":
continue
if "validator" not in contents and data[0] == "unique":
continue
if p not in new:
properties.append(self.prop(p, italic=False, delete=True, underline=False))
if data[1] is not None:
local_calculated_properties[p] = [{"annotation": data[1], "delete": True}]
else:
previous = new = []
others = []
if "type" in contents and "variable_type" in informations:
others.append({"name": informations["variable_type"], "type": "type"})
if informations.get("multiple"):
others.append({"name": "multiple", "type": "multiple"})
if "properties" not in contents and "properties" in informations:
for prop in informations["properties"]:
if prop["ori_name"] == "mandatory":
others.append(prop)
break
if "mode" in contents and "mode" in informations:
others.append({"name": informations["mode"], "type": "mode"})
if "properties" in informations:
if "properties" in contents:
for prop in informations["properties"]:
if prop.get("access_control"):
if "access_control" in contents:
others.append(prop)
elif prop["ori_name"] != "unique" or "validator" in contents:
others.append(prop)
elif "access_control" in contents:
for prop in informations["properties"]:
if prop.get("access_control"):
others.append(prop)
elif "validator" in contents:
for prop in informations["properties"]:
if prop["name"] == "unique":
others.append(prop)
for prop in others:
prop_name = prop["name"]
if "type" not in contents and prop.get("ori_name", prop_name) == "mandatory":
continue
if prop_name not in previous and prop_name in new:
underline = True
else:
underline = False
if prop["type"] == "type":
properties.append(self.link(prop_name, ROUGAIL_VARIABLE_TYPE, underline=underline))
else:
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]
):
underline_ = True
# prop_annotation = self.underline(prop_annotation)
else:
underline_ = False
local_calculated_properties.setdefault(prop["name"], []).append(
{"annotation": prop_annotation, "underline": underline_}
)
else:
italic = False
properties.append(self.prop(prop_name, italic=italic, delete=False, underline=underline))
if local_calculated_properties:
for (
calculated_property_name,
calculated_property,
) in local_calculated_properties.items():
# calculated_property = calculated_property_data["annotation"]
data = []
for calc in calculated_property:
annotation = self.message_to_string(calc["annotation"], None)[1]
if calc.get("underline", False):
annotation = self.underline(annotation)
if calc.get("delete", False):
annotation = self.delete(annotation)
data.append(annotation)
if len(calculated_property) > 1:
calculated_property = self.join(data)
else:
calculated_property = data[0]
calculated_properties.append(
self.section(
calculated_property_name.capitalize(), calculated_property
)
)
if not properties:
return ""
return " ".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["ori_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 tabular(self, with_header: bool = True) -> str:
"""Transform list to a tabular in string format"""
if with_header:
headers = self.tabular_header(self.tabular_datas.headers())
else:
headers = ()
msg = (
tabulate(
self.tabular_datas.get(),
headers=headers,
tablefmt=self._tabular_name,
)
+ "\n\n"
)
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
if "identifiers" in msg["path"]:
msg["identifiers"] = [msg["path"]["identifiers"]]
path = self.link_variable(calc_path(msg["path"], self, identifiers), msg["path"]["path"], self.get_description("variable", msg, {}, None), filename=filename)
msg = msg["message"].format(path)
elif "description" in msg:
if "variables" in msg:
paths = []
for variable in msg["variables"]:
filename = None
if self.other_root_filenames:
path = msg["path"]
for root in self.other_root_filenames:
if path == root or path.startswith(f'{root}.'):
filename = self.other_root_filenames[root]
break
identifiers = variable.get("identifiers")
path = calc_path(variable, self, identifiers)
paths.append(self.link_variable(path, variable["path"], self.get_description("variable", variable, {}, force_identifiers=identifiers), filename=filename))
msg = msg["description"].format(*paths)
else:
msg = msg["description"]
return ret, msg
def section(
self,
name: str,
msg: str,
submessage: str = "",
type_ = "variable",
section_name=True,
with_to_phrase=False
) -> 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, type_=type_, with_enter=section_name)
else:
submessage += elt
else:
lst = []
for p in msg:
submessage, elt = self.message_to_string(p, submessage)
lst.append(elt)
submessage += self.list(lst, type_=type_, with_enter=section_name)
msg = ""
if not isinstance(msg, str):
submessage += dump(msg)
else:
submessage += msg
if section_name:
return _("{0}: {1}").format(self.bold(name), submessage)
if with_to_phrase:
return to_phrase(submessage)
return 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

@ -0,0 +1,41 @@
%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

@ -0,0 +1,21 @@
%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

@ -0,0 +1,21 @@
== 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]` `multiple` `standard` `mandatory` `unique` | 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

@ -0,0 +1,10 @@
<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) `multiple` `standard` `mandatory` `unique` | Fourth variable.<br/>**Default**: <br/>&nbsp;the value of the variable "[First variable](#var1)"<br/>&nbsp;the value of the variable "[A second variable](#family.var2)"<br/>&nbsp;the value of the variable "[A third variable](#family2.var3)" |
</details>

View file

@ -0,0 +1,15 @@
<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>multiple</mark> <mark>standard</mark> <mark>mandatory</mark> <mark>unique</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

@ -0,0 +1,8 @@
# New variables
| 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) `multiple` `standard` `mandatory` `unique` | Fourth variable.<br/>**Default**: <br/>&nbsp;the value of the variable "[First variable](#var1)"<br/>&nbsp;the value of the variable "[A second variable](#family.var2)"<br/>&nbsp;the value of the variable "[A third variable](#family2.var3)" |

View file

@ -0,0 +1,22 @@
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   multiple   standard    │ Default: │
mandatory   unique  │ • the value of the variable "var1"
│ │ • the value of the variable │
│ │ "family.var2"
│ │ • the value of the variable │
│ │ "family2.var3"
└───────────────────────────────────────┴──────────────────────────────────────┘

View file

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

View file

@ -0,0 +1,11 @@
%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

@ -0,0 +1,14 @@
== 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

@ -0,0 +1,13 @@
<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

@ -0,0 +1,14 @@
<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

@ -0,0 +1,10 @@
# New variable
| 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. |
# Deleted variable
- variable_to_family.var

View file

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

View file

@ -0,0 +1,41 @@
%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

@ -0,0 +1,39 @@
%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

@ -0,0 +1,9 @@
== 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

@ -0,0 +1,8 @@
<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

@ -0,0 +1,11 @@
<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

@ -0,0 +1,6 @@
# New variable
| 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. |

View file

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

View file

@ -0,0 +1,11 @@
%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

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

View file

@ -0,0 +1,14 @@
== 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

@ -0,0 +1,13 @@
<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

@ -0,0 +1,14 @@
<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

@ -0,0 +1,10 @@
# New variable
| 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. |
# Deleted variable
- variable_to_family

View file

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

View file

@ -0,0 +1,43 @@
%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

@ -0,0 +1,39 @@
%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

@ -0,0 +1,11 @@
== 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

@ -0,0 +1,9 @@
<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

@ -0,0 +1,12 @@
<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

@ -0,0 +1,7 @@
# New variables
| 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. |

View file

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

View file

@ -0,0 +1,21 @@
%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

@ -0,0 +1,41 @@
%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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,39 @@
%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

@ -0,0 +1,41 @@
%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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,39 @@
%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

@ -0,0 +1,43 @@
%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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,8 @@
<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` | <ins>New description.</ins> |
</details>

View file

@ -0,0 +1,11 @@
<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><ins>New description.</ins></td></tr>
</tbody>
</table>

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,10 @@
== 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

@ -0,0 +1,8 @@
<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

@ -0,0 +1,11 @@
<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

@ -0,0 +1,6 @@
# Modified variable
| 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> |

View file

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

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