目标
export const searchBank = async (payload) => {
const url = `/api/hello/${payload.name}/_fuzzy`
// const url = '/api/v1/hello/' + encodeURIComponent('/123');
// const url = '/api/v1/hello/';
// const url = `/api/v1/hello?jwt=${payload.channelId}`;
try {
const response = await request({
method: 'GET',
// url: `https://apis.hello.com`,
url: `/api/hello?jwt=${jwt}`
});
return response.data;
} catch (error) {
console.log(error);
return false;
}
}
export const fetchTagsLists = () => axios.get(`/api/hello`);
// 暂不支持
//export const fetchTagsLists = () => axios.get('/api/hello');
如上代码,我们的目标就是:
- 接口请求方法内的
url
变量(因地制宜,变量命名可以更改,但变量的意义是请求url
即可); - 直接使用
模版字符串
且包含特定字符串(这个只是筛选条件)的
也就是以下5种情况:
{url: ''}
{url: ``}
var url = '';
var url = ``
`/api/xxx`
为什么要使用 AST
因为 AST 是基于语法词法分析目标代码得到的一个抽象语法树对象,可以准确地找到以上5种情况对应的内容,且可修改(当然,我们现在只是为了统计,并不做修改)。
代码
// babel-core plugin
const getVariableStatement = function (opts, {filename}) {
const _path = path;
if (filename === undefined) {
throw Error('filename 必须填入');
}
return {
visitor: {
VariableDeclaration(path) {
const node = path.node;
if (node.declarations && node.declarations.length > 0) {
const declarations = node.declarations;
const id = declarations[0].id;
const init = declarations[0].init;
const type = init.type;
let name = '';
if ((id && id.name) && (type && type === 'ArrowFunctionExpression')) {
name = id.name;
const basename = _path.basename(filename);
if (result[basename] === undefined) {
result[basename] = {};
}
result[basename][name] = '未知,请确认'
path.traverse({
/*
寻找目标,对应:
`/api/xxx`
*/
TemplateLiteral(path) {
console.log('TemplateLiteral---');
const node = path.node;
if (node.quasis && node.quasis.length > 0) {
let expressions = node.expressions;
const quasis = node.quasis;
let string = '';
if (/(^\/api)/.test(quasis[0].value.raw)) {
quasis.forEach(function(item, index) {
string += item.value.raw;
if (expressions.length >= index + 1) {
if (expressions[index].name) {
string += '${' + expressions[index].name + '}'
} else if (expressions[index].object){
string += '${' + expressions[index].object.name + '.' + expressions[index].property.name + '}'
}
}
})
result[basename][name] = string;
}
}
return ;
},
/*
寻找目标,对应:
url = '' || url = ``
*/
VariableDeclaration(path) {
console.log('---VariableDeclaration')
const node = path.node;
const declarations = node.declarations;
if (declarations.length > 0 && declarations[0].id.name === 'url') {
const init = declarations[0].init;
let string = '';
if (init.value) {
string = init.value;
result[basename][name] = string;
}
if (init.quasis && init.quasis.length > 0) {
let expressions = init.expressions;
const quasis = init.quasis;
let string = '';
if (/(^\/api)/.test(quasis[0].value.raw)) {
quasis.forEach(function(item, index) {
string += item.value.raw;
if (expressions.length >= index + 1) {
if (expressions[index].name) {
string += '${' + expressions[index].name + '}'
} else if (expressions[index].object){
string += '${' + expressions[index].object.name + '.' + expressions[index].property.name + '}'
}
}
})
result[basename][name] = string;
}
}
} else {
return ;
}
},
/*
寻找目标,对应:
url: '' || url: ``
*/
ObjectExpression(path) {
console.log('---ObjectExpression')
const node = path.node;
let string = '';
if (node.properties.length > 0) {
node.properties.forEach(function(item) {
if (item.key && item.key.name === 'url') {
let value = item.value;
if (value.value) {
string = value.value;
} else if (value.quasis) {
const expressions = value.expressions;
value.quasis.forEach(function(item, index) {
string += item.value.raw;
if (expressions.length >= index + 1) {
string += '${' + expressions[index].name + '}'
}
})
}
if (string) {
result[basename][name] = string;
}
}
})
}
}
})
}
}
return ;
}
}
}
}
// 省略其他不相关代码
// plugin 使用
babel.transform(code, {
filename: filePath,
// 如读取的文件是 ts 类型的,则需要添加 @babel/preset-typescript
presets: ["@babel/preset-typescript"],
plugins: [
[getVariableStatement, {
filename: filePath
}]
]
})
以上,我们就很简单地实现了一个 统计接口情况
的 AST
的实践案例。