fr-docs 2.1.0__tar.gz → 2.1.2__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.
- {fr_docs-2.1.0 → fr_docs-2.1.2}/PKG-INFO +1 -1
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/build.py +78 -2
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/html_pipeline.py +13 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/template.py +6 -2
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs.egg-info/PKG-INFO +1 -1
- {fr_docs-2.1.0 → fr_docs-2.1.2}/pyproject.toml +1 -1
- {fr_docs-2.1.0 → fr_docs-2.1.2}/LICENSE.md +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/README.md +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/__init__.py +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/__main__.py +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/config.py +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/config_accessors.py +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/frontmatter.py +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/git.py +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/init.py +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/markdown.py +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/search.py +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/slug.py +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/syntax.py +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs/utils.py +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs.egg-info/SOURCES.txt +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs.egg-info/dependency_links.txt +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs.egg-info/entry_points.txt +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs.egg-info/requires.txt +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/fr_docs.egg-info/top_level.txt +0 -0
- {fr_docs-2.1.0 → fr_docs-2.1.2}/setup.cfg +0 -0
|
@@ -8,8 +8,11 @@ import argparse
|
|
|
8
8
|
import concurrent.futures
|
|
9
9
|
import json
|
|
10
10
|
import os
|
|
11
|
+
import re
|
|
11
12
|
import shutil
|
|
13
|
+
import subprocess
|
|
12
14
|
import sys
|
|
15
|
+
import tempfile
|
|
13
16
|
from pathlib import Path
|
|
14
17
|
|
|
15
18
|
import xxhash
|
|
@@ -42,6 +45,76 @@ def _compute_hash(data: str) -> str:
|
|
|
42
45
|
return xxhash.xxh3_128_hexdigest(data.encode("utf-8"))
|
|
43
46
|
|
|
44
47
|
|
|
48
|
+
def _minify_static_asset(config, src: Path, dst: Path, name: str) -> None:
|
|
49
|
+
"""Minify a static asset in-place (JS via terser, CSS via html-minifier).
|
|
50
|
+
|
|
51
|
+
Falls back to a plain copy if the minifier is unavailable. CSS is minified
|
|
52
|
+
by wrapping it in a `<style>` tag (html-minifier-next only processes CSS
|
|
53
|
+
embedded in HTML) and stripping the wrapper afterwards.
|
|
54
|
+
"""
|
|
55
|
+
repo_root = Path(config["_docs_dir"]).resolve().parent
|
|
56
|
+
node_modules = repo_root / "node_modules"
|
|
57
|
+
|
|
58
|
+
if name.endswith(".js"):
|
|
59
|
+
terser_bin = node_modules / ".bin" / "terser"
|
|
60
|
+
cmd = [
|
|
61
|
+
str(terser_bin) if terser_bin.exists() else "npx",
|
|
62
|
+
"--yes" if not terser_bin.exists() else "",
|
|
63
|
+
*(["terser"] if not terser_bin.exists() else []),
|
|
64
|
+
str(src),
|
|
65
|
+
"--compress",
|
|
66
|
+
"warnings=false",
|
|
67
|
+
"--mangle",
|
|
68
|
+
"--output",
|
|
69
|
+
str(dst),
|
|
70
|
+
]
|
|
71
|
+
cmd = [c for c in cmd if c]
|
|
72
|
+
result = subprocess.run(cmd, capture_output=True, text=True, check=False, cwd=str(repo_root))
|
|
73
|
+
if result.returncode != 0 or not dst.exists() or dst.stat().st_size == 0:
|
|
74
|
+
print(f" ! minify failed for {name}, copying raw: {result.stderr[-300:]}")
|
|
75
|
+
shutil.copyfile(src, dst)
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
# CSS: html-minifier-next only minifies CSS embedded in HTML, so wrap the
|
|
79
|
+
# stylesheet in a <style> tag, minify, then strip the wrapper.
|
|
80
|
+
minifier_bin = node_modules / ".bin" / "html-minifier-next"
|
|
81
|
+
raw_css = src.read_text(encoding="utf-8")
|
|
82
|
+
wrapped = f"<style>{raw_css}</style>"
|
|
83
|
+
wrapper = Path(tempfile.mkstemp(suffix=".html")[1])
|
|
84
|
+
min_out = Path(tempfile.mkstemp(suffix=".html")[1])
|
|
85
|
+
try:
|
|
86
|
+
wrapper.write_text(wrapped, encoding="utf-8")
|
|
87
|
+
cmd = [
|
|
88
|
+
str(minifier_bin) if minifier_bin.exists() else "npx",
|
|
89
|
+
"--yes" if not minifier_bin.exists() else "",
|
|
90
|
+
*(["html-minifier-next"] if not minifier_bin.exists() else ""),
|
|
91
|
+
"--minify-css=true",
|
|
92
|
+
"--remove-comments",
|
|
93
|
+
"--output",
|
|
94
|
+
str(min_out),
|
|
95
|
+
str(wrapper),
|
|
96
|
+
]
|
|
97
|
+
cmd = [c for c in cmd if c]
|
|
98
|
+
result = subprocess.run(cmd, capture_output=True, text=True, check=False, cwd=str(repo_root))
|
|
99
|
+
if result.returncode == 0 and min_out.exists():
|
|
100
|
+
out = min_out.read_text(encoding="utf-8")
|
|
101
|
+
m = re.search(r"<style>([\s\S]*)</style>", out)
|
|
102
|
+
if m:
|
|
103
|
+
dst.write_text(m.group(1), encoding="utf-8")
|
|
104
|
+
return
|
|
105
|
+
print(f" ! minify failed for {name}, copying raw: {result.stderr[-300:]}")
|
|
106
|
+
finally:
|
|
107
|
+
try:
|
|
108
|
+
wrapper.unlink()
|
|
109
|
+
except OSError:
|
|
110
|
+
pass
|
|
111
|
+
try:
|
|
112
|
+
min_out.unlink()
|
|
113
|
+
except OSError:
|
|
114
|
+
pass
|
|
115
|
+
shutil.copyfile(src, dst)
|
|
116
|
+
|
|
117
|
+
|
|
45
118
|
class BuildCache:
|
|
46
119
|
"""Manage caching of build data to avoid unnecessary regeneration."""
|
|
47
120
|
|
|
@@ -287,7 +360,7 @@ def main(argv=None):
|
|
|
287
360
|
config["_source_files"] = source_files
|
|
288
361
|
print(f" Found {len(source_files)} source files")
|
|
289
362
|
|
|
290
|
-
# Copy static assets
|
|
363
|
+
# Copy static assets (minifying JS/CSS when production)
|
|
291
364
|
docs_path = Path(config["_docs_dir"])
|
|
292
365
|
os.makedirs(Path(config["_out_dir"]), exist_ok=True)
|
|
293
366
|
for legacy_name in (
|
|
@@ -303,7 +376,10 @@ def main(argv=None):
|
|
|
303
376
|
dst = Path(config["_out_dir"]) / name
|
|
304
377
|
|
|
305
378
|
try:
|
|
306
|
-
|
|
379
|
+
if config.get("production", False) and name.endswith((".js", ".css")):
|
|
380
|
+
_minify_static_asset(config, src, dst, name)
|
|
381
|
+
else:
|
|
382
|
+
shutil.copyfile(src, dst)
|
|
307
383
|
except FileNotFoundError:
|
|
308
384
|
print(f"File not found: {os.getcwd()}, {src}->{dst}")
|
|
309
385
|
except OSError as e:
|
|
@@ -81,6 +81,18 @@ def _render_template_placeholders(config):
|
|
|
81
81
|
<input type="text" id="header-search" placeholder="Search docs… (Ctrl+K)" autocomplete="off">
|
|
82
82
|
<div id="search-results" class="search-results"></div>"""
|
|
83
83
|
|
|
84
|
+
def _get_search_preloads_html():
|
|
85
|
+
if not feature_enabled(config, "search"):
|
|
86
|
+
return ""
|
|
87
|
+
sp = output_href("", config)
|
|
88
|
+
return (
|
|
89
|
+
f'<link rel="preload" as="fetch" href="{sp}search_index.zst" crossorigin>\n'
|
|
90
|
+
f' <link rel="preload" as="fetch" href="{sp}symbol_index.zst" crossorigin>\n'
|
|
91
|
+
f' <link rel="preload" as="fetch" href="{sp}file_index.zst" crossorigin>\n'
|
|
92
|
+
f' <link rel="preload" as="fetch" href="{sp}git_meta.zst" crossorigin>\n'
|
|
93
|
+
f' <link rel="modulepreload" href="https://cdn.jsdelivr.net/npm/fzstd@0.1.1/umd/index.min.js">'
|
|
94
|
+
)
|
|
95
|
+
|
|
84
96
|
return {
|
|
85
97
|
"site_prefix": output_href("", config),
|
|
86
98
|
"page_title": "",
|
|
@@ -95,6 +107,7 @@ def _render_template_placeholders(config):
|
|
|
95
107
|
"subtitle_html": "",
|
|
96
108
|
"body": "",
|
|
97
109
|
"search_index_inline": "",
|
|
110
|
+
"search_preloads": _get_search_preloads_html(),
|
|
98
111
|
"copyright_year": _get_copyright_year(),
|
|
99
112
|
"copyright_holder": _get_copyright_holder(),
|
|
100
113
|
}
|
|
@@ -17,11 +17,14 @@ TEMPLATE = """\
|
|
|
17
17
|
<meta property="og:site_name" content="{project_name} Docs">
|
|
18
18
|
<meta name="theme-color" content="#6366f1">
|
|
19
19
|
<meta name="color-scheme" content="dark">
|
|
20
|
+
<link rel="stylesheet" href="{site_prefix}style.css">
|
|
20
21
|
<link rel="icon" href="{site_prefix}favicon.svg" type="image/svg+xml">
|
|
21
22
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
22
23
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,400..800&family=JetBrains+Mono:wght@400..700&display=optional" rel="stylesheet">
|
|
25
|
+
<link rel="preload" as="font" href="https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmM.woff2" type="font/woff2" crossorigin>
|
|
26
|
+
<link rel="preload" as="font" href="https://fonts.gstatic.com/s/inter/v20/UcCo3FwrK3iLTcviYwYZ8UA3.woff2" type="font/woff2" crossorigin>
|
|
27
|
+
<link rel="preload" as="font" href="https://fonts.gstatic.com/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0P.woff2" type="font/woff2" crossorigin>
|
|
25
28
|
</head>
|
|
26
29
|
<body>
|
|
27
30
|
<!-- Header -->
|
|
@@ -72,6 +75,7 @@ TEMPLATE = """\
|
|
|
72
75
|
</button>
|
|
73
76
|
|
|
74
77
|
{search_index_inline}
|
|
78
|
+
{search_preloads}
|
|
75
79
|
<script id="code-refs-data" type="application/json">{code_refs_json}</script>
|
|
76
80
|
<script id="search-config" type="application/json">{search_config_json}</script>
|
|
77
81
|
<script src="{site_prefix}script.js" defer></script>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|