mcpField
L
liveview-code-review

liveview-code-review

github.com/existential-birds测试与质量8588 次安装11 周前更新
代码仓库

关于 liveview-code-review

面向 Phoenix LiveView 项目的代码审查技能,覆盖生命周期、数据管理、组件和安全检查,并通过审查门槛要求问题有经核实的证据支持。

主要功能

  1. 01LiveView 生命周期检查
  2. 02assigns、streams 与异步状态指导
  3. 03函数组件和 LiveComponent 审查
  4. 04授权与客户端数据校验检查
  5. 05证据及情境化审查门槛

适用场景

  1. 01审查 LiveView 事件的授权检查
  2. 02检查异步加载与错误处理
  3. 03评估大型集合的数据处理方式
  4. 04审查组件和 slot 的用法

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/existential-birds/beagle --skill liveview-code-review

安装后在 Claude Code 中输入/liveview-code-review确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
assigns-streams.md
components.md
lifecycle.md
security.md

详细介绍

LiveView 代码审查

快速参考

问题类型参考资料
mount、handle_params、handle_event、handle_asyncreferences/lifecycle.md
何时使用 assigns 而非 streams、AsyncResultreferences/assigns-streams.md
函数组件与 LiveComponent、插槽、属性references/components.md
按事件进行授权、信任 phx-valuereferences/security.md

审查清单

严重问题
  • 不要将 socket 复制到异步函数中(先提取值)
  • 每个 handle_event 都会验证授权
  • assigns 中没有敏感数据(这些数据会显示在 DOM 中)
  • phx-value 数据经过验证(用户可以修改)
生命周期
  • 订阅由 connected?(socket) 包裹
  • 使用 handle_params 管理基于 URL 的状态
  • handle_async 处理 :loading 和 :error 状态
数据管理
  • 大型集合(100 项以上)使用 streams
  • 对渲染后不再需要的数据使用 temporary_assigns
  • 使用 AsyncResult 模式处理加载状态
组件
  • 优先使用函数组件,而非 LiveComponents
  • LiveComponents 在 update/2 中保留 :inner_block
  • 插槽使用恰当的 attr 声明
  • 文本输入使用 phx-debounce

有效模式(不要标记)

  • 空 mount 返回 {:ok, socket} - 对简单的 LiveView 有效
  • 使用 assigns 保存小型列表 - 只有 100 项以上才需要使用 streams
  • LiveComponent 未实现 update/2 - 默认的 update/2 会分配所有属性
  • phx-click 未使用 phx-value - 事件可能不需要数据
  • heex 中的内联函数 - 用于简单转换时有效

依上下文而定的规则

问题仅在以下情况下标记
缺少防抖输入为 text/textarea,且会触发服务端事件
使用 streams集合有 100 项以上,或采用分页
缺少授权检查事件会修改数据,且 mount 中没有授权检查

严重反模式

复制 Socket(最重要)
# BAD - socket copied into async function
def handle_event("load", _, socket) do
  Task.async(fn ->
    user = socket.assigns.user  # Socket copied!
    fetch_data(user.id)
  end)
  {:noreply, socket}
end

# GOOD - extract values first
def handle_event("load", _, socket) do
  user_id = socket.assigns.user.id
  Task.async(fn ->
    fetch_data(user_id)  # Only primitive copied
  end)
  {:noreply, socket}
end
缺少授权
# BAD - trusts phx-value without auth
def handle_event("delete", %{"id" => id}, socket) do
  Posts.delete_post!(id)  # Anyone can delete any post!
  {:noreply, socket}
end

# GOOD - verify authorization
def handle_event("delete", %{"id" => id}, socket) do
  post = Posts.get_post!(id)

  if post.user_id == socket.assigns.current_user.id do
    Posts.delete_post!(post)
    {:noreply, stream_delete(socket, :posts, post)}
  else
    {:noreply, put_flash(socket, :error, "Unauthorized")}
  end
end

严格门槛(按顺序)

只有在每个通过条件都客观成立后才能继续(避免在没有证据的情况下报告问题):

门槛通过条件
G1 — 证据中的文件你有明确的待审查路径列表(例如 *.ex、*.heex,或用户指定的路径)。每一项发现都要标明该列表中的文件。
G2 — 验证协议在将某项内容视为发现之前,你已加载 review-verification-protocol,并应用其报告前验证流程(以及相关的问题类型章节)。
G3 — 行号锚点每项发现均使用 [FILE:LINE],且该行确实存在于当前文件中(通过读取或 grep 输出确认,而非推断)。
G4 — 有效模式筛查你已根据有效模式(不要标记)和依上下文而定的规则检查该发现;如果它符合“不要标记”的情形,或不满足“仅在以下情况下标记”的条件,则不要报告。

问题格式

每项发现使用 [FILE:LINE] ISSUE_TITLE。

评论

支持 Markdown