commit cc72b5a6b358b551abf5abbbc48efe517edfa40d Author: Vick Scarlet Date: Sun Aug 15 11:01:01 2021 +0800 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e858bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,108 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +excel/ +data/ +view/ \ No newline at end of file diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..021cf75 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,3 @@ +{ + "esversion": 9 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..713b86d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "test", + "program": "${workspaceFolder}/app.js", + "skipFiles": [ + "/**" + ] + }, + { + "type": "node", + "request": "launch", + "name": "convert", + "program": "${workspaceFolder}/util/xlsxTransform.js", + "skipFiles": [ + "/**" + ] + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..49549fc --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# lifeRestart +Game Life Restart diff --git a/package.json b/package.json new file mode 100644 index 0000000..257ea15 --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "name": "xlsx_transform", + "module": "true", + "bin": "convert.js", + "dependencies": { + "xlsx": "^0.17.0" + } +} diff --git a/src/condition.js b/src/condition.js new file mode 100644 index 0000000..bcf11bf --- /dev/null +++ b/src/condition.js @@ -0,0 +1,129 @@ +class Condition { + constructor(prop) { + this._prop = prop; + } + + parse(condition) { + + const conditions = []; + const length = condition.length; + const stack = []; + stack.unshift(conditions); + let cursor = 0; + const catchString = i => { + const str = condition.substring(cursor, i).trim(); + cursor = i; + if(str) stack[0].push(str); + }; + + for(let i=0; i<\!\?=]/); + + const prop = condition.substring(0,i); + const symbol = condition.substring(i, i+=(condition[i+1]=='='?2:1)); + const d = condition.substring(i, length); + + const propData = this.getProp(prop); + const conditionData = d[0]=='['? JSON.parse(d): Number(d); + + switch(symbol) { + case '>': return propData > conditionData; + case '<': return propData < conditionData; + case '>=': return propData >= conditionData; + case '<=': return propData <= conditionData; + case '=': + if(Array.isArray(propData)) + return propData.includes(conditionData); + return propData == conditionData; + case '!=': + if(Array.isArray(propData)) + return !propData.includes(conditionData); + return propData == conditionData; + case '?': + if(Array.isArray(propData)) { + for(const p of propData) + if(conditionData.includes(p)) return true; + return false; + } + return conditionData.includes(propData); + case '!': + if(Array.isArray(propData)) { + for(const p of propData) + if(conditionData.includes(p)) return false; + return true; + } + return !conditionData.includes(propData); + + default: return false; + } + } + + getProp(prop) { + return this.prop.get(prop); + } + + get prop() {return this._prop;} + set prop(p) {this._prop = p;} +} + +export default Condition; \ No newline at end of file diff --git a/src/prop.js b/src/prop.js new file mode 100644 index 0000000..815dad7 --- /dev/null +++ b/src/prop.js @@ -0,0 +1,74 @@ +class Prop { + constructor(initialData) { + this._data = {}; + for(const key in initialData) + this.set(key, initialData[key]); + } + + get(prop) { + switch(prop) { + case 'CHR': + case 'INT': + case 'STR': + case 'MNY': + case 'SPR': + case 'LIF': + case 'TLT': + case 'EVT': + return this._data[prop]; + default: return 0; + } + } + + set(prop, value) { + switch(prop) { + case 'CHR': + case 'INT': + case 'STR': + case 'MNY': + case 'SPR': + case 'LIF': + case 'TLT': + case 'EVT': + this._data[prop] = this.clone(value); + break; + default: return 0; + } + } + + change(prop, value) { + switch(prop) { + case 'CHR': + case 'INT': + case 'STR': + case 'MNY': + case 'SPR': + case 'LIF': + this._data[prop] += value; + break; + case 'TLT': + case 'EVT': + const v = this._data[prop]; + if(value<0) { + const index = v.indexOf(value); + if(index!=-1) v.splice(index,1); + } + if(!v.includes(value)) v.push(value); + break; + default: return; + } + } + + clone(value) { + switch(typeof value) { + case 'object': + if(Array.isArray(value)) return value.map(v=>this.clone(v)); + const newObj = {}; + for(const key in value) newObj[key] = this.clone(value[key]); + return newObj; + default: return value; + } + } +} + +export default Prop; \ No newline at end of file diff --git a/test.js b/test.js new file mode 100644 index 0000000..7d0abb2 --- /dev/null +++ b/test.js @@ -0,0 +1,190 @@ +// const DEFAULT_PROP = { +// CHR: 5, // 颜值 charm CHR +// INT: 5, // 智力 intelligence INT +// STR: 5, // 体质 strength STR +// MNY: 5, // 家境 money MNY +// SPR: 5, // 快乐 spirit SPR +// LIF: 5, // 生命 life LIF +// TLT: [5], // 天赋 talent TLT +// EVT: [5], // 事件 event EVT +// }; + +// debug( +// '(STR<2&MNY>3)|(MNY<2&CHR<2)', +// '(STR<2&MNY>3)', +// '(STR>2&MNY>3)', +// '((((STR>2&MNY>2))))', +// '((((STR>2&MNY>2)|(MNY<2&CHR<2))))', +// '((((STR>2&MNY>2)|(MNY<2&CHR<2)&(STR>2&MNY>3))))', +// '((((STR>2&MNY>2)|(MNY<2&CHR<2))&(STR>2&MNY>3)))', +// 'EVT![1,2,3]', +// 'EVT![1,2]', +// 'EVT?[1,2,3]', +// 'EVT?[1,2]', +// ); + +// function getProp(prop) { +// switch(prop) { +// case 'CHR': +// case 'INT': +// case 'STR': +// case 'MNY': +// case 'SPR': +// case 'LIF': +// case 'TLT': +// case 'EVT': return DEFAULT_PROP[prop]; +// default: return null; +// } +// } + +// function check(condition) { +// const conditions = parseCondition(condition); +// return checkParsedCondition(conditions); +// } + +// function checkParsedCondition(conditions) { +// if(!Array.isArray(conditions)) return checkLogic(conditions); +// if(conditions.length == 0) return true; +// if(conditions.length == 1) return checkParsedCondition(conditions[0]); + +// let ret = checkParsedCondition(conditions[0]); +// for(let i=1; i<\!\?=]/); + +// const prop = condition.substring(0,i); +// const symbol = condition.substring(i, i+=(condition[i+1]=='='?2:1)); +// const d = condition.substring(i, length); + +// const propData = getProp(prop); +// const conditionData = d[0]=='['? JSON.parse(d): Number(d); + +// switch(symbol) { +// case '>': return propData > conditionData; +// case '<': return propData < conditionData; +// case '>=': return propData >= conditionData; +// case '<=': return propData <= conditionData; +// case '=': +// if(Array.isArray(propData)) +// return propData.includes(conditionData); +// return propData == conditionData; +// case '!=': +// if(Array.isArray(propData)) +// return !propData.includes(conditionData); +// return propData == conditionData; +// case '?': +// if(Array.isArray(propData)) { +// for(const p of propData) +// if(conditionData.includes(p)) return true; +// return false; +// } +// return conditionData.includes(propData); +// case '!': +// if(Array.isArray(propData)) { +// for(const p of propData) +// if(conditionData.includes(p)) return false; +// return true; +// } +// return !conditionData.includes(propData); + +// default: return false; +// } +// } + +// function parseCondition(condition) { +// const conditions = []; +// const length = condition.length; +// const stack = []; +// stack.unshift(conditions); +// let cursor = 0; +// const catchString = i => { +// const str = condition.substring(cursor, i).trim(); +// cursor = i; +// if(str) stack[0].push(str); +// }; + +// for(let i=0; i3)|(MNY<2&CHR<2)', + '(STR<2&MNY>3)', + '(STR>2&MNY>3)', + '((((STR>2&MNY>2))))', + '((((STR>2&MNY>2)|(MNY<2&CHR<2))))', + '((((STR>2&MNY>2)|(MNY<2&CHR<2)&(STR>2&MNY>3))))', + '((((STR>2&MNY>2)|(MNY<2&CHR<2))&(STR>2&MNY>3)))', + 'EVT![1,2,3]', + 'EVT![1,2]', + 'EVT?[1,2,3]', + 'EVT?[1,2]', +); + + diff --git a/utils/xlsxTransform.js b/utils/xlsxTransform.js new file mode 100644 index 0000000..1db188f --- /dev/null +++ b/utils/xlsxTransform.js @@ -0,0 +1,91 @@ +import { readFile, writeFile, stat, readdir } from 'fs/promises'; +import * as XLSX from 'xlsx'; +import { join, extname, dirname } from 'path'; + +// const { readFile, writeFile, stat, readdir } = require('fs/promises'); +// const XLSX = require('xlsx'); +// const { join, extname, dirname } = require('path'); + +async function transform(filePath) { + const xlsxFileBuffer = await readFile(filePath); + const xlsx = XLSX.read(xlsxFileBuffer, {type: 'buffer'}); + const sheets = xlsx.Sheets; + + const data = {}; + for(const sheetName in sheets) { + const sheetRawData = sheets[sheetName]; + if(!sheetRawData['!ref']) break; + const rawData = XLSX.utils.sheet_to_json(sheetRawData); + const newData = []; + data[sheetName] = newData; + rawData.shift(); + for(const row of rawData) { + const rowData = {}; + newData.push(rowData) + for(const key in row) { + const cell = row[key]; + if(key.includes(':')) { + const keys = key.split(':'); + const lastKey = keys.pop(); + let temp = rowData; + for(const subKey of keys) + if(!temp[subKey]) temp = temp[subKey] = {}; + temp[lastKey] = cell; + } else if(key.includes('[]')) { + const aKey = key.split('[]')[0]; + if(!rowData[aKey]) rowData[aKey] = [cell]; + else rowData[aKey].push(cell); + } else { + rowData[key] = cell; + } + } + } + } + return data; +} + +async function walk(filePath) { + const xlsxPaths = []; + if(Array.isArray(filePath)) { + for(const subPath of filePath) + xlsxPaths.push(await walk(subPath)); + return xlsxPaths.flat(); + } + const fileStat = await stat(filePath); + if(!fileStat.isDirectory()) { + const ext = extname(filePath); + if( ext=='.xls' || ext=='.xlsx' ) xlsxPaths.push(filePath); + return xlsxPaths; + } + + const dirData = await readdir(filePath); + for(const subPath of dirData) + xlsxPaths.push(await walk(join(filePath, subPath))); + return xlsxPaths.flat(); +} + +async function main() { + const filePaths = process.argv.slice(2); + if(filePaths.length<0) process.exit(0); + const xlsxs = await walk(filePaths); + for(const p of xlsxs) { + const data = await transform(p); + const d = dirname(p); + for(const sheetName in data) { + const savePath = join(d, `${sheetName}.json`); + console.info(`[Transform] XLSX(${p}:${sheetName}) -> JSON(${savePath})`); + await writeFile( + savePath, + JSON.stringify(data[sheetName], null, 4), + ); + } + } + console.info(` +------------------------ +| Transform Complete | +------------------------ +`); + setTimeout(()=>{}, 1000); +} + +main(); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..68b3d70 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,99 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +adler-32@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/adler-32/-/adler-32-1.2.0.tgz#6a3e6bf0a63900ba15652808cb15c6813d1a5f25" + integrity sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU= + dependencies: + exit-on-epipe "~1.0.1" + printj "~1.1.0" + +cfb@^1.1.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/cfb/-/cfb-1.2.0.tgz#6a4d0872b525ed60349e1ef51fb4b0bf73eca9a8" + integrity sha512-sXMvHsKCICVR3Naq+J556K+ExBo9n50iKl6LGarlnvuA2035uMlGA/qVrc0wQtow5P1vJEw9UyrKLCbtIKz+TQ== + dependencies: + adler-32 "~1.2.0" + crc-32 "~1.2.0" + printj "~1.1.2" + +codepage@~1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.14.0.tgz#8cbe25481323559d7d307571b0fff91e7a1d2f99" + integrity sha1-jL4lSBMjVZ19MHVxsP/5HnodL5k= + dependencies: + commander "~2.14.1" + exit-on-epipe "~1.0.1" + +commander@~2.14.1: + version "2.14.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" + integrity sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw== + +commander@~2.17.1: + version "2.17.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== + +crc-32@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" + integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA== + dependencies: + exit-on-epipe "~1.0.1" + printj "~1.1.0" + +exit-on-epipe@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" + integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== + +fflate@^0.3.8: + version "0.3.11" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.3.11.tgz#2c440d7180fdeb819e64898d8858af327b042a5d" + integrity sha512-Rr5QlUeGN1mbOHlaqcSYMKVpPbgLy0AWT/W0EHxA6NGI12yO1jpoui2zBBvU2G824ltM6Ut8BFgfHSBGfkmS0A== + +frac@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b" + integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA== + +printj@~1.1.0, printj@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" + integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== + +ssf@~0.11.2: + version "0.11.2" + resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c" + integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g== + dependencies: + frac "~1.1.2" + +wmf@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da" + integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw== + +word@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961" + integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA== + +xlsx@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/xlsx/-/xlsx-0.17.0.tgz#028176a0140967dcee1817d221678461e47481c8" + integrity sha512-bZ36FSACiAyjoldey1+7it50PMlDp1pcAJrZKcVZHzKd8BC/z6TQ/QAN8onuqcepifqSznR6uKnjPhaGt6ig9A== + dependencies: + adler-32 "~1.2.0" + cfb "^1.1.4" + codepage "~1.14.0" + commander "~2.17.1" + crc-32 "~1.2.0" + exit-on-epipe "~1.0.1" + fflate "^0.3.8" + ssf "~0.11.2" + wmf "~1.0.1" + word "~0.3.0"