JavaScript 靜態分析工具

JavaScript靜態程式碼分析:ESLint、TypeScript、Semgrep和安全掃描實用指南

JavaScript 是唯一無所不在的語言:瀏覽器、伺服器端(透過 Node.js)、行動應用程式(透過 React Native)、雲端函數以及邊緣運算。這種無所不在的特性也帶來了品質上的代價。 JavaScript 的動態類型、原型鍊和非同步執行模型使得編寫程式碼變得容易,程式碼在正常情況下可以正常運行,但在條件改變時卻會以不易察覺的方式出現問題。 TypeScript 對此大有裨益,但型別安全性並不等於程式碼品質、安全性或架構健康。靜態分析彌補了這一不足。

為 JavaScript 或 TypeScript 專案選擇合適的靜態分析工具組合並非一蹴可幾。程式碼檢查、安全掃描、類型檢查、死程式碼偵測和架構分析是不同的問題,需要不同的工具類別來解決。如果在需要安全掃描的地方使用程式碼檢查工具,或在需要依賴分析的地方依賴類型檢查,都會導致覆蓋範圍不完整,並造成虛假的自信。本指南中的工具按其功能分類,以便團隊能夠建立一個涵蓋所有品質維度且避免冗餘的技術堆疊。

SMART TS XL 支援企業級 JavaScript 靜態分析

本指南中介紹的所有工具都運行在 JavaScript 的邊界內。 ESLint 分析 JavaScript 檔案。 TypeScript 檢查 TypeScript 專案中的類型定義。 Semgrep 掃描 JavaScript 和 TypeScript 原始程式碼以尋找漏洞模式。 SonarQube 追蹤整個 JavaScript 程式碼庫的品質指標。但它們都無法存取 JavaScript 應用程式以外的系統,也無法存取其所依賴的系統。

SMART TS XL 靜態分析採用相反的方法:它從整個系統出發,並逐步建構到元件層級。對於 JavaScript 而言,這意味著它會將 JavaScript 和 TypeScript 原始程式碼與環境中的所有其他語言(COBOL、JCL、Java、Python、RPG、PL/I、SQL)一起納入考慮,並建立一個統一的交叉引用模型,該模型表示所有這些語言之間的結構關係。例如,一個 JavaScript 模組呼叫一個 REST API,該 API 由一個 Java 服務提供支持,而該服務則從 COBOL 批次程式填入的 DB2 表中讀取資料: SMART TS XL 這張圖包含了所有四個圖層及其相互連接。沒有任何專門的 JavaScript 工具能夠產生這樣的圖像。

具體來說,對於 JavaScript 開發團隊而言: SMART TS XL 提供多種功能,可與程式碼檢查和安全掃描層相輔相成:

跨語言影響分析。 在修改使用企業 API 的 JavaScript 模組之前, SMART TS XL“ 影響分析 識別系統中所有受此變更影響的其他元件,包括用其他語言編寫的元件。團隊在變更實施之前,而不是在生產環境中出現意外故障之後,才能真正了解變更的影響範圍。

系統級死代碼和可達性分析。 Knip 和 ts-prune 在 JavaScript 專案中尋找未使用的匯出項目的位置 SMART TS XL 可以識別系統中任何位置(包括 Java 服務、後端 API 或大型主機程式)沒有呼叫者的 JavaScript 函數和模組。這種系統級死程式碼分析對於 JavaScript 前端與其他語言編寫的後端緊密整合的組織尤其重要。

跨語言邊界的依存關係視覺化。 SMART TS XL“ 程式碼視覺化 產生依賴關係圖,在一個可導航的圖表中顯示 JavaScript 模組如何連接到 Java 服務、COBOL 程式、共享資料庫和外部 API,而不是使用單獨的特定語言的視圖。

適用於異質堆疊的統一品質指標。 向管理階層或合規團隊報告程式碼品質指標的組織可以從涵蓋整個技術堆疊(而不僅僅是 JavaScript 層)的指標中受益。 SMART TS XL“ 靜態程式碼分析 涵蓋 JavaScript 和 TypeScript,具有相同的品質維度、圈複雜度、可維護性指數、依賴耦合度,並在環境中的每種語言中一致應用。

