Skip to content

影響範圍 —— blueprint deps

blueprint deps 在動任何 unit 之前,先回答一個問題:改這個 unit,會波及誰?
它是唯讀指令,除了 blueprint config 本身不需要任何額外設定,也不會寫入任何檔案。

它與 blueprint inspect 的分工:
inspect 負責裁決架構(違規、循環相依、exit code 1),
deps 只負責描述 —— 逐 unit 列出被誰引用、引用了誰,不做任何判定。

兩者讀的是同一張圖,而那張圖是從原始碼文字掃出來的,不是解析 AST —— 見 import graph 是怎麼讀出來的
算出來的 import(path) 不會出現在被引用次數裡,所以影響範圍要當成下限看,不是精確值。
deps 的每一種輸出都會以那段說明收尾。

操作方式

bash
npx @kekkai/blueprint deps                      # 全 unit 排行:依被引用數排序
npx @kekkai/blueprint deps hooks/useCart        # 以 unit key 查詢單一 unit
npx @kekkai/blueprint deps src/hooks/useCart/useCart.ts   # 以檔案路徑查詢,結果相同

三種輸入形式都會解析為相同的 unit key ——
是否帶有 src/ 前綴、是否附上副檔名,均不影響查詢結果。

  • --json —— 輸出機器可讀格式(供工具或 AI Agent 使用)
  • --framework vue|react —— 專案無 config 且框架無法自動判定時,強制指定 preset

輸出結果

不帶參數 —— 影響範圍排行榜。
所有 unit 依「被多少 unit 匯入」排序,異動風險最高的 unit 列於最上方:

Blast radius (imported-by count):
  2 ← hooks/useCart
  1 ← services/api
  0 ← containers/Cart
  0 ← pages/Home
  (outside the declared architecture, invisible to deps: legacy/)

指定 unit —— 同時呈現上下游兩個方向。
imported by 為異動此 unit 的影響範圍;imports 為此 unit 所依賴的對象:

hooks/useCart
  imported by (2):
    ← containers/Cart
    ← pages/Home
  imports (1):
    → services/api

加上 --json —— 相同資料的結構化形式。
排行榜的輸出結構為 { units, skipped };單一 unit 查詢則回傳該 unit 物件:

json
{
  "unit": "hooks/useCart",
  "importedBy": ["containers/Cart", "pages/Home"],
  "imports": ["services/api"]
}

查詢不存在的 unit 時,以 exit code 1 結束,並提示可以跑排行榜列出所有 unit;
查詢成功則以 exit code 0 結束。

查詢粒度 —— 由 layer.layout 決定

每個查詢結果的單位是 unit,其界定方式由各 layer 的 layout 決定:

  • folder 佈局 —— 分層之下的每個直屬子項各自成為一個 unit(hooks/useCartcomponents/HelloWorld)。
    直屬檔案的 unit key 不含副檔名,因此 deps components/HelloWorldcomponents/HelloWorld.vue 指向同一個 unit。
  • file 佈局 —— 保留原 flat 佈局行為,整個分層收斂為單一節點
    此佈局適用於「巢狀資料夾只用來整理檔案,而非宣告 unit」的分層 —— 例如 styles/themes/dark.ts 仍可歸入同一個 styles 節點。
    粒度切換時,deps 會明確標示,不會無聲改變回答的層級:
styles (file-layout layer — answers at layer granularity)

相依圖的涵蓋範圍與邊界

  • 僅涵蓋已宣告的分層。
    layer-first 設定中,architecture.layers 以外的資料夾不會納入相依圖;排行榜會將其列為略過項目(如上例的 legacy/),避免把「未被掃描」誤讀為「沒有任何 unit 引用」。
    module-first 設定則以 architecture.modules 為外層邊界,且每個 module 的內層資料夾必須位於共用的 architecture.layers 清單中。外層或內層不在契約裡的資料夾都會列為略過;查詢時會直接說明原因:✗ "legacy/" is outside the declared architecture
  • 測試檔案排除在外architecture.testFiles)——
    測試對 unit 的匯入不算進影響範圍,跟 lint 側的行為一致。
    這件事只成立到 glob 掃得到的範圍 ——
    掃到、而且沒有一條 glob 對得上的測試檔,兩邊都算一般原始碼,它的匯入就會被計入。
  • 僅有別名匯入與相對路徑匯入會構成相依邊。
    套件匯入(axiosvue)不屬於 unit 相依圖 —— 套件的所有權檢核屬於 inspect 的職責。
  • 循環相依僅如實列出,不作裁決。
    兩個互相匯入的 unit,會分別出現在彼此的上下游清單中;裁決屬於 inspect 的職責。

config 驗證

手寫、沒包 defineBlueprintblueprint.config.mjs,載入時一樣會跑完整驗證。
結構性錯誤會立刻以精確訊息回報,而不是在指令跑到一半時炸出一個難以定位的例外:

✗ blueprint.config.mjs: architecture.module is retired in Blueprint 4.0 — move layout and entry onto each layer.