From 374812334decc4953e8135b72f487cb3cde06a8a Mon Sep 17 00:00:00 2001 From: Geequlim Date: Sun, 24 May 2020 23:30:30 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20TypeScript=20=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + README.md | 18 ++- excel-exporter.json | 13 ++- .../ExcelExporterApplication.ts | 2 + .../exporters/TypeScriptExporter.ts | 104 ++++++++++++++++++ 5 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 src/excel-exporter/exporters/TypeScriptExporter.ts diff --git a/.gitignore b/.gitignore index e97b349..3caffac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ dist/ +output/ node_modules/ yarn.lock package-lock.json diff --git a/README.md b/README.md index d4258d9..27f3bb7 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ## 支持将Excel配置表导出为: - [x] JSON 文件 - [x] C# 类型声明 -- [ ] TypeScript 声明文件、类型文件(可用 `instanceof` 进行类型检查) +- [x] TypeScript interface类型声明、class类型定义(可用 `instanceof` 进行类型检查) - [ ] Godot 引擎的 GDScript 脚本文件 ## 表格格式说明 @@ -42,8 +42,7 @@ npm run build ```json { "input": [ - { "file": "装备表.xlsx", "encode": "GBK"}, - { "file": "关卡表.xlsx", "encode": "GBK"}, + { "file": "配置表.xlsx", "encode": "GBK"} ], "parser": { "first_row_as_field_comment": true @@ -51,16 +50,25 @@ npm run build "output": { "json": { "enabled": true, - "directory": "../../client/Assets/Resources/data/json", + "directory": "output/json", "indent": "\t" }, "csharp": { "enabled": true, - "directory": "../../client/Assets/Resources/data/csharp", + "directory": "output/csharp", "namespace": "game.data", "base_type": "tiny.data.UniqueIDObject", "file_name": "data", "ignore_id": true + }, + "typescript": { + "enabled": true, + "declaration": false, + "type": "class", + "class_name_prefix": "", + "class_name_extension": "Data", + "directory": "output/typescript", + "file_name": "data" } } } diff --git a/excel-exporter.json b/excel-exporter.json index 03eb2be..5efbf23 100644 --- a/excel-exporter.json +++ b/excel-exporter.json @@ -8,16 +8,25 @@ "output": { "json": { "enabled": true, - "directory": "../../client/Assets/Resources/data/json", + "directory": "output/json", "indent": "\t" }, "csharp": { "enabled": true, - "directory": "../../client/Assets/Resources/data/csharp", + "directory": "output/csharp", "namespace": "game.data", "base_type": "tiny.data.UniqueIDObject", "file_name": "data", "ignore_id": true + }, + "typescript": { + "enabled": true, + "declaration": false, + "type": "class", + "class_name_prefix": "", + "class_name_extension": "Data", + "directory": "output/typescript", + "file_name": "data" } } } \ No newline at end of file diff --git a/src/excel-exporter/ExcelExporterApplication.ts b/src/excel-exporter/ExcelExporterApplication.ts index de42d16..cae8ca2 100644 --- a/src/excel-exporter/ExcelExporterApplication.ts +++ b/src/excel-exporter/ExcelExporterApplication.ts @@ -4,6 +4,7 @@ import { ExporterConfigs, TableExporter } from "./TableExporter"; import { JSONExporter } from "./exporters/JSONExporter"; import { CSharpExporter } from "./exporters/CSharpExporter"; import * as colors from "colors"; +import { TypeScriptExporter } from "./exporters/TypeScriptExporter"; export interface Configurations { /** 解析配置 */ @@ -18,6 +19,7 @@ export interface Configurations { const exporters: {[key:string]: new(config: ExporterConfigs) => TableExporter } = { json: JSONExporter, csharp: CSharpExporter, + typescript: TypeScriptExporter, } diff --git a/src/excel-exporter/exporters/TypeScriptExporter.ts b/src/excel-exporter/exporters/TypeScriptExporter.ts new file mode 100644 index 0000000..12ff4c8 --- /dev/null +++ b/src/excel-exporter/exporters/TypeScriptExporter.ts @@ -0,0 +1,104 @@ +import { TableExporter, ExporterConfigs } from "excel-exporter/TableExporter"; +import { TableData, DataType } from "excel-exporter/TableParser"; +import * as colors from "colors"; +import { path } from "tiny/path"; + +interface TypeScriptExporterConfigs extends ExporterConfigs { + type: "interface" | "class", + declaration: boolean, + file_name: string, + class_name_prefix: string, + class_name_extension: string, +} + +export class TypeScriptExporter extends TableExporter { + + classes: string[] = []; + + constructor(configs: TypeScriptExporterConfigs) { + super(configs); + configs.class_name_prefix = configs.class_name_prefix || ""; + configs.class_name_extension = configs.class_name_extension || ""; + } + + export (name: string, table: TableData) { + this.export_table( + name, + table, + (this.configs as TypeScriptExporterConfigs).type, + (this.configs as TypeScriptExporterConfigs).declaration, + ); + } + + protected export_table(name: string, table: TableData, export_type: "class" | "interface", declaration: boolean) { + let configs = (this.configs as TypeScriptExporterConfigs); + let class_name = `${configs.class_name_prefix}${name}${configs.class_name_extension}`; + + let body = ""; + for (const field of table.headers) { + let type = "any"; + switch (field.type) { + case DataType.bool: + type = "boolean"; + case DataType.string: + type = "string"; + break; + case DataType.float: + case DataType.int: + type = "number"; + break; + default: + type = "any"; + break; + } + if (field.is_array) { + type += "[]"; + } + if (field.comment) { + if (field.comment.trim().length) { + let comments = field.comment.split("\n"); + if (comments.length > 1) { + body += this.line("/** ", 1); + for (const comment of comments) { + body += this.line(" * " + comment.trim() + " ", 1); + } + body += this.line(" */", 1); + } else { + body += this.line(`/** ${comments[0].trim()} */`, 1); + } + } + } + body += this.line(`${field.name}: ${type};`, 1); + } + if (export_type == "class" && !declaration) { + body += this.line(); + body += this.line(`static $bind_rows(rows: object[]) {`, 1); + body += this.line(`for (const row of rows) {`, 2); + body += this.line(`Object.setPrototypeOf(row, ${class_name}.prototype);`, 3); + body += this.line("}", 2); + body += this.line("}", 1); + } + let export_method = declaration ? "declare" : "export"; + let class_text = this.line(`${export_method} ${export_type} ${class_name} {\n${body}\n}`); + this.classes.push(class_text); + } + + finalize() { + let configs = (this.configs as TypeScriptExporterConfigs); + const extension = configs.declaration ? ".d.ts" : ".ts"; + let class_text = this.line("// Tool generated file DO NOT MODIFY"); + class_text += this.line(); + + for (const cls of this.classes) { + class_text += cls; + class_text += this.line(); + } + let file = path.join(this.configs.directory, (this.configs as TypeScriptExporterConfigs).file_name); + if (!file.endsWith(extension)) { + file += extension; + } + this.save_text(file, class_text); + console.log(colors.green(`\t${file}`)); + } + +} \ No newline at end of file