對於獨立開發 JavaScript 應用程式的團隊而言,本指南中的開源和商業工具提供了全面的支援。而對於將 JavaScript 應用程式作為大型企業系統的一個元件來開發的團隊而言, SMART TS XL 提供架構可見性層,使其餘分析能夠在系統層級而不是檔案層級上執行。

林廷試驗與靜態分析:二者有何不同?

這些術語經常被混用,但它們描述的是不同的分析層次。這種區別對於工具的選擇至關重要。

林亭 程式碼檢查工具(linter)是靜態分析的子集,專注於風格一致性、常見錯誤模式和編碼規範的執行。 linter 讀取原始程式碼並標記出與已定義規則集的偏差。 ESLint 是一款 linter。 Biome 是一款 linter-formatter。它們都能捕獲錯誤。 no-unused-vars, no-console以及 prefer-const 違規行為。它們不會追蹤函數呼叫之間的資料流,也不會發現諸如 SQL 注入之類的安全漏洞。

廣義的靜態分析不僅包含程式碼檢查工具的所有功能,還包括更深入的分析:控制流程分析、資料流(污點)分析、呼叫圖建構、類型級推理以及跨檔案和模組的過程間分析。 CodeQL、具有污點模式的 Semgrep 和 SonarQube 等工具都能夠執行這種更全面的靜態分析。它們不僅能發現變數是否被聲明,還能發現需要理解不受信任的資料如何在程式中流動的漏洞。

項目類別發現代表性工具
林亭風格、慣例、常見錯誤ESLint、Biome、OxcLint、StandardJS
類型檢查類型錯誤、類型缺失、類型不匹配TypeScript (TSC)、typescript-eslint
SAST/安全掃描SQL注入、XSS攻擊、原型污染、不安全依賴Semgrep、CodeQL、Snyk Code、SonarQube
死代碼檢測未使用的匯出、無法存取的程式碼、未使用的變數Knip、ts-prune、ESLint no-unused-vars
建築分析依賴關係圖、影響分析、呼叫圖SMART TS XLCodeScene、Sourcetrail

任何成熟的 JavaScript 專案至少應涵蓋前三類。大型或企業級專案應涵蓋全部五類。

ESLint:JavaScript 程式碼檢查的業界標準

幾乎所有 JavaScript 專案都安裝了 ESLint。它是 create-react-app、Next.js、Vite 和大多數企業級腳手架的預設程式碼檢查工具。它的插件生態系統涵蓋了所有主流框架(React、Vue、Angular、Node.js)和語言擴展(TypeScript)。熟練 ESLint 是 JavaScript 開發的先決條件。

打壞

# Install ESLint
npm init @eslint/config@latest

# Run on the project
npx eslint src/

# Auto-fix fixable issues
npx eslint src/ --fix

ESLint v9 和扁平配置ESLint v9 取代了 .eslintrc.* 採用扁平化配置格式 eslint.config.js 文件。這是一項重大變更,影響了許多現有項目。扁平化配置格式更簡潔,移除了級聯繼承系統,並使配置更加明確:

JavaScript的

// eslint.config.js (ESLint v9 flat config)
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";

export default [
  js.configs.recommended,
  ...tseslint.configs.recommended,
  {
    languageOptions: {
      globals: globals.browser,
    },
    rules: {
      "no-unused-vars": "error",
      "no-console": "warn",
      "prefer-const": "error",
    },
  },
];

TypeScript 的 ESLint 需要 typescript-eslint 該軟體包取代了舊版本。 @typescript-eslint/eslint-plugin 以及 @typescript-eslint/parser它提供了 100 多個 TypeScript 特有的規則,而 TSC 並沒有強制執行這些規則:

打壞

npm install --save-dev typescript-eslint

ESLint 安全插件 為 ESLint 新增以安全性為中心的規則,偵測諸如使用以下方式等問題: eval()不安全的正規表示式和原型注入:

打壞

npm install --save-dev eslint-plugin-security

JavaScript的

// eslint.config.js
import security from "eslint-plugin-security";
export default [security.configs.recommended];

