DrewRidley/surrealguard
GitHub: DrewRidley/surrealguard
针对 SurrealQL 的静态分析与类型推断工具,在查询到达数据库前捕获字段、类型和图遍历错误,并为 Rust 和 TypeScript 提供编译期类型检查。
Stars: 2 | Forks: 0
# 🛡️ SurrealGuard
### 针对 SurrealQL 的静态分析与类型推断
在查询到达 SurrealDB *之前*捕获未知字段、类型不匹配和错误的图遍历——
并在 **Rust** 和 **TypeScript** 中获得完全类型化的结果。
[](https://www.npmjs.com/package/@surrealguard/client)
[](https://github.com/DrewRidley/surrealguard/actions/workflows/ci.yml)
[](#license)
[**文档**](https://surrealguard.dev/docs/) · [**在线演示**](https://surrealguard.dev/#playground) · [**npm**](https://www.npmjs.com/org/surrealguard) · [**DESIGN.md**](docs/DESIGN.md)
SurrealGuard 将你的 `.surql` schema 和查询解析为带有跨度信息的类型化 AST,
推断每条语句的响应类型,并报告违反每个构造契约的行为。该引擎同时为
CLI、语言服务器、Rust proc-macro 以及一系列 TypeScript 包提供支持。
## 为什么需要它
SurrealDB 在运行时非常宽松:跨类型比较会按类型排序而不是直接报错,强制转换会静默成功,
而拼写错误的字段只会返回 `NONE`。这正是 bug 隐藏的地方。SurrealGuard 是
**契约优先**的——每个构造都有一个契约(作者必须表达的含义才能使语句有意义),
并且分析器会报告违反该契约的行为,即使引擎本身能够正常执行该查询。
SurrealDB 自身的解析器在生成 AST 之前就丢弃了跨度信息,因此它无法为分析器或
编辑器工具提供支持。SurrealGuard 使用 tree-sitter 将其解析为带有跨度信息的
类型化 AST,并在此基础上运行所有分析。
## 编译器即检查器 (Rust)
```
use surrealguard_rs::query;
// Checked against your schema at compile time. A wrong table, unknown field,
// bad arity, or kind mismatch is a `cargo check` error — no external step.
let users = query!("SELECT name, age FROM user");
// users: Query
> ← nameless, inferred
```
`query!` 在编译期间运行真正的分析器,将发现的问题转化为带有跨度信息的
`compile_error!`,然后根据推断出的响应类型生成结果类型——无需代码生成步骤,
无需语言服务器,也无需运行时获取 schema。将其指向 `schema/` 或 `migrations/`
目录(按顺序应用),它就能解析出真实的表和字段。`surql!` 是更轻量的形式:
检查查询,并展开为其文本。
## 类型化查询,无需包装器 (TypeScript)
```
// One import: the generated file re-exports a ready client that IS a SurrealDB
// `Surreal` (every SDK method) and loads the typed query registry.
import { SurrealGuardClient } from "./surrealguard.generated"; // from `surrealguard generate`
const db = new SurrealGuardClient();
await db.connect("ws://localhost:8000/rpc");
// SurrealDB returns one result per statement, so destructure the first result.
const [users] = await db.query("SELECT name FROM user WHERE team = $team", { team: "red" });
// ^ result typed from the query text; params required + typed; wrong/missing params
// are compile errors. Dynamic strings degrade to `unknown[]` and still run.
```
框架适配器构建于响应式核心 (`@surrealguard/query`) 之上,该核心隐藏了
SSR 水合和实时查询的生命周期:
```
{#each $users.data as user (user.id)}{user.name}{/each}
```
`LIVE SELECT` 会开启一个共享的、基于引用计数的订阅,并根据记录 id 对
变更通知进行调节;`@surrealguard/next` 通过 `useLiveQuery` hook 提供相同的功能。
## 分析内容
- **全语句覆盖** —— SELECT(projections、图遍历、FETCH/SPLIT/GROUP/OMIT),
六种 mutations,RELATE,LET/RETURN/IF/FOR/blocks,transactions,
DEFINE/REMOVE/ALTER,LIVE SELECT/KILL 等。
- **类型推断** —— 响应类型作为上游的 `surrealdb_types::Kind`:已知行的
闭合 object literals,来自 IF/ELSE 的 unions,record-link 和 graph-edge
形状,完整的内置函数表以及 `fn::` 声明,closure 和 subquery 推断,
以及常量值求值。
- **包含约 80 种诊断的契约目录**,分为多个系列(1xxx schema 引用,
2xxx 类型,3xxx 图,4xxx 语句误用,5xxx 函数,6xxx 参数,
7xxx lints,8xxx 版本兼容性)。严重性是每种发现固有的;使用者在其边界
应用策略(将警告视为错误、lint 级别),风格类似于 rustc。
- **参数约束** —— 源文件读取的每个 `$param` 都会根据其使用情况导出对应的
类型和值域(`UPDATE user SET age = $age` → `age: int`;
`LIMIT $n` → 非负 int)。
- **精确到字节的跨度信息**,附加在每项发现上,用于编辑器波浪线提示。
## 使用方式
- **CLI** —— `surrealguard check` 分析工作区(`--json` 用于机器输出;
退出码反映应用策略后的错误);`surrealguard generate` 生成
TypeScript 类型;`surrealguard init` 编写初始配置。
- **编辑器 (LSP)** —— `surrealguard-lsp` 通过 stdio 为 `.surql` 文件*以及*
嵌入在宿主文件中的 SurrealQL(TypeScript, Svelte, Vue, Astro)发布诊断信息——
波浪线提示会精确地落在你的内联查询中的具体 token 上。
- **Rust** —— `surrealguard-rs` crate 重新导出了 `query!` / `surql!` 宏。
- **TypeScript** —— `@surrealguard/client`、`@surrealguard/query`、
`@surrealguard/next`、`@surrealguard/svelte`。
## 项目布局
```
surrealguard/
├── crates/
│ ├── syntax/ # tree-sitter parsing, typed span-carrying AST, lowering
│ ├── diagnostics/ # finding types, code catalog, severity/lint policy
│ ├── workspace/ # schema index, analyzers, inference, analysis pipeline
│ ├── codegen/ # Kind → TypeScript generation
│ ├── embed/ # embedded-SurrealQL extraction from host files
│ ├── macros/ # the surql! / query! proc-macros
│ ├── rs/ # surrealguard-rs runtime (typed results)
│ ├── cli/ # the `surrealguard` binary
│ └── lsp/ # the `surrealguard-lsp` binary
├── packages/ # @surrealguard/{client,query,next,svelte} (pnpm workspace)
└── docs/ # DESIGN.md + design plans (incl. the diagnostic catalog)
```
## 安装
**TypeScript**(已发布):
```
npm i @surrealguard/client # + @surrealguard/{query,next,svelte}
```
**Rust / CLI**(在 crates.io 版本最终确定之前从源码构建):
```
cargo install --path crates/cli
surrealguard init && surrealguard check
```
工作区会按顺序分析每个 `.surql` 源文件,因此 schema 定义对于
后续的查询是可见的。
## 状态
该引擎(类型化 AST、完整的推断、约 80 种契约诊断、参数约束)、
CLI、LSP、Rust 的 `surql!` / `query!` 宏以及 TypeScript 包
均已构建完成,并且 CI 测试通过。
- **npm** —— `@surrealguard/{client,query,next,svelte}` **已发布** (0.2.x)。
- **Grammar** —— 优先级修复和功能增加已**合并至上游**
[`surrealdb/surrealql-tree-sitter`](https://github.com/surrealdb/surrealql-tree-sitter) 仓库中。
- **crates.io** —— Rust crates(`surrealguard`、`surrealguard-rs`)即将推出。
有关架构和路线图,请参阅 [`docs/DESIGN.md`](docs/DESIGN.md)。
## 许可证
根据你的选择,受 [Apache License, Version 2.0](LICENSE-APACHE) 或
[MIT license](LICENSE-MIT) 许可。除非你明确声明,否则你出于包含在本项目中的目的
而有意提交的任何贡献(如 Apache-2.0 许可证中所定义),均应按上述方式进行双重许可,
不附加任何额外的条款或条件。标签:AST解析, Rust, SurrealDB, SurrealQL, TypeScript, 云安全监控, 可视化界面, 安全插件, 暗色界面, 类型推断, 网络流量审计, 语言服务器协议, 通知系统, 静态分析