typsphinx 0.4.4__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {typsphinx-0.4.4/typsphinx.egg-info → typsphinx-0.6.0}/PKG-INFO +16 -18
- {typsphinx-0.4.4 → typsphinx-0.6.0}/README.md +9 -9
- {typsphinx-0.4.4 → typsphinx-0.6.0}/pyproject.toml +23 -12
- typsphinx-0.6.0/tests/test_admonitions.py +433 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_builder.py +1 -1
- typsphinx-0.6.0/tests/test_confval_field_body_render_gate.py +192 -0
- typsphinx-0.6.0/tests/test_corpus_gate.py +557 -0
- typsphinx-0.6.0/tests/test_cross_doc_label_namespace_render_gate.py +230 -0
- typsphinx-0.6.0/tests/test_deflist_definition_multiblock_render_gate.py +174 -0
- typsphinx-0.6.0/tests/test_deflist_nested_definition_render_gate.py +229 -0
- typsphinx-0.6.0/tests/test_deflist_term_concat_render_gate.py +167 -0
- typsphinx-0.6.0/tests/test_deflist_term_inline_children_gate.py +321 -0
- typsphinx-0.6.0/tests/test_desc_container_propagated_target_render_gate.py +224 -0
- typsphinx-0.6.0/tests/test_desc_signature_anchor_render_gate.py +195 -0
- typsphinx-0.6.0/tests/test_desc_signature_concat_render_gate.py +195 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_documentation_configuration.py +2 -1
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_documentation_usage.py +2 -1
- typsphinx-0.6.0/tests/test_duplicate_include_label_render_gate.py +202 -0
- typsphinx-0.6.0/tests/test_epigraph_render_gate.py +202 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_extension.py +19 -0
- typsphinx-0.6.0/tests/test_field_list_in_list_item_render_gate.py +179 -0
- typsphinx-0.6.0/tests/test_footnotes.py +173 -0
- typsphinx-0.6.0/tests/test_glob_image_render_gate.py +190 -0
- typsphinx-0.6.0/tests/test_label_at_char_render_gate.py +213 -0
- typsphinx-0.6.0/tests/test_line_blocks.py +147 -0
- typsphinx-0.6.0/tests/test_list_item_nested_block_render_gate.py +177 -0
- typsphinx-0.6.0/tests/test_paragraph_propagated_target_render_gate.py +212 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_pdf_generation.py +1 -1
- typsphinx-0.6.0/tests/test_pdf_render_gate.py +1777 -0
- typsphinx-0.6.0/tests/test_preview_smoke_gate.py +112 -0
- typsphinx-0.6.0/tests/test_ref_target_nested_list_render_gate.py +232 -0
- typsphinx-0.6.0/tests/test_rubric_propagated_target_render_gate.py +245 -0
- typsphinx-0.6.0/tests/test_static_asset_copy_gate.py +155 -0
- typsphinx-0.6.0/tests/test_substitution_definition_render_gate.py +224 -0
- typsphinx-0.6.0/tests/test_table_in_list_item_render_gate.py +189 -0
- typsphinx-0.6.0/tests/test_target_label_render_gate.py +159 -0
- typsphinx-0.6.0/tests/test_topics.py +202 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_translator.py +355 -68
- typsphinx-0.6.0/tests/test_typst_string_escape_gate.py +65 -0
- typsphinx-0.6.0/tests/test_xref_orphan_degrade_render_gate.py +195 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/typsphinx/__init__.py +7 -3
- {typsphinx-0.4.4 → typsphinx-0.6.0}/typsphinx/builder.py +166 -5
- {typsphinx-0.4.4 → typsphinx-0.6.0}/typsphinx/template_engine.py +4 -4
- {typsphinx-0.4.4 → typsphinx-0.6.0}/typsphinx/templates/base.typ +3 -3
- typsphinx-0.6.0/typsphinx/translator.py +4581 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/typsphinx/writer.py +3 -3
- {typsphinx-0.4.4 → typsphinx-0.6.0/typsphinx.egg-info}/PKG-INFO +16 -18
- typsphinx-0.6.0/typsphinx.egg-info/SOURCES.txt +76 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/typsphinx.egg-info/requires.txt +5 -7
- typsphinx-0.4.4/tests/test_admonitions.py +0 -216
- typsphinx-0.4.4/typsphinx/translator.py +0 -2679
- typsphinx-0.4.4/typsphinx.egg-info/SOURCES.txt +0 -46
- {typsphinx-0.4.4 → typsphinx-0.6.0}/LICENSE +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/setup.cfg +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_builder_requirement13.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_config.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_config_other_options.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_config_template_mapping.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_config_toctree_defaults.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_documentation_installation.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_entry_points.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_examples_basic.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_inline_references.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_integration_advanced.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_integration_basic.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_integration_multi_doc.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_integration_nested_toctree.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_math_fallback.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_math_mitex.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_math_native.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_nested_toctree_paths.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_preview_version_sync.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_template_assets.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_template_codly.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_template_engine.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_template_mitex.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/tests/test_toctree_requirement13.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/typsphinx/pdf.py +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/typsphinx.egg-info/dependency_links.txt +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/typsphinx.egg-info/entry_points.txt +0 -0
- {typsphinx-0.4.4 → typsphinx-0.6.0}/typsphinx.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: typsphinx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Sphinx extension for Typst output
|
|
5
5
|
Author-email: YuSabo <yusabo90002@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -13,18 +13,16 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
13
13
|
Classifier: Framework :: Sphinx :: Extension
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
18
|
Classifier: Topic :: Documentation :: Sphinx
|
|
21
19
|
Classifier: Topic :: Software Development :: Documentation
|
|
22
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.12
|
|
23
21
|
Description-Content-Type: text/markdown
|
|
24
22
|
License-File: LICENSE
|
|
25
|
-
Requires-Dist: sphinx<9
|
|
26
|
-
Requires-Dist: docutils<0.
|
|
27
|
-
Requires-Dist: typst<0.
|
|
23
|
+
Requires-Dist: sphinx<10,>=9.1
|
|
24
|
+
Requires-Dist: docutils<0.23,>=0.21
|
|
25
|
+
Requires-Dist: typst<0.16,>=0.15.0
|
|
28
26
|
Provides-Extra: dev
|
|
29
27
|
Requires-Dist: pytest<10,>=8.4; extra == "dev"
|
|
30
28
|
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
@@ -34,14 +32,14 @@ Requires-Dist: black<27,>=26; extra == "dev"
|
|
|
34
32
|
Requires-Dist: ruff<0.16,>=0.15; extra == "dev"
|
|
35
33
|
Requires-Dist: mypy<3.0,>=1.13; extra == "dev"
|
|
36
34
|
Requires-Dist: pre-commit>=3.0; extra == "dev"
|
|
37
|
-
Requires-Dist: types-docutils>=0.
|
|
35
|
+
Requires-Dist: types-docutils>=0.21; extra == "dev"
|
|
38
36
|
Requires-Dist: twine>=5.0; extra == "dev"
|
|
39
37
|
Requires-Dist: build>=1.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pypdf<7,>=6.14; extra == "dev"
|
|
40
39
|
Provides-Extra: docs
|
|
41
40
|
Requires-Dist: furo>=2024.0; extra == "docs"
|
|
42
41
|
Requires-Dist: sphinx-autodoc-typehints>=1.0; extra == "docs"
|
|
43
42
|
Requires-Dist: sphinx-intl>=2.0; extra == "docs"
|
|
44
|
-
Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "docs"
|
|
45
43
|
Dynamic: license-file
|
|
46
44
|
|
|
47
45
|
# typsphinx
|
|
@@ -66,7 +64,7 @@ typsphinx is a Sphinx extension that enables generating Typst documents from reS
|
|
|
66
64
|
- **Convert Sphinx documentation to Typst format**: Seamlessly transform your reStructuredText/Markdown documents
|
|
67
65
|
- **Standard docutils nodes**: Full support for paragraphs, sections, lists, tables, admonitions, and more
|
|
68
66
|
- **Mathematical expressions**:
|
|
69
|
-
- LaTeX syntax via mitex (`@preview/mitex:0.2.
|
|
67
|
+
- LaTeX syntax via mitex (`@preview/mitex:0.2.7`)
|
|
70
68
|
- Native Typst math syntax
|
|
71
69
|
- **Code blocks with syntax highlighting**: Using codly package (`@preview/codly:1.3.0`)
|
|
72
70
|
- Automatic line numbering
|
|
@@ -80,9 +78,9 @@ typsphinx is a Sphinx extension that enables generating Typst documents from reS
|
|
|
80
78
|
|
|
81
79
|
## Requirements
|
|
82
80
|
|
|
83
|
-
- Python 3.
|
|
84
|
-
- Sphinx
|
|
85
|
-
- typst-py 0.
|
|
81
|
+
- Python 3.12 or higher
|
|
82
|
+
- Sphinx 9.1 or higher
|
|
83
|
+
- typst-py 0.15.0 or higher
|
|
86
84
|
|
|
87
85
|
## Installation
|
|
88
86
|
|
|
@@ -266,7 +264,7 @@ This project uses uv for fast package management and follows TDD (Test-Driven De
|
|
|
266
264
|
# Install with development dependencies
|
|
267
265
|
uv sync --extra dev
|
|
268
266
|
|
|
269
|
-
# Run tests (
|
|
267
|
+
# Run tests (413 tests)
|
|
270
268
|
uv run pytest
|
|
271
269
|
|
|
272
270
|
# Run tests with coverage report
|
|
@@ -278,7 +276,7 @@ uv run tox
|
|
|
278
276
|
# Run specific tox environments
|
|
279
277
|
uv run tox -e lint # Run linters (black, ruff)
|
|
280
278
|
uv run tox -e type # Run type checking (mypy)
|
|
281
|
-
uv run tox -e
|
|
279
|
+
uv run tox -e py312 # Run tests on Python 3.12
|
|
282
280
|
uv run tox -e docs-html # Build HTML documentation
|
|
283
281
|
uv run tox -e docs-pdf # Build PDF documentation
|
|
284
282
|
uv run tox -e docs # Build both HTML and PDF docs
|
|
@@ -286,7 +284,7 @@ uv run tox -e docs # Build both HTML and PDF docs
|
|
|
286
284
|
|
|
287
285
|
### Testing Strategy
|
|
288
286
|
|
|
289
|
-
- **Unit tests**:
|
|
287
|
+
- **Unit tests**: 413 tests covering all major components
|
|
290
288
|
- **Integration tests**: Full build process validation
|
|
291
289
|
- **Example projects**: `examples/basic/` and `examples/advanced/`
|
|
292
290
|
- **Code coverage**: 93% overall
|
|
@@ -366,5 +364,5 @@ See [CHANGELOG.md](CHANGELOG.md) for detailed version history.
|
|
|
366
364
|
|
|
367
365
|
---
|
|
368
366
|
|
|
369
|
-
**Status**: Stable (v0.
|
|
370
|
-
**Python**: 3.
|
|
367
|
+
**Status**: Stable (v0.5.0) - Production ready
|
|
368
|
+
**Python**: 3.12+ | **Sphinx**: 9.1+ | **Typst**: 0.15+
|
|
@@ -20,7 +20,7 @@ typsphinx is a Sphinx extension that enables generating Typst documents from reS
|
|
|
20
20
|
- **Convert Sphinx documentation to Typst format**: Seamlessly transform your reStructuredText/Markdown documents
|
|
21
21
|
- **Standard docutils nodes**: Full support for paragraphs, sections, lists, tables, admonitions, and more
|
|
22
22
|
- **Mathematical expressions**:
|
|
23
|
-
- LaTeX syntax via mitex (`@preview/mitex:0.2.
|
|
23
|
+
- LaTeX syntax via mitex (`@preview/mitex:0.2.7`)
|
|
24
24
|
- Native Typst math syntax
|
|
25
25
|
- **Code blocks with syntax highlighting**: Using codly package (`@preview/codly:1.3.0`)
|
|
26
26
|
- Automatic line numbering
|
|
@@ -34,9 +34,9 @@ typsphinx is a Sphinx extension that enables generating Typst documents from reS
|
|
|
34
34
|
|
|
35
35
|
## Requirements
|
|
36
36
|
|
|
37
|
-
- Python 3.
|
|
38
|
-
- Sphinx
|
|
39
|
-
- typst-py 0.
|
|
37
|
+
- Python 3.12 or higher
|
|
38
|
+
- Sphinx 9.1 or higher
|
|
39
|
+
- typst-py 0.15.0 or higher
|
|
40
40
|
|
|
41
41
|
## Installation
|
|
42
42
|
|
|
@@ -220,7 +220,7 @@ This project uses uv for fast package management and follows TDD (Test-Driven De
|
|
|
220
220
|
# Install with development dependencies
|
|
221
221
|
uv sync --extra dev
|
|
222
222
|
|
|
223
|
-
# Run tests (
|
|
223
|
+
# Run tests (413 tests)
|
|
224
224
|
uv run pytest
|
|
225
225
|
|
|
226
226
|
# Run tests with coverage report
|
|
@@ -232,7 +232,7 @@ uv run tox
|
|
|
232
232
|
# Run specific tox environments
|
|
233
233
|
uv run tox -e lint # Run linters (black, ruff)
|
|
234
234
|
uv run tox -e type # Run type checking (mypy)
|
|
235
|
-
uv run tox -e
|
|
235
|
+
uv run tox -e py312 # Run tests on Python 3.12
|
|
236
236
|
uv run tox -e docs-html # Build HTML documentation
|
|
237
237
|
uv run tox -e docs-pdf # Build PDF documentation
|
|
238
238
|
uv run tox -e docs # Build both HTML and PDF docs
|
|
@@ -240,7 +240,7 @@ uv run tox -e docs # Build both HTML and PDF docs
|
|
|
240
240
|
|
|
241
241
|
### Testing Strategy
|
|
242
242
|
|
|
243
|
-
- **Unit tests**:
|
|
243
|
+
- **Unit tests**: 413 tests covering all major components
|
|
244
244
|
- **Integration tests**: Full build process validation
|
|
245
245
|
- **Example projects**: `examples/basic/` and `examples/advanced/`
|
|
246
246
|
- **Code coverage**: 93% overall
|
|
@@ -320,5 +320,5 @@ See [CHANGELOG.md](CHANGELOG.md) for detailed version history.
|
|
|
320
320
|
|
|
321
321
|
---
|
|
322
322
|
|
|
323
|
-
**Status**: Stable (v0.
|
|
324
|
-
**Python**: 3.
|
|
323
|
+
**Status**: Stable (v0.5.0) - Production ready
|
|
324
|
+
**Python**: 3.12+ | **Sphinx**: 9.1+ | **Typst**: 0.15+
|
|
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "typsphinx"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.6.0"
|
|
8
8
|
description = "Sphinx extension for Typst output"
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
11
|
license = "MIT"
|
|
12
12
|
authors = [
|
|
13
13
|
{name = "YuSabo", email = "yusabo90002@gmail.com"}
|
|
@@ -18,8 +18,6 @@ classifiers = [
|
|
|
18
18
|
"Framework :: Sphinx :: Extension",
|
|
19
19
|
"Intended Audience :: Developers",
|
|
20
20
|
"Programming Language :: Python :: 3",
|
|
21
|
-
"Programming Language :: Python :: 3.10",
|
|
22
|
-
"Programming Language :: Python :: 3.11",
|
|
23
21
|
"Programming Language :: Python :: 3.12",
|
|
24
22
|
"Programming Language :: Python :: 3.13",
|
|
25
23
|
"Topic :: Documentation :: Sphinx",
|
|
@@ -27,9 +25,9 @@ classifiers = [
|
|
|
27
25
|
]
|
|
28
26
|
|
|
29
27
|
dependencies = [
|
|
30
|
-
"sphinx>=
|
|
31
|
-
"docutils>=0.
|
|
32
|
-
"typst>=0.
|
|
28
|
+
"sphinx>=9.1,<10",
|
|
29
|
+
"docutils>=0.21,<0.23",
|
|
30
|
+
"typst>=0.15.0,<0.16",
|
|
33
31
|
]
|
|
34
32
|
|
|
35
33
|
[project.optional-dependencies]
|
|
@@ -42,15 +40,15 @@ dev = [
|
|
|
42
40
|
"ruff>=0.15,<0.16",
|
|
43
41
|
"mypy>=1.13,<3.0",
|
|
44
42
|
"pre-commit>=3.0",
|
|
45
|
-
"types-docutils>=0.
|
|
43
|
+
"types-docutils>=0.21",
|
|
46
44
|
"twine>=5.0",
|
|
47
45
|
"build>=1.0",
|
|
46
|
+
"pypdf>=6.14,<7",
|
|
48
47
|
]
|
|
49
48
|
docs = [
|
|
50
49
|
"furo>=2024.0",
|
|
51
50
|
"sphinx-autodoc-typehints>=1.0",
|
|
52
51
|
"sphinx-intl>=2.0",
|
|
53
|
-
"tomli>=2.0; python_version < '3.11'",
|
|
54
52
|
]
|
|
55
53
|
|
|
56
54
|
[project.urls]
|
|
@@ -82,10 +80,23 @@ markers = [
|
|
|
82
80
|
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
|
|
83
81
|
"integration: marks tests as integration tests",
|
|
84
82
|
]
|
|
83
|
+
filterwarnings = [
|
|
84
|
+
"error::DeprecationWarning",
|
|
85
|
+
# Escalated beyond CONTEXT.md's literal "DeprecationWarning" text: Sphinx's own
|
|
86
|
+
# RemovedInSphinxNNWarning family (e.g. builder.app) subclasses
|
|
87
|
+
# PendingDeprecationWarning, not DeprecationWarning — without this line, future
|
|
88
|
+
# Sphinx deprecations would pass through un-gated. See 08-RESEARCH.md Pitfall 2.
|
|
89
|
+
"error::PendingDeprecationWarning",
|
|
90
|
+
# No third-party ignore:: entries needed as of Sphinx 9.1.0/docutils 0.22.4/
|
|
91
|
+
# typst-py 0.15.0 (verified zero third-party warnings in 08-RESEARCH.md). If a
|
|
92
|
+
# future dependency bump introduces one, add a targeted
|
|
93
|
+
# ignore::DeprecationWarning:<module> entry here — do not weaken the two `error`
|
|
94
|
+
# lines above.
|
|
95
|
+
]
|
|
85
96
|
|
|
86
97
|
[tool.black]
|
|
87
98
|
line-length = 88
|
|
88
|
-
target-version = ["
|
|
99
|
+
target-version = ["py312", "py313"]
|
|
89
100
|
include = '\.pyi?$'
|
|
90
101
|
exclude = '''
|
|
91
102
|
/(
|
|
@@ -100,7 +111,7 @@ exclude = '''
|
|
|
100
111
|
|
|
101
112
|
[tool.ruff]
|
|
102
113
|
line-length = 88
|
|
103
|
-
target-version = "
|
|
114
|
+
target-version = "py312"
|
|
104
115
|
|
|
105
116
|
[tool.ruff.lint]
|
|
106
117
|
select = ["E", "F", "W", "I", "N", "UP", "B", "A", "C4", "T20"]
|
|
@@ -117,7 +128,7 @@ ignore = [
|
|
|
117
128
|
]
|
|
118
129
|
|
|
119
130
|
[tool.mypy]
|
|
120
|
-
python_version = "3.
|
|
131
|
+
python_version = "3.12"
|
|
121
132
|
warn_return_any = false
|
|
122
133
|
warn_unused_configs = true
|
|
123
134
|
disallow_untyped_defs = false
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for admonition node conversion to Typst gentle-clues.
|
|
3
|
+
|
|
4
|
+
Task 3.4: アドモニション(Admonition)の変換
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from docutils import nodes
|
|
8
|
+
from docutils.parsers.rst import states
|
|
9
|
+
from docutils.utils import Reporter
|
|
10
|
+
from sphinx import addnodes
|
|
11
|
+
from sphinx.testing.util import SphinxTestApp
|
|
12
|
+
|
|
13
|
+
from typsphinx.translator import TypstTranslator
|
|
14
|
+
from typsphinx.writer import TypstWriter
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_document():
|
|
18
|
+
"""Helper function to create a minimal document with reporter."""
|
|
19
|
+
reporter = Reporter("", 2, 4)
|
|
20
|
+
doc = nodes.document("", reporter=reporter)
|
|
21
|
+
doc.settings = states.Struct()
|
|
22
|
+
doc.settings.env = None
|
|
23
|
+
doc.settings.language_code = "en"
|
|
24
|
+
doc.settings.strict_visitor = False
|
|
25
|
+
return doc
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TestAdmonitionConversion:
|
|
29
|
+
"""Test admonition node conversion using gentle-clues package."""
|
|
30
|
+
|
|
31
|
+
def test_note_converts_to_info(self, temp_sphinx_app: SphinxTestApp):
|
|
32
|
+
"""Test that nodes.note converts to info[]."""
|
|
33
|
+
# Create a note admonition
|
|
34
|
+
note = nodes.note()
|
|
35
|
+
para = nodes.paragraph(text="This is a note.")
|
|
36
|
+
note += para
|
|
37
|
+
|
|
38
|
+
# Create document
|
|
39
|
+
doc = create_document()
|
|
40
|
+
doc += note
|
|
41
|
+
|
|
42
|
+
# Translate
|
|
43
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
44
|
+
writer.document = doc
|
|
45
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
46
|
+
doc.walkabout(translator)
|
|
47
|
+
|
|
48
|
+
output = translator.astext()
|
|
49
|
+
assert "info({" in output
|
|
50
|
+
assert "info[" not in output
|
|
51
|
+
assert 'par({text("This is a note.")})' in output
|
|
52
|
+
|
|
53
|
+
def test_warning_converts_to_warning(self, temp_sphinx_app: SphinxTestApp):
|
|
54
|
+
"""Test that nodes.warning converts to warning[]."""
|
|
55
|
+
warning = nodes.warning()
|
|
56
|
+
para = nodes.paragraph(text="This is a warning.")
|
|
57
|
+
warning += para
|
|
58
|
+
|
|
59
|
+
doc = create_document()
|
|
60
|
+
doc += warning
|
|
61
|
+
|
|
62
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
63
|
+
writer.document = doc
|
|
64
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
65
|
+
doc.walkabout(translator)
|
|
66
|
+
|
|
67
|
+
output = translator.astext()
|
|
68
|
+
assert "warning({" in output
|
|
69
|
+
assert "warning[" not in output
|
|
70
|
+
assert 'par({text("This is a warning.")})' in output
|
|
71
|
+
|
|
72
|
+
def test_tip_converts_to_tip(self, temp_sphinx_app: SphinxTestApp):
|
|
73
|
+
"""Test that nodes.tip converts to tip[]."""
|
|
74
|
+
tip = nodes.tip()
|
|
75
|
+
para = nodes.paragraph(text="Here's a tip.")
|
|
76
|
+
tip += para
|
|
77
|
+
|
|
78
|
+
doc = create_document()
|
|
79
|
+
doc += tip
|
|
80
|
+
|
|
81
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
82
|
+
writer.document = doc
|
|
83
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
84
|
+
doc.walkabout(translator)
|
|
85
|
+
|
|
86
|
+
output = translator.astext()
|
|
87
|
+
assert "tip({" in output
|
|
88
|
+
assert "tip[" not in output
|
|
89
|
+
assert 'par({text("Here\'s a tip.")})' in output
|
|
90
|
+
|
|
91
|
+
def test_important_converts_to_warning_with_title(
|
|
92
|
+
self, temp_sphinx_app: SphinxTestApp
|
|
93
|
+
):
|
|
94
|
+
"""Test that nodes.important converts to warning(title: "Important")[]."""
|
|
95
|
+
important = nodes.important()
|
|
96
|
+
para = nodes.paragraph(text="This is important.")
|
|
97
|
+
important += para
|
|
98
|
+
|
|
99
|
+
doc = create_document()
|
|
100
|
+
doc += important
|
|
101
|
+
|
|
102
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
103
|
+
writer.document = doc
|
|
104
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
105
|
+
doc.walkabout(translator)
|
|
106
|
+
|
|
107
|
+
output = translator.astext()
|
|
108
|
+
assert "warning({" in output
|
|
109
|
+
assert "warning[" not in output
|
|
110
|
+
assert ', title: "Important"' in output
|
|
111
|
+
assert 'par({text("This is important.")})' in output
|
|
112
|
+
|
|
113
|
+
def test_caution_converts_to_warning(self, temp_sphinx_app: SphinxTestApp):
|
|
114
|
+
"""Test that nodes.caution converts to warning[]."""
|
|
115
|
+
caution = nodes.caution()
|
|
116
|
+
para = nodes.paragraph(text="Be cautious.")
|
|
117
|
+
caution += para
|
|
118
|
+
|
|
119
|
+
doc = create_document()
|
|
120
|
+
doc += caution
|
|
121
|
+
|
|
122
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
123
|
+
writer.document = doc
|
|
124
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
125
|
+
doc.walkabout(translator)
|
|
126
|
+
|
|
127
|
+
output = translator.astext()
|
|
128
|
+
assert "warning({" in output
|
|
129
|
+
assert "warning[" not in output
|
|
130
|
+
assert 'par({text("Be cautious.")})' in output
|
|
131
|
+
|
|
132
|
+
def test_seealso_converts_to_info_with_title(self, temp_sphinx_app: SphinxTestApp):
|
|
133
|
+
"""Test that addnodes.seealso converts to info(title: "See Also")[]."""
|
|
134
|
+
seealso = addnodes.seealso()
|
|
135
|
+
para = nodes.paragraph(text="See related documentation.")
|
|
136
|
+
seealso += para
|
|
137
|
+
|
|
138
|
+
doc = create_document()
|
|
139
|
+
doc += seealso
|
|
140
|
+
|
|
141
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
142
|
+
writer.document = doc
|
|
143
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
144
|
+
doc.walkabout(translator)
|
|
145
|
+
|
|
146
|
+
output = translator.astext()
|
|
147
|
+
assert "info({" in output
|
|
148
|
+
assert "info[" not in output
|
|
149
|
+
assert ', title: "See Also"' in output
|
|
150
|
+
assert 'par({text("See related documentation.")})' in output
|
|
151
|
+
|
|
152
|
+
def test_admonition_with_multiple_paragraphs(self, temp_sphinx_app: SphinxTestApp):
|
|
153
|
+
"""Test admonition with multiple paragraphs."""
|
|
154
|
+
note = nodes.note()
|
|
155
|
+
para1 = nodes.paragraph(text="First paragraph.")
|
|
156
|
+
para2 = nodes.paragraph(text="Second paragraph.")
|
|
157
|
+
note += para1
|
|
158
|
+
note += para2
|
|
159
|
+
|
|
160
|
+
doc = create_document()
|
|
161
|
+
doc += note
|
|
162
|
+
|
|
163
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
164
|
+
writer.document = doc
|
|
165
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
166
|
+
doc.walkabout(translator)
|
|
167
|
+
|
|
168
|
+
output = translator.astext()
|
|
169
|
+
assert "info({" in output
|
|
170
|
+
assert "info[" not in output
|
|
171
|
+
assert 'par({text("First paragraph.")})' in output
|
|
172
|
+
assert 'par({text("Second paragraph.")})' in output
|
|
173
|
+
|
|
174
|
+
def test_nested_admonitions(self, temp_sphinx_app: SphinxTestApp):
|
|
175
|
+
"""Test nested admonitions."""
|
|
176
|
+
outer_note = nodes.note()
|
|
177
|
+
para1 = nodes.paragraph(text="Outer note.")
|
|
178
|
+
inner_warning = nodes.warning()
|
|
179
|
+
para2 = nodes.paragraph(text="Inner warning.")
|
|
180
|
+
inner_warning += para2
|
|
181
|
+
outer_note += para1
|
|
182
|
+
outer_note += inner_warning
|
|
183
|
+
|
|
184
|
+
doc = create_document()
|
|
185
|
+
doc += outer_note
|
|
186
|
+
|
|
187
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
188
|
+
writer.document = doc
|
|
189
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
190
|
+
doc.walkabout(translator)
|
|
191
|
+
|
|
192
|
+
output = translator.astext()
|
|
193
|
+
assert "info({" in output
|
|
194
|
+
assert "info[" not in output
|
|
195
|
+
assert 'par({text("Outer note.")})' in output
|
|
196
|
+
assert "warning({" in output
|
|
197
|
+
assert "warning[" not in output
|
|
198
|
+
assert 'par({text("Inner warning.")})' in output
|
|
199
|
+
|
|
200
|
+
def test_nested_list_in_note(self, temp_sphinx_app: SphinxTestApp):
|
|
201
|
+
"""Test a bullet list nested inside a note (D-05)."""
|
|
202
|
+
note = nodes.note()
|
|
203
|
+
bullet_list = nodes.bullet_list()
|
|
204
|
+
item1 = nodes.list_item()
|
|
205
|
+
item1 += nodes.paragraph(text="Item one.")
|
|
206
|
+
item2 = nodes.list_item()
|
|
207
|
+
item2 += nodes.paragraph(text="Item two.")
|
|
208
|
+
bullet_list += item1
|
|
209
|
+
bullet_list += item2
|
|
210
|
+
note += bullet_list
|
|
211
|
+
|
|
212
|
+
doc = create_document()
|
|
213
|
+
doc += note
|
|
214
|
+
|
|
215
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
216
|
+
writer.document = doc
|
|
217
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
218
|
+
doc.walkabout(translator)
|
|
219
|
+
|
|
220
|
+
output = translator.astext()
|
|
221
|
+
# The note stays in code-mode content-block form and the nested
|
|
222
|
+
# list's code-mode form evaluates inside it (no literal-source leak).
|
|
223
|
+
assert "info({" in output
|
|
224
|
+
assert "info[" not in output
|
|
225
|
+
assert "list(" in output
|
|
226
|
+
assert 'text("Item one.")' in output
|
|
227
|
+
assert 'text("Item two.")' in output
|
|
228
|
+
|
|
229
|
+
def test_nested_code_block_in_note(self, temp_sphinx_app: SphinxTestApp):
|
|
230
|
+
"""Test a literal/code block nested inside a note (D-05)."""
|
|
231
|
+
note = nodes.note()
|
|
232
|
+
literal_block = nodes.literal_block(text="x = 1")
|
|
233
|
+
note += literal_block
|
|
234
|
+
|
|
235
|
+
doc = create_document()
|
|
236
|
+
doc += note
|
|
237
|
+
|
|
238
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
239
|
+
writer.document = doc
|
|
240
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
241
|
+
doc.walkabout(translator)
|
|
242
|
+
|
|
243
|
+
output = translator.astext()
|
|
244
|
+
assert "info({" in output
|
|
245
|
+
assert "info[" not in output
|
|
246
|
+
assert "```" in output
|
|
247
|
+
assert "x = 1" in output
|
|
248
|
+
|
|
249
|
+
def test_admonition_with_title_in_content(self, temp_sphinx_app: SphinxTestApp):
|
|
250
|
+
"""Test admonition with custom title in first paragraph."""
|
|
251
|
+
# In Sphinx, custom admonitions have the title as the first child
|
|
252
|
+
note = nodes.note()
|
|
253
|
+
title = nodes.title(text="Custom Title")
|
|
254
|
+
para = nodes.paragraph(text="Content here.")
|
|
255
|
+
note += title
|
|
256
|
+
note += para
|
|
257
|
+
|
|
258
|
+
doc = create_document()
|
|
259
|
+
doc += note
|
|
260
|
+
|
|
261
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
262
|
+
writer.document = doc
|
|
263
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
264
|
+
doc.walkabout(translator)
|
|
265
|
+
|
|
266
|
+
output = translator.astext()
|
|
267
|
+
# Should use the dynamic (node-derived) title buffered as a code
|
|
268
|
+
# block, emitted exactly once, with the body evaluating in code mode.
|
|
269
|
+
assert "info({" in output
|
|
270
|
+
assert "info[" not in output
|
|
271
|
+
assert ", title: {" in output
|
|
272
|
+
assert output.count("Custom Title") == 1
|
|
273
|
+
assert "heading(" not in output # double-emission bug fixed
|
|
274
|
+
assert 'par({text("Content here.")})' in output
|
|
275
|
+
|
|
276
|
+
def test_admonition_title_preserves_inline_markup(
|
|
277
|
+
self, temp_sphinx_app: SphinxTestApp
|
|
278
|
+
):
|
|
279
|
+
"""Test that an admonition title preserves inline markup (D-02).
|
|
280
|
+
|
|
281
|
+
The title's rendered content is captured via the buffer-swap idiom
|
|
282
|
+
(routing through the normal inline visitors) rather than flattened
|
|
283
|
+
with node.astext(), so an emphasis child inside the title survives
|
|
284
|
+
as an emph(...) code-mode call instead of being reduced to plain
|
|
285
|
+
text. This also locks down the title double-emission regression
|
|
286
|
+
found in RESEARCH.md: heading( must never appear in the output.
|
|
287
|
+
|
|
288
|
+
Note: nodes.note() does not carry a title in real rST usage; this
|
|
289
|
+
is a constructed shape used purely to exercise the admonition-aware
|
|
290
|
+
visit_title/depart_title branch. The real docutils shape for a
|
|
291
|
+
title-bearing admonition is nodes.admonition (generic `.. admonition::`),
|
|
292
|
+
covered by Plan 03's D-06 generic-admonition test.
|
|
293
|
+
"""
|
|
294
|
+
note = nodes.note()
|
|
295
|
+
title = nodes.title()
|
|
296
|
+
title += nodes.Text("Custom ")
|
|
297
|
+
title += nodes.emphasis(text="Title")
|
|
298
|
+
para = nodes.paragraph(text="Content here.")
|
|
299
|
+
note += title
|
|
300
|
+
note += para
|
|
301
|
+
|
|
302
|
+
doc = create_document()
|
|
303
|
+
doc += note
|
|
304
|
+
|
|
305
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
306
|
+
writer.document = doc
|
|
307
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
308
|
+
doc.walkabout(translator)
|
|
309
|
+
|
|
310
|
+
output = translator.astext()
|
|
311
|
+
assert "info({" in output
|
|
312
|
+
assert "info[" not in output
|
|
313
|
+
assert ", title: {" in output
|
|
314
|
+
assert "emph({" in output
|
|
315
|
+
assert output.count("Custom") == 1
|
|
316
|
+
assert output.count("Title") == 1
|
|
317
|
+
assert "heading(" not in output # double-emission bug fixed
|
|
318
|
+
|
|
319
|
+
def test_hint_converts_to_tip(self, temp_sphinx_app: SphinxTestApp):
|
|
320
|
+
"""Test that nodes.hint converts to tip[] (D-06).
|
|
321
|
+
|
|
322
|
+
gentle-clues 1.3.1 has no dedicated `hint` clue; `tip` is the
|
|
323
|
+
verified closest analog.
|
|
324
|
+
"""
|
|
325
|
+
hint = nodes.hint()
|
|
326
|
+
para = nodes.paragraph(text="Here's a hint.")
|
|
327
|
+
hint += para
|
|
328
|
+
|
|
329
|
+
doc = create_document()
|
|
330
|
+
doc += hint
|
|
331
|
+
|
|
332
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
333
|
+
writer.document = doc
|
|
334
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
335
|
+
doc.walkabout(translator)
|
|
336
|
+
|
|
337
|
+
output = translator.astext()
|
|
338
|
+
assert "tip({" in output
|
|
339
|
+
assert "tip[" not in output
|
|
340
|
+
assert 'par({text("Here\'s a hint.")})' in output
|
|
341
|
+
|
|
342
|
+
def test_error_converts_to_error(self, temp_sphinx_app: SphinxTestApp):
|
|
343
|
+
"""Test that nodes.error converts to error[] (D-06)."""
|
|
344
|
+
error = nodes.error()
|
|
345
|
+
para = nodes.paragraph(text="This is an error.")
|
|
346
|
+
error += para
|
|
347
|
+
|
|
348
|
+
doc = create_document()
|
|
349
|
+
doc += error
|
|
350
|
+
|
|
351
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
352
|
+
writer.document = doc
|
|
353
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
354
|
+
doc.walkabout(translator)
|
|
355
|
+
|
|
356
|
+
output = translator.astext()
|
|
357
|
+
assert "error({" in output
|
|
358
|
+
assert "error[" not in output
|
|
359
|
+
assert 'par({text("This is an error.")})' in output
|
|
360
|
+
|
|
361
|
+
def test_danger_converts_to_danger(self, temp_sphinx_app: SphinxTestApp):
|
|
362
|
+
"""Test that nodes.danger converts to danger[] (D-06)."""
|
|
363
|
+
danger = nodes.danger()
|
|
364
|
+
para = nodes.paragraph(text="This is dangerous.")
|
|
365
|
+
danger += para
|
|
366
|
+
|
|
367
|
+
doc = create_document()
|
|
368
|
+
doc += danger
|
|
369
|
+
|
|
370
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
371
|
+
writer.document = doc
|
|
372
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
373
|
+
doc.walkabout(translator)
|
|
374
|
+
|
|
375
|
+
output = translator.astext()
|
|
376
|
+
assert "danger({" in output
|
|
377
|
+
assert "danger[" not in output
|
|
378
|
+
assert 'par({text("This is dangerous.")})' in output
|
|
379
|
+
|
|
380
|
+
def test_attention_converts_to_warning(self, temp_sphinx_app: SphinxTestApp):
|
|
381
|
+
"""Test that nodes.attention converts to warning[] (D-06).
|
|
382
|
+
|
|
383
|
+
gentle-clues 1.3.1 has no dedicated `attention` clue; `warning` is
|
|
384
|
+
the verified analog, consistent with the existing `caution`/
|
|
385
|
+
`important` -> `warning` precedent.
|
|
386
|
+
"""
|
|
387
|
+
attention = nodes.attention()
|
|
388
|
+
para = nodes.paragraph(text="Pay attention.")
|
|
389
|
+
attention += para
|
|
390
|
+
|
|
391
|
+
doc = create_document()
|
|
392
|
+
doc += attention
|
|
393
|
+
|
|
394
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
395
|
+
writer.document = doc
|
|
396
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
397
|
+
doc.walkabout(translator)
|
|
398
|
+
|
|
399
|
+
output = translator.astext()
|
|
400
|
+
assert "warning({" in output
|
|
401
|
+
assert "warning[" not in output
|
|
402
|
+
assert 'par({text("Pay attention.")})' in output
|
|
403
|
+
|
|
404
|
+
def test_generic_admonition_converts_to_clue(self, temp_sphinx_app: SphinxTestApp):
|
|
405
|
+
"""Test that a generic nodes.admonition converts to clue[] (D-06).
|
|
406
|
+
|
|
407
|
+
Uses the real docutils shape produced by `.. admonition:: <title>` —
|
|
408
|
+
a `nodes.admonition` with a real `nodes.title` child — rather than
|
|
409
|
+
an injected title on an unrelated admonition type. The title flows
|
|
410
|
+
through the same buffer-swap `visit_title`/`depart_title` path used
|
|
411
|
+
by all other admonition types.
|
|
412
|
+
"""
|
|
413
|
+
admonition = nodes.admonition()
|
|
414
|
+
title = nodes.title(text="My Note")
|
|
415
|
+
para = nodes.paragraph(text="Generic admonition body.")
|
|
416
|
+
admonition += title
|
|
417
|
+
admonition += para
|
|
418
|
+
|
|
419
|
+
doc = create_document()
|
|
420
|
+
doc += admonition
|
|
421
|
+
|
|
422
|
+
writer = TypstWriter(temp_sphinx_app.builder)
|
|
423
|
+
writer.document = doc
|
|
424
|
+
translator = TypstTranslator(doc, temp_sphinx_app.builder)
|
|
425
|
+
doc.walkabout(translator)
|
|
426
|
+
|
|
427
|
+
output = translator.astext()
|
|
428
|
+
assert "clue({" in output
|
|
429
|
+
assert "clue[" not in output
|
|
430
|
+
assert ", title: {" in output
|
|
431
|
+
assert output.count("My Note") == 1
|
|
432
|
+
assert "heading(" not in output
|
|
433
|
+
assert 'par({text("Generic admonition body.")})' in output
|