ESLint涵蓋的內容程式碼風格,常見錯誤(no-undef, no-unused-vars)、反模式、框架約定和基本安全模式(透過插件)。

ESLint 不涵蓋的內容:跨函數呼叫的資料流/污點分析、跨檔案影響分析、依賴性漏洞、架構映射或非同步特定漏洞模式。

TypeScript:編譯器層級的靜態安全性

TypeScript 編譯器 (TSC) 為 JavaScript 專案執行最強大的靜態分析:它會在每個函數邊界處驗證整個程式碼庫的類型正確性。啟用 strict 模式進入 tsconfig.json 發現的問題數量最多:

JSON

{
  "compilerOptions": {
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "exactOptionalPropertyTypes": true
  }
}

noUnusedLocals 以及 noUnusedParameters 在編譯器層級捕獲未使用的變數和函數參數,這與 ESLint 的功能重疊。 no-unused-vars 但對於 TypeScript 特有的模式要更精確。

typescript-eslint 它彌合了 TypeScript 類型檢查器和 ESLint 規則系統之間的差距。例如,規則如下: @typescript-eslint/no-floating-promises 以及 @typescript-eslint/await-thenable 利用型別資訊來偵測TSC和ESLint單獨都無法捕捉的非同步程式錯誤:

JavaScript的

// eslint.config.js -- typescript-eslint with type-checked rules
import tseslint from "typescript-eslint";

export default tseslint.config(
  ...tseslint.configs.strictTypeChecked,
  {
    languageOptions: {
      parserOptions: {
        project: true,  // enables type-aware rules
        tsconfigRootDir: import.meta.dirname,
      },
    },
    rules: {
      "@typescript-eslint/no-floating-promises": "error",
      "@typescript-eslint/await-thenable": "error",
      "@typescript-eslint/no-misused-promises": "error",
    },
  }
);

這三條規則專門針對本文中 Search Console 資料出現的 async/await 錯誤模式;不正確的 Promise 處理是現代 JavaScript 中最常見的 bug 之一; typescript-eslint 無需單獨的工具即可捕獲它們。

Biome 與 OxcLint:下一代 JavaScript 工具

ESLint 十年來一直是 JavaScript 預設的語法檢查工具。如今,兩款性能大幅提升的新工具正在挑戰其地位。

Biome是一款集 ESLint 和 Prettier 於一體的工具,可在一個二進位檔案中提供程式碼檢查、格式化和匯入組織功能,基本使用無需任何設定。它使用 Rust 編寫,在大型程式碼庫上的運行速度比 ESLint 快 25-35 倍。 Biome 支援 JavaScript、TypeScript、JSX 和 JSON。

打壞

# Install
npm install --save-dev --save-exact @biomejs/biome

# Initialize config
npx @biomejs/biome init

# Check (lint + format check)
npx @biomejs/biome check --write src/

OxcLint(Oxc 專案的一部分)是另一個基於 Rust 的程式碼檢查工具,它提供的規則與 ESLint 相容,執行速度卻快 50-100 倍。它的設計目標是直接取代 ESLint 的核心規則,並允許在程式碼遷移過程中與 ESLint 並行運行,而無需立即完全切換。

打壞

# Install
npm install --save-dev oxlint

# Run
npx oxlint src/

何時使用:對於新項目,Biome 是功能最強大的單工具,可用於程式碼檢查和格式化。對於已有大量 ESLint 配置和外掛程式的現有項目,遷移到 Biome 需要驗證規則覆蓋率。 OxcLint 更適合在大型現有專案中逐步取代 ESLint,因為在這些專案中,插件生態系統無法立即被放棄。

工具速度 vs ESLint取代 PrettierTypeScript 支援插件生態系統
ESLintBaseline否(搭配 Prettier 搭配)透過 typescript-eslint最大的(約 3,000 個插件)
生物群系快 25-35 倍可以內建的有限但不斷成長
奧克林特快 50-100 倍沒有內建的ESLint 相容子集
標準JS與 ESLint 類似局部的有限固定規則集

Semgrep:基於模式的 JavaScript 安全靜態應用語法測試工具

