asteria-ssg 1.0.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.
Files changed (83) hide show
  1. asteria_ssg-1.0.0/PKG-INFO +177 -0
  2. asteria_ssg-1.0.0/README.md +152 -0
  3. asteria_ssg-1.0.0/pyproject.toml +50 -0
  4. asteria_ssg-1.0.0/setup.cfg +4 -0
  5. asteria_ssg-1.0.0/src/asteria/__init__.py +3 -0
  6. asteria_ssg-1.0.0/src/asteria/api.py +124 -0
  7. asteria_ssg-1.0.0/src/asteria/build.py +794 -0
  8. asteria_ssg-1.0.0/src/asteria/cache.py +136 -0
  9. asteria_ssg-1.0.0/src/asteria/cli.py +219 -0
  10. asteria_ssg-1.0.0/src/asteria/config.py +285 -0
  11. asteria_ssg-1.0.0/src/asteria/converter.py +352 -0
  12. asteria_ssg-1.0.0/src/asteria/dates.py +101 -0
  13. asteria_ssg-1.0.0/src/asteria/discovery.py +219 -0
  14. asteria_ssg-1.0.0/src/asteria/document.py +185 -0
  15. asteria_ssg-1.0.0/src/asteria/errors.py +67 -0
  16. asteria_ssg-1.0.0/src/asteria/feed.py +87 -0
  17. asteria_ssg-1.0.0/src/asteria/frontmatter.py +123 -0
  18. asteria_ssg-1.0.0/src/asteria/highlight.py +172 -0
  19. asteria_ssg-1.0.0/src/asteria/i18n_strings.py +60 -0
  20. asteria_ssg-1.0.0/src/asteria/nav.py +126 -0
  21. asteria_ssg-1.0.0/src/asteria/odt_builder.py +76 -0
  22. asteria_ssg-1.0.0/src/asteria/pagination.py +41 -0
  23. asteria_ssg-1.0.0/src/asteria/raw.py +52 -0
  24. asteria_ssg-1.0.0/src/asteria/references.py +137 -0
  25. asteria_ssg-1.0.0/src/asteria/scaffold.py +32 -0
  26. asteria_ssg-1.0.0/src/asteria/server.py +494 -0
  27. asteria_ssg-1.0.0/src/asteria/site/source/content/pages/welcome.odt +0 -0
  28. asteria_ssg-1.0.0/src/asteria/site/source/content/posts/example_post.odt +0 -0
  29. asteria_ssg-1.0.0/src/asteria/site/source/site.yaml +18 -0
  30. asteria_ssg-1.0.0/src/asteria/site/source/static/favicon/android-chrome-192x192.png +0 -0
  31. asteria_ssg-1.0.0/src/asteria/site/source/static/favicon/android-chrome-512x512.png +0 -0
  32. asteria_ssg-1.0.0/src/asteria/site/source/static/favicon/apple-touch-icon.png +0 -0
  33. asteria_ssg-1.0.0/src/asteria/site/source/static/favicon/favicon-16x16.png +0 -0
  34. asteria_ssg-1.0.0/src/asteria/site/source/static/favicon/favicon-32x32.png +0 -0
  35. asteria_ssg-1.0.0/src/asteria/site/source/static/favicon/favicon.ico +0 -0
  36. asteria_ssg-1.0.0/src/asteria/site/source/static/favicon/site.webmanifest +1 -0
  37. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/README.md +1 -0
  38. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/base.html +83 -0
  39. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/css/dark.css +18 -0
  40. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/css/light.css +510 -0
  41. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/i18n.yaml +44 -0
  42. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/images/discord.svg +1 -0
  43. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/images/email.svg +1 -0
  44. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/images/facebook.svg +1 -0
  45. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/images/github.svg +1 -0
  46. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/images/gitlab.svg +1 -0
  47. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/images/gmail.svg +1 -0
  48. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/images/instagram.svg +1 -0
  49. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/images/mastodon.svg +1 -0
  50. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/images/rss.svg +1 -0
  51. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/images/telegram.svg +1 -0
  52. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/images/x.svg +1 -0
  53. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/images/youtube.svg +1 -0
  54. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/js/nav.js +67 -0
  55. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/layouts/404.html +8 -0
  56. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/layouts/blog.html +29 -0
  57. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/layouts/page.html +24 -0
  58. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/layouts/post.html +41 -0
  59. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/layouts/taxonomy_index.html +18 -0
  60. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/layouts/taxonomy_term.html +17 -0
  61. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/partials/_breadcrumbs.html +15 -0
  62. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/partials/_footer.html +28 -0
  63. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/partials/_header.html +35 -0
  64. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/partials/_lang_switcher.html +30 -0
  65. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/partials/_nav.html +29 -0
  66. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/partials/_site_menu.html +9 -0
  67. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/partials/_social_links.html +18 -0
  68. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/partials/_toc.html +10 -0
  69. asteria_ssg-1.0.0/src/asteria/site/source/themes/minimal/theme.yaml +8 -0
  70. asteria_ssg-1.0.0/src/asteria/sitemap.py +26 -0
  71. asteria_ssg-1.0.0/src/asteria/social.py +32 -0
  72. asteria_ssg-1.0.0/src/asteria/taxonomy.py +45 -0
  73. asteria_ssg-1.0.0/src/asteria/templating.py +156 -0
  74. asteria_ssg-1.0.0/src/asteria/theme_config.py +32 -0
  75. asteria_ssg-1.0.0/src/asteria/toc.py +60 -0
  76. asteria_ssg-1.0.0/src/asteria/urls.py +60 -0
  77. asteria_ssg-1.0.0/src/asteria/writer.py +171 -0
  78. asteria_ssg-1.0.0/src/asteria_ssg.egg-info/PKG-INFO +177 -0
  79. asteria_ssg-1.0.0/src/asteria_ssg.egg-info/SOURCES.txt +81 -0
  80. asteria_ssg-1.0.0/src/asteria_ssg.egg-info/dependency_links.txt +1 -0
  81. asteria_ssg-1.0.0/src/asteria_ssg.egg-info/entry_points.txt +2 -0
  82. asteria_ssg-1.0.0/src/asteria_ssg.egg-info/requires.txt +7 -0
  83. asteria_ssg-1.0.0/src/asteria_ssg.egg-info/top_level.txt +1 -0
