oak-cli/config/babel-plugin/oakI18n.js

206 lines
8.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const fs = require('fs');
const { relative, resolve, join } = require('path');
const t = require('@babel/types');
const assert = require('assert');
const { fork } = require('child_process');
const Regex =
/([\\/]*[a-zA-Z0-9_-\w\W]|[\\/]*[a-zA-Z0-9_-\w\W]:)*[\\/](lib|src|es)([\\/]*[a-zA-Z0-9_-])*[\\/](pages|components)+[\\/]/;
const ModuleDict = {};
const ReactNativeProjectDict = {};
const ProcessRecord = {};
function parseFileModuleAndNs(cwd, filename) {
let cwd2 = cwd;
if (cwd.endsWith('native')) {
// react-native环境需要重新定位一下项目根目录
if (ReactNativeProjectDict.hasOwnProperty(cwd)) {
if (ReactNativeProjectDict[cwd]) {
cwd2 = join(cwd, '..');
}
}
else {
const nodeModulePath = join(cwd, '..', 'node_modules');
const packageJsonPath = join(cwd, '..', 'package.json');
if (fs.existsSync(packageJsonPath) && fs.existsSync(nodeModulePath)) {
ReactNativeProjectDict[cwd] = true;
cwd2 = join(cwd, '..');
}
else {
ReactNativeProjectDict[cwd] = false;
}
}
}
const relativePath = relative(cwd2, filename);
if (relativePath.startsWith('node_modules') || relativePath.startsWith('..')) { // 在测试环境下是相对路径
const moduleRelativePath = relativePath
.replace(/\\/g, '/')
.split('/')
.slice(0, 2);
const modulePath = join(cwd2, ...moduleRelativePath);
const moduleDir = moduleRelativePath[1];
let moduleName = ModuleDict[moduleDir];
if (!moduleName) {
const { name } = require(join(modulePath, 'package.json'));
ModuleDict[moduleDir] = name;
moduleName = name;
}
const rel2paths = relative(modulePath, filename)
.replace(/\\/g, '/')
.split('/');
let ns;
switch (rel2paths[1]) {
case 'pages': {
ns = `${moduleName}-p-${rel2paths.slice(2, rel2paths.length - 1).join('-')}`;
break;
}
default: {
assert(rel2paths[1] === 'components', rel2paths.join('//'));
ns = `${moduleName}-c-${rel2paths.slice(2, rel2paths.length - 1).join('-')}`;
break;
}
}
return {
moduleName,
ns,
};
}
else {
let moduleName = ModuleDict['./'];
if (!moduleName) {
const { name } = require(join(cwd2, 'package.json'));
ModuleDict['./'] = name;
moduleName = name;
}
const rel2paths = relative(cwd2, filename)
.replace(/\\/g, '/')
.split('/');
let ns;
switch (rel2paths[1]) {
case 'pages': {
ns = `${moduleName}-p-${rel2paths.slice(2, rel2paths.length - 1).join('-')}`;
break;
}
case 'components': {
ns = `${moduleName}-c-${rel2paths.slice(2, rel2paths.length - 1).join('-')}`;
break;
}
default: {
// 处理web/wechatMp中的数据
assert(rel2paths[1] === 'src');
const p1 = rel2paths[0];
if (p1 === 'web') {
ns = `${moduleName}-w-${rel2paths.slice(2, rel2paths.length - 1).join('-')}`;
}
else if (p1 === 'wechatMp') {
ns = `${moduleName}-wmp-${rel2paths.slice(2, rel2paths.length - 1).join('-')}`;
}
else {
assert(p1.startsWith('wechatMp'));
const iter = parseInt(p1.slice(8), 10);
ns = `${moduleName}-wmp${iter}-${rel2paths.slice(2, rel2paths.length - 1).join('-')}`;
}
break;
}
}
return {
moduleName,
ns,
};
}
}
const oakNsPropName = '#oakNamespace';
const oakModulePropName = '#oakModule';
module.exports = (babel) => {
return {
visitor: {
CallExpression(path, state) {
const { cwd, filename } = state;
const res = resolve(cwd, filename).replace(/\\/g, '/');
// this.props.t/this.t/t
// 处理策略为给第二个参数中加上'#oakNameSpace, #oakModule两个参数告知t模块此文件相应的位置再加以处理寻找
if (
/(pages|components|namespaces)[\w|\W]+(.tsx|.ts|.jsx|.js)$/.test(res)
) {
const { node } = path;
if (
node &&
node.callee &&
((t.isIdentifier(node.callee) &&
node.callee.name === 't') ||
(t.isMemberExpression(node.callee) &&
t.isIdentifier(node.callee.property) &&
node.callee.property.name === 't'))
) {
const { moduleName, ns } = parseFileModuleAndNs(cwd, filename);
const arguments = node.arguments;
// react-native会调用两次这里要保护一下
// 代码看上去可以避免被调用两次rn待测试 by Xc 20240108
const [arg0, arg1] = arguments;
assert(arg0);
if (arg1) {
// 一般是对象,也可能是变量,表达式不予考虑
if (t.isObjectExpression(arg1)) {
const { properties } = arg1;
const oakNsProp = properties.find(
ele => t.isStringLiteral(ele.key) && ele.key.value === oakNsPropName
);
if (!oakNsProp) {
properties.push(
t.objectProperty(t.stringLiteral(oakNsPropName), t.stringLiteral(ns)),
t.objectProperty(t.stringLiteral(oakModulePropName), t.stringLiteral(moduleName))
);
}
}
else if (t.isIdentifier(arg1)) {
arguments.splice(1, 1, t.callExpression(
t.memberExpression(
t.identifier('Object'),
t.identifier('assign')
),
[
arg1,
t.objectExpression(
[
t.objectProperty(t.stringLiteral(oakNsPropName), t.stringLiteral(ns)),
t.objectProperty(t.stringLiteral(oakModulePropName), t.stringLiteral(moduleName))
]
)
]
));
}
else {
// 不处理,这里似乎会反复调用,不知道为什么
}
}
else {
// 如果无参数就构造一个对象传入
arguments.push(
t.objectExpression(
[
t.objectProperty(t.stringLiteral(oakNsPropName), t.stringLiteral(ns)),
t.objectProperty(t.stringLiteral(oakModulePropName), t.stringLiteral(moduleName))
]
)
);
}
}
}
},
},
};
};