fy-convertor
Version:
Convert excel/xml/json/bin/protocl/ts/as ...
216 lines • 8.9 kB
JavaScript
import fs from "fs-extra";
import path from "path";
import xlsx from 'xlsx';
import { JsonStructParser } from "./JsonStructParser.js";
import xml2js from "xml-js";
import { md5 } from "../tools/vendor.js";
import { CharLike, NumberLike, isComplexType } from "./def.js";
import _ from "lodash";
import { toolchain } from "../tools/toolchain.js";
import { SvnHolder } from "./SvnHolder.js";
export class Xls2Xml {
static ins;
static get Instance() {
if (!Xls2Xml.ins)
Xls2Xml.ins = new Xls2Xml();
return Xls2Xml.ins;
}
keyWordMap = {};
async execute() {
if (!toolchain.options.input)
return;
const tmpFolder = toolchain.options.publish ? toolchain.options.project + '_publish' : toolchain.options.project;
const temp = path.join(toolchain.options.workspace, tmpFolder);
const xmlPath = path.join(temp, 'xml');
const xlsPath = path.join(temp, 'xls');
const structPath = path.join(temp, 'struct');
// 更新svn
await SvnHolder.Instance.checkSVN(!toolchain.options.debug, structPath, this.adjustSVN(toolchain.projCfg.Svn.DesignerSvn, toolchain.options.publish) + 'xml');
await SvnHolder.Instance.checkSVN(!toolchain.options.debug, xmlPath, this.adjustSVN(toolchain.projCfg.Svn.DesignerSvn, toolchain.options.publish) + 'bin/Client');
await SvnHolder.Instance.checkSVN(!toolchain.options.debug, xlsPath, this.adjustSVN(toolchain.projCfg.Svn.DesignerSvn, toolchain.options.publish) + 'xls');
await JsonStructParser.Instance.readStructs(structPath, false);
const macros = JsonStructParser.Instance.getMacrosOfFile('KeyWord.xml');
for (const macro of macros) {
this.keyWordMap[macro._attributes.cname] = Number(macro._attributes.value);
}
const xlsFiles = toolchain.options.input.split(',');
for (const x of xlsFiles) {
const xls = path.join(xlsPath, x);
const cinfos = JsonStructParser.Instance.getConvInfosByXls(xls);
if (cinfos.length == 0) {
console.error('no convert info:', xls);
continue;
}
const xlsxBook = xlsx.readFile(xls);
for (const info of cinfos) {
// 由于不支持服务器bin文件生成,故只处理前台表格
if (!info.meta.endsWith('_Flash'))
continue;
const def = JsonStructParser.Instance.getStructDef(info.meta.replace('_Flash', 'M'));
if (!def) {
console.error('no struct def:', info.meta);
continue;
}
const sheets = info.sheet.split(' ');
const arr = [];
for (const s of sheets) {
const sheet = xlsxBook.Sheets[s];
const rows = xlsx.utils.sheet_to_json(sheet, { blankrows: true });
for (const row of rows) {
if (this.isEmptyRow(row)) {
break;
}
const o = this.readRow(row, def);
arr.push(o);
}
}
if (def._attributes.sortkey) {
_.sortBy(arr, def._attributes.sortkey);
}
const doc = this.makeXmlDoc(info, arr);
await fs.writeFile(path.join(xmlPath, path.basename(info.bin.replace('.bin', '.xml'))), doc, 'utf-8');
}
}
// 提交svn
if (!toolchain.options.debug) {
console.log("Committing...");
await SvnHolder.Instance.commitSVN('xls2xml@fy-convertor~', xmlPath);
}
else {
console.log("Debug mode, committing skipped.");
}
}
adjustSVN(raw, publish) {
if (publish) {
raw = raw.replace('trunk', 'branches/publish');
}
return raw;
}
readRow(row, def, prefix = '') {
const o = {};
if (def._attributes.rootflag) {
o._attributes = { version: '1' };
}
else {
o._attributes = { type: def._attributes.__rawName__ };
}
for (const entry of def.entries) {
let arrSize = -1;
if (entry._attributes.refer) {
const referedEntry = def.entries.find(v => v._attributes.name == entry._attributes.refer);
arrSize = Number(row[referedEntry._attributes.cname]) || 0;
}
else if (entry._attributes.count) {
if (entry._attributes.count.match(/^\d+$/)) {
arrSize = Number(entry._attributes.count);
}
else {
const macro = JsonStructParser.Instance.getMacro(entry._attributes.count);
if (!macro) {
console.error('no macro definition:', entry._attributes.count);
process.exit(1);
}
arrSize = Number(macro._attributes.value);
}
}
if (isComplexType(entry._attributes.type)) {
const entryDef = JsonStructParser.Instance.getStructDef(entry._attributes.type);
if (!entryDef) {
console.error('no struct def:', entry._attributes.type);
process.exit(1);
}
if (arrSize >= 0) {
const arr = [];
for (let i = 0; i < arrSize; i++) {
const e = this.readRow(row, entryDef, entry._attributes.cname + (i + 1));
arr.push(e);
}
o[entry._attributes.name] = arr;
}
else {
o[entry._attributes.name] = this.readRow(row, entryDef);
}
}
else {
if (arrSize >= 0) {
const arr = [];
for (let i = 0; i < arrSize; i++) {
const v = this.convertSimpleValue(row[entry._attributes.cname + (i + 1)], entry._attributes.type);
arr.push(v);
}
o[entry._attributes.name] = { _text: arr.join('') };
}
else {
let v = this.convertSimpleValue(row[prefix + entry._attributes.cname], entry._attributes.type);
o[entry._attributes.name] = { _text: v };
}
}
}
return o;
}
convertSimpleValue(v, type) {
if (v == undefined) {
// xml里定了这个字段,但表格里没有对应的列
v = NumberLike.includes(type) ? 0 : '';
}
if (NumberLike.includes(type)) {
if (typeof (v) == 'string') {
const kwv = this.keyWordMap[v];
if (kwv != null) {
v = kwv;
}
else {
v = Number(v) || 0;
}
}
if (typeof (v) == 'number') {
if (CharLike.includes(type)) {
v = '0x' + v.toString(16) + ' ';
}
else {
v = String(v) + ' ';
}
}
}
return v;
}
isEmptyRow(row) {
for (const key in row) {
if (row[key]) {
return false;
}
}
return true;
}
makeXmlDoc(info, arr) {
// var json = '{"name":{"_text":"Ali"},"age":{"_text":"30"}}';
// var options = {compact: true};
// var content = xml2js.json2xml(json, options);
const o = {};
o[info.meta] = arr;
const content = xml2js.js2xml(o, { compact: true, spaces: 4 });
const hash = md5(content);
const doc = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<${info.meta}_Tab>
<TResHeadAll version="5">
<resHead type="TResHead">
<Magic>1397052237 </Magic>
<Version>6 </Version>
<Unit>0 </Unit>
<Count>${arr.length} </Count>
<MetalibHash>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</MetalibHash>
<ResVersion>0 </ResVersion>
<CreateTime> 0-00-00 00:00:00</CreateTime>
<ResEncording>UTF-8</ResEncording>
<ContentHash>${hash}</ContentHash>
</resHead>
<resHeadExt type="TResHeadExt">
<DataOffset>136 </DataOffset>
</resHeadExt>
</TResHeadAll>
${content}
</${info.meta}_Tab>`;
return doc;
}
}
//# sourceMappingURL=Xls2Xml.js.map