架构
mooncake_impact_factor 是一个更大应用中的 MoonBit 模块。MoonBit 包定义评分规则和少量 JavaScript 辅助函数;Python 构建数据;Next.js 应用提供服务,既可以基于 SQLite 动态运行,也可以作为静态文件发布。本指南沿着数据从注册表到浏览器的路径,指出每一步由哪个文件负责。
组件
| 组件 | 路径 | 语言 | 职责 |
|---|---|---|---|
score | src/score | MoonBit | 分数、等级和势头规则(API)。 |
cli | src/cli | MoonBit (JS) | 为其他语言计算分数快照的命令(API)。 |
static_search | src/static_search | MoonBit (JS) | 静态模式的版本标记和文本规范化(API)。 |
| 索引构建器 | scripts/build_index.py | Python | 读取注册表,写入 SQLite 数据库。 |
| 静态导出器 | scripts/export_static_json.py | Python | 从数据库写出 public/data/**。 |
| 查询层 | lib/query.ts, lib/data.ts | TypeScript | 查询 AST、表达式解析器、SQL 编译。 |
| Web 应用 | app, frontend/src | TypeScript | 页面、路由处理器和静态搜索 worker。 |
从注册表到分数
scripts/build_index.py 每次运行都从零重建数据库。
-
读取注册表。
~/.moon/registry/index/user下每个*.index文件的每一行都是一个已发布的版本:名称、版本、创建时间、元数据和依赖。moon update会刷新这份本地副本;排名恰好覆盖其中的包。 -
选出最新版本: 每个包先按创建时间、再按语义化版本选出最新版本。该版本的描述、关键词、仓库和许可证用于描述这个包。
-
收集下载量。 除非指定了
--skip-mooncakes-downloads,构建器会用八个线程向https://mooncakes.io/api/v0/manifest/<package>查询每个尚未在data/download_cache.json中的包,并把结果存入缓存。--downloads-json可以覆盖单个包的计数。未知的计数为0。 -
构建边。 对于每个依赖快照中另一个包的版本,构建器记录一条从依赖方指向被依赖包的包级边。自依赖会被忽略。
first_seen_at是依赖方中最早使用该依赖的版本的创建时间。 -
统计信号。 设 为构建时间,一个包的信号为
信号 定义 dependents指向该包的边数。 recent_dependentsfirst_seen_at天的边。downloads收集到的下载量。 days_since_release从最新发布到 的整天数;日期未知时为 3650。historical_dependentsfirst_seen_at天的边。historical_recent_dependentsfirst_seen_at位于 天内的边。historical_downloads始终为 0;注册表没有下载历史。historical_days_since_release最新发布至少已有 30 天时为 days_since_release,否则为0。历史窗口就是把近期窗口向前平移 30 天,因此两个快照以同样的方式计算。
-
评分。 构建器对每个包用这八个信号运行
cli命令,并把返回的快照存入package_scores表。因此评分规则只存在于src/score中。 -
索引文本。 一个 SQLite FTS5 表保存完整名称、所有者、包名、描述和关键词,用于全文搜索。
数据库表包括 packages、versions、dependencies、package_edges、package_scores 和 search_index。
服务
动态模式
设置 MOONCAKE_DB_PATH 后运行 npm run dev 或 npm run start,即可提供基于数据库的页面和 JSON 路由处理器:
| 路由 | 返回 |
|---|---|
GET /api/feeds/top?limit=<n> | 按分数降序、再按名称排列的包。 |
GET /api/feeds/hot?limit=<n> | 按 30 天增长量、再按分数、再按名称排列的 Hot 包。 |
GET /api/feeds/rising?limit=<n> | Rising 包,排序方式与 hot 相同。 |
GET /api/search?... | { "items": [...] },最多 100 条包摘要。 |
GET /api/packages/<owner>/<package>/analysis | { "detail": ..., "dependents": [...] }. |
入门指南列出了搜索参数。ast 或 expr 参数中的查询会被编译成 SQL WHERE 子句;文本项使用 FTS5。
静态模式
npm run build:static-data 先运行索引构建器,再运行 scripts/export_static_json.py,后者把各个 feed、一个搜索索引、每个包一个文件以及一个清单写入 public/data。npm run build:static 编译 static_search,并以 NEXT_PUBLIC_APP_MODE=static 运行 next build,把站点导出到不含路由处理器的 out/。在浏览器中,feed 和包页面只是普通的文件请求,搜索则在 Web Worker 中运行;static_search 设计对此有详细说明。deploy-static 工作流每天重建并发布这个站点。
规则归属
每条规则都只有一个归属者,其他部分调用它:
| 规则 | 归属 |
|---|---|
| 分数、等级和势头 | src/score(通过 src/cli 调用) |
| 信号定义和时间窗口 | scripts/build_index.py |
| 查询语言和 AST | lib/query.ts |
| SQL 编译和动态排序 | lib/data.ts |
| 静态求值和排序 | frontend/src/static-search.worker.ts |
scripts/build_index.py 中仍有与 MoonBit 规则对应的 Python 函数 compute_score 和 compute_momentum_label;构建过程不会调用它们。