ESCheck工具原理解析及增强实现(1):https://developer.aliyun.com/article/1394806
精简实现的运行结果如下,完整源码见Github
小结
- 检测输出的结果相对友好(比较理想的格式),内置了sourcemap解析逻辑
- 不支持html
- 需要额外维护一套规则(相对ECMAScript迭代频率来说,可以接受)
增强实现es-check
综上2个对比,从源码实现反应来看 es-check
的实现更简单,维护成本也相对较低
@sugarat/es-check 也将基于es-check
做1个增强实现,弥补单文件多次检测
,支持HTML
、sourcemap解析
等能力
单文件多次检测
现状:利用acorn.parse
直接对code
进行解析时候,将会直接抛出code
中的一处解析错误
,然后就结束了
那咱们只需要将code
拆成多个代码片段,那这个问题理论上就迎刃而解了
现在的问题就是怎么拆了?
我们这直接简单暴力一点,对AST直接进行节点遍历,然后分别检测每个节点对应的代码是否合法
首先使用latest
版本生成这棵AST
const ast = acorn.parse(code, { ecmaVersion: 'latest' })
接下来使用acorn-walk进行遍历
import * as acornWalk from 'acorn-walk' acornWalk.full(ast, (node, _state, _type) => { // 节点对应的源码 const codeSnippet = code.slice(node.start, node.end) try { acorn.parse(codeSnippet, { ecmaVersion, }) } catch (error) { // 在这里输出错误片段和解析报错原因 console.log(codeSnippet) console.log(error.message) } })
还是以前面的测试代码为例,输出的错误信息如下
var str = 'hello' var str2 = 'world' const varConst = 'const' let varLet = 'let' const arrFun = () => { console.log('hello world'); }
完整demo1代码
部分节点对应的片段可能不完整,会导致解析错误
用于测试的片段如下
const obj = { 'boolean': true, }
这里可以再parse
检测error
前再parse一次latest
用于排除语法错误,额外逻辑如下
let isValidCode = true // 判断代码片段 是否合法 try { acorn.parse(codeSnippet, { ecmaVersion: 'latest' }) } catch (_) { isValidCode = false } // 不合法不处理 if (!isValidCode) { return }
完整demo2代码
此时输出的错误存在一些重复的情况,比如父节点包含子节点的问题代码
,这里做一下过滤
const codeErrorList: any[] = [] acornWalk.full(ast, (node, _state, _type) => { // 节点对应的源码 const codeSnippet = code.slice(node.start, node.end) // 省略重复代码。。。 try { acorn.parse(codeSnippet, { ecmaVersion: '5' } as any) } catch (error: any) { // 与先存错误进行比较 const isRepeat = codeErrorList.find((e) => { // 判断是否是包含关系 return e.start >= node.start && e.end <= node.end }) if (!isRepeat) { codeErrorList.push({ codeSnippet, message: error.message, start: node.start, end: node.end }) } } }) console.log(codeErrorList)
修正后结果如下
ESCheck工具原理解析及增强实现(3) :https://developer.aliyun.com/article/1394821?spm=a2c6h.13148508.setting.17.55964f0ez7IHhI