Scripted 中的依賴分析

工程 | Kris De Volder | 2012 年 11 月 20 日 | ...

Scripted,一款 VMware 出品的 JavaScript 編輯器,上個月已在本部落格上宣佈。在本文中,我們將深入探討 Scripted 的依賴分析引擎。但在深入細節之前,先說明一下為何我們需要它。

主要動機:跨檔案內容輔助

為了提供出色的 JavaScript 編輯體驗,Scripted 需要針對您當前編輯器上下文可使用的函式、方法或識別符號提供準確的建議。

[caption id="attachment_12178" align="aligncenter" width="533" caption="跨檔案內容輔助"][/caption]

兩個元件協同工作以實現此目標

  • 細粒度型別推斷分析引擎
  • 粗粒度依賴分析引擎
推斷引擎解析您的程式碼,並遍歷每個宣告、語句和表示式。這使得它能夠確定在給定上下文中哪些識別符號有效,並很好地猜測可能儲存在這些變數中的內容型別。然後,此資訊用於生成內容輔助建議。

如果您想簡單地將所有程式碼放入一個大檔案中,那麼僅一個高質量的推斷器就足以提供相當不錯的內容輔助。實際上,專案會被劃分為模組。在上面的示例中,'main' 模組匯入了一個 'utils' 模組。當您編輯 main 模組時,Scripted 會適當地建議來自 'utils' 的函式。依賴分析引擎使這成為可能。

依賴分析的其他用途

Scripted 還使用依賴分析將未解析的依賴標記為錯誤。例如,如果我們嘗試匯入一個 'bogus' 模組,Scripted 將顯示一個 錯誤標記

[caption id="attachment_12180" align="aligncenter" width="518" caption="未解析模組的錯誤標記"][/caption]

Scripted 還使用依賴分析來支援輕鬆導航。在已解析的依賴名稱上按 Shift 或 Ctrl 鍵並點選,將帶您到相應的檔案。

將來,依賴分析還可能使我們能夠實現重構工具。例如,如果您將 .js 檔案拖放到不同的目錄,Scripted 可以根據需要自動更新相對路徑引用。

它做什麼?

依賴分析引擎僅向其客戶端——型別推斷引擎——提供了一個 getDGraph 函式
getDGraph :: <path-to-js-file> -> <dependency-graph>
此函式計算依賴圖的 JSON 表示。該圖包含目標檔案直接或間接依賴的所有檔案的節點。如果我們向它傳遞我們的 'main' 模組,它將返回如下內容
getDGraph('/sample/main.js') ==>
{
  ...
  "/NODE-NATIVES/stream.js": {
    "kind": "commonjs",
    "refs": { ... }
  },
  "/NODE-NATIVES/fs.js": {
    "kind": "commonjs",
    "refs": {
      "stream": {
        "kind": "commonjs",
        "name": "stream",
        "path": "/NODE-NATIVES/stream.js"
      },
      ...
    }
  },
  "/sample/utils.js": {
    "kind": "commonjs",
    "refs": {}
  },
  "/sample/main.js": {
    "kind": "commonjs",
    "refs": {
      "fs": {
        "kind": "commonjs",
        "name": "fs",
        "path": "/NODE-NATIVES/fs.js"
      },
      "./utils": {
        "kind": "commonjs",
        "name": "./utils",
        "path": "/sample/utils.js"
      }
    }
  }
}
此 JSON 物件中的每個屬性代表圖中的一個節點。'refs' 屬性包含邊。每條邊對應一個模組匯入。

一個有趣的細節是,依賴分析器為原生 Node 模組返回特殊的 path 字串。當推斷引擎請求此類路徑的原始碼時,用 JavaScript 編寫並在 Node.js 上執行的 Scripted 伺服器會從其自身的 Node.js 程序中提取原始碼。推斷引擎就像分析普通 JavaScript 檔案一樣分析它。結果是對內建 Node 模組的良好內容輔助。

