% \iffalse meta-comment % %% regulatory-md.dtx %% Copyright 2024-2026 E. Nijenhuis % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3c or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % This work has the LPPL maintenance status ‘maintained’. % % The Current Maintainer of this work is E. Nijenhuis. % % This work consists of the files listed in the meta-comment of % regulatory-struct.dtx. % % \fi % % \iffalse %<*driver> \ProvidesFile{regulatory-md.dtx} % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{regulatory-md} % [2026/09/10 1.0.0 Xerdi's Regulatory Package (Markdown)] % %<*driver> \documentclass[10pt,english]{ltxdoc} %! suppress = InclusionLoop \usepackage{regulatory} \usepackage{tabularx} \usepackage[english,dutch]{babel} \input{regulatory-preamble} \newcommand\translation[2]{#1} \begin{document} \selectlanguage{english} \DocInput{regulatory-md.dtx} \end{document} % % \fi % % \subsection{\texorpdfstring{\package{regulatory-md}}{regulatory-md}} % \setcounter{CodelineNo}{0} % % \subsubsection{\translation{Prerequisites}{Vereisten}} % % This module is loaded by \package{regulatory-struct} as soon as \package{markdown} is loaded, which is % what the \option{md} option comes down to. \package{regulatory-defs} comes with it, because a Markdown % definition list is aligned on the widest name \package{glossaries-extra} knows of. Both prerequisites are therefore normally settled already; % they are stated for the document that loads this module on its own. % \iffalse %<*package> % \fi % \begin{macrocode} \RequirePackage{regulatory-struct} \RequirePackage{regulatory-defs} \RequirePackage{markdown} % \end{macrocode} % % \subsubsection{\translation{Conversion options}{Conversieopties}} % % The renderers below only see what the reader was told to look for, so the options they depend on are % set here rather than left to the document or to the \option{md} option of \package{regulatory-struct}. % A document that loads \package{markdown} by itself then gets the same conversion as one that asked for % it through the option. % % \package{markdown} forwards its package options to \cmd{\markdownSetup} and reads them at conversion % time rather than at load time, so setting them here is the same thing as naming them when the package % is loaded, only later. % % \option{extension} names the file that adds the standalone identifier of \zcref{sec:syntax} to the % grammar of the reader. It is the singular of \option{extensions}, which appends rather than replaces, so % an extension of the document's own is left in place. \package{markdown} looks the file up with kpathsea % and stops with an error when it is not there, which is the one way round this bundle can fail loudly. % % \option{hybrid} is off. It made every backslash in a Markdown source reach \TeX{}, which is how the % examples of this bundle used to write a label or a reference; \package{markdown} soft-deprecated it and % names \option{rawAttribute} among its replacements. What it costs to leave it on is not a warning but a % wrong document: with \option{hybrid} off, raw \TeX{} is typeset verbatim, so a source that still % contains it prints its own control sequences and loses every reference without a single error. The % constructs that used to need it each have a Markdown form of their own below. % \begin{macrocode} \markdownSetup{ extension = regulatory-syntax.lua, hybrid = false, hashEnumerators, headerAttributes, bracketedSpans, relativeReferences, definitionLists, fencedDivs, jekyllData, tightLists, } % \end{macrocode} % % \subsubsection{\translation{Structures}{Structuren}} % % A renderer tells \package{markdown} how to typeset one construct of a Markdown source. Only the % constructs that have a counterpart in this bundle are redirected; everything else keeps the rendering of % the \package{markdown} defaults. % % \begin{macro}{\markdownRendererHeadingOne} % A first level heading is an article. Deeper headings are left alone: a regulatory document numbers its % paragraphs as list items, not as headings. % % An article is labelled with the attribute syntax of \option{headerAttributes}, \verb|# Heading {#art:x}|. % The \package{markdown} defaults theme turns such an identifier into a \cmd{\label} of its own, after the % heading renderer has run, so the label lands on the article and carries its reference properties without % this module having to do anything. % \begin{macrocode} \markdownSetup{ renderers = { headingOne = {\article{#1}}, % \end{macrocode} % \end{macro} % % \begin{macro}{\markdownRendererOlBegin} % \begin{macro}{\markdownRendererOlItemWithNumber} % An ordered list is a \texttt{paras} environment, and its numbering is composed by this bundle rather than % taken from the Markdown source. Tight and loose lists are rendered the same way, since the spacing of % \texttt{paras} is set by \package{enumitem}. % % The item carries no label of its own. It used to be given one made from the number in the source, % \texttt{ml:}\meta{number}, but \package{markdown} hands a renderer nothing except that number: no % nesting depth, no list identity. The number restarts in every list, so \texttt{ml:1} existed once per % list and per article, and a reference to it silently resolved to whichever item was declared last. % Worse, such a key is positional: inserting a paragraph moves every reference after it to another % provision without anything failing. An item that is referred to is labelled by hand, with the bracketed % span below. % \begin{macrocode} olBegin = {\begin{paras}}, olEnd = {\end{paras}}, olBeginTight = {\begin{paras}}, olEndTight = {\end{paras}}, olItemWithNumber = {\item{}}, % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\markdownRendererLink} % Every reference of a Markdown source arrives here: \option{relativeReferences} lets an autolink hold % something that is not a web address, and a link whose target starts with \texttt{\#} is a reference to a % label of this document or of another one declared with \cmd{\refdocument}. % % The three shapes a Markdown link can take are enough to reach the whole reference family without any % syntax of our own, and each of them says what it means: % % \begin{labeling}{\texttt{[text](\#label)}} % \item[\texttt{<\#label>}] an autolink, where the text equals the target, becomes \cmd{\Aref}: the % reference names the structures it points at, and several labels may be given at once, % \verb|<#lid:a,lid:b>|. % \item[\texttt{[](\#label)}] a link with no text becomes \cmd{\rref}: the bare number of the % structure. % \item[\texttt{[text](\#label)}] a link with text keeps that text and turns it into a hyperlink. % \end{labeling} % % An attribute writes a label and a link reads one, which is the whole of it: \verb|{#lid:a}| on a heading % or a span is where a provision is named, and the three shapes above are how it is referred to. A % definition is referred to in exactly the same way. Its label is not a label of the document but an entry % of the glossary, so the target is looked up there first: a reference to one is a citation, hyperlinked to % the definition list, which is what \cmd{\gls} and \cmd{\glslink} produce. % % The target arrives in the third argument, which \package{markdown} escapes far less than the first two: % braces, backslashes and line ends only, so a label comes through exactly as it was written. Anything % that is not a reference is handed back to the \package{markdown} prototype, which is what turns a real % web address into a link. % \begin{macrocode} link = {\regulatory@md@link{#1}{#2}{#3}{#4}}, % \end{macrocode} % \end{macro} % % \begin{macro}{\markdownRendererDlItem} % A definition list declares definitions. The term carries the label as a bracketed span, % \verb|[Term]{#label}|, and the body of the item becomes the description, so that one construct produces % an entry that both prints in the list and can be cited with \cmd{\gls} elsewhere in the document. % % The list itself typesets nothing where it stands. Where the definitions appear is decided by % \cmd{\printdefs}, or from the source by the division below, which keeps the declaration and the % placement apart in the same way the file-based routes of \zcref{sec:defs} do. % \begin{macrocode} dlBegin = {}, dlEnd = {}, dlBeginTight = {}, dlEndTight = {}, dlItem = {\regulatory@md@dlitem{#1}}, dlItemEnd = {\regulatory@md@dlitemend}, }, % \end{macrocode} % \end{macro} % % \begin{macro}{\markdownRendererTilde} % Without \option{hybrid} a tilde no longer reaches \TeX{} as the non-breaking space it is there; the % default prototype prints the character itself. A legal text is full of them\,---\,\enquote{artikel~2} % keeps its number on the same line as its noun\,---\,so the prototype is set back to what an author % typing a tilde means by it. % \begin{macrocode} rendererPrototypes = { tilde = {~}, }, } % \end{macrocode} % \end{macro} % % \begin{macro}{\markdownRendererRegulatoryLabel} % The renderer the syntax extension calls. An identifier that stands on its own is a label, and nothing % else: it is written where it stands, so within a \texttt{paras} item it names that item. % % The renderer is declared rather than set through \cmd{\markdownSetup}, which only accepts the names % \package{markdown} knows. % \begin{macrocode} \newcommand\markdownRendererRegulatoryLabel[1]{\label{#1}} % \end{macrocode} % \end{macro} % % \subsubsection{\translation{References}{Verwijzingen}} % % \begin{macro}{\regulatory@md@link} % Decides which of the three shapes above a link has. The test is on the target: a leading \texttt{\#} % makes it a reference, and what remains is the label list, handed to the reference family as it stands. % The labels are trimmed, since \verb|<#a, b>| is the natural thing to write and a space would otherwise % end the list at the first item. % \begin{macrocode} \newcommand\regulatory@md@full[1]{% \ifglsentryexists{#1}{\gls{#1}}{\Aref{#1}}% } \newcommand\regulatory@md@bare[1]{% \ifglsentryexists{#1}{\gls{#1}}{\rref{#1}}% } \newcommand\regulatory@md@named[2]{% \ifglsentryexists{#1}{\glslink{#1}{#2}}{\hyperref[#1]{#2}}% } \ExplSyntaxOn \str_new:N \l__regulatory_md_target_str \tl_new:N \l__regulatory_md_labels_tl \seq_new:N \l__regulatory_md_labels_seq \cs_new_protected:Npn \__regulatory_md_labels:n #1 { \seq_set_split:Nnn \l__regulatory_md_labels_seq { , } { #1 } \seq_set_map_x:NNn \l__regulatory_md_labels_seq \l__regulatory_md_labels_seq { \tl_trim_spaces:n { ##1 } } \tl_set:Nx \l__regulatory_md_labels_tl { \seq_use:Nn \l__regulatory_md_labels_seq { , } } } \cs_new_protected:Npn \regulatory@md@link #1#2#3#4 { \str_set:Nn \l__regulatory_md_target_str { #3 } \str_if_eq:eeTF { \str_range:Nnn \l__regulatory_md_target_str { 1 } { 1 } } { \c_hash_str } { \__regulatory_md_labels:n { \str_range:Nnn \l__regulatory_md_target_str { 2 } { -1 } } \tl_if_blank:nTF { #1 } { \exp_args:NV \regulatory@md@bare \l__regulatory_md_labels_tl } { \str_if_eq:nnTF { #1 } { #2 } { \exp_args:NV \regulatory@md@full \l__regulatory_md_labels_tl } { \exp_args:NV \regulatory@md@named \l__regulatory_md_labels_tl { #1 } } } } { \markdownRendererLinkPrototype { #1 } { #2 } { #3 } { #4 } } } \ExplSyntaxOff % \end{macrocode} % \end{macro} % % \subsubsection{\translation{Definitions}{Definities}} % % \begin{macro}{\regulatory@md@dlitem} % Collects one item of a definition list. The term is executed into a box that is thrown away, with the % attribute renderers replaced, so that the identifier of its bracketed span is captured instead of % becoming a label of its own and the name is captured instead of being typeset. Executing it is what % makes the capture work: the renderers of \package{markdown} are not expandable, so reading the term as % text would store the calls themselves rather than what they carry. A term that turns out to have no % span is read as text after all, since then it holds nothing but the name. % % A term without an identifier still becomes a definition, but one that cannot be cited by name, so it is % reported. % \begin{macrocode} \ExplSyntaxOn \cs_new_protected:Npn \regulatory@md@declare #1#2#3 { \use:x { \exp_not:N \newdefinition { #1 } { \exp_not:V #2 } { \exp_not:V #3 } } } \ExplSyntaxOff \newcommand\regulatory@md@deflabel{} \newcommand\regulatory@md@defname{} \newcommand\regulatory@md@defbody{} \newcounter{regulatory@md@defs} \newcounter{regulatory@md@declared} \newcommand\regulatory@md@dlitem[1]{% \gdef\regulatory@md@deflabel{}% \gdef\regulatory@md@defname{}% \gdef\regulatory@md@defbody{}% \begingroup% \def\markdownRendererBracketedSpanAttributeContextBegin{}% \def\markdownRendererBracketedSpanAttributeContextEnd{}% \def\markdownRendererAttributeIdentifier##1{\gdef\regulatory@md@deflabel{##1}}% \def\markdownRendererAttributeClassName##1{}% \def\markdownRendererAttributeKeyValue##1##2{}% \def\markdownRendererBracketedSpan##1{\gdef\regulatory@md@defname{##1}}% \setbox\z@\hbox{#1}% \endgroup% \ifx\regulatory@md@defname\@empty% \protected@xdef\regulatory@md@defname{#1}% \fi% \ifx\regulatory@md@deflabel\@empty% \stepcounter{regulatory@md@defs}% \xdef\regulatory@md@deflabel{regulatory@md@\arabic{regulatory@md@defs}}% \PackageWarning{regulatory-md}{% Definition without an identifier; give the term a bracketed\MessageBreak span with one, so that it can be cited with \string\gls. Reported}% \fi% } % \end{macrocode} % \end{macro} % % \begin{macro}{\markdownRendererDlDefinitionBegin} % The description of a definition is not handed to a renderer as an argument: it is streamed between % \cmd{\markdownRendererDlDefinitionBegin} and \cmd{\markdownRendererDlDefinitionEnd}, which are both % ordinary tokens in the converted file. Making the first of the two a delimited macro therefore hands % the whole body over as an argument. A term may carry more than one description, which are collected in % the order they are written. % \begin{macrocode} \long\def\markdownRendererDlDefinitionBegin#1\markdownRendererDlDefinitionEnd{% \ifx\regulatory@md@defbody\@empty% \protected@xdef\regulatory@md@defbody{#1}% \else% \protected@xdef\regulatory@md@defbody{\regulatory@md@defbody\space#1}% \fi% } % \end{macrocode} % \end{macro} % % \begin{macro}{\regulatory@md@dlitemend} % Declares what was collected. \cmd{\newdefinition} is the same route a document takes when it declares a % definition by hand, so a Markdown definition list and a \cmd{\newdefinition} in the preamble produce % entries that are indistinguishable afterwards. % \begin{macrocode} \newcommand\regulatory@md@dlitemend{% \stepcounter{regulatory@md@declared}% \regulatory@md@declare\regulatory@md@deflabel\regulatory@md@defname\regulatory@md@defbody% } % \end{macrocode} % \end{macro} % % \begin{macro}{\markdownRendererFencedDivAttributeContextBegin} % A division marks where the definitions are printed, \verb|::: {.definitions}|. The class is what selects % it; a \texttt{style} and a \texttt{widest} attribute may be given along with it, which are the two % arguments of \cmd{\printdefs}. The list is printed after the content of the division, so that a % sentence introducing it can be written inside. % % \package{markdown} does not recognise an empty division, so a division that is to print nothing but the % list still needs a line of text in it. % \begin{macrocode} \newcommand\regulatory@md@divdefs{false} \newcommand\regulatory@md@divstyle{\regulatory@defstyle} \newcommand\regulatory@md@divwidest{} \renewcommand\markdownRendererFencedDivAttributeContextBegin{% \def\regulatory@md@divdefs{false}% \def\regulatory@md@divstyle{\regulatory@defstyle}% \def\regulatory@md@divwidest{}% \def\markdownRendererAttributeClassName##1{% \def\regulatory@md@class{##1}% \def\regulatory@md@definitionsclass{definitions}% \ifx\regulatory@md@class\regulatory@md@definitionsclass% \def\regulatory@md@divdefs{true}% \fi% }% \def\markdownRendererAttributeKeyValue##1##2{% \def\regulatory@md@key{##1}% \def\regulatory@md@stylekey{style}% \def\regulatory@md@widestkey{widest}% \ifx\regulatory@md@key\regulatory@md@stylekey\def\regulatory@md@divstyle{##2}\fi% \ifx\regulatory@md@key\regulatory@md@widestkey\def\regulatory@md@divwidest{##2}\fi% }% } \renewcommand\markdownRendererFencedDivAttributeContextEnd{% \def\regulatory@md@true{true}% \ifx\regulatory@md@divdefs\regulatory@md@true% \par% \printdefs[\regulatory@md@divstyle]{\regulatory@md@divwidest}% \fi% } % \end{macrocode} % \end{macro} % % \subsubsection{\translation{Definitions in the metadata}{Definities in de metadata}} % % \begin{macro}{\regulatory@md@yaml} % The other way to declare a definition is the \textsc{yaml} block a Markdown source may open with, where % a definition is a record with named fields rather than a construct of the text. It is the sturdier of % the two: nothing in the prose can perturb it, and any field \package{glossaries} knows could be added to % it. What it costs is that the definitions are no longer where the reader of the source expects them. % % The fields of one record do not arrive in the order they are written but alphabetically, so they are % collected and the entry is declared when the record ends. That is a prototype rather than a renderer: % the renderer of a mapping end is what pops the address stack of \package{markdown} itself, so it is % appended to instead of replaced. % \begin{macrocode} \newcommand\regulatory@md@yamllabel{} \newcommand\regulatory@md@yamlname{} \newcommand\regulatory@md@yamldesc{} \markdownSetup{ jekyllDataRenderers = { /definitions/*/label = {\gdef\regulatory@md@yamllabel{#1}}, /definitions/*/name = {\gdef\regulatory@md@yamlname{#1}}, /definitions/*/description = {\gdef\regulatory@md@yamldesc{#1}}, }, rendererPrototypes = { jekyllDataMappingEnd + = {\regulatory@md@yamlflush}, }, } \newcommand\regulatory@md@yamlflush{% \ifx\regulatory@md@yamllabel\@empty\else% \stepcounter{regulatory@md@declared}% \regulatory@md@declare\regulatory@md@yamllabel\regulatory@md@yamlname\regulatory@md@yamldesc% \gdef\regulatory@md@yamllabel{}% \gdef\regulatory@md@yamlname{}% \gdef\regulatory@md@yamldesc{}% \fi% } % \end{macrocode} % \end{macro} % % \subsubsection{\translation{Citing a definition}{Een definitie aanhalen}} % % \begin{macro}{\autocitedefs} % A definition is cited the same way anything else is referred to, with a bracketed span: % \verb|[verwerking]{#vw}| prints that text and links it to the entry. That is explicit, and it is the % documented way. % % \cmd{\autocitedefs} is the other one, for a document that would rather keep its prose free of markup: it % hands the names of the definitions declared so far to the \option{acronyms} machinery of % \package{markdown}, which then marks up every occurrence of such a name in the text that follows and % turns it into a \cmd{\gls}. It is opt-in for good reason. The matching is literal: case sensitive, blind % to inflection\,---\,\enquote{persoonsgegevens} is not \enquote{persoonsgegeven}\,---\,and it does not % see a term that a line break has split. It also only affects text converted after the call, so the % definitions have to be declared in a file of their own, converted first. % \begin{macrocode} \ExplSyntaxOn \prop_new:N \g__regulatory_md_names_prop \tl_new:N \l__regulatory_md_name_tl \cs_new_protected:Npn \regulatory@md@register #1 { \tl_set:Nx \l__regulatory_md_name_tl { \glsentryname { #1 } } \prop_gput:NVn \g__regulatory_md_names_prop \l__regulatory_md_name_tl { #1 } \tl_gput_right:Nx \markdownOptionAcronyms { , { \l__regulatory_md_name_tl } } } \cs_new_protected:Npn \regulatory@md@cite #1 { \prop_get:NnNTF \g__regulatory_md_names_prop { #1 } \l__regulatory_md_name_tl { \exp_args:NV \gls \l__regulatory_md_name_tl } { #1 } } \ExplSyntaxOff \newcommand\autocitedefs{% \forglsentries[definitions]\regulatory@md@entry{% \expandafter\regulatory@md@register\expandafter{\regulatory@md@entry}% }% \renewcommand\markdownRendererAcronymPrototype[1]{\regulatory@md@cite{##1}}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\regulatory@md@nodefs} % A definition list that is never printed is the one mistake this module cannot catch while it happens: % the entries are declared, the conversion succeeds, and the definitions article of the document is simply % empty. The end of the document is the first moment at which that is knowable, so it is said there. % \begin{macrocode} \AtEndDocument{% \ifnum\value{regulatory@md@declared}>0% \ifnum\value{regulatory@defsprinted}=0% \PackageWarning{regulatory-md}{% Definitions were declared but never printed;\MessageBreak call \string\printdefs\space or mark the place with a\MessageBreak definitions division. Reported}% \fi% \fi% } % \end{macrocode} % \end{macro} % \iffalse % % \fi % % \Finale %