Skip to content

Commit

Permalink
Feat: 增加 ast 解析目录
Browse files Browse the repository at this point in the history
  • Loading branch information
pandaoh committed Oct 31, 2024
1 parent a877723 commit 59a1740
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 3 deletions.
17 changes: 15 additions & 2 deletions bin/xcmd.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @Author: HxB
* @Date: 2022-04-25 16:27:06
* @LastEditors: DoubleAm
* @LastEditTime: 2024-10-30 14:31:25
* @LastEditTime: 2024-10-31 18:20:12
* @Description: 命令处理文件
* @FilePath: \js-xcmd\bin\xcmd.js
*/
Expand Down Expand Up @@ -32,6 +32,7 @@ const {
} = require('../utils/files');
const { cmd } = require('../utils/cmd');
const { node2es6, sortJSON, mergeObj, versionUpgrade, isValidJson, jsonToExcel } = require('../utils/tools');
const { extractParamsFromFiles } = require('../utils/ast');
const nodeCmd = require('node-cmd');
const readline = require('readline');

Expand Down Expand Up @@ -730,14 +731,26 @@ program
console.error('输入的内容不是有效的JSON格式');
}
});
} else {
} else if (`${jsonFilePath}`?.toLowerCase()?.includes('.json')) {
const filePath = getResolvePath(jsonFilePath);
const jsonData = getJSONFileObj(filePath);
if (jsonData) {
jsonToExcel(projectCode, jsonData);
} else {
console.error('JSON 文件中的内容不是有效的 JSON 格式');
}
} else {
const filePath = getResolvePath(jsonFilePath);
const listData = extractParamsFromFiles(filePath);
if (!listData) {
console.error('读取文件失败');
return;
}
const jsonData = {};
listData?.forEach((i) => {
jsonData[i] = i;
});
jsonToExcel(projectCode, jsonData);
}
});

Expand Down
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "js-xcmd",
"version": "1.5.11",
"version": "1.5.12",
"description": "XCmd library for node.js.",
"main": "main.js",
"bin": {
Expand Down Expand Up @@ -30,6 +30,11 @@
},
"homepage": "https://github.com/biugle/js-xcmd#readme",
"dependencies": {
"@babel/core": "^7.26.0",
"@babel/parser": "^7.26.2",
"@babel/plugin-proposal-decorators": "^7.25.9",
"@babel/preset-env": "^7.26.0",
"@babel/traverse": "^7.25.9",
"commander": "^9.2.0",
"download-git-repo": "^3.0.2",
"fs-extra": "^11.2.0",
Expand Down
87 changes: 87 additions & 0 deletions utils/ast.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
const fs = require('fs');
const path = require('path');
const { parse } = require('@babel/parser');
const traverse = require('@babel/traverse').default;

/**
* 提取指定函数调用中的字符串参数
* @param {string} targetPath - 文件或目录路径
* @param {string[]} functionNames - 函数名称列表
* @returns {string[]} 提取出的参数集合
*/
function extractParamsFromFiles(targetPath, functionNames = ['t', '$t']) {
console.log('Reading', targetPath);
try {
const params = new Set();

/**
* 提取字符串参数(包括模板字符串)
* @param {object} arg - AST节点参数
*/
function extractStringArg(arg) {
if (arg.type === 'StringLiteral') {
params.add(arg.value);
} else if (arg.type === 'TemplateLiteral') {
arg.quasis.forEach((quasi) => params.add(quasi.value.raw));
}
}

/**
* 解析文件内容并提取函数调用中的参数
* @param {string} filePath - 文件路径
*/
function parseFile(filePath) {
const code = fs.readFileSync(filePath, 'utf-8');
const ast = parse(code, { sourceType: 'module', plugins: ['jsx', 'typescript', 'decorators'] });

traverse(ast, {
CallExpression({ node }) {
const { callee, arguments: args } = node;
const isTargetFunction =
(callee.type === 'Identifier' && functionNames.includes(callee.name)) ||
(callee.type === 'MemberExpression' && functionNames.includes(callee.property.name));

if (isTargetFunction && args.length) {
const arg = args[0];
if (['StringLiteral', 'TemplateLiteral', 'ConditionalExpression'].includes(arg.type)) {
arg.type === 'ConditionalExpression'
? [arg.consequent, arg.alternate].forEach(extractStringArg)
: extractStringArg(arg);
}
}
}
});
}

/**
* 递归解析目录或文件
* @param {string} target - 目标路径
*/
function parseDirectoryOrFile(target) {
const stats = fs.statSync(target);
if (stats.isDirectory()) {
fs.readdirSync(target).forEach((file) => parseDirectoryOrFile(path.join(target, file)));
} else if (stats.isFile() && /\.(js|ts|tsx|jsx)$/.test(target)) {
parseFile(target);
}
}

parseDirectoryOrFile(targetPath);
return [...params].filter(Boolean);
} catch (e) {
console.error('Error occurred:', e);
return null;
}
}
module.exports = { extractParamsFromFiles };

// 示例用法
// const targetPath = process.argv[2];

// if (!targetPath) {
// console.error('Please provide a target directory or file path');
// process.exit(1);
// }

// const allParams = extractParamsFromFiles(targetPath);
// console.log('All params:', allParams, 'Total params count:', allParams.length);

0 comments on commit 59a1740

Please sign in to comment.