@@ -0,0 +1,177 @@
1
+ Metadata-Version: 2.4
2
+ Name: asteria-ssg
3
+ Version: 1.0.0
4
+ Summary: Python SSG (Static Site Generator) based exclusively on ODT documents
5
+ Author-email: "Diego C. Sampaio" <slavelix@ymail.com>
6
+ License-Expression: AGPL-3.0-only
7
+ Project-URL: Homepage, https://github.com/kriptolix/Asteria-Project
8
+ Project-URL: Repository, https://github.com/kriptolix/Asteria-Project
9
+ Project-URL: Issues, https://github.com/kriptolix/Asteria-Project/issues
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Topic :: Software Development :: Libraries
15
+ Classifier: Topic :: Documentation
16
+ Classifier: Topic :: Text Processing
17
+ Requires-Python: >=3.13
18
+ Description-Content-Type: text/markdown
19
+ Requires-Dist: PyYAML>=6.0
20
+ Requires-Dist: Jinja2>=3.1
21
+ Requires-Dist: odt2web>=0.8
22
+ Requires-Dist: MarkupSafe>=3.0.3
23
+ Provides-Extra: watch
24
+ Requires-Dist: watchfiles>=0.21; extra == "watch"
25
+
26
+ # Asteria
27
+
28
+ **Asteria** is a static site generator that builds your pages and blog posts
29
+ straight from **OpenDocument Text (`.odt`)** files. Write in LibreOffice
30
+ Writer, Word, or any ODT-compatible editor — Asteria converts it into a
31
+ fast, themeable static site.
32
+
33
+ > Looking for the full configuration reference? See
34
+ > **[MANUAL.md](MANUAL.md)** for a complete guide covering every setting,
35
+ > front matter field, and template variable.
36
+
37
+ ## Features
38
+
39
+ - **Write in ODT, not Markdown.** Headings, lists, tables, and images
40
+ convert automatically — no learning curve for non-technical writers.
41
+ - **Pages and posts**, with tags, categories, pagination, and RSS/Atom
42
+ feeds out of the box.
43
+ - **Multi-language content.** Translate any page or post with a simple
44
+ filename convention; Asteria handles URL prefixes, per-language blog
45
+ indexes, feeds, and a ready-made language switcher.
46
+ - **Cache-safe by default.** Static assets are automatically
47
+ content-hashed, so browsers never serve a stale CSS/JS file during
48
+ development or after a deploy.
49
+ - **Internal cross-references** (`[[page-id]]`) between your own content,
50
+ validated at build time.
51
+ - **Live-reloading dev server** (`asteria serve`) that rebuilds on save.
52
+ - **Fully themeable** with plain Jinja2 templates.
53
+
54
+ ## Requirements
55
+
56
+ - Python 3.11+
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ pip install asteria
62
+ ```
63
+
64
+ *(or, from a local checkout: `pip install -e .`)*
65
+
66
+ ## Quick start
67
+
68
+ ```bash
69
+ # Scaffold a new project (defaults to ./my_site if no path is given)
70
+ asteria new my-blog
71
+ cd my-blog
72
+
73
+ # Serve locally with auto-rebuild on changes
74
+ asteria serve
75
+ # -> http://127.0.0.1:8000
76
+
77
+ # Build the final static site
78
+ asteria build
79
+ ```
80
+
81
+ ## Project structure
82
+
83
+ ```
84
+ my-blog/
85
+ └── source/
86
+ ├── site.yaml # site configuration
87
+ ├── content/
88
+ │ ├── pages/ # standalone pages (*.odt)
89
+ │ └── posts/ # blog posts (*.odt)
90
+ ├── static/ # copied as-is to the site root
91
+ └── themes/
92
+ └── minimal/ # the active theme
93
+ ```
94
+
95
+ `asteria build` writes the generated site to `my-blog/result/` by default.
96
+
97
+ ## Basic usage
98
+
99
+ ### Writing a page or post
100
+
101
+ Create an `.odt` file under `content/pages/` or `content/posts/`. Start it
102
+ with a front matter block, then write your content normally:
103
+
104
+ ```
105
+ ---
106
+ title: My First Post
107
+ date: 2024-03-15
108
+ author: Jane Doe
109
+ tags: hello, first-post
110
+ ---
111
+
112
+ Welcome to my new blog! This is a regular paragraph, written like any
113
+ other document in your ODT editor.
114
+ ```
115
+
116
+ The filename (without extension) becomes the page's unique ID and, by
117
+ default, its URL slug — `content/posts/my-first-post.odt` becomes
118
+ `/blog/my-first-post/`.
119
+
120
+ ### Configuring your site
121
+
122
+ Edit `source/site.yaml`:
123
+
124
+ ```yaml
125
+ site:
126
+ title: "My Blog"
127
+ description: "Thoughts on things I like."
128
+ url: "https://myblog.example.com"
129
+ home_page: "welcome"
130
+
131
+ blog:
132
+ posts_per_page: 10
133
+ ```
134
+
135
+ You only need to set the keys you want to change — everything else falls
136
+ back to sensible defaults. See **[MANUAL.md](MANUAL.md#6-configuration-siteyaml)**
137
+ for the full list of options (multi-language setup, feeds, sitemap,
138
+ URL patterns, asset fingerprinting, and more).
139
+
140
+ ### Linking to your own content
141
+
142
+ ```
143
+ See the [[getting-started]] guide for more details.
144
+ ```
145
+
146
+ ### CLI commands
147
+
148
+ | Command | What it does |
149
+ |---|---|
150
+ | `asteria new [path]` | Scaffold a new project (default: `./my_site`) |
151
+ | `asteria build` | Build the full static site |
152
+ | `asteria serve` | Build and serve locally, rebuilding on changes |
153
+ | `asteria check` | Validate content and configuration without writing any files |
154
+ | `asteria clean` | Remove the generated output (and optionally the build cache) |
155
+
156
+ Run `asteria <command> --help` for all available flags.
157
+
158
+ ## Documentation
159
+
160
+ The **[complete manual](MANUAL.md)** covers:
161
+
162
+ - Every `site.yaml` option, with examples
163
+ - Front matter reference
164
+ - Multi-language content (i18n)
165
+ - Internal references
166
+ - Blog excerpts (`[[more]]`)
167
+ - Asset fingerprinting / cache busting
168
+ - Theming: required templates, available context variables, filters
169
+ - Known limitations
170
+
171
+ ## License
172
+
173
+ AGPL-3.0.
174
+
175
+ ## Contributing
176
+
177
+ Issues and pull requests are welcome.
@@ -0,0 +1,152 @@
1
+ # Asteria
2
+
3
+ **Asteria** is a static site generator that builds your pages and blog posts
4
+ straight from **OpenDocument Text (`.odt`)** files. Write in LibreOffice
5
+ Writer, Word, or any ODT-compatible editor — Asteria converts it into a
6
+ fast, themeable static site.
7
+
8
+ > Looking for the full configuration reference? See
9
+ > **[MANUAL.md](MANUAL.md)** for a complete guide covering every setting,
10
+ > front matter field, and template variable.
11
+
12
+ ## Features
13
+
14
+ - **Write in ODT, not Markdown.** Headings, lists, tables, and images
15
+ convert automatically — no learning curve for non-technical writers.
16
+ - **Pages and posts**, with tags, categories, pagination, and RSS/Atom
17
+ feeds out of the box.
18
+ - **Multi-language content.** Translate any page or post with a simple
19
+ filename convention; Asteria handles URL prefixes, per-language blog
20
+ indexes, feeds, and a ready-made language switcher.
21
+ - **Cache-safe by default.** Static assets are automatically
22
+ content-hashed, so browsers never serve a stale CSS/JS file during
23
+ development or after a deploy.
24
+ - **Internal cross-references** (`[[page-id]]`) between your own content,
25
+ validated at build time.
26
+ - **Live-reloading dev server** (`asteria serve`) that rebuilds on save.
27
+ - **Fully themeable** with plain Jinja2 templates.
28
+
29
+ ## Requirements
30
+
31
+ - Python 3.11+
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install asteria
37
+ ```
38
+
39
+ *(or, from a local checkout: `pip install -e .`)*
40
+
41
+ ## Quick start
42
+
43
+ ```bash
44
+ # Scaffold a new project (defaults to ./my_site if no path is given)
45
+ asteria new my-blog
46
+ cd my-blog
47
+
48
+ # Serve locally with auto-rebuild on changes
49
+ asteria serve
50
+ # -> http://127.0.0.1:8000
51
+
52
+ # Build the final static site
53
+ asteria build
54
+ ```
55
+
56
+ ## Project structure
57
+
58
+ ```
59
+ my-blog/
60
+ └── source/
61
+ ├── site.yaml # site configuration
62
+ ├── content/
63
+ │ ├── pages/ # standalone pages (*.odt)
64
+ │ └── posts/ # blog posts (*.odt)
65
+ ├── static/ # copied as-is to the site root
66
+ └── themes/
67
+ └── minimal/ # the active theme
68
+ ```
69
+
70
+ `asteria build` writes the generated site to `my-blog/result/` by default.
71
+
72
+ ## Basic usage
73
+
74
+ ### Writing a page or post
75
+
76
+ Create an `.odt` file under `content/pages/` or `content/posts/`. Start it
77
+ with a front matter block, then write your content normally:
78
+
79
+ ```
80
+ ---
81
+ title: My First Post
82
+ date: 2024-03-15
83
+ author: Jane Doe
84
+ tags: hello, first-post
85
+ ---
86
+
87
+ Welcome to my new blog! This is a regular paragraph, written like any
88
+ other document in your ODT editor.
89
+ ```
90
+
91
+ The filename (without extension) becomes the page's unique ID and, by
92
+ default, its URL slug — `content/posts/my-first-post.odt` becomes
93
+ `/blog/my-first-post/`.
94
+
95
+ ### Configuring your site
96
+
97
+ Edit `source/site.yaml`:
98
+
99
+ ```yaml
100
+ site:
101
+ title: "My Blog"
102
+ description: "Thoughts on things I like."
103
+ url: "https://myblog.example.com"
104
+ home_page: "welcome"
105
+
106
+ blog:
107
+ posts_per_page: 10
108
+ ```
109
+
110
+ You only need to set the keys you want to change — everything else falls
111
+ back to sensible defaults. See **[MANUAL.md](MANUAL.md#6-configuration-siteyaml)**
112
+ for the full list of options (multi-language setup, feeds, sitemap,
113
+ URL patterns, asset fingerprinting, and more).
114
+
115
+ ### Linking to your own content
116
+
117
+ ```
118
+ See the [[getting-started]] guide for more details.
119
+ ```
120
+
121
+ ### CLI commands
122
+
123
+ | Command | What it does |
124
+ |---|---|
125
+ | `asteria new [path]` | Scaffold a new project (default: `./my_site`) |
126
+ | `asteria build` | Build the full static site |
127
+ | `asteria serve` | Build and serve locally, rebuilding on changes |
128
+ | `asteria check` | Validate content and configuration without writing any files |
129
+ | `asteria clean` | Remove the generated output (and optionally the build cache) |
130
+
131
+ Run `asteria <command> --help` for all available flags.
132
+
133
+ ## Documentation
134
+
135
+ The **[complete manual](MANUAL.md)** covers:
136
+
137
+ - Every `site.yaml` option, with examples
138
+ - Front matter reference
139
+ - Multi-language content (i18n)
140
+ - Internal references
141
+ - Blog excerpts (`[[more]]`)
142
+ - Asset fingerprinting / cache busting
143
+ - Theming: required templates, available context variables, filters
144
+ - Known limitations
145
+
146
+ ## License
147
+
148
+ AGPL-3.0.
149
+
150
+ ## Contributing
151
+
152
+ Issues and pull requests are welcome.
@@ -0,0 +1,50 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "asteria-ssg"
7
+ version = "1.0.0"
8
+ description = "Python SSG (Static Site Generator) based exclusively on ODT documents"
9
+ readme = "README.md"
10
+ requires-python = ">=3.13"
11
+ license = "AGPL-3.0-only"
12
+
13
+ authors = [
14
+ { name = "Diego C. Sampaio", email = "slavelix@ymail.com" }
15
+ ]
16
+
17
+ classifiers = [
18
+ "Development Status :: 5 - Production/Stable",
19
+ "Intended Audience :: Developers",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Topic :: Software Development :: Libraries",
23
+ "Topic :: Documentation",
24
+ "Topic :: Text Processing",
25
+ ]
26
+
27
+ dependencies = [
28
+ "PyYAML>=6.0",
29
+ "Jinja2>=3.1",
30
+ "odt2web>=0.8",
31
+ "MarkupSafe>=3.0.3",
32
+ ]
33
+
34
+ [project.optional-dependencies]
35
+ watch = ["watchfiles>=0.21"]
36
+
37
+ [project.scripts]
38
+ asteria = "asteria.cli:main"
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+ include = ["asteria*"]
43
+
44
+ [tool.setuptools.package-data]
45
+ asteria = ["site/**/*"]
46
+
47
+ [project.urls]
48
+ Homepage = "https://github.com/kriptolix/Asteria-Project"
49
+ Repository = "https://github.com/kriptolix/Asteria-Project"
50
+ Issues = "https://github.com/kriptolix/Asteria-Project/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """Asteria — A Python Static Site Generator (SSG) whose only content source is ODT."""
2
+
3
+ __version__ = "1.0.0"
@@ -0,0 +1,124 @@
1
+ """
2
+ Public, frontend-agnostic API for Asteria.
3
+
4
+ `cli.py` is a thin wrapper around this module. Any other frontend
5
+ (a GTK4 app, a script, a test) should
6
+ import straight from here instead of going through the CLI or shelling
7
+ out to `asteria ...` as a subprocess.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from dataclasses import dataclass
13
+ from pathlib import Path
14
+
15
+ from .build import BuildResult, run_build
16
+ from .cache import clear_cache
17
+ from .config import SiteConfig, load_config
18
+ from .config import reset_theme as _reset_bundled_theme
19
+ from .errors import AsteriaError
20
+ from .scaffold import create_project
21
+ from .server import (
22
+ DevServer,
23
+ DevServerStatus,
24
+ discover_watch_paths,
25
+ watch_backend_available,
26
+ )
27
+ from .writer import clean_output
28
+
29
+ __all__ = [
30
+ "AsteriaError",
31
+ "BuildResult",
32
+ "SiteConfig",
33
+ "CleanResult",
34
+ "DevServer",
35
+ "DevServerStatus",
36
+ "build_project",
37
+ "check_project",
38
+ "clean_project",
39
+ "clear_project_cache",
40
+ "create_new_project",
41
+ "discover_watch_paths",
42
+ "load_project_config",
43
+ "reset_project_theme",
44
+ "watch_backend_available",
45
+ ]
46
+
47
+
48
+ def load_project_config(project_root: Path, config_filename: str = "site.yaml") -> SiteConfig:
49
+ """Loads and returns a project's parsed `site.yaml` (merged with the
50
+ built-in defaults). Raises AsteriaError if the file is missing or not valid YAML.
51
+ """
52
+ return load_config(project_root / "source" / config_filename)
53
+
54
+
55
+ def build_project(
56
+ project_root: Path,
57
+ converter_name: str = "odt2web",
58
+ config_filename: str = "site.yaml",
59
+ ) -> BuildResult:
60
+ """Runs a full build and writes the output to disk.
61
+ """
62
+ return run_build(project_root, config_filename=config_filename, converter_name=converter_name)
63
+
64
+
65
+ def check_project(
66
+ project_root: Path,
67
+ converter_name: str = "auto",
68
+ config_filename: str = "site.yaml",
69
+ ) -> BuildResult:
70
+ """Validates the project (YAML, ODT files, ids, references) without
71
+ writing anything to disk.
72
+ """
73
+ return run_build(
74
+ project_root,
75
+ config_filename=config_filename,
76
+ converter_name=converter_name,
77
+ dry_run=True,
78
+ )
79
+
80
+
81
+ @dataclass
82
+ class CleanResult:
83
+ """What `clean_project` actually did, so a UI can report it without
84
+ re-deriving it from a SiteConfig itself."""
85
+
86
+ output_dir: Path
87
+ output_removed: bool
88
+ cache_removed: bool
89
+
90
+
91
+ def clean_project(
92
+ project_root: Path,
93
+ remove_cache: bool = False,
94
+ config_filename: str = "site.yaml",
95
+ ) -> CleanResult:
96
+ """Removes the generated site (`config.output_dir`) and, optionally,
97
+ the incremental conversion cache.
98
+ """
99
+ config = load_config(project_root / "source" / config_filename)
100
+ output_removed = config.output_dir.exists()
101
+ clean_output(config)
102
+ cache_removed = remove_cache and clear_cache(project_root)
103
+ return CleanResult(
104
+ output_dir=config.output_dir,
105
+ output_removed=output_removed,
106
+ cache_removed=cache_removed,
107
+ )
108
+
109
+
110
+ def clear_project_cache(project_root: Path) -> bool:
111
+
112
+ return clear_cache(project_root)
113
+
114
+
115
+ def create_new_project(target_dir: Path) -> list[str]:
116
+
117
+ return create_project(target_dir)
118
+
119
+
120
+ def reset_project_theme(project_root: Path) -> Path:
121
+ """Overwrites `source/themes/minimal` with Asteria's bundled
122
+ 'minimal' theme, discarding any local edits to it.
123
+ """
124
+ return _reset_bundled_theme(project_root)