mirror of
https://github.com/hectorqin/reader.git
synced 2026-11-12 14:01:00 +08:00
两个分支各自演进:一侧引入格式注册表、H5 客户端与 Android 外壳,另一侧 引入漫画目录书与逐页取图。冲突集中在扫描器、metadata、library 路由和 web 客户端,逐项按「两边能力都要保留」的原则合并。 合并后修复了 4 个被冲突掩盖的真实缺陷: - scanner 同时保留了两套目录书实现,类型检查与测试均无法通过;改为统一 走格式注册表,目录书在文件遍历之前发现,其内容不再重复入库。 - /manifest 的 files 对漫画目录书返回的是文件夹路径,客户端无法逐页取图; 改为由 manifest 派生真实页路径。 - 单个文件端点只认 book_files 行,漫画目录书的每一页都 404;改为目录书 额外认领其目录下的路径,并修正路径归一化使穿越尝试仍被拒绝。 - 目录书判定只看图片数量,会把夹着一本书的目录整体吞掉;改为注册表驱动 的判定,含书籍文件的目录始终是书架。 同时修复了 web 端两套测试运行器互相无法执行对方用例的问题(vitest 与 node:test 混跑会静默跳过),以及 web 侧 5 处类型错误。 Ref: #9
76 lines
3.0 KiB
Bash
Executable File
76 lines
3.0 KiB
Bash
Executable File
#!/bin/sh
|
|
# Static checks on the Android shell that do not need a JDK or the Android SDK.
|
|
#
|
|
# CI compiles the shell for real, but that job needs a large SDK image and takes
|
|
# minutes. This runs in a second, so a typo in a package declaration or a bridge
|
|
# method that the web client calls but the shell does not expose is caught before
|
|
# anyone waits for a build — which matters more than usual here, because the two
|
|
# halves of the bridge are written in different languages and cannot be
|
|
# type-checked against each other.
|
|
set -eu
|
|
|
|
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
android_dir=$(dirname -- "$script_dir")
|
|
repo_dir=$(dirname -- "$android_dir")
|
|
fail=0
|
|
|
|
note() { printf '%s\n' "$1"; }
|
|
err() { printf 'FAIL: %s\n' "$1" >&2; fail=1; }
|
|
|
|
# 1. Package declaration must match the file's directory under src/main/java.
|
|
note "==> checking package declarations match directory layout"
|
|
for file in $(find "$android_dir/app/src" -name '*.kt'); do
|
|
pkg=$(sed -n 's/^package \(.*\)$/\1/p' "$file" | head -1)
|
|
rel=${file#"$android_dir"/app/src/main/java/}
|
|
expected=$(dirname "$rel" | tr '/' '.')
|
|
if [ "$pkg" != "$expected" ]; then
|
|
err "$file declares '$pkg' but lives in '$expected'"
|
|
fi
|
|
done
|
|
|
|
# 2. Every import of our own code must resolve to a file that exists.
|
|
note "==> checking project imports resolve"
|
|
for file in $(find "$android_dir/app/src" -name '*.kt'); do
|
|
sed -n 's/^import cool\.cnb\.reader\.\(.*\)$/\1/p' "$file" | while read -r symbol; do
|
|
# `BuildConfig` is generated, and a class name is the last dot segment.
|
|
case "$symbol" in
|
|
BuildConfig) continue ;;
|
|
esac
|
|
path="$android_dir/app/src/main/java/cool/cnb/reader/$(printf '%s' "$symbol" | tr '.' '/').kt"
|
|
if [ ! -f "$path" ]; then
|
|
err "$file imports cool.cnb.reader.$symbol but $path does not exist"
|
|
fi
|
|
done
|
|
done
|
|
|
|
# 3. Every bridge method the web client calls must exist, and every bridge method
|
|
# the shell exposes must be declared. This is the cross-language seam.
|
|
note "==> checking the JS bridge contract in both directions"
|
|
bridge_file="$android_dir/app/src/main/java/cool/cnb/reader/bridge/ReaderBridge.kt"
|
|
declared=$(sed -n 's/^ fun \([A-Za-z][A-Za-z0-9_]*\)(.*/\1/p' "$bridge_file" | sort -u)
|
|
types_file="$repo_dir/web/src/android-bridge.d.ts"
|
|
consumed=$(sed -n 's/^ \([a-z][A-Za-z0-9_]*\)[?]\?(.*:.*;.*$/\1/p' "$types_file" | sort -u)
|
|
|
|
for method in $consumed; do
|
|
if ! printf '%s\n' "$declared" | grep -qx "$method"; then
|
|
err "web client calls ReaderAndroid.$method() but ReaderBridge.kt does not declare it"
|
|
fi
|
|
done
|
|
|
|
# Every bridge method must also appear in the client-facing declaration, or the
|
|
# next person writing client code will not know it is available.
|
|
missing_from_types=0
|
|
for method in $declared; do
|
|
if ! printf '%s\n' "$consumed" | grep -qx "$method"; then
|
|
err "ReaderBridge.$method exists but is missing from android-bridge.d.ts"
|
|
missing_from_types=1
|
|
fi
|
|
done
|
|
[ "$missing_from_types" -eq 0 ] || true
|
|
|
|
if [ "$fail" -ne 0 ]; then
|
|
note "==> shell checks failed"
|
|
exit 1
|
|
fi
|
|
note "==> shell checks passed"
|