docs: explain Tessera modules and execution flows in Chinese
This commit is contained in:
@@ -1,18 +1,22 @@
|
||||
#!/bin/sh
|
||||
# Native macOS build and app bundle. No Docker, mirror configuration, or tests.
|
||||
set -eu
|
||||
# 此入口只能在 macOS 使用;构建授权由调用方确认,脚本不自动执行测试或部署。
|
||||
if [ "$(uname -s)" != Darwin ]; then
|
||||
echo "Build this app bundle on macOS." >&2
|
||||
exit 1
|
||||
fi
|
||||
cd "$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
|
||||
# 锁定依赖并生成 release 可执行文件;附加参数原样交给 Cargo。
|
||||
cargo build --release --locked "$@"
|
||||
version=$(awk -F '"' '$1 ~ /^version[[:space:]]*=/ { print $2; exit }' Cargo.toml)
|
||||
test -n "$version"
|
||||
bundle="$(pwd)/target/release/Tessera.app"
|
||||
mkdir -p "$bundle/Contents/MacOS"
|
||||
# 先写临时文件再重命名,避免复制途中将半个二进制留作 bundle 的主程序。
|
||||
cp target/release/tessera "$bundle/Contents/MacOS/tessera.new"
|
||||
mv -f "$bundle/Contents/MacOS/tessera.new" "$bundle/Contents/MacOS/tessera"
|
||||
# 生成最小 macOS bundle 元数据;应用名、入口与高分辨率标志供系统启动/显示使用。
|
||||
cat > "$bundle/Contents/Info.plist.new" <<PLIST
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
|
||||
@@ -7,6 +7,7 @@ import path from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
|
||||
const tools = process.env.UML_RENDER_TOOLS;
|
||||
// 工具依赖放在独立目录,避免给应用运行依赖增加文档渲染包。
|
||||
if (!tools) throw new Error('Set UML_RENDER_TOOLS to the documentation tool directory; see docs/architecture/uml/README.md');
|
||||
const require = createRequire(path.join(path.resolve(tools), 'package.json'));
|
||||
const { createCanvas } = require('@napi-rs/canvas');
|
||||
@@ -23,6 +24,7 @@ const document = new DOMImplementation().createDocument(null, 'root', null);
|
||||
const element = document.createElement.bind(document);
|
||||
const elementNS = document.createElementNS.bind(document);
|
||||
function measurementCanvas() {
|
||||
// PlantUML 的文本布局需要真实字体宽高,统一用本机 Canvas 测量而非固定字符宽度。
|
||||
const canvas = createCanvas(1, 1);
|
||||
const context = canvas.getContext('2d');
|
||||
const measure = context.measureText.bind(context);
|
||||
@@ -41,6 +43,7 @@ function measurementCanvas() {
|
||||
}
|
||||
document.createElement = tag => tag === 'canvas' ? measurementCanvas() : element(tag);
|
||||
document.createElementNS = (namespace, tag) => {
|
||||
// 为无浏览器 DOM 补齐样式与 getBBox,满足官方渲染引擎的 SVG 文本布局需求。
|
||||
const node = elementNS(namespace, tag);
|
||||
node.style = {};
|
||||
node.getBBox = () => {
|
||||
@@ -65,6 +68,7 @@ const source = path.join(root, 'docs/architecture/uml');
|
||||
const output = path.join(source, 'rendered');
|
||||
await mkdir(output, { recursive: true });
|
||||
for (const filename of (await readdir(source)).filter(name => name.endsWith('.puml')).sort()) {
|
||||
// 每张图独立渲染并检查错误文本;错误图不能被当作正常产物覆盖已有预览。
|
||||
const text = await readFile(path.join(source, filename), 'utf8');
|
||||
const rendered = await new Promise((resolve, reject) => renderToString(text.split('\n'), resolve, reject));
|
||||
const xml = new DOMParser().parseFromString(rendered, 'image/svg+xml');
|
||||
@@ -77,6 +81,7 @@ for (const filename of (await readdir(source)).filter(name => name.endsWith('.pu
|
||||
for (const [key, value] of Object.entries({ x: '0', y: '0', width: '100%', height: '100%', fill: '#FFFFFF' })) paper.setAttribute(key, value);
|
||||
xml.documentElement.insertBefore(paper, xml.documentElement.firstChild);
|
||||
const svg = new XMLSerializer().serializeToString(xml);
|
||||
// 同时保存可缩放 SVG 和通用 PNG;写完读取 PNG 元数据确认生成尺寸。
|
||||
const stem = filename.slice(0, -5);
|
||||
await writeFile(path.join(output, `${stem}.svg`), svg);
|
||||
// High-resolution PNG is the universally visible Markdown preview; SVG keeps zoomable text.
|
||||
|
||||
Reference in New Issue
Block a user