mirror of
https://github.com/CatalaLang/catala.git
synced 2024-11-08 07:51:43 +03:00
feat(backends/html): improve the code generation with ToC and details tags
This commit is contained in:
parent
525226e7c6
commit
03aebf7f1c
31
catala.opam
31
catala.opam
@ -17,27 +17,28 @@ license: "Apache-2.0"
|
||||
homepage: "https://github.com/CatalaLang/catala"
|
||||
bug-reports: "https://github.com/CatalaLang/catala/issues"
|
||||
depends: [
|
||||
"ocamlfind" {!= "1.9.5"}
|
||||
"dune" {>= "2.8"}
|
||||
"ocaml" {>= "4.13.0"}
|
||||
"ANSITerminal" {>= "0.8.2"}
|
||||
"sedlex" {>= "2.4"}
|
||||
"benchmark" {>= "1.6"}
|
||||
"bindlib" {>= "5.0.1"}
|
||||
"calendar" {>= "2.04"}
|
||||
"camomile" {>= "1.0.2"}
|
||||
"cmdliner" {>= "1.1.0"}
|
||||
"cppo" {>= "1"}
|
||||
"dune" {>= "2.8"}
|
||||
"js_of_ocaml-ppx" {>= "3.8.0"}
|
||||
"menhir" {>= "20200211"}
|
||||
"menhirLib" {>= "20200211"}
|
||||
"unionFind" {>= "20200320"}
|
||||
"bindlib" {>= "5.0.1"}
|
||||
"cmdliner" {>= "1.1.0"}
|
||||
"ocaml" {>= "4.13.0"}
|
||||
"ocamlfind" {!= "1.9.5"}
|
||||
"ocamlgraph" {>= "1.8.8"}
|
||||
"ppx_yojson_conv" {>= "0.14.0"}
|
||||
"re" {>= "1.9.0"}
|
||||
"sedlex" {>= "2.4"}
|
||||
"ubase" {>= "0.05"}
|
||||
"unionFind" {>= "20200320"}
|
||||
"visitors" {>= "20200210"}
|
||||
"zarith" {>= "1.12"}
|
||||
"zarith_stubs_js" {>= "v0.14.1"}
|
||||
"ocamlgraph" {>= "1.8.8"}
|
||||
"calendar" {>= "2.04"}
|
||||
"visitors" {>= "20200210"}
|
||||
"benchmark" {>= "1.6"}
|
||||
"js_of_ocaml-ppx" {>= "3.8.0"}
|
||||
"ppx_yojson_conv" {>= "0.14.0"}
|
||||
"camomile" {>= "1.0.2"}
|
||||
"cppo" {>= "1"}
|
||||
"alcotest" {with-test & >= "1.5.0"}
|
||||
"odoc" {with-doc}
|
||||
"ocamlformat" {cataladevmode & = "0.21.0"}
|
||||
|
@ -1,7 +1,7 @@
|
||||
(library
|
||||
(name literate)
|
||||
(public_name catala.literate)
|
||||
(libraries re utils surface))
|
||||
(libraries re utils surface ubase))
|
||||
|
||||
(documentation
|
||||
(package catala)
|
||||
|
@ -75,6 +75,7 @@ let wrap_html
|
||||
Format.fprintf fmt
|
||||
"<head>\n\
|
||||
<style>\n\
|
||||
summary { cursor: pointer; font-style: italic; }\n\
|
||||
%s\n\
|
||||
</style>\n\
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>\n\
|
||||
@ -158,6 +159,10 @@ let pygmentize_code (c : string Marked.pos) (language : C.backend_lang) : string
|
||||
|
||||
(** {1 Weaving} *)
|
||||
|
||||
let sanitize_html_href str =
|
||||
str |> Ubase.from_utf8
|
||||
|> R.substitute ~rex:(R.regexp "[' '°]") ~subst:(function _ -> "%20")
|
||||
|
||||
let rec law_structure_to_html
|
||||
(language : C.backend_lang)
|
||||
(print_only_law : bool)
|
||||
@ -178,23 +183,47 @@ let rec law_structure_to_html
|
||||
| A.CodeBlock _ -> ()
|
||||
| A.LawHeading (heading, children) ->
|
||||
let h_number = heading.law_heading_precedence + 1 in
|
||||
Format.fprintf fmt "<h%d class='law-heading'><a href='%s'>%s</a></h%d>\n"
|
||||
h_number
|
||||
let h_name = Marked.unmark heading.law_heading_name in
|
||||
let fmt_details_open fmt () =
|
||||
if 2 = h_number then
|
||||
Format.fprintf fmt "<details><summary>%s</summary>" h_name
|
||||
in
|
||||
let fmt_details_close fmt () =
|
||||
if 2 >= h_number then Format.fprintf fmt "</details>"
|
||||
in
|
||||
Format.fprintf fmt
|
||||
"%a<h%d class='law-heading' id=\"%s\"><a href=\"%s\">%s</a></h%d>@\n%a"
|
||||
fmt_details_close () h_number
|
||||
(sanitize_html_href h_name)
|
||||
(match heading.law_heading_id, language with
|
||||
| Some id, Fr ->
|
||||
let ltime = Unix.localtime (Unix.time ()) in
|
||||
P.sprintf "https://legifrance.gouv.fr/codes/id/%s/%d-%02d-%02d" id
|
||||
(1900 + ltime.Unix.tm_year)
|
||||
(ltime.Unix.tm_mon + 1) ltime.Unix.tm_mday
|
||||
| _ -> "#")
|
||||
(pre_html (Marked.unmark heading.law_heading_name))
|
||||
h_number;
|
||||
| _ -> "#" ^ sanitize_html_href h_name)
|
||||
(pre_html h_name) h_number fmt_details_open ();
|
||||
Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "\n")
|
||||
(law_structure_to_html language print_only_law)
|
||||
fmt children
|
||||
| A.LawInclude _ -> ()
|
||||
|
||||
let fmt_toc fmt (items : A.law_structure list) =
|
||||
Format.fprintf fmt "@[<v 2><ol class=\"toc\">@\n%a@\n@]</ol>"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
(fun fmt item ->
|
||||
match item with
|
||||
| A.LawHeading (heading, _children) ->
|
||||
let h_name = Marked.unmark heading.law_heading_name in
|
||||
Format.fprintf fmt
|
||||
"<li class=\"toc-item\"><a href=\"#%s\">%s</a></li>"
|
||||
(sanitize_html_href h_name)
|
||||
h_name
|
||||
| _ -> ()))
|
||||
items
|
||||
|
||||
(** {1 API} *)
|
||||
|
||||
let ast_to_html
|
||||
@ -202,7 +231,16 @@ let ast_to_html
|
||||
~(print_only_law : bool)
|
||||
(fmt : Format.formatter)
|
||||
(program : A.program) : unit =
|
||||
Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "\n\n")
|
||||
(law_structure_to_html language print_only_law)
|
||||
fmt program.program_items
|
||||
let toc =
|
||||
match language with
|
||||
| C.Fr -> "Sommaire"
|
||||
| C.En -> "Table of contents"
|
||||
| C.Pl -> "Spis treści."
|
||||
in
|
||||
|
||||
Format.fprintf fmt "<h1>%s</h1>\n%a\n%a" toc fmt_toc program.program_items
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "\n\n")
|
||||
(fun fmt ->
|
||||
Format.fprintf fmt "%a" (law_structure_to_html language print_only_law)))
|
||||
program.program_items
|
||||
|
@ -1,4 +1,4 @@
|
||||
## Tutoriel d'utilisation du langage Catala
|
||||
# Tutoriel d'utilisation du langage Catala
|
||||
|
||||
Bienvenue dans ce tutoriel, son objectif est de vous accompagner dans les
|
||||
fonctionnalités du langage Catala et de vous apprendre à annoter des textes
|
||||
@ -13,7 +13,7 @@ en informatique devraient pouvoir s'en sortir.
|
||||
# la référence pour le langage.
|
||||
```
|
||||
|
||||
### Programmation littéraire
|
||||
## Programmation littéraire
|
||||
|
||||
Pour commencer à écrire un programme Catala, vous devez partir du texte
|
||||
d'une source législative qui va justifier le code que vous écrirez.
|
||||
@ -34,7 +34,7 @@ diminuer l'importance du titre en augmentant le nombre de "#" après le titre de
|
||||
l'entête.
|
||||
Étudions un exemple fictif qui définit un impôt sur le revenu.
|
||||
|
||||
#### Article 1
|
||||
### Article 1
|
||||
|
||||
L'impôt sur le revenu d'un individu est calculé en tant qu'un pourcentage
|
||||
fixe des revenus d'une personne pour une année.
|
||||
@ -52,7 +52,7 @@ et aussi proche que possible de la phrase qui justifie le code. Ce style
|
||||
s'appelle programmation littéraire, un paradigme de programmation inventé par le
|
||||
célèbre informaticien Donald Knuth dans les années 70.
|
||||
|
||||
### Définir un impôt sur le revenu fictif
|
||||
## Définir un impôt sur le revenu fictif
|
||||
|
||||
Le contenu de l'article 1 utilise beaucoup d'éléments du contexte implicite :
|
||||
il existe une personne avec un revenu et en même temps un impôt sur le revenu,
|
||||
@ -128,7 +128,7 @@ déclaration champ d'application CalculImpôtRevenu:
|
||||
Nous avons maintenant tout ce dont nous avons besoin pour annoter le contenu
|
||||
de l'article 1 qui a été copié ci-dessous.
|
||||
|
||||
#### Article 1
|
||||
### Article 1
|
||||
|
||||
L'impôt sur le revenu pour une personne est défini comme un pourcentage fixe
|
||||
des revenus de la personne pour une année.
|
||||
@ -162,7 +162,7 @@ Mais dans l'article 1, une question reste sans réponse: quelle est la valeur
|
||||
de la pourcentage fixe? Souvent, des valeurs précises sont définis ailleurs
|
||||
dans les sources législatives. Ici, supposons que nous avons:
|
||||
|
||||
#### Article 2
|
||||
### Article 2
|
||||
|
||||
Le pourcentage fixe mentionné à l'article 1 est égal à 20%.
|
||||
|
||||
@ -176,12 +176,12 @@ Vous pouvez voir ici que Catala permet des définitions réparties dans toute
|
||||
l'annotation du texte législatif, afin que chaque définition soit le plus
|
||||
proche possible de sa localisation dans le texte.
|
||||
|
||||
### Définitions conditionnelles
|
||||
## Définitions conditionnelles
|
||||
|
||||
Jusqu'à là tout va bien mais maintenant le texte législatif présente quelques
|
||||
difficultés. Supposons que le troisième article dispose :
|
||||
|
||||
#### Article 3
|
||||
### Article 3
|
||||
|
||||
Si l'individu a à sa charge deux ou plus enfants alors
|
||||
le pourcentage fixe mentionné à l'article 1 vaut 15 %.
|
||||
@ -210,7 +210,7 @@ une seule condition soit vraie à tout moment. Toutefois, si ce n'est pas le cas
|
||||
Catala vous permettra de définir un ordre des priorités sur les conditions,
|
||||
qui doit être justifié par un raisonnement juridique.
|
||||
|
||||
### Fonctions
|
||||
## Fonctions
|
||||
|
||||
Catala vous permet de définir des fonctions partout dans vos données. Voici
|
||||
à quoi cela ressemble dans la définition des métadonnées quand nous voulons
|
||||
@ -229,7 +229,7 @@ déclaration champ d'application CalculImpôtDeuxTranches :
|
||||
|
||||
Et dans le code :
|
||||
|
||||
#### Article4
|
||||
### Article4
|
||||
|
||||
Le montant d'impôt pour le calcul à deux tranches
|
||||
est égal au montant d'impôt dans chaque tranche multiplié
|
||||
@ -246,13 +246,13 @@ champ d'application CalculImpôtDeuxTranches :
|
||||
)
|
||||
```
|
||||
|
||||
### Inclusion de champ d'application
|
||||
## Inclusion de champ d'application
|
||||
|
||||
Maintenant que nous avons défini notre champ d'application utilitaire pour
|
||||
calculer un impôt à deux tranches, nous voulons l'utiliser dans notre champ
|
||||
d'application principal de calcul de l'impôt.
|
||||
|
||||
#### Article 5
|
||||
### Article 5
|
||||
|
||||
Pour les individus dont le revenu est supérieur à 100 000€,
|
||||
l'impôt sur le revenu de l'article 1 est de 40% du revenu au-dessus de
|
||||
@ -278,7 +278,7 @@ champ d'application NouveauCalculImpôtRevenu :
|
||||
deux_tranches.formule_imposition de personne.revenu
|
||||
```
|
||||
|
||||
#### Article 6
|
||||
### Article 6
|
||||
|
||||
Les personnes ayant moins de 10 000€ de revenus sont exemptés de l'impôt
|
||||
sur le revenu prévu à l'article 1.
|
||||
@ -300,7 +300,7 @@ La loi ne le précise pas; nos articles sont clairement mal rédigés.
|
||||
Mais Catala vous aide à trouver ce genre d'erreur par de simples tests ou
|
||||
même la vérification formelle. Commençons par les tests.
|
||||
|
||||
### Tester les programmes Catala
|
||||
## Tester les programmes Catala
|
||||
|
||||
Tester les programmes Catala peut se faire directement en Catala. En effet,
|
||||
écrire des cas de tests pour chaque champ d'application Catala que vous
|
||||
@ -308,7 +308,7 @@ définissez est une bonne pratique appelée "tests unitaires" dans la
|
||||
communauté du génie logicielle. Les cas de test sont définis dans des
|
||||
champ d'application :
|
||||
|
||||
#### Tester NouveauCalculImpotRevenu
|
||||
### Tester NouveauCalculImpotRevenu
|
||||
|
||||
```catala
|
||||
déclaration champ d'application Test1:
|
||||
@ -356,7 +356,7 @@ Ce cas de test devrait calculer un impôt sur le revenu de 0€,
|
||||
en raison de l'article 6. Mais au lieu de cela, l'exécution produira
|
||||
une erreur car il y a un conflit entre les règles.
|
||||
|
||||
### Définir des exceptions à des règles
|
||||
## Définir des exceptions à des règles
|
||||
|
||||
En effet, la définition d'un impôt sur le revenu à l'article 6 entre en
|
||||
conflit avec la définition de l'article 5. Mais en réalité, l'article 6
|
||||
@ -364,7 +364,7 @@ est une simple exception à l'article 5. Dans la loi, il est implicite que
|
||||
si l'article 6 est applicable, alors son application est prioritaire
|
||||
sur l'article 5.
|
||||
|
||||
#### Régler correctement le calcul
|
||||
### Régler correctement le calcul
|
||||
|
||||
Cette priorité implicite doit être explicitement déclaré en Catala. Voici une
|
||||
version correcte du champ d'application NouveauCalculImpotRevenu :
|
||||
@ -413,7 +413,7 @@ champ d'application Test3:
|
||||
assertion impôt_revenu = 0€
|
||||
```
|
||||
|
||||
### Conclusion
|
||||
## Conclusion
|
||||
|
||||
Ce tutoriel présente les concepts de base et la syntaxe des fonctionnalités
|
||||
du langage Catala. C'est à vous de les utiliser pour annoter du texte
|
||||
|
Loading…
Reference in New Issue
Block a user