Skip to content

Repository files navigation

ECMAScript Syntax Compatibility Analyzer

这个仓库提供一个 Rust 实现的 ECMAScript 语法兼容性分析器。它读取 JavaScript 文件,识别当前代码里实际出现的语法特性,并根据内置的 MDN Browser Compat Data 规则判断这些语法在目标运行时中是否可用。

当前定位是 syntax compatibility,不是完整的 JavaScript 运行时兼容性扫描。因此它会检测 ?.??、class fields、ESM import/export 等语法事实;不会检测 Promise.any()Array.prototype.at()Object.hasOwn() 这类运行时 API。

能力边界

  • 分析 JavaScript 构建产物或源码文件。
  • 自动发现 sourceMappingURL,并支持相邻 .map 文件回退。
  • 支持本地文件 Source Map 和 data URI Source Map。
  • 报告保留 generated 文件位置;Source Map 成功时额外提供 original source 位置。
  • 兼容性数据来自手工校对后的内置静态表,当前同步来源是 MDN Browser Compat Data。

不覆盖的场景:

  • 运行时 API 兼容性。
  • 被构建工具转换掉的原始语法。detector 只能看到输入文件中仍然存在的语法。
  • TypeScript 类型语法。输入应当是可被 JavaScript parser 解析的代码。
  • HTTP Source Map、Source Map response header、index source map、多级 Source Map 链路。

支持的语法特性

当前 detector 共识别 42 种语法特性。表中的“特性标识”与 SyntaxFeatureId 枚举一一对应,是兼容性规则查询和诊断输出使用的稳定标识。

分类 特性标识 语法示例
运算符与表达式 OptionalChaining object?.property
运算符与表达式 NullishCoalescing value ?? fallback
运算符与表达式 LogicalAndAssignment value &&= next
运算符与表达式 LogicalOrAssignment value ||= next
运算符与表达式 NullishCoalescingAssignment value ??= fallback
运算符与表达式 DynamicImport import("./module.js")
运算符与表达式 ImportMeta import.meta.url
运算符与表达式 Await await task
运算符与表达式 PrivateClassFieldIn #value in object
字面量 BigIntLiteral 1n
字面量 TemplateLiteral `hello ${name}`
字面量 NumericSeparator 1_000
函数与参数 ArrowFunction value => value + 1
函数与参数 AsyncFunction async function run() {}
函数与参数 GeneratorFunction function* values() {}
函数与参数 AsyncGeneratorFunction async function* values() {}
函数与参数 DefaultParameter function run(value = 1) {}
函数与参数 RestParameter function run(...values) {}
方法 MethodDefinition { run() {} }class C { run() {} }
方法 AsyncMethod { async run() {} }
方法 AsyncGeneratorMethod { async *run() {} }
方法 ShorthandObjectMethod { run() {} }
Class Class class Example {}
Class PublicClassField class C { value = 1 }
Class PrivateClassField class C { #value = 1 }
Class PrivateClassMethod class C { #run() {} }
Class ClassStaticInitializationBlock class C { static {} }
控制流 ForOf for (const item of items) {}
控制流 ForAwaitOf for await (const item of items) {}
控制流 OptionalCatchBinding try {} catch {}
展开与解构 Spread fn(...args)[...items]
展开与解构 ObjectSpreadProperty { ...source }
展开与解构 Destructuring const { value } = source
展开与解构 ArrayRestDestructuring const [head, ...tail] = values
展开与解构 ObjectRestDestructuring const { value, ...rest } = source
对象字面量 ComputedObjectPropertyName { [key]: value }
对象字面量 ShorthandObjectProperty { value }
ESM ImportStatement import value from "pkg"
ESM ExportStatement export { value }
ESM ExportDefaultStatement export default value
ESM ExportNamespaceStatement export * as ns from "pkg"
ESM ImportAttribute import data from "./x.json" with { type: "json" }

一个语法节点可能产生多条特性记录。例如 async () => {} 会同时记录 ArrowFunctionAsyncFunctionexport default value 会同时记录 ExportStatementExportDefaultStatement

CLI

cargo run -p ecmascript_compatibility -- <generated-js-file> <target> [target...]

示例:

cargo run -p ecmascript_compatibility -- dist/app.js "chrome 60" "safari 13"

CLI 会输出:

  • 输入文件和解析后的 targets。
  • Source Map 文件级状态。
  • Unsupported、Mixed、Unknown 诊断。
  • 每条诊断的 generated 位置和可用的 original source 位置。

Library API

最常用入口是 CompatAnalyzer::analyze_path

use ecmascript_compatibility::CompatAnalyzer;

fn main() -> Result<(), Box<dyn std::error::Error>> {
  let analyzer = CompatAnalyzer::new();
  let targets = analyzer.resolve_targets(["chrome 60", "safari 13"])?;
  let report = analyzer.analyze_path("dist/app.js", &targets)?;

  for diagnostic in report.diagnostics() {
    println!(
      "{:?} at {:?}",
      diagnostic.feature(),
      diagnostic.position()
    );
  }

  Ok(())
}

也可以运行仓库内示例:

cargo run -p ecmascript_compatibility --example analyze_file -- dist/app.js "chrome 60"

更完整的 API 说明见 docs/api-usage.md

Node.js API

仓库提供 napi-rs binding 包。JS 侧调用方负责决定要分析哪些文件, binding 只接收明确文件路径列表并在 native worker 中批量分析:

const { checkFileList } = require("@shined/ecma-compat");

const report = await checkFileList(["dist/app.js", "dist/chunk.js"], ["chrome 60", "safari 13"], {
  cwd: process.cwd(),
});

console.log(report.counts.reportedFiles);
console.log(report.counts.diagnostics);

checkFileList 返回 Promise,并会在 native worker 中并行分析文件。需要限制 worker 数时可以传 parallelism。 默认只返回有诊断的文件;需要保留空诊断文件报告时可以传 includeEmptyReports: true

本地构建 binding:

pnpm --filter @shined/ecma-compat build

数据同步

MDN 数据同步脚本只生成 SyntaxFeatureId 实际引用的条目,不把完整 JavaScript BCD 表写进源码:

node scripts/sync_mdn_bcd.js

同步后需要人工检查生成表和语法特性映射是否符合当前项目边界。

详细流程见 docs/mdn-data-sync.md

验证

cargo fmt --all
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
pnpm --filter @shined/ecma-compat build

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages