fast-cocos 1.0.8 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,284 @@
1
+ #!/usr/bin/env python3
2
+ from fontTools.ttLib import TTFont
3
+ import argparse
4
+ import os
5
+ import re
6
+ import shutil
7
+ import sys
8
+
9
+ # 字体选择标志常量
10
+ FS_SELECTION_BOLD = 0x20
11
+ FS_SELECTION_REGULAR = 0x40
12
+
13
+ # macStyle标志常量
14
+ MAC_STYLE_BOLD = 0x01
15
+
16
+ def get_font_info(font_path):
17
+ """获取字体的原始信息"""
18
+ try:
19
+ font = TTFont(font_path)
20
+ name_table = font['name']
21
+
22
+ info = {
23
+ 'family': None,
24
+ 'subfamily': None,
25
+ 'fullname': None,
26
+ 'postscript': None,
27
+ 'weight': 400
28
+ }
29
+
30
+ # 获取字体信息
31
+ for record in name_table.names:
32
+ if record.nameID == 1: # Family name
33
+ info['family'] = record.toUnicode()
34
+ elif record.nameID == 2: # Subfamily
35
+ info['subfamily'] = record.toUnicode()
36
+ elif record.nameID == 4: # Full name
37
+ info['fullname'] = record.toUnicode()
38
+ elif record.nameID == 6: # PostScript name
39
+ info['postscript'] = record.toUnicode()
40
+
41
+ # 获取字重
42
+ if 'OS/2' in font:
43
+ info['weight'] = font['OS/2'].usWeightClass
44
+
45
+ font.close()
46
+ return info
47
+ except Exception as e:
48
+ print(f"获取字体信息失败: {e}")
49
+ return {
50
+ 'family': 'Unknown',
51
+ 'subfamily': 'Regular',
52
+ 'fullname': 'Unknown Regular',
53
+ 'postscript': 'Unknown-Regular',
54
+ 'weight': 400
55
+ }
56
+
57
+ def detect_weight_from_font(font_path):
58
+ """从字体文件的OS/2表获取实际字重"""
59
+ try:
60
+ font = TTFont(font_path)
61
+ weight = 400 # 默认
62
+
63
+ if 'OS/2' in font:
64
+ weight = font['OS/2'].usWeightClass
65
+
66
+ font.close()
67
+ except Exception as e:
68
+ print(f"读取字体文件失败: {e}")
69
+ weight = 400
70
+ raise
71
+
72
+ # 根据字重值返回对应的样式名
73
+ if weight <= 100:
74
+ return weight, 'Thin'
75
+ elif weight <= 200:
76
+ return weight, 'ExtraLight'
77
+ elif weight <= 300:
78
+ return weight, 'Light'
79
+ elif weight <= 450:
80
+ return weight, 'Regular'
81
+ elif weight <= 550:
82
+ return weight, 'Medium'
83
+ elif weight <= 650:
84
+ return weight, 'SemiBold'
85
+ elif weight <= 750:
86
+ return weight, 'Bold'
87
+ elif weight <= 850:
88
+ return weight, 'ExtraBold'
89
+ else:
90
+ return weight, 'Black'
91
+
92
+ def generate_unique_family_name(original_family, weight_style, index):
93
+ """基于索引生成唯一的字体家族名"""
94
+ # 移除原始家族名中的非ASCII字符和特殊字符
95
+ clean_name = re.sub(r'[^\w]', '', original_family)
96
+ clean_name = ''.join(c for c in clean_name if ord(c) < 128) # 只保留ASCII字符
97
+
98
+ # 如果清理后为空,使用默认名称
99
+ if not clean_name:
100
+ clean_name = "Font"
101
+
102
+ # 生成简短的唯一标识
103
+ if len(clean_name) > 8:
104
+ clean_name = clean_name[:8]
105
+
106
+ # 基于索引和字重生成唯一名称
107
+ return f"{clean_name}{weight_style}{index}"
108
+
109
+ def sanitize_postscript_name(name):
110
+ """清理PostScript名称,确保符合命名规范"""
111
+ # PostScript名称只能包含ASCII字母、数字和连字符
112
+ # 不能有空格,必须以字母开头
113
+ sanitized = re.sub(r'[^a-zA-Z0-9-]', '', name.replace(' ', ''))
114
+
115
+ # 确保以字母开头
116
+ if sanitized and not sanitized[0].isalpha():
117
+ sanitized = 'Font' + sanitized
118
+
119
+ # 如果完全为空,返回默认值
120
+ if not sanitized:
121
+ sanitized = 'Font-Regular'
122
+
123
+ return sanitized
124
+
125
+ def modify_font_complete(font_path, new_family_name=None, weight_value=None, style_name=None, index=1):
126
+ """完全修改字体的所有相关元数据"""
127
+ # 验证字体文件
128
+ if not os.path.exists(font_path):
129
+ raise FileNotFoundError(f"字体文件不存在: {font_path}")
130
+
131
+ if not font_path.lower().endswith(('.ttf')):
132
+ raise ValueError(f"不支持的字体格式: {font_path}")
133
+
134
+ # 如果没有提供参数,自动检测
135
+ if not all([new_family_name, weight_value, style_name]):
136
+ font_info = get_font_info(font_path)
137
+
138
+ # 从字体文件获取实际字重
139
+ detected_weight, detected_style = detect_weight_from_font(font_path)
140
+
141
+ # 如果没有提供参数,使用检测到的值
142
+ if not new_family_name:
143
+ new_family_name = generate_unique_family_name(font_info['family'], detected_style, index)
144
+ if not weight_value:
145
+ weight_value = detected_weight
146
+ if not style_name:
147
+ style_name = "Regular" # iOS推荐所有独立字体都使用Regular
148
+
149
+ # 验证字重值
150
+ if not isinstance(weight_value, int) or weight_value < 1 or weight_value > 1000:
151
+ raise ValueError(f"无效的字重值: {weight_value},必须在1-1000之间")
152
+
153
+ print(f"\n处理字体: {os.path.basename(font_path)}")
154
+ print(f"新家族名: {new_family_name}")
155
+ print(f"字重: {weight_value}")
156
+ print(f"样式: {style_name}")
157
+
158
+ try:
159
+ font = TTFont(font_path)
160
+ except Exception as e:
161
+ raise ValueError(f"无法打开字体文件: {e}")
162
+
163
+ # 获取name表
164
+ name_table = font['name']
165
+
166
+ # 需要修改的所有nameID
167
+ # 1 = Family name
168
+ # 2 = Subfamily name
169
+ # 3 = Unique identifier
170
+ # 4 = Full name
171
+ # 6 = PostScript name
172
+ # 16 = Typographic Family name (Preferred family)
173
+ # 17 = Typographic Subfamily name (Preferred subfamily)
174
+
175
+ # 使用清理函数生成符合规范的PostScript名称
176
+ postscript_name = sanitize_postscript_name(f"{new_family_name}-{style_name}")
177
+ full_name = f"{new_family_name} {style_name}"
178
+
179
+ # 创建新的name记录
180
+ name_updates = {
181
+ 1: new_family_name, # Family
182
+ 2: style_name, # Subfamily
183
+ 3: f"{new_family_name} {style_name}", # Unique ID
184
+ 4: full_name, # Full name
185
+ 6: postscript_name, # PostScript name
186
+ 16: new_family_name, # Preferred Family
187
+ 17: style_name, # Preferred Subfamily
188
+ }
189
+
190
+ # 更新所有相关的name记录
191
+ for record in name_table.names:
192
+ if record.nameID in name_updates:
193
+ old_value = record.toUnicode()
194
+ new_value = name_updates[record.nameID]
195
+ try:
196
+ # 使用UTF-16-BE编码,这是字体行业的通用标准
197
+ record.string = new_value.encode('utf-16-be')
198
+ print(f"NameID {record.nameID}: {old_value} -> {new_value}")
199
+ except Exception as e:
200
+ print(f"编码失败 (NameID {record.nameID}): {e}")
201
+ # 保持原值不变
202
+ continue
203
+
204
+ # 修改OS/2表
205
+ if 'OS/2' in font:
206
+ os2_table = font['OS/2']
207
+ old_weight = os2_table.usWeightClass
208
+ os2_table.usWeightClass = weight_value
209
+ print(f"OS/2 Weight: {old_weight} -> {weight_value}")
210
+
211
+ # 设置字体选择标志
212
+ os2_table.fsSelection = 0
213
+ if weight_value >= 700: # Bold
214
+ os2_table.fsSelection |= FS_SELECTION_BOLD
215
+ elif weight_value == 400: # Regular
216
+ os2_table.fsSelection |= FS_SELECTION_REGULAR
217
+
218
+ # 修改head表中的macStyle
219
+ if 'head' in font:
220
+ head_table = font['head']
221
+ head_table.macStyle = 0
222
+ if weight_value >= 700:
223
+ head_table.macStyle |= MAC_STYLE_BOLD
224
+
225
+ # 保存修改后的字体
226
+ base_name = os.path.splitext(font_path)[0]
227
+ output_path = f"{base_name}.ttf"
228
+
229
+ try:
230
+ font.save(output_path)
231
+ print(f"Saved to: {output_path}\n")
232
+ font.close()
233
+ return output_path
234
+ except Exception as e:
235
+ font.close()
236
+ print(f"保存字体失败: {e}")
237
+ raise
238
+
239
+ def copy_files(src_folder, dst_folder):
240
+ """
241
+ 将源文件夹所有文件复制到目标文件夹
242
+ :param src_folder: 源文件夹路径
243
+ :param dst_folder: 目标文件夹路径
244
+ """
245
+ try:
246
+ # 确保目标文件夹存在
247
+ os.makedirs(dst_folder, exist_ok=True)
248
+
249
+ # 遍历源文件夹
250
+ for item in os.listdir(src_folder):
251
+ src_path = os.path.join(src_folder, item)
252
+ dst_path = os.path.join(dst_folder, item)
253
+
254
+ # 如果是文件则复制
255
+ if os.path.isfile(src_path):
256
+ shutil.copy2(src_path, dst_path)
257
+ print(f"已复制: {src_path} -> {dst_path}")
258
+ # 如果是子文件夹则递归处理(可选)
259
+ # else:
260
+ # copy_files(src_path, dst_path)
261
+
262
+ print(f"操作完成!共复制了{len(os.listdir(src_folder))}个文件")
263
+ except Exception as e:
264
+ print(f"发生错误: {e}")
265
+
266
+
267
+
268
+ def main():
269
+ parser = argparse.ArgumentParser(description="修改 TTF 字体元数据(name / OS/2 / head)")
270
+ parser.add_argument(
271
+ "font_path",
272
+ help="要处理的 TTF 字体文件路径(通常为瘦身后的输出文件)",
273
+ )
274
+ args = parser.parse_args()
275
+ font_path = os.path.abspath(args.font_path)
276
+ if not os.path.isfile(font_path):
277
+ raise SystemExit(f"字体文件不存在: {font_path}")
278
+ modify_font_complete(font_path)
279
+
280
+
281
+ if __name__ == "__main__":
282
+ # main()
283
+ modify_font_complete(sys.argv[1])
284
+
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ttf = void 0;
7
+ const child_process_1 = require("child_process");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const logger_1 = __importDefault(require("../../logger"));
11
+ const utils_1 = require("../../utils");
12
+ class TTF {
13
+ /**
14
+ * 字体瘦身:抽取字符、合并 JSON 与自定义字表,再用 sfnttool 生成子集 TTF。
15
+ * 流程对齐参考脚本 `ttf.js`。
16
+ * @param options 选项
17
+ */
18
+ parse(options) {
19
+ // 获取所有指定目录下所有后缀文件
20
+ const outFiles = utils_1.utils.findFiles(options.output, [".ttf"]);
21
+ const srcFiles = utils_1.utils.findFiles(options.source, [".ttf"]);
22
+ // 需要处理的文件名
23
+ const needProcessFileNames = outFiles.map((file) => path_1.default.basename(file));
24
+ // 需要处理的文件信息
25
+ const processFiles = [];
26
+ for (const file of srcFiles) {
27
+ const fileName = path_1.default.basename(file);
28
+ if (needProcessFileNames.includes(fileName)) {
29
+ processFiles.push({ src: file, dst: path_1.default.join(options.output, fileName) });
30
+ }
31
+ }
32
+ // 处理
33
+ const pyPath = path_1.default.join(__dirname, "..", "py", "modify_fonts.py");
34
+ // 处理字符集
35
+ const fontPath = this.handleTxt(options);
36
+ // 构建后 __dirname 为 dist/ttf/src,与 copy-assets 中 dist/ttf/jar 对齐
37
+ const jarDir = path_1.default.join(__dirname, "..", "jar");
38
+ const sfnttoolJar = path_1.default.join(jarDir, "sfnttool.jar");
39
+ logger_1.default.info(`[${new Date().toLocaleString()}] 开始字体瘦身`);
40
+ for (const { src, dst } of processFiles) {
41
+ (0, child_process_1.execFileSync)("java", ["-jar", sfnttoolJar, "-c", fontPath, src, dst], { stdio: "inherit" });
42
+ logger_1.default.info(`字体瘦身完成: ${dst}`);
43
+ if (fs_1.default.existsSync(pyPath)) {
44
+ const python = process.platform === "win32" ? "python" : "python3";
45
+ (0, child_process_1.execFileSync)(python, [pyPath, dst], { stdio: "inherit" });
46
+ }
47
+ else {
48
+ logger_1.default.warn(`未找到脚本,跳过元数据修改: ${pyPath}`);
49
+ }
50
+ }
51
+ // 删除临时文件
52
+ utils_1.utils.rmSync(path_1.default.join(options.output, "font.txt"));
53
+ // utils.rmSync(fontPath);
54
+ }
55
+ /**
56
+ * 处理字符集
57
+ * @param options
58
+ * @returns 字符集文本路径
59
+ */
60
+ handleTxt(options) {
61
+ // 抽取输出目录中的字符集
62
+ const jarDir = path_1.default.join(__dirname, "..", "jar");
63
+ const fontJar = path_1.default.join(jarDir, "font.jar");
64
+ (0, child_process_1.execFileSync)("java", ["-jar", fontJar, options.output], { stdio: "inherit" });
65
+ let fontStr = fs_1.default.readFileSync(path_1.default.join(options.output, "font.txt"), "utf-8");
66
+ const fontSet = new Set([...fontStr]);
67
+ // 自定义字符集
68
+ const txtFiles = utils_1.utils.findFiles(options.source, [".txt"]);
69
+ for (const txtFile of txtFiles) {
70
+ const str = fs_1.default.readFileSync(txtFile, "utf-8");
71
+ [...str].forEach((s) => fontSet.add(s));
72
+ }
73
+ // 将新的字符集写入临时文件
74
+ const tmpTxtPath = path_1.default.join(options.source, "tmp.txt");
75
+ if (fs_1.default.existsSync(tmpTxtPath)) {
76
+ fs_1.default.unlinkSync(tmpTxtPath);
77
+ }
78
+ fs_1.default.writeFileSync(tmpTxtPath, [...fontSet].join(""), "utf-8");
79
+ console.info("\x1b[32m%s\x1b[0m", `临时字符集文件路径: ${tmpTxtPath}`);
80
+ return tmpTxtPath;
81
+ }
82
+ }
83
+ exports.ttf = new TTF();
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const commander_1 = require("commander");
13
+ const TTF_1 = require("./TTF");
14
+ /**
15
+ * 解析机器人消息命令参数,并按类型发送到对应平台。
16
+ */
17
+ function main() {
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ commander_1.program
20
+ .name("ttf")
21
+ .description("ttf parser")
22
+ .version("1.0.0")
23
+ .requiredOption("-s, --source <directory>", "source directory")
24
+ .requiredOption("-o, --output <directory>", "output directory")
25
+ .parse(process.argv);
26
+ const options = commander_1.program.opts();
27
+ TTF_1.ttf.parse(options);
28
+ });
29
+ }
30
+ // 捕获入口异步异常并以非零状态码退出。
31
+ void main().catch((err) => {
32
+ console.error(err);
33
+ process.exit(1);
34
+ });
package/dist/utils.js CHANGED
@@ -36,6 +36,7 @@ var utils;
36
36
  function getSubDirsSync(dir) {
37
37
  const subDirs = [];
38
38
  const files = fs_1.default.readdirSync(dir);
39
+ // 将目录项过滤成完整路径形式的子目录列表。
39
40
  files.forEach((file) => {
40
41
  const filePath = path_1.default.join(dir, file);
41
42
  const fileStat = fs_1.default.statSync(filePath);
@@ -55,6 +56,7 @@ var utils;
55
56
  if (!fs_1.default.existsSync(dir)) {
56
57
  return false;
57
58
  }
59
+ // 只要存在一个目标扩展名文件,即认为目录满足条件。
58
60
  return fs_1.default.readdirSync(dir).some((file) => path_1.default.extname(file) === ext);
59
61
  }
60
62
  utils.containsFileExt = containsFileExt;
@@ -96,6 +98,7 @@ var utils;
96
98
  exts = [exts];
97
99
  }
98
100
  const fileList = fs_1.default.readdirSync(dir);
101
+ // 递归收集匹配扩展名的文件路径。
99
102
  fileList.forEach((file) => {
100
103
  const filePath = path_1.default.join(dir, file);
101
104
  const fileStat = fs_1.default.statSync(filePath);
@@ -202,6 +205,7 @@ var utils;
202
205
  return;
203
206
  }
204
207
  const files = fs_1.default.readdirSync(dir); // 同步读取目录内容
208
+ // 仅删除当前目录中符合扩展名且未被排除的文件。
205
209
  files.forEach((file) => {
206
210
  const filePath = path_1.default.join(dir, file);
207
211
  // 获取文件的状态
@@ -20,6 +20,10 @@ var SheetType;
20
20
  * Xlsx解析器
21
21
  */
22
22
  class XlsxParser {
23
+ /**
24
+ * 初始化解析器配置,并清理上一次导出的临时目录。
25
+ * @param options xlsx 解析与输出路径配置
26
+ */
23
27
  constructor(options) {
24
28
  /** 数组分隔符类 */
25
29
  this.separators = ["|", ";", ",", "-", "_"];
@@ -40,10 +44,12 @@ class XlsxParser {
40
44
  */
41
45
  parse() {
42
46
  const xlsxFiles = this.findFilesWithExtensions(this.options.xlsxDir, [".xlsx", ".xls"]);
47
+ // 逐个解析源目录下的 Excel 文件。
43
48
  xlsxFiles.forEach((filePath) => {
44
49
  console.info("\x1b[35m%s\x1b[0m", "解析文件: " + filePath);
45
50
  const xlsxName = path_1.default.basename(filePath, path_1.default.extname(filePath));
46
51
  const workSheetsFromFile = node_xlsx_1.default.parse(filePath);
52
+ // 将同一个工作簿中的每个工作表分别按表类型导出。
47
53
  workSheetsFromFile.forEach((workSheet) => {
48
54
  this.parseWorkSheet(xlsxName, workSheet);
49
55
  });
@@ -63,6 +69,7 @@ class XlsxParser {
63
69
  // 解析表名、类型、版本
64
70
  const [basename, sheetType, version] = arr;
65
71
  // 去除空数组
72
+ // 丢弃完全为空的行,避免表头或数据解析被空行干扰。
66
73
  data = data.filter((item) => item.length > 0);
67
74
  /** 介绍(第一行) */
68
75
  let intros = data[0];
@@ -82,7 +89,11 @@ class XlsxParser {
82
89
  data.shift();
83
90
  data.shift();
84
91
  }
85
- data.forEach((row) => row.forEach((v, i) => (row[i] = String(v || "").trim())));
92
+ // 统一清洗每行中的单元格文本。
93
+ data.forEach((row) => {
94
+ // 将单元格转成字符串并去掉首尾空白。
95
+ row.forEach((v, i) => (row[i] = String(v || "").trim()));
96
+ });
86
97
  let fileName = `${basename}${sheetType}`;
87
98
  let typeName = fileName;
88
99
  // 带版本号
@@ -143,6 +154,7 @@ class XlsxParser {
143
154
  for (let i = 0; i < row.length; ++i) {
144
155
  const field = fields[i];
145
156
  if (field) {
157
+ // 提供整列值,供数组类型自动推断真实分隔符。
146
158
  const columns = data.map((v) => v[i]);
147
159
  rowInfo[field] = this.parseValue(types[i], row[i], columns);
148
160
  }
@@ -172,6 +184,7 @@ class XlsxParser {
172
184
  for (let j = 0; j < col.length; ++j) {
173
185
  const field = fields[j];
174
186
  if (field) {
187
+ // 提供整列值,供数组类型自动推断真实分隔符。
175
188
  const columns = data.map((v) => v[j]);
176
189
  info[field] = this.parseValue(types[j], col[j], columns);
177
190
  }
@@ -197,6 +210,7 @@ class XlsxParser {
197
210
  for (let i = 0; i < data.length; ++i) {
198
211
  const col = data[i];
199
212
  if (col[0]) {
213
+ // 新的首列值表示一个新的合并行分组。
200
214
  const columns = data.map((v) => v[0]);
201
215
  group = {
202
216
  [fields[0]]: this.parseValue(types[0], col[0], columns),
@@ -223,6 +237,7 @@ class XlsxParser {
223
237
  for (let i = 0; i < row.length; ++i) {
224
238
  const field = fields[i];
225
239
  if (field) {
240
+ // 提供整列值,供数组类型自动推断真实分隔符。
226
241
  const columns = data.map((v) => v[i]);
227
242
  info[field] = this.parseValue(types[i], row[i], columns);
228
243
  }
@@ -237,6 +252,7 @@ class XlsxParser {
237
252
  if (data.length <= 0 || !data[0][0]) {
238
253
  return false;
239
254
  }
255
+ // 首列后续行为空但同一行仍有值时,视为首列合并行数组。
240
256
  return data.some((row, index) => index > 0 && !row[0] && row.some((value) => value));
241
257
  }
242
258
  /**
@@ -260,7 +276,7 @@ class XlsxParser {
260
276
  this.writeSheetSync(sheetInfo.outPath, content);
261
277
  }
262
278
  /**
263
- * 解析键值表
279
+ * 解析三列表结构的变量映射表
264
280
  * @param sheetInfo 工作表信息
265
281
  */
266
282
  parseVMap(sheetInfo) {
@@ -353,6 +369,7 @@ class XlsxParser {
353
369
  // 分隔符数量
354
370
  let separatorCount = separators.length;
355
371
  // 逆序分隔符
372
+ // 去掉空分隔符声明,并反向应用以匹配递归拆分顺序。
356
373
  let realSeparators = separators.filter((item) => item !== "").reverse();
357
374
  // 从列中抽取分隔符
358
375
  if (realSeparators.length <= 0 && separatorCount > 0) {
@@ -397,6 +414,7 @@ class XlsxParser {
397
414
  return [this.splitStringToNestedArray(baseType, valueStr, remainingDelimiters)];
398
415
  }
399
416
  // 分割当前层级并递归处理每个部分
417
+ // 当前层拆分后的每一段继续使用剩余分隔符递归解析。
400
418
  return valueStr.split(currentDelimiter).map((part) => this.splitStringToNestedArray(baseType, part, remainingDelimiters));
401
419
  }
402
420
  /**
@@ -411,6 +429,7 @@ class XlsxParser {
411
429
  extensions = [extensions];
412
430
  }
413
431
  const fileList = fs_1.default.readdirSync(dir);
432
+ // 递归收集匹配扩展名的文件路径。
414
433
  fileList.forEach((file) => {
415
434
  const filePath = path_1.default.join(dir, file);
416
435
  const fileStat = fs_1.default.statSync(filePath);
@@ -531,7 +550,7 @@ class XlsxParser {
531
550
  }
532
551
  /**
533
552
  * 去除多余类型字符
534
- * @param str
553
+ * @param str 原始类型字符串
535
554
  */
536
555
  removeExtraType(str) {
537
556
  // 使用正则表达式匹配所有方括号中的内容
@@ -552,7 +571,7 @@ class XlsxParser {
552
571
  }
553
572
  /**
554
573
  * 处理字符串,确保它不以数字开头,并且移除所有空格、制表符和换行符
555
- * @param input
574
+ * @param input 原始字符串
556
575
  */
557
576
  processString(input) {
558
577
  // Remove leading digits
@@ -569,6 +588,7 @@ class XlsxParser {
569
588
  const jsonDir = path_1.default.join(this.options.tmpDir);
570
589
  const files = this.findFilesWithExtensions(jsonDir, [".json"]);
571
590
  const json = {};
591
+ // 将每个临时表 JSON 合并到最终 xlsx.json 的表名键下。
572
592
  files.forEach((filePath) => {
573
593
  const basename = path_1.default.basename(filePath);
574
594
  const arr = this.processString(basename).split(".");
@@ -618,10 +638,12 @@ class XlsxParser {
618
638
  declareStr += `\n /** 整数 */`;
619
639
  declareStr += `\n type int = number;`;
620
640
  // 遍历声明表
641
+ // 拼接每张表解析过程中收集到的 TypeScript 类型声明。
621
642
  this.declareMap.forEach((value) => {
622
643
  if (value.length <= 0) {
623
644
  return;
624
645
  }
646
+ // 为 namespace 内部声明增加统一缩进。
625
647
  value = value.map((v) => " ".repeat(4) + v);
626
648
  declareStr += "\n\n";
627
649
  declareStr += value.join("\n");
@@ -15,6 +15,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const commander_1 = require("commander");
16
16
  const path_1 = __importDefault(require("path"));
17
17
  const XlsxParser_1 = __importDefault(require("./XlsxParser"));
18
+ /**
19
+ * 解析 xlsx 导出命令参数,并初始化表格解析器。
20
+ */
18
21
  function main() {
19
22
  return __awaiter(this, void 0, void 0, function* () {
20
23
  commander_1.program
@@ -43,6 +46,7 @@ function main() {
43
46
  xlsxParser.parse();
44
47
  });
45
48
  }
49
+ // 捕获入口异步异常并以非零状态码退出。
46
50
  void main().catch((err) => {
47
51
  console.error(err);
48
52
  process.exit(1);
@@ -92,6 +92,4 @@ class Xlsx {
92
92
  }
93
93
 
94
94
  export const xlsx = Xlsx.instance;
95
- if (cc.sys.isBrowser) {
96
- (window as any)["xlsx"] = xlsx;
97
- }
95
+ (window as any)["xlsx"] = xlsx;
@@ -27,6 +27,9 @@ function generateKey() {
27
27
  // 组合成 8-4-2 格式
28
28
  return `${part1}-${part2}-${part3}`;
29
29
  }
30
+ /**
31
+ * 读取指定 JSON 文件,生成并写入新的 xxteaKey 字段。
32
+ */
30
33
  function main() {
31
34
  return __awaiter(this, void 0, void 0, function* () {
32
35
  commander_1.program
@@ -50,6 +53,7 @@ function main() {
50
53
  console.log(`xxteaKey: ${xxteaKey}`);
51
54
  });
52
55
  }
56
+ // 捕获入口异步异常并以非零状态码退出。
53
57
  void main().catch((err) => {
54
58
  console.error(err);
55
59
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fast-cocos",
3
- "version": "1.0.8",
3
+ "version": "1.1.1",
4
4
  "scripts": {
5
5
  "clean": "rm -rf dist",
6
6
  "start": "node ./dist/index.js",