Semgrep 是一款多語言靜態分析安全測試 (SAST) 工具,它透過程式碼模式匹配來發現安全漏洞。與 ESLint 強制執行程式碼風格和規範不同,Semgrep 可以偵測 SQL 注入、XSS、原型污染、硬編碼憑證、不安全的 Express.js 配置以及 JavaScript 和 TypeScript 中數百種其他安全模式。

與 ESLint 的主要區別在於:Semgrep 規則是用程式碼模式編寫的,其語法與目標語言非常相似,因此即使沒有深厚的靜態分析專業知識的開發人員也能閱讀和編寫它們:

雅姆

# Custom Semgrep rule: flag direct use of user input in SQL queries
rules:
  - id: sql-injection-express
    patterns:
      - pattern: |
          $APP.get($ROUTE, ($REQ, $RES) => {
            ...
            $DB.query($REQ.query.$INPUT, ...);
            ...
          })
    message: User input directly used in SQL query -- use parameterized queries
    languages: [javascript, typescript]
    severity: ERROR

打壞

# Run Semgrep with the community security rule registry
semgrep scan --config=p/javascript src/

# Run with a specific rule set for Node.js
semgrep scan --config=p/nodejs src/

Semgrep 與 ESLint:它們是互補的,而非競爭關係。 ESLint 用於程式碼品質和規範,Semgrep 用於安全掃描。大多數 JavaScript 團隊應該在持續整合 (CI) 環境中同時執行這兩個工具。 GitLab 最近宣布將其 SAST 分析器從 ESLint 過渡到 Semgrep,逐步淘汰 ESLint 的安全掃描功能,但保留其程式碼檢查功能。這反映了目前逐漸形成的共識:ESLint 是程式碼檢查的理想工具,而 Semgrep 是安全分析的理想工具。

SonarQube 和 SonarLint:持續品質門

SonarQube 提供了一個品質閘控模型:每個拉取請求都會根據預先定義的品質標準進行評估,如果程式碼不符合閾值,合併請求將被封鎖。對於 JavaScript 和 TypeScript,它可以偵測錯誤、程式碼異味、安全隱患和重複程式碼,並追蹤其隨時間變化的趨勢。

SonarLint是一個 IDE 擴展,它能在開發人員編寫程式碼時在本地顯示 SonarQube 規則,從而實現即時回饋,而無需等待 CI。

SonarQube 相較於純粹的程式碼檢查工具,其價值在於其持續的測量模型:它可以追蹤技術債、程式碼覆蓋率和安全熱點隨時間推移的演變。對於既需要面向開發人員的診斷訊息,又需要管理層級程式碼品質報告的團隊而言,SonarQube 是理想之選。

JavaScript/TypeScript 專案的關鍵配置

  • 設置一個質量門,當出現任何新的阻塞者或關鍵安全熱點時,質量門都會失效。
  • 啟用 Sonar Way 以規則設定檔為基準
  • 在 VS Code 或 IntelliJ 中搭配 SonarLint 使用,可獲得編輯器內回饋
  • 使用以下方式與 GitHub Actions 或 GitLab CI 整合: SonarQube Scan 行動

CodeQL:用於深度漏洞偵測的語意程式碼掃描

CodeQL 由 GitHub 開發,它透過將程式碼轉換為可查詢的資料庫並對其執行查詢來進行語義分析。它支援 JavaScript 和 TypeScript,並且可以透過 GitHub 高級安全計劃免費提供給開源專案使用。

CodeQL 能夠發現那些需要理解資料在整個程式中流動方式的漏洞:例如,使用者控制的值經過多次函數呼叫最終到達不安全的操作。當程式碼路徑較為間接時,CodeQL 可以擷取 Semgrep 等模式匹配工具無法發現的漏洞。

雅姆

# .github/workflows/codeql.yml
name: CodeQL Analysis
on: [push, pull_request]
jobs:
  analyze:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
        with:
          languages: javascript-typescript
      - uses: github/codeql-action/autobuild@v3
      - uses: github/codeql-action/analyze@v3

CodeQL 的設定成本比 Semgrep 更高,運行速度也更慢,但它可以捕捉不同類型的漏洞:跨函數、跨檔案的污點流,這是任何基於模式的工具都無法在不進行完整資料流分析的情況下識別的。

