Espree 是 ESLint 使用的 JavaScript 解析器,基于 Acorn 实现,结合 Acorn-JSX 插件也可解析 React.js JSX。
Espree 将 JavaScript 解析成 AST ,再将 AST Node 传递给 ESLint rule 获得 report 给开发工具,在代码中错误和不符合规范的地方给予开发者提示。当我们在开发 ESLint 规则时,node 将作为参数获取,用于分析代码风格。
以下是解析一段 js 代码的示例:
// demo.jsconst a = "123";console.log("xxx", a);const jsx = <div className="test">{a}</div>const issueName = { a: 123, b: 123, c: 123 };for (let i = 0; i < 99; i++) {console.log('xxx', i)}if (1 > 0) {console.log('xxx', true)}
// 使用 espree 解析 demo.js 文件import { readFile, writeFile } from "fs/promises";import * as espree from "espree";// 解析成 AST 并保存async function parseSave(code) {const node = espree.parse(code, {ecmaVersion: 11,ecmaFeatures: { jsx: true },})await writeFile("./file/nodeResult.json", JSON.stringify(node, null, 4))}// 解析成 token 并保存async function tokenSave(code) {const token = espree.tokenize(code, {ecmaVersion: 11,ecmaFeatures: { jsx: true },})await writeFile("./file/tokenResult.json", JSON.stringify(token, null, 4))}async function parseFile(filePath) {const file = readFile(filePath, { encoding: "utf-8" })const code = await fileparseSave(code)tokenSave(code)}parseFile('./file/demo.js')
// tokenResult.json 解析为 token 结果(部分)[{"type": "Keyword","value": "const","start": 0,"end": 5},// ...]
// nodeResult.json 解析为 node 结果(部分){"type": "Program","start": 0,"end": 233,"body": [{"type": "VariableDeclaration","start": 0,"end": 16,"declarations": [{"type": "VariableDeclarator","start": 6,"end": 15,"id": {"type": "Identifier","start": 6,"end": 7,"name": "a"},"init": {"type": "Literal","start": 10,"end": 15,"value": "123","raw": "\"123\""}}],"kind": "const"},// ...],"sourceType": "script"}
// VisitorKeys.json AST 中的 node 类型,// 通过 espree.VisitorKeys 获取,// 用于遍历 AST(all visitor keys for traversing the AST){"AssignmentExpression": ["left", "right"],"AssignmentPattern": ["left", "right"],"ArrayExpression": ["elements"],"ArrayPattern": ["elements"],"ArrowFunctionExpression": ["params", "body"],"AwaitExpression": ["argument"],"BlockStatement": ["body"],"BinaryExpression": ["left", "right"],"BreakStatement": ["label"],"CallExpression": ["callee", "arguments"],"CatchClause": ["param", "body"],"ChainExpression": ["expression"],"ClassBody": ["body"],"ClassDeclaration": ["id", "superClass", "body"],"ClassExpression": ["id", "superClass", "body"],"ConditionalExpression": ["test", "consequent", "alternate"],"ContinueStatement": ["label"],"DebuggerStatement": [],"DoWhileStatement": ["body", "test"],"EmptyStatement": [],"ExportAllDeclaration": ["exported", "source"],"ExportDefaultDeclaration": ["declaration"],"ExportNamedDeclaration": ["declaration", "specifiers", "source"],"ExportSpecifier": ["exported", "local"],"ExpressionStatement": ["expression"],"ExperimentalRestProperty": ["argument"],"ExperimentalSpreadProperty": ["argument"],"ForStatement": ["init", "test", "update", "body"],"ForInStatement": ["left", "right", "body"],"ForOfStatement": ["left", "right", "body"],"FunctionDeclaration": ["id", "params", "body"],"FunctionExpression": ["id", "params", "body"],"Identifier": [],"IfStatement": ["test", "consequent", "alternate"],"ImportDeclaration": ["specifiers", "source"],"ImportDefaultSpecifier": ["local"],"ImportExpression": ["source"],"ImportNamespaceSpecifier": ["local"],"ImportSpecifier": ["imported", "local"],"JSXAttribute": ["name", "value"],"JSXClosingElement": ["name"],"JSXElement": ["openingElement", "children", "closingElement"],"JSXEmptyExpression": [],"JSXExpressionContainer": ["expression"],"JSXIdentifier": [],"JSXMemberExpression": ["object", "property"],"JSXNamespacedName": ["namespace", "name"],"JSXOpeningElement": ["name", "attributes"],"JSXSpreadAttribute": ["argument"],"JSXText": [],"JSXFragment": ["openingFragment", "children", "closingFragment"],"Literal": [],"LabeledStatement": ["label", "body"],"LogicalExpression": ["left", "right"],"MemberExpression": ["object", "property"],"MetaProperty": ["meta", "property"],"MethodDefinition": ["key", "value"],"NewExpression": ["callee", "arguments"],"ObjectExpression": ["properties"],"ObjectPattern": ["properties"],"PrivateIdentifier": [],"Program": ["body"],"Property": ["key", "value"],"PropertyDefinition": ["key", "value"],"RestElement": ["argument"],"ReturnStatement": ["argument"],"SequenceExpression": ["expressions"],"SpreadElement": ["argument"],"StaticBlock": ["body"],"Super": [],"SwitchStatement": ["discriminant", "cases"],"SwitchCase": ["test", "consequent"],"TaggedTemplateExpression": ["tag", "quasi"],"TemplateElement": [],"TemplateLiteral": ["quasis", "expressions"],"ThisExpression": [],"ThrowStatement": ["argument"],"TryStatement": ["block", "handler", "finalizer"],"UnaryExpression": ["argument"],"UpdateExpression": ["argument"],"VariableDeclaration": ["declarations"],"VariableDeclarator": ["id", "init"],"WhileStatement": ["test", "body"],"WithStatement": ["object", "body"],"YieldExpression": ["argument"]}
