
- 那么具体这个jscodeshift 是怎么去修改源代码的
在 generate
函数中,将节点类型直接转换为代码的过程是通过一个 switch
语句实现的。switch
语句根据节点类型的不同,生成相应的代码字符串。
例如,对于一个标识符节点,generate
函数会生成一个表示标识符名称的字符串,如 foo
。这个过程可以通过以下代码实现:
js
case 'Identifier':
return node.name;
对于一个函数节点,generate
函数会生成一个包含函数名称、参数列表和函数体的字符串,如 function foo(a, b) { return a + b; }
。这个过程可以通过以下代码实现:
js
case 'FunctionDeclaration':
return 'function ' + node.id.name + '(' + generate(node.params) + ') {' +
generate(node.body) + '}';
在这个例子中,generate
函数会递归调用自身来生成函数参数列表和函数体的代码字符串 总之,generate
函数通过一个 switch
语句将节点类型直接转换为代码的过程。根据节点类型的不同,generate
函数会生成相应的代码字符串,并在需要时递归调用自身来生成子节点的代码字符串。 其实还是去判断当前元素节点是什么样的类型然后去返回对应的字符串。
i18n
js
function transform(fileInfo, language) {
const content = fs.readFileSync(fileInfo, {
encoding: "utf-8",
});
const parse = fileInfo.substr(fileInfo.lastIndexOf(".") + 1);
//不同类型解析器
const j = jscodeshift.withParser(parse);
const root = j(content);
const StringLiteralNodes = root.find(j.Literal);
const JsxLiteralNodes = root.find(j.JSXAttribute);
const TemplateLiteralNodes = root.find(j.TemplateElement);
const JsxTextNodes = root.find(j.JSXText);
const callExpressionNodes = root.find(j.CallExpression);
console.log("fileInfo", fileInfo);
// 函数类型检测
callExpressionNodes
?.filter((path) => {
if (path?.value?.callee?.name === "intl") {
intlIndex++;
if (!supplement) {
const noParamsCommonBlock =
path?.node?.arguments?.[0]?.comments?.[0]?.type === "CommentBlock";
const paramsCommonBlock =
path?.node?.arguments?.[0]?.trailingComments?.[0]?.type ===
"CommentBlock";
const i18nId = path?.node?.arguments?.[0]?.value;
const i18nValue = geti18nValue(language, i18nId);
if (!(paramsCommonBlock || noParamsCommonBlock) && i18nValue) {
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
})
.replaceWith((item) => {
const i18nId = item?.node?.arguments?.[0]?.value;
const i18nValue = geti18nValue(language, i18nId);
const locStart = item?.node;
const { loc } = locStart;
if (i18nValue) {
currentReplace(
`${fileInfo}:${loc?.start?.line}:${loc?.start?.column + 1} `,
`(${loc?.start?.line}, ${loc?.start?.line})`,
trimUtils(i18nValue)
);
return `intl('${i18nId}'${"/* "}${i18nValue}${" */"})`;
}
});
// 模板字符串
TemplateLiteralNodes?.filter((path) => {
const { callee, leadingComments } = path?.parentPath?.node;
return (
path?.node?.type === "TemplateElement" &&
chineseRegx.test(trimUtils(path.node?.value?.raw)) &&
!i18nDisabled(callee, leadingComments)
);
}).replaceWith((item) => {
let totalString = "";
// const params = item?.parentPath?.parentPath?.value?.expressions?.[0]?.name;
const totalValue = item?.parentPath?.value;
const { loc } = item?.value;
//拼接模板里面的字符串
totalValue?.forEach((item) => {
if (typeof item === "object") {
if (item?.value) {
totalString += item?.value?.cooked;
}
} else {
totalString += item;
}
});
const value = geti18nIdValue(
language,
trimUtils(item?.value?.value?.cooked),
j
);
chineseInfo(
`${fileInfo}:${loc?.start?.line}:${loc?.start?.column + 1}`,
`(${loc?.start?.line}, ${loc?.start?.column})`,
trimUtils(totalString)
);
chineseIndex(trimUtils(totalString));
if (value) {
return "$" + `{intl(${value})}`;
} else {
return item.value.value.cooked;
}
});
// jsx属性
JsxLiteralNodes?.forEach((path) => {
const leadingCommen = path?.value?.value?.expression;
// 规避掉无需国际化项
const i18nDisabled = leadingCommen?.leadingComments?.some(
(item) => item.type === "CommentBlock" && item.value === "i18n-disable"
);
const { loc } = path.node;
chineseInfo(
`${fileInfo}:${loc?.start?.line}:${loc?.start?.column + 1} `,
`(${loc?.start?.line}, ${loc?.start?.line})`,
trimUtils(path?.node?.value?.raw)
);
if (
path?.node?.value?.type !== "JSXExpressionContainer" &&
chineseRegx.test(trimUtils(path.node?.value?.value))
) {
chineseIndex(trimUtils(path.node?.value?.value));
const jsxContainer = geti18nId(
language,
trimUtils(path.node?.value?.value),
j
);
if (
tesI18nLanguage(trimUtils(path.node?.value?.value), language) &&
!i18nDisabled
) {
// 统计当前替换内容
currentReplace(
`${fileInfo}:${loc?.start?.line}:${loc?.start?.column + 1} `,
`(${loc?.start?.line}, ${loc?.start?.line})`,
trimUtils(path.node?.value?.value)
);
path.node.value = j.jsxExpressionContainer(jsxContainer);
}
}
});
StringLiteralNodes?.filter((path) => {
const { value, leadingComments, loc } = path.node;
const { callee } = path?.parentPath?.node;
chineseIndex(trimUtils(value));
// 函数参数,也不应该被替换
const CallExpressionType =
path?.parentPath?.node?.type === "CallExpression";
// 三元表达式
const conditionType =
path?.parentPath?.node?.type === "ConditionalExpression";
// if 表达式
const ifCondition =
path?.parentPath?.parentPath?.value?.type === "IfStatement";
// switch 表达式
const switchCondition = path?.parentPath?.value?.type === "SwitchCase";
// 排除 jsxText 以及jsx 属性
const jsxTextAttribute =
path?.parentPath?.value?.type === "JSXAttribute" &&
path?.node?.type === "JSXText";
if (conditionType || ifCondition || switchCondition || CallExpressionType) {
uncertainChineseInfo(
`${fileInfo}:${loc?.start.line}:${loc?.start?.column + 1}`,
`(${loc?.start?.line}, ${loc?.start?.column})`,
trimUtils(path?.node?.value)
);
} else if (!i18nDisabled(callee, leadingComments)) {
chineseInfo(
`${fileInfo}:${loc?.start.line}:${loc?.start?.column + 1}`,
`(${loc?.start?.line}, ${loc?.start?.column})`,
trimUtils(path?.node?.value)
);
}
const filternoI18n =
chineseRegx.test(trimUtils(value)) &&
tesI18nLanguage(trimUtils(value), language) &&
!i18nDisabled(callee, leadingComments);
// 规避掉if,switch 语句中的中文,避免被误替换导致异常
return (
!jsxTextAttribute &&
!switchCondition &&
!ifCondition &&
!switchCondition &&
!conditionType &&
filternoI18n &&
!CallExpressionType
);
}).replaceWith((item) => {
const { loc } = item.node;
// 统计当前替换内容
currentReplace(
`${fileInfo}:${loc?.start?.line}:${loc?.start?.column + 1} `,
`(${loc?.start?.line}, ${loc?.start?.line})`,
trimUtils(item?.value?.value)
);
return geti18nId(language, item.value.value, j);
});
// jsx 文本节点
JsxTextNodes?.filter((path) => {
const { loc } = path.node;
chineseInfo(
`${fileInfo}:${loc?.start.line}:${loc?.start?.column + 1}`,
`(${loc?.start?.line}, ${loc?.start?.column})`,
trimUtils(path?.node?.value)
);
chineseIndex(trimUtils(path.node?.value));
return (
chineseRegx.test(trimUtils(path.node?.value)) &&
tesI18nLanguage(trimUtils(path.node?.value), language)
);
}).replaceWith((item) => {
const { loc } = item.node;
const jsxContainer = geti18nId(language, trimUtils(item.node?.value), j);
if (jsxContainer) {
currentReplace(
`${fileInfo}:${loc?.start?.line}:${loc?.start?.column + 1} `,
`(${loc?.start?.line}, ${loc?.start?.line})`,
trimUtils(item?.node?.value)
);
return j.jsxExpressionContainer(jsxContainer);
}
});
if (scan || supplement) {
fs.writeFileSync(
fileInfo,
root.toSource({
quto: "single",
}),
{
encoding: "utf-8",
}
);
}
}