死代碼檢測:未使用的匯出和不可達程式碼

在 JavaScript 和 TypeScript 專案中,死程式碼尤其難以察覺,因為模組系統無法阻止未使用的導出項目不斷累積。一個函數可能會被匯出,但從未被匯入,除非進行專門配置,否則任何標準工具都不會對此發出警告。

剪刀 是目前功能最強大的工具。它會分析整個專案圖,尋找未使用的匯出項和相依性。 package.json以及無法存取的文件:

打壞

npm install --save-dev knip
npx knip

ts-prune專門針對 TypeScript,尋找從未被匯入的已匯出符號:

打壞

npm install --save-dev ts-prune
npx ts-prune

ESLint no-unused-vars 以及 @typescript-eslint/no-unused-vars Knip 可以捕獲檔案中未使用的局部變量,但無法偵測到未使用的模組級導出。 Knip 彌補了 ESLint 的不足。

死程式碼會直接影響前端應用程式的打包大小,並增加開發人員在程式碼庫中工作的認知負荷。移除死程式碼是目前最有效的維護活動之一,而且只能透過工具發現,因為人工審核人員無法可靠地追蹤大型程式碼庫中模組層級的使用情況。

非同步/等待與 Promise:靜態分析的挑戰

本文的 Google Search Console 資料顯示,大量搜尋查詢集中在非同步 JavaScript 靜態分析工具上,例如 TAJS、Jelly 靜態分析器、SonarJS 非同步規則等。這反映出現有工具領域有明顯的不足。

標準的 lint 工具無法模擬 Promise 和非同步函數之間的交互方式。缺少 await未處理的拒絕或並發非同步程式碼中的競態條件在語法上看起來有效,並且通過了所有程式碼檢查規則。偵測這些問題需要能夠模擬非同步執行語意的工具。

目前的實用方法

typescript-eslint 提供最直接有用的非同步特定規則:

JavaScript的

// Rules that catch common async mistakes
"@typescript-eslint/no-floating-promises": "error",    // await or .catch() required
"@typescript-eslint/await-thenable": "error",          // only await actual Promises
"@typescript-eslint/no-misused-promises": "error",     // Promises in non-async contexts
"@typescript-eslint/require-await": "warn",            // async functions must use await

TAJS(JavaScript類型分析器)、Jelly和SAFE等研究工具是學術靜態分析器,它們模擬JavaScript的非同步執行模型,包括Promise鏈、async/await和事件循環語義。這些並非生產開發工具,而是用於漏洞研究和形式化分析的研究平台。在Search Console資料中,關於「jelly static analyzer javascript async support paper」和「TAJS async await support」的查詢反映出開發者正在研究或引用這些學術工具,而不是在尋找日常開發工具。

SonarQube 的 javascript:S4328 相關的非同步規則可以檢測生產品質分析中一些常見的非同步反模式。

對於實際生產應用,TypeScript 的類型檢查器、 typescript-eslintSonarQube 的非同步感知規則和品質閘門提供了當今標準工具中最徹底的非同步安全性覆蓋範圍。

Snyk 代碼:以開發者為先的安全掃描

Snyk Code 提供以開發者體驗為中心的靜態應用安全測試 (SAST) 掃描:它整合到 VS Code 和 JetBrains IDE 中,在開發者編寫程式碼時直接顯示掃描結果,並為每個結果提供相應的修復範例。它使用專有的基於機器學習的分析引擎,可對 JavaScript 和 TypeScript 程式碼庫進行污點追蹤。

打壞

# Install Snyk CLI
npm install --save-dev snyk

# Authenticate and scan
npx snyk auth
npx snyk code test

Snyk Code 對於希望在不離開 IDE 的情況下獲得安全回饋的團隊來說尤其有效。與 CodeQL 以查詢為中心的輸出相比,它的修復建議對開發人員更加友好,因此是漏洞檢測之外進行安全教育的更佳選擇。

建構分層 JavaScript 靜態分析堆疊

正確的 JavaScript 靜態分析方法不是選擇單一工具,而是結合使用能夠涵蓋不同層面且功能重疊度不高的工具:

