Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"symfony/polyfill-php82": "*",
"t3docs/typo3-api": "self.version",
"t3docs/typo3-docs-theme": "self.version",
"t3docs/typo3-docs-theme-md": "self.version",
"t3docs/typo3-guides-cli": "self.version",
"t3docs/typo3-guides-extension": "self.version",
"t3docs/typo3-version-handling": "self.version"
Expand All @@ -53,6 +54,7 @@
"psr-4": {
"T3Docs\\GuidesCli\\": "packages/typo3-guides-cli/src/",
"T3Docs\\GuidesExtension\\": "packages/typo3-guides-extension/src/",
"T3Docs\\Typo3DocsThemeMd\\": "packages/typo3-docs-theme-md/src/",
"T3Docs\\Typo3DocsTheme\\": "packages/typo3-docs-theme/src/",
"T3Docs\\VersionHandling\\": "packages/typo3-version-handling/src/"
}
Expand Down
2 changes: 1 addition & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions config.subsplit-publish.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
"name": "t3docs-typo3-api",
"directory": "packages/typo3-api",
"target": "git@github.com:TYPO3-Documentation/t3docs-typo3-api.git"
},
{
"name": "t3docs-typo3-docs-theme-md",
"directory": "packages/typo3-docs-theme-md",
"target": "git@github.com:TYPO3-Documentation/t3docs-typo3-docs-theme-md.git"
}
]
}
16 changes: 16 additions & 0 deletions packages/typo3-docs-theme-md/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "t3docs/typo3-docs-theme-md",
"description": "Markdown output format for TYPO3 Documentation",
"license": "MIT",
"type": "library",
"require": {
"php": "^8.2",
"phpdocumentor/guides": "^1.9",
"twig/twig": "^3.20"
},
"autoload": {
"psr-4": {
"T3Docs\\Typo3DocsThemeMd\\": "src/"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use T3Docs\Typo3DocsThemeMd\Renderer\MdRenderer;
use T3Docs\Typo3DocsThemeMd\Twig\MdExtension;

use function Symfony\Component\DependencyInjection\Loader\Configurator\service;

return static function (ContainerConfigurator $container): void {
$container->services()
->defaults()
->autowire()
->autoconfigure()

->load(
'T3Docs\\Typo3DocsThemeMd\\NodeRenderers\\Md\\',
'../../src/NodeRenderers/Md',
)
->tag('phpdoc.guides.noderenderer.md')

->set(MdRenderer::class)
->tag(
'phpdoc.renderer.typerenderer',
[
'noderender_tag' => 'phpdoc.guides.noderenderer.md',
'format' => 'md',
],
)


->set(MdExtension::class)
->arg('$nodeRenderer', service('phpdoc.guides.output_node_renderer'))
->tag('twig.extension')
->autowire();
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{#- GFM alerts cover five kinds; the RST set is wider, so each admonition maps
to the closest alert and keeps its own wording as the first line when the
two do not coincide. A titled generic admonition has no alert at all and
renders as a blockquote with a bold title. -#}
{%- set alertMap = {
'note': 'NOTE',
'seealso': 'NOTE',
'tip': 'TIP',
'hint': 'TIP',
'important': 'IMPORTANT',
'warning': 'WARNING',
'attention': 'WARNING',
'caution': 'WARNING',
'danger': 'CAUTION',
'error': 'CAUTION'
} -%}
{%- set labelMap = {
'note': 'Note',
'seealso': 'See also',
'tip': 'Tip',
'hint': 'Hint',
'important': 'Important',
'warning': 'Warning',
'attention': 'Attention',
'caution': 'Caution',
'danger': 'Danger',
'error': 'Error'
} -%}
{%- set alert = alertMap[name]|default(null) -%}
{%- set label = labelMap[name]|default(null) -%}
{%- set body -%}
{{- renderNode(node) -}}
{%- endset -%}
{%- set inner -%}
{%- if alert %}[!{{ alert }}]
{% if label and label|lower != alert|lower %}**{{ label }}**

{% endif %}
{%- elseif isTitled and title %}**{{ renderNode(title)|trim|raw }}**

{% elseif label %}**{{ label }}**

{% endif %}
{{- body|clean_content|raw -}}
{%- endset -%}
{{ renderMdPrefix(inner|clean_content, "> ")|raw }}
{{ "\n" }}
{{ "\n" }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{% for child in node.children -%}
{{- renderNode(child)|raw -}}
{% endfor -%}
{{ "\n" }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{%- set body -%}{%- for child in node.children -%}{{- renderNode(child) -}}{%- endfor -%}{%- endset -%}
[{{ node.anchor|raw }}]: {{ body|inline_cell|raw }}
{{ "\n" }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{#- A caption says which file the snippet belongs in, or whether it is the
before or the after of a migration. Dropping it leaves consecutive blocks
in the same language indistinguishable, so it is carried as a bold line
above the fence, where HTML puts it too. -#}
{%- if node.caption -%}
**{{ renderNode(node.caption)|inline_text|raw }}**
{{ "\n" }}
{% endif -%}
```{{ node.language|default('')|raw }}
{{ node.value|raw }}
```
{{ "\n" }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{#- A collection is what "rst-class" leaves behind once it has applied its CSS
classes to the nodes inside it: the classes are presentation, the nodes are
the content. Without this the children are dropped, and because a
collection is structural the fallback marker was suppressed too, so the
loss was silent. -#}
{%- for child in node.children -%}{{- renderNode(child) -}}{%- endfor -%}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{#- A container carries its meaning in its classes. A line block is a run of
lines whose breaks are part of the text - an address, a verse - and the
parser marks each one with the "line" class rather than a newline node, so
without this they run together.

The break is written as a trailing backslash, not two trailing spaces: the
output is right-trimmed per line, which would silently remove the spaces
and the break with them. -#}
{%- set classes = node.classes -%}
{%- if 'line' in classes -%}
{%- for child in node.children -%}{{- renderNode(child) -}}{%- endfor -%}
{%- elseif 'line-block' in classes -%}
{%- set lines = [] -%}
{%- for child in node.children -%}
{%- set lines = lines|merge([renderNode(child)|inline_text]) -%}
{%- endfor -%}
{{ lines|join("\\\n")|raw }}
{{ "\n" }}
{{ "\n" }}
{%- else -%}
{%- for child in node.children -%}{{- renderNode(child) -}}{%- endfor -%}
{%- endif -%}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{#- Markdown has no definition list, so the term becomes a list item and its
definitions the item's body. Inside a list item indentation is
continuation, which is what ties the definition to its term; under a bare
paragraph it would be an indented code block. -#}
{%- set term -%}
{{- renderNode(node.term)|inline_text|raw -}}
{%- for classifier in node.classifiers %} : {{ renderNode(classifier)|inline_text|raw }}{% endfor -%}
{%- endset -%}
{%- set body -%}
{%- for definition in node.children -%}{{- renderNode(definition) -}}{%- endfor -%}
{%- endset -%}
- **{{ term|raw }}**
{{ "\n" }}
{{ renderMdIndent(body|clean_content, 2)|raw }}
{{ "\n" }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{%- for child in node.children -%}{{- renderNode(child) -}}{%- endfor -%}
{{ "\n" }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{#- The body of one definition; its term is written by the list item that
holds it. -#}
{%- for child in node.children -%}{{- renderNode(child) -}}{%- endfor -%}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{%- set title = node.title ? renderNode(node.title.value)|inline_text : '' -%}
{%- if title %}**{{ title|raw }}**
{{ "\n" }}
{% endif -%}
{{- renderNode(node.value) -}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{#- An accordion is a stack of collapsed panels. Collapsing is presentation;
the titles and the content are not, so they are written out in order. -#}
{%- for item in node.value -%}
{{- renderNode(item) -}}
{%- endfor -%}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{#- The grid is the layout; the cards are the content. -#}
{%- for child in node.children -%}{{- renderNode(child) -}}{%- endfor -%}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{#- The grid is the layout; the cards are the content. -#}
{%- for child in node.children -%}{{- renderNode(child) -}}{%- endfor -%}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{#- A card is a box with an optional image, header, title, body and footer. The
box is presentation; everything inside it is content, written out in the
order the card shows it.

Header and footer carry their text in "content" when the directive was
given an argument and in "value" when it was given a block, which is the
same pair the HTML template checks. A footer given a block can hold a whole
list, so it is written out as blocks; collapsing it onto one line turned a
list of version links into a single run-on line. -#}
{%- set title = node.title ? renderNode(node.title.value)|inline_text : '' -%}
{%- set header -%}
{%- if node.cardHeader -%}{{- renderNode(node.cardHeader.content) -}}{{- renderNode(node.cardHeader.value) -}}{%- endif -%}
{%- endset -%}
{%- set footer -%}
{%- if node.cardFooter -%}{{- renderNode(node.cardFooter.content) -}}{{- renderNode(node.cardFooter.value) -}}{%- endif -%}
{%- endset -%}
{%- if node.cardImage %}![{{ node.cardImage.alt|md_escape|raw }}]({{ node.cardImage.plainContent|raw }})
{{ "\n" }}
{% endif -%}
{%- if header|trim %}**{{ header|inline_text|raw }}**
{{ "\n" }}
{% endif -%}
{%- if title %}**{{ title|raw }}**
{{ "\n" }}
{% endif -%}
{{- renderNode(node.value) -}}
{%- if footer|trim %}
{{ footer|clean_content|raw }}
{% endif -%}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{#- The confval menu is an overview of the values that follow it, offered as a
list, a tree or a table. In HTML that is a navigational aid: it lets a
reader scan the available options and jump to one. Markdown has no jumping
and no collapsed tree, so the overview would only repeat, in shorter form,
what the full entries say directly below it.

The caption is kept: it names the group of values, which the author wrote
as content rather than as decoration. -#}
{%- if node.caption %}**{{ node.caption|raw }}**
{{ "\n" }}
{% endif -%}
{%- for child in node.children -%}
{{- renderNode(child) -}}
{%- endfor -%}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{#- A configuration value: its name, the properties that constrain it and what
it does.

Written as a list item so that the definition has an end. Markdown has no
definition lists, in GFM or otherwise, and indenting under a bare paragraph
does not express containment -- four spaces after a blank line is an
indented code block. Inside a list item the same indentation is a
continuation, which is what makes a nested confval nest and the next one
start somewhere visible.

The name is bold and the property labels are italic, so the term being
explained outweighs the labels that describe it.

The name is bold and nothing else. Bold around a code span is valid
CommonMark and GitHub renders it, but not every renderer parses emphasis
around a code span -- PhpStorm drops the bold silently -- and the term being
explained has to stand out, which is what bold does everywhere.

Properties that are not set are left out: "Default: N/A" is noise a reader
has to skip. -#}
{%- set properties = [] -%}
{%- if node.type != null -%}
{%- set properties = properties|merge([{'label': 'Type', 'value': renderNode(node.type)}]) -%}
{%- endif -%}
{%- if node.required -%}
{%- set properties = properties|merge([{'label': 'Required', 'value': 'true'}]) -%}
{%- endif -%}
{%- if node.default != null -%}
{%- set properties = properties|merge([{'label': 'Default', 'value': renderNode(node.default)}]) -%}
{%- endif -%}
{%- for key, option in node.additionalOptions -%}
{%- if not (key in ['searchFacet', 'searchKeywords']) -%}
{%- set properties = properties|merge([{'label': key, 'value': renderNode(option)}]) -%}
{%- endif -%}
{%- endfor -%}
{%- set body -%}
{%- for property in properties -%}
- *{{ property.label|md_escape|raw }}:* {{ property.value|inline_text|raw }}{{ "\n" }}
{%- endfor -%}
{{ "\n" }}
{{- renderNode(node.value) -}}
{%- endset -%}
- **{{ node.plainContent|md_escape|raw }}**
{{ "\n" }}
{{ renderMdIndent(body|clean_content, 2)|raw }}
{{ "\n" }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{#- An argument of a console command: the name and what it does.

No properties, the same as the HTML template. ArgumentNode carries
isRequired, isArray and default, but CommandNodeService fills two of the
three from the wrong keys: isRequired comes from "is_value_required", an
option key, so it is always false, and the default is given the
description. Nothing to render here until that is fixed upstream.

The HTML template also offers a "Type" property that ArgumentNode does not
have, so that branch never renders anything either. -#}
{%- set body -%}
{{- node.description|md_escape|raw -}}
{%- if node.value -%}
{{ "\n\n" }}
{{- renderNode(node.value)|raw -}}
{%- endif -%}
{%- endset -%}
- **{{ node.plainContent|md_escape|raw }}**
{{ "\n" }}
{{ renderMdIndent(body|clean_content, 2)|raw }}
{{ "\n" }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{#- An overview table of the commands, followed by the commands themselves.

A pipe table breaks on a blank line, so every row emits exactly one newline
and the whitespace control has to be explicit.

A command is only linked when it can be linked: the anchor of a noindex
command is registered nowhere, so a permalink to it would lead to a 404 in
a downloaded file rather than to the command. -#}
{%- set namespaceCount = node.commandsByNamespace|length -%}
{{- '| Command | Description |' -}}{%- if node.showHidden %} Hidden |{% endif -%}{{- "\n" -}}
{{- '| --- | --- |' -}}{%- if node.showHidden %} --- |{% endif -%}{{- "\n" -}}
{%- for namespaceName, namespace in node.commandsByNamespace -%}
{%- if namespaceCount > 1 -%}
{{- ('| **' ~ (namespaceName is empty ? 'global' : namespaceName|md_escape) ~ '** | |')|raw -}}
{%- if node.showHidden %} |{% endif -%}{{- "\n" -}}
{%- endif -%}
{%- for command in namespace -%}
{%- set label = '`' ~ command.plainContent ~ '`' -%}
{%- if command.noindex -%}
{%- set cell = label -%}
{%- else -%}
{%- set cell = '[' ~ label ~ '](' ~ markdownLinkUrl('#' ~ command.anchor) ~ ')' -%}
{%- endif -%}
{{- ('| ' ~ cell ~ ' | ' ~ command.description|md_escape|inline_cell ~ ' |')|raw -}}
{%- if node.showHidden %} {{ command.hidden ? 'True' : '' }} |{% endif -%}
{{- "\n" -}}
{%- endfor -%}
{%- endfor -%}
{{- "\n" -}}
{%- for child in node.children -%}
{{- renderNode(child)|raw -}}
{%- endfor -%}
Loading