401 lines
13 KiB
JavaScript
401 lines
13 KiB
JavaScript
// Excel2Json.js
|
||
//
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const nodeXlsx = require('node-xlsx');
|
||
const typeFile = 'D:\\Jenkins\\fishClient\\fishClient\\config.d.ts'
|
||
|
||
let FileTarget = {
|
||
General: 0,
|
||
Client: 1,
|
||
Server: 2
|
||
};
|
||
|
||
let MainRun = {
|
||
sourceFile: process.argv[2],
|
||
clientFile: process.argv[3],
|
||
serverFile: process.argv[4],
|
||
options: process.argv[5],
|
||
sourceDir: '',
|
||
typeMap: {},
|
||
|
||
start() {
|
||
|
||
// 非绝对路径则加上当前目录
|
||
if (this.sourceFile && !path.isAbsolute(this.sourceFile)) {
|
||
this.sourceFile = path.join(__dirname, this.sourceFile);
|
||
}
|
||
if (this.clientFile && !path.isAbsolute(this.clientFile)) {
|
||
this.clientFile = path.join(__dirname, this.clientFile);
|
||
}
|
||
if (this.serverFile && !path.isAbsolute(this.serverFile)) {
|
||
this.serverFile = path.join(__dirname, this.serverFile);
|
||
}
|
||
|
||
if (!this.options || this.options != '-add') {
|
||
this.delAllFiles(this.clientFile);
|
||
this.delAllFiles(this.serverFile);
|
||
}
|
||
|
||
this.traversalDir(this.sourceFile, this.clientFile, this.serverFile);
|
||
|
||
},
|
||
|
||
traversalDir(srcDir, clientDir, serverDir) {
|
||
if (!srcDir || !fs.existsSync(srcDir)) {
|
||
console.error("invalid srcDir=" + srcDir);
|
||
return;
|
||
}
|
||
|
||
this.sourceDir = srcDir;
|
||
let files = fs.readdirSync(srcDir);
|
||
for (let i = 0, len = files.length; i < len; i++) {
|
||
let file = files[i];
|
||
if (file.indexOf('~$') === 0 || (file.indexOf('.xlsx') < 0 && file.indexOf('.xlsm') < 0)) {
|
||
continue; // 排除无效文件
|
||
}
|
||
|
||
let curPath = path.join(srcDir, file);
|
||
|
||
let stats = fs.statSync(curPath);
|
||
if (stats.isDirectory()) {
|
||
this.traversalDir(curPath, clientDir, serverDir);
|
||
continue;
|
||
}
|
||
|
||
this.readExcelFile(curPath, clientDir, serverDir);
|
||
}
|
||
|
||
if (fs.existsSync(typeFile)) {
|
||
let str = JSON.stringify(this.typeMap)
|
||
str = str.replace('{', 'declare type ')
|
||
str = str.replace(/-/g, '')
|
||
str = str.replace(/"/g, '')
|
||
str = str.replace(/(int)/g, 'number')
|
||
str = str.replace(/(float)/g, 'number')
|
||
str = str.replace(/},/g, '}\ndeclare type ')
|
||
str = str.replace(/(:{)/g, ' = {')
|
||
str = str.substr(0, str.length - 1)
|
||
|
||
fs.writeFileSync(typeFile, str)
|
||
}
|
||
},
|
||
|
||
// 一个Excel文件可能包含N张表
|
||
readExcelFile(srcFile, clientDir, serverDir) {
|
||
if (!srcFile || !fs.existsSync(srcFile)) {
|
||
console.error('readExcelFile: invalid file path');
|
||
return;
|
||
}
|
||
|
||
let sheetArr = nodeXlsx.parse(srcFile);
|
||
for (let i = 0, len = sheetArr.length; i < len; i++) {
|
||
let sheet = sheetArr[i];
|
||
let sheetName = this.getSheetName(sheet);
|
||
if (!sheetName || sheetName.length <= 0) {
|
||
console.error('sheet is invalid. name=' + sheet.name);
|
||
continue;
|
||
}
|
||
|
||
try {
|
||
let outData = {};
|
||
let csArr = this.lowerArray(sheet.data[0]);
|
||
let typeArr = this.lowerArray(sheet.data[1]);
|
||
let keyArr = sheet.data[2];
|
||
|
||
if (csArr && csArr[0] === 'key-value') { // key-value表
|
||
outData = this.jsonObjectFromSheet(sheet, csArr, typeArr, keyArr);
|
||
} else if (csArr && csArr[0] === 'language') { // 多语言js文件特殊处理
|
||
let content = this.i18nJsFromSheet(sheet, csArr, typeArr, keyArr);
|
||
let fullPath = path.join(this.sourceDir, 'zh.js');
|
||
if (fullPath && content && content.length > 0) {
|
||
this.writeFile(fullPath, content);
|
||
}
|
||
continue;
|
||
} else { // 普通表
|
||
outData = this.jsonArrayFromSheet(sheet, csArr, typeArr, keyArr);
|
||
}
|
||
|
||
// 输出客户端配置文件
|
||
if (!!clientDir && clientDir.length > 0) {
|
||
let clientFile = path.join(clientDir, sheetName);
|
||
if (outData && outData.clientStr && outData.clientStr.length > 0) {
|
||
let outStr = outData.clientStr.replace(/\\\\n/g, "\\n");
|
||
this.writeFile(clientFile, outStr);
|
||
}
|
||
}
|
||
// 输出服务器配置文件
|
||
if (!!serverDir && serverDir.length > 0) {
|
||
let serverFile = path.join(serverDir, sheetName);
|
||
if (outData && outData.serverStr && outData.serverStr.length > 0) {
|
||
this.writeFile(serverFile, outData.serverStr);
|
||
}
|
||
}
|
||
|
||
} catch (err) {
|
||
console.error('error to convert sheet, name=' + sheet.name + ', err=' + err.message);
|
||
}
|
||
}
|
||
},
|
||
|
||
// 返回Array格式的字符串
|
||
jsonArrayFromSheet(sheet, csArr, typeArr, keyArr) {
|
||
if (!sheet || !csArr || !typeArr || !keyArr) {
|
||
return null;
|
||
}
|
||
|
||
let clientArr = [];
|
||
let serverArr = [];
|
||
|
||
let objKey = this.getSheetName(sheet).replace('Conf', '').replace('.json', '')
|
||
// console.log("-------------sheet----------" + objKey)
|
||
let obj = {}
|
||
|
||
let typesArr = sheet.data[0]
|
||
let valueTypeArr = sheet.data[1]
|
||
let keysArr = sheet.data[2]
|
||
keysArr[0] = keysArr[0].toLowerCase()
|
||
|
||
for (let i = 0; i < typeArr.length; i++) {
|
||
let type = typesArr[i]
|
||
if ('c' == type || 'cs' == type) {
|
||
obj[keysArr[i]] = valueTypeArr[i]
|
||
this.typeMap[objKey] = obj
|
||
}
|
||
}
|
||
|
||
for (let i = 4, len = sheet.data.length; i < len; i++) {
|
||
let data = sheet.data[i];
|
||
if (data.length <= 0 || data[0] == undefined) {
|
||
break; // 碰到空行则直接跳出
|
||
}
|
||
let clientData = {};
|
||
let serverData = {};
|
||
for (let j = 0, len2 = csArr.length; j < len2; j++) {
|
||
if (!this.checkColumnIsValid(csArr[j], typeArr[j], keyArr[j])) {
|
||
break;
|
||
}
|
||
// 第一列表头转换为小写(兼容以前格式)
|
||
let keyName = keyArr[j];
|
||
if (j === 0) {
|
||
keyName = keyName.toLowerCase();
|
||
}
|
||
|
||
let value = this.formatValueByType(data[j], typeArr[j]);
|
||
let target = this.getFileTarget(csArr[j]);
|
||
if (FileTarget.Client === target) {
|
||
clientData[keyName] = value;
|
||
} else if (FileTarget.Server === target) {
|
||
serverData[keyName] = value;
|
||
} else {
|
||
clientData[keyName] = value;
|
||
serverData[keyName] = value;
|
||
}
|
||
}
|
||
|
||
let keys = Object.keys(clientData);
|
||
if (keys.length > 0) {
|
||
clientArr.push(clientData);
|
||
}
|
||
keys = Object.keys(serverData);
|
||
if (keys.length > 0) {
|
||
serverArr.push(serverData);
|
||
}
|
||
}
|
||
|
||
let clientStr = '';
|
||
let serverStr = '';
|
||
if (clientArr && clientArr.length > 0) {
|
||
clientStr = JSON.stringify(clientArr, null, '\t'); // 格式化Json输出
|
||
}
|
||
if (serverArr && serverArr.length > 0) {
|
||
serverStr = JSON.stringify(serverArr, null, '\t'); // 格式化Json输出
|
||
}
|
||
return { clientStr, serverStr };
|
||
},
|
||
|
||
// 返回Object格式的字符串
|
||
jsonObjectFromSheet(sheet, csArr, typeArr, keyArr) {
|
||
if (!sheet || !csArr || !typeArr || !keyArr) {
|
||
return null;
|
||
}
|
||
|
||
let clientObj = {};
|
||
let serverObj = {};
|
||
|
||
// 如果指定了特殊key,则取指定列,否则默认取第1列
|
||
let langIndex = 1;
|
||
if (this.options && this.options.length > 0) {
|
||
let data = sheet.data[2];
|
||
for (let line = 0; line < 10; line++) { // 只遍历前10列
|
||
if (data[line] && data[line] == this.options) {
|
||
langIndex = line;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
for (let i = 4, len = sheet.data.length; i < len; i++) {
|
||
let data = sheet.data[i];
|
||
if (data.length <= 0 || !data[0]) {
|
||
break; // 碰到空行则直接跳出
|
||
}
|
||
|
||
let keyName = data[0];
|
||
let value = this.formatValueByType(data[langIndex], typeArr[1]);
|
||
let target = this.getFileTarget(csArr[1]);
|
||
|
||
if (FileTarget.Client === target) {
|
||
clientObj[keyName] = value;
|
||
} else if (FileTarget.Server === target) {
|
||
serverObj[keyName] = value;
|
||
} else {
|
||
clientObj[keyName] = value;
|
||
serverObj[keyName] = value;
|
||
}
|
||
}
|
||
|
||
let clientStr = '';
|
||
let serverStr = '';
|
||
|
||
let keys = Object.keys(clientObj);
|
||
if (keys.length > 0) {
|
||
clientStr = JSON.stringify(clientObj, null, '\t'); // 格式化Json输出
|
||
}
|
||
keys = Object.keys(serverObj);
|
||
if (keys.length > 0) {
|
||
serverStr = JSON.stringify(serverObj, null, '\t'); // 格式化Json输出
|
||
}
|
||
|
||
return { clientStr, serverStr };
|
||
},
|
||
|
||
// 返回i18n标准的js代码字符串
|
||
i18nJsFromSheet(sheet, csArr, typeArr, keyArr) {
|
||
let outData = this.jsonObjectFromSheet(sheet, csArr, typeArr, keyArr);
|
||
let str = '';
|
||
if (outData && outData.clientStr && outData.clientStr.length > 0) {
|
||
let outStr = outData.clientStr.replace(/\\\\n/g, "\\n");
|
||
str = `if (!window.i18n) {window.i18n = {};}
|
||
if (!window.i18n.languages) {window.i18n.languages = {};}
|
||
window.i18n.languages['zh'] = ` + outStr + ';';
|
||
}
|
||
return str;
|
||
},
|
||
|
||
writeFile(fullPath, content) {
|
||
if (!fullPath || !content) {
|
||
console.error('writeFile: invalid params, path=' + fullPath);
|
||
return;
|
||
}
|
||
|
||
fs.writeFile(fullPath, content, (err) => {
|
||
if (err) {
|
||
console.error('writeFile error: ' + err);
|
||
return;
|
||
}
|
||
// console.log(content);
|
||
//console.log('Success to write file: ' + fullPath);
|
||
});
|
||
},
|
||
|
||
// 删除目录下所有文件(不包含子目录)
|
||
delAllFiles(dir) {
|
||
if (dir && fs.existsSync(dir)) {
|
||
let files = fs.readdirSync(dir);
|
||
files.forEach((file, index) => {
|
||
let curPath = path.join(dir, file);
|
||
if (!fs.statSync(curPath).isDirectory()) {
|
||
fs.unlinkSync(curPath);
|
||
}
|
||
});
|
||
}
|
||
},
|
||
|
||
// 获取有效数组并转换为小写
|
||
lowerArray(data) {
|
||
let arr = [];
|
||
if (!data || data.length <= 0) {
|
||
return arr;
|
||
}
|
||
for (let i = 0, len = data.length; i < len; i++) {
|
||
let str = data[i];
|
||
if (!str || str.length <= 0) {
|
||
break; // 碰到空字符串代表之后的列都不需要,所以直接返回
|
||
}
|
||
arr.push(str.toLowerCase());
|
||
}
|
||
return arr;
|
||
},
|
||
|
||
getFileTarget(cs) {
|
||
let ret = FileTarget.General;
|
||
if (cs === 'c') {
|
||
ret = FileTarget.Client;
|
||
} else if (cs === 's') {
|
||
ret = FileTarget.Server;
|
||
}
|
||
return ret;
|
||
},
|
||
|
||
checkColumnIsValid(cs, type, key) {
|
||
if (!cs || cs.length <= 0) {
|
||
return false;
|
||
}
|
||
if (cs !== 'cs' && cs !== 'c' && cs !== 's') {
|
||
return false;
|
||
}
|
||
if (!type || type.length <= 0) {
|
||
return false;
|
||
}
|
||
if (key == undefined || key.length <= 0) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
|
||
getSheetName(sheet) {
|
||
let name = '';
|
||
if (!sheet.name || sheet.name.length <= 0 || !sheet.data || sheet.data.length <= 0) {
|
||
return name;
|
||
}
|
||
let arr = sheet.name.split('|');
|
||
if (!arr || arr.length !== 2) {
|
||
return name;
|
||
}
|
||
name = 'Conf' + arr[1] + '.json';
|
||
return name;
|
||
},
|
||
|
||
formatValueByType(value, type) {
|
||
let ret = null;
|
||
switch (type) {
|
||
case 'string':
|
||
case 'int[]':
|
||
ret = (value != undefined) ? String(value) : '';
|
||
break;
|
||
case 'int':
|
||
ret = (value != undefined) ? parseInt(value) : 0;
|
||
break;
|
||
case 'float':
|
||
ret = (value != undefined) ? parseFloat(value) : 0;
|
||
ret = this.keepFloat8(ret);
|
||
break;
|
||
default:
|
||
ret = null;
|
||
break;
|
||
}
|
||
return ret;
|
||
},
|
||
|
||
// 保留小数点后8位,输入参数为浮点数
|
||
keepFloat8(num) {
|
||
let ret = Math.round(num * 100000000) / 100000000;
|
||
return ret;
|
||
},
|
||
|
||
};
|
||
|
||
module.exports = MainRun;
|
||
|
||
MainRun.start(); |