工具當它運行時
格式化生物群落或更漂亮預提交(快速)
林亭ESLint + typescript-eslint預提交 + CI
類型檢查tsc --noEmitCI
安全掃描Semgrep 或 Snyk 程式碼CI(每個 PR)
深度漏洞掃描代碼QLCI(計劃內或PR)
死代碼檢測剪刀CI(每週或每月)
品質門控 + 趨勢跟踪聲納CI(每個 PR)
依賴項漏洞掃描npm audit + SnykCI(每次建置)

從零開始組建團隊所需的最簡技術堆疊: ESLint + typescript-eslint + npm audit當安全需求增加時,加入 Semgrep 或 Snyk 程式碼。當團隊需要高品質的趨勢視覺化和管理報告時,請添加 SonarQube。

雅姆

# .github/workflows/quality.yml
name: JavaScript Code Quality
on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: "20" }
      - run: npm ci
      - run: npx tsc --noEmit
      - run: npx eslint src/ --max-warnings 0

  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: "20" }
      - run: npm ci
      - run: npm audit --audit-level=high
      - run: npx semgrep scan --config=p/javascript --error src/

當 JavaScript 存在於大型企業系統時

在企業環境中,JavaScript 和 TypeScript 服務越來越多地與 COBOL 程式、Java 後端、Python 資料管道和傳統大型主機系統共存。在這種情況下,上述靜態分析工具雖然能夠提供 JavaScript 邊界內的全面可視性,但卻完全無法辨識跨越邊界的連結。

一個從由 COBOL 批次作業填入的資料庫讀取資料的 Node.js 服務,對該 COBOL 程式存在依賴關係,而這種依賴關係是任何 JavaScript 分析工具都無法察覺的。一個呼叫 Java API 的 React 前端,該 API 又呼叫 COBOL 程序,其依賴鏈跨越了三種語言邊界,而任何單一語言分析工具都無法識別這些依賴關係。

SMART TS XL 它透過提供跨語言的依賴關係分析來解決這個問題,分析範圍涵蓋整個應用程式組合。它建立了一個統一的模型,該模型描述了 JavaScript 模組如何依賴共享資料結​​構、API 契約如何連接前端和後端服務,以及系統中一部分的變更如何傳播到其他語言的元件。這就是 跨語言架構分析 企業架構團隊在規劃跨多種語言和平台的系統變更時需要這種能力,而這種能力是對本指南中 JavaScript 專用工具的補充,而不是與之競爭。正如在以下上下文中所述: 依賴關係圖和應用程式風險在進行變更之前,了解系統的完整依賴結構,是區分安全重構和導致元件出現意外故障(而這些元件是沒人想到要測試的)的變更的關鍵所在。

針對這些大型環境中的 JavaScript 特定分析, SMART TS XL“ 企業程式碼智能 涵蓋 JavaScript 和 TypeScript,以及 COBOL、JCL、Java、Python 和其他企業語言,在單一平台上提供統一的品質指標和依賴關係可見性。

根據實際情況選擇合適的工具

沒有哪一款工具能夠涵蓋 JavaScript 靜態分析的所有面向。選擇哪一款取決於團隊規模、安全需求、現有工具鏈,以及 JavaScript 應用程式是獨立運作還是作為大型多語言企業系統的一部分。

對於獨立開發者或小型團隊的新專案:從 Biome(程式碼檢查和格式化)和 TypeScript 嚴格模式開始。 npm audit 為了依賴項安全。

對於建立生產 Web 應用程式的中型團隊:ESLint(帶 typescript-eslint)、Prettier、TypeScript 嚴格模式、CI 中的 Semgrep 用於安全性,以及 Knip 用於死程式碼偵測。

對於有合規性和安全性要求的企業團隊:SonarQube 用於品質門控和趨勢跟踪,CodeQL 用於深度漏洞掃描,Snyk Code 用於面向開發人員的安全反饋,以及 SMART TS XL 如果 JavaScript 應用程式與舊版或多語言系統互動。

對於一個因效能問題而在單體倉庫中評估 ESLint 替代方案的團隊:OxcLint 是一款注重速度的即插即用工具,而 Biome 則是一款完整的 linter-formatter 替代方案。