[caption id="attachment_12184" align="aligncenter" width="587" caption="內建 Node 模組的推斷建議"][/caption]

支援哪些模組系統?

目前我們僅支援 AMD 和 CommonJS。對於 CommonJS,我們使用 enhanced-resolve 庫來解析對路徑的引用。對於 AMD,我們目前使用自定義的解析器。如果找到符合我們需求的現有庫,我們可能會替換它。

它是如何工作的?

該過程始於目標檔案(即傳遞給 getDGraph 函式的引數)。其大致步驟如下
  1. 檢測模組型別(CommonJS 與 AMD)。
  2. 在目標模組中查詢引用。
  3. 解析引用(即確定將為引用載入的實際檔案的路徑)。
  4. 對每個已解析的引用重複步驟 1 的過程。
步驟 1 基於檢測一些典型的程式碼模式。例如,“一個未巢狀在 'define' 呼叫中的 'require' 呼叫” 是  我們正在處理 CommonJS 模組的標誌。

步驟 2 和 3 根據步驟 1 的模組型別分派給不同的支援模組。新增對其他模組型別的支援應該相對容易(前提是步驟 1 的檢測器能夠識別新的模組型別)。

自動解析器配置

依賴分析器嘗試發現它需要知道的資訊,而不是要求手動配置。這是 Scripted 的一個通用理念,依賴分析器也不例外。事實上,目前無法手動配置依賴分析器或其任何元件,儘管我們將來可能會使其成為可能。

對於 Node/CommonJS,這工作得很好,主要是因為確實沒有太多需要配置的。也就是說,如果我們假定使用標準的 Node.js 載入器演算法,那幾乎就是我們需要的所有資訊。

對於 AMD,情況不幸更復雜。典型的 AMD 載入器(例如 requirejs)是高度可配置的。此外,這種配置在專案原始碼中的表達方式往往因專案而異。這使得在隨機專案中確定在哪裡找到所需資訊成為一個挑戰。

我們採取的方法是檢視一些示例專案及其使用的“典型”模式。發現透過識別這些模式來工作。希望如果我們支援足夠多的常見模式,最終發現將適用於大多數專案。對於那些失敗的情況,我們可能還會新增一些手動配置選項作為最後的手段。

為了瞭解 AMD 如何進行發現,這裡是目前我們檢測到的一種模式的示例

這裡的模式是一個帶有 data-main 屬性的 script 標籤... 如果 Scripted 找到它,它將在 data-main 檔案中尋找 requirejs 風格的配置塊

AMD 配置發現正在進行中。隨著人們如何設定其 AMD 載入器的示例不斷出現,我們正在嘗試為它們新增檢測器。如果 Scripted 錯誤地將許多依賴標記為錯誤,那可能是它未能發現您的 AMD 配置。您可以透過提交錯誤報告來幫助我們。如果您附帶一個程式碼示例來說明您的“典型模式”。這將有助於我們擴充套件“模式目錄”。

結論

我們深入瞭解了 Scripted 的內部。我們介紹了 Scripted 依賴分析引擎。它目前支援 AMD 和 CommonJS 模組系統。依賴分析為型別推斷引擎提供了依賴圖。基於此圖的跨檔案分析使我們能夠為其他模組中定義的功能提供準確的內容輔助建議。依賴資訊還用於為不可解析的模組引用建立錯誤標記,並允許快速導航到已解析的依賴。將來,依賴分析還可能支援實現準確的重構工具來移動或重新命名模組。

想試用 Scripted 嗎?從 GitHub 獲取它。安裝非常簡單。下載和安裝說明位於 readme 檔案中。

連結

獲取 Spring 新聞通訊

訂閱 Spring 新聞通訊,保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速前進。

瞭解更多

獲取支援

Tanzu Spring 透過一份簡單的訂閱,為 OpenJDK™、Spring 和 Apache Tomcat® 提供支援和二進位制檔案。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視全部