如何在节点 js 中读取文件,找到函数的所有实例,然后提取每个函数的参数?
How can I read a file in node js, find all instances of a function and then extract each function's argument?
我正在尝试编写一个节点脚本来识别我的 React 项目中未使用的翻译字符串。
首先,我想获得 使用的所有翻译的列表。为此,我在我的 /src/components
文件夹中获取每个 JS 文件的列表,然后读取该文件。
我的翻译字符串如下所示:t('some.translation.key')
,所以基本上,我想使用 RegEx 识别 t('...')
的每个实例,然后获取这些括号之间的键(即“some.translation.key”)。从那里,我应该能够将密钥与我的翻译 JSON 文件中的密钥进行比较,并删除未使用的密钥。
unused.js
const path = require('path');
const fs = require('fs');
let files = [];
//
function getFiles(dir) {
fs.readdirSync(dir).forEach(file => {
const absolute = path.join(dir, file);
if (fs.statSync(absolute).isDirectory()) {
getFiles(absolute);
} else {
if (absolute.includes('.js')) {
files.push(absolute);
}
}
});
return files;
}
function getTranslations() {
const pathComponents = path.join(__dirname, '../../src/components');
// get all js files in components directory
const files = getFiles(pathComponents);
const translationKeys = [];
// for each js file
for(let i = 0; i < files.length; i++) {
// read contents of file
const contents = fs.readFileSync(files[i]).toString();
// search contents for all instances of t('...')
// and get the key between the parentheses
}
}
getTranslations();
如何使用正则表达式在 contents
中查找 t('...')
的所有实例,然后提取括号之间的 ...
字符串?
是的,您可以使用正则表达式:
for (const [, str] of contents.matchAll(/\bt\(['"](.*?)['"]\)/g)) {
console.log('t called with string argument:', str)
}
但是,对于正则表达式,问题在于它们 理解 代码,并且会在匹配包含 ( )
或 [=13 的字符串时出现问题=] 他们自己,在连接字符串或额外空格等方面存在问题,然后您还可以从字面上获取内容,包括可能的转义序列。
一种更可靠的方法是从代码创建一个 AST (abstract syntax tree) 并在其中查找对 t
的调用。
一个流行的 AST 解析器是 acorn. There is also the supplementary module acorn-walk,它可以帮助遍历整个语法树,而无需构建您自己的递归算法。
import acorn from 'acorn'
import walk from 'acorn-walk'
// Example
const contents = "function a () { if (123) { t('hello') } return t('world') }"
// The arguments to acorn.parse would have to be adjusted based
// on what kind of syntax your files can use.
const result = acorn.parse(contents, {ecmaVersion: 2020})
walk.full(result, node => {
if (node.type === 'CallExpression' && node.callee.type === 'Identifier' && node.callee.name === 't') {
if (node.arguments.length === 1 && node.arguments[0].type === 'Literal' && typeof node.arguments[0].value === 'string') {
// This is for the case `t` is called with a single string
// literal as argument.
console.log('t called with string argument:', node.arguments[0].value)
} else {
// In case you have things like template literals as well,
// or multiple arguments, you'd need to handle them here too.
console.log('t called with unknown arguments:', node.arguments)
}
}
})
// Will output:
// t called with string argument: hello
// t called with string argument: world
我正在尝试编写一个节点脚本来识别我的 React 项目中未使用的翻译字符串。
首先,我想获得 使用的所有翻译的列表。为此,我在我的 /src/components
文件夹中获取每个 JS 文件的列表,然后读取该文件。
我的翻译字符串如下所示:t('some.translation.key')
,所以基本上,我想使用 RegEx 识别 t('...')
的每个实例,然后获取这些括号之间的键(即“some.translation.key”)。从那里,我应该能够将密钥与我的翻译 JSON 文件中的密钥进行比较,并删除未使用的密钥。
unused.js
const path = require('path');
const fs = require('fs');
let files = [];
//
function getFiles(dir) {
fs.readdirSync(dir).forEach(file => {
const absolute = path.join(dir, file);
if (fs.statSync(absolute).isDirectory()) {
getFiles(absolute);
} else {
if (absolute.includes('.js')) {
files.push(absolute);
}
}
});
return files;
}
function getTranslations() {
const pathComponents = path.join(__dirname, '../../src/components');
// get all js files in components directory
const files = getFiles(pathComponents);
const translationKeys = [];
// for each js file
for(let i = 0; i < files.length; i++) {
// read contents of file
const contents = fs.readFileSync(files[i]).toString();
// search contents for all instances of t('...')
// and get the key between the parentheses
}
}
getTranslations();
如何使用正则表达式在 contents
中查找 t('...')
的所有实例,然后提取括号之间的 ...
字符串?
是的,您可以使用正则表达式:
for (const [, str] of contents.matchAll(/\bt\(['"](.*?)['"]\)/g)) {
console.log('t called with string argument:', str)
}
但是,对于正则表达式,问题在于它们 理解 代码,并且会在匹配包含 ( )
或 [=13 的字符串时出现问题=] 他们自己,在连接字符串或额外空格等方面存在问题,然后您还可以从字面上获取内容,包括可能的转义序列。
一种更可靠的方法是从代码创建一个 AST (abstract syntax tree) 并在其中查找对 t
的调用。
一个流行的 AST 解析器是 acorn. There is also the supplementary module acorn-walk,它可以帮助遍历整个语法树,而无需构建您自己的递归算法。
import acorn from 'acorn'
import walk from 'acorn-walk'
// Example
const contents = "function a () { if (123) { t('hello') } return t('world') }"
// The arguments to acorn.parse would have to be adjusted based
// on what kind of syntax your files can use.
const result = acorn.parse(contents, {ecmaVersion: 2020})
walk.full(result, node => {
if (node.type === 'CallExpression' && node.callee.type === 'Identifier' && node.callee.name === 't') {
if (node.arguments.length === 1 && node.arguments[0].type === 'Literal' && typeof node.arguments[0].value === 'string') {
// This is for the case `t` is called with a single string
// literal as argument.
console.log('t called with string argument:', node.arguments[0].value)
} else {
// In case you have things like template literals as well,
// or multiple arguments, you'd need to handle them here too.
console.log('t called with unknown arguments:', node.arguments)
}
}
})
// Will output:
// t called with string argument: hello
// t called with string argument: world