scancscode 1.0.28 → 1.0.29

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.
@@ -14,7 +14,15 @@ export class CmdExecutor {
14
14
  let outCsvFile = "E:/DATA/Projects/e-gbl-client/client/Assets/Bundles/GameConfigs/Translation/hello.csv"
15
15
  let langs = ["zh_cn"];
16
16
  let literalCollector = new LiteralCollector();
17
- literalCollector.convert(cscodeFolders, gameConfigFolders, outCsvFile, langs)
17
+ // return literalCollector.convert(cscodeFolders, gameConfigFolders, outCsvFile, langs,undefined,false,true)
18
+ return literalCollector.convert(cscodeFolders,
19
+ // [
20
+ // "E:/DATA/Projects/ZhiYou/DXTSProject/Client/Assets/Bundles/UI/",
21
+ // "E:/DATA/Projects/ZhiYou/DXTSProject/Client/Assets/Bundles/Battle/",
22
+ // "E:/DATA/Projects/ZhiYou/DXTSProject/Client/Assets/Scripts/",
23
+ // "E:/DATA/Projects/ZhiYou/ProjectFClient/GameClient/Assets/Bundles/FGUI/",
24
+ // ],
25
+ gameConfigFolders, outCsvFile, langs)
18
26
  // node . --cscodedir ../../../GameClient/Assets/Bundles/FGUI/ --configdir ../../../GameClient/Assets/Bundles/GameConfigs/ --outcsv E:/DATA/Projects/e-gbl-client/client/Assets/Bundles/GameConfigs/Translation/hello.csv --langs zh_cn
19
27
  }
20
28
  static async runConvertWithCmdOptions() {
@@ -7,7 +7,7 @@ import { TableScanner } from "./TableScanner";
7
7
 
8
8
  export class LiteralCollector {
9
9
 
10
- scanCodeInFolder(folder: string, literals: string[], unexpects: string[], trmethod: string, scanonly: boolean, verbose: boolean) {
10
+ async scanCodeInFolder(folder: string, literals: string[], unexpects: string[], trmethod: string, scanonly: boolean, verbose: boolean) {
11
11
  if (fs.existsSync(folder) == false) {
12
12
  console.warn(`代码目录不存在: ${folder}`);
13
13
  return;
@@ -15,32 +15,54 @@ export class LiteralCollector {
15
15
 
16
16
  let files = glob.sync("**/*.cs", { cwd: folder });
17
17
  let testFullPath = "@";
18
- // let testFullPath = "E:/DATA/Projects/ZhiYou/ProjectFClient/GameClient/Assets/Bundles/FGUI/SutraUI_Detail/MainSutraDetailDialog.cs";
19
- for (const filePath of files) {
20
- let fullPath = folder + filePath;
21
- if (testFullPath != "@") {
22
- fullPath = testFullPath;
23
- }
24
- if (verbose) {
25
- console.log(`处理文件: ${filePath}`);
26
- }
27
- const content = fs.readFileSync(fullPath, "utf-8");
28
- const snippets = CSCodeScanner.scanFile(fullPath, content, trmethod);
29
- if (snippets.length > 0) {
30
- if (!scanonly) {
31
- let convertedContent = CSCodeScanner.replaceInFile(content, snippets);
32
- if (convertedContent != content) {
33
- fs.writeFileSync(fullPath, convertedContent, "utf-8");
34
- }
18
+ // let testFullPath = "E:/DATA/Projects/ZhiYou/ProjectFClient/GameClient/Assets/Bundles/GameConfigs/Main/UnitAttributeTable-UnitAttributeTable.cs";
19
+
20
+ // 限制并行处理的文件数量,避免内存占用过高
21
+ const batchSize = 10;
22
+ for (let i = 0; i < files.length; i += batchSize) {
23
+ const batchFiles = files.slice(i, i + batchSize);
24
+ const batchPromises = batchFiles.map(async (filePath) => {
25
+ let fullPath = folder + filePath;
26
+ if (testFullPath != "@") {
27
+ fullPath = testFullPath;
28
+ }
29
+ if (verbose) {
30
+ console.log(`处理文件: ${filePath}, ${fullPath}`);
35
31
  }
32
+ try {
33
+ const content = await fs.promises.readFile(fullPath, "utf-8");
34
+ const snippets = CSCodeScanner.scanFile(fullPath, content, trmethod);
35
+ CSCodeScanner.filterSnippets(snippets);
36
+
37
+ if (snippets.length > 0) {
38
+ if (!scanonly) {
39
+ let convertedContent = CSCodeScanner.replaceInFile(content, snippets);
40
+ if (convertedContent != content) {
41
+ await fs.promises.writeFile(fullPath, convertedContent, "utf-8");
42
+ }
43
+ }
36
44
 
37
- for (const snippet of snippets) {
38
- literals.push(...snippet.literals);
39
- unexpects.push(...snippet.unexpects);
45
+ const fileLiterals: string[] = [];
46
+ const fileUnexpects: string[] = [];
47
+ for (const snippet of snippets) {
48
+ fileLiterals.push(...snippet.literals);
49
+ fileUnexpects.push(...snippet.unexpects);
50
+ }
51
+ return { literals: fileLiterals, unexpects: fileUnexpects };
52
+ }
53
+ } catch (error) {
54
+ console.error(`处理文件失败: ${fullPath}`, error);
40
55
  }
56
+ return { literals: [], unexpects: [] };
57
+ });
58
+
59
+ const batchResults = await Promise.all(batchPromises);
60
+ for (const result of batchResults) {
61
+ literals.push(...result.literals);
62
+ unexpects.push(...result.unexpects);
41
63
  }
42
64
 
43
- if (fullPath == testFullPath) {
65
+ if (testFullPath != "@") {
44
66
  break;
45
67
  }
46
68
  }
@@ -49,13 +71,18 @@ export class LiteralCollector {
49
71
 
50
72
  }
51
73
 
52
- scanTablesInFolder(folder: string, literals: string[], verbose: boolean) {
74
+ async scanTablesInFolder(folder: string, literals: string[], verbose: boolean) {
53
75
  if (fs.existsSync(folder) == false) {
54
76
  console.warn(`表格目录不存在: ${folder}`);
55
77
  return;
56
78
  }
57
79
  let scanner = new TableScanner();
58
- scanner.scanTablesLiterals(folder + "Main/", literals, verbose);
80
+ await scanner.scanTablesLiterals(folder + "Main/", literals, verbose);
81
+ }
82
+
83
+ static needTranslate(literal: string): boolean {
84
+ let match = literal.match(/^[\da-zA-Z!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/? ]+$/m);
85
+ return match == null;
59
86
  }
60
87
 
61
88
  /**
@@ -66,8 +93,8 @@ export class LiteralCollector {
66
93
  let literalsSet = new Set(literals);
67
94
  literalsSet.delete("");
68
95
  for (let literal of literals) {
69
- let match = literal.match(/^[\da-zA-Z!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+$/m);
70
- if (match != null) {
96
+ let needTr = LiteralCollector.needTranslate(literal);
97
+ if (!needTr) {
71
98
  literalsSet.delete(literal)
72
99
  }
73
100
  }
@@ -79,12 +106,28 @@ export class LiteralCollector {
79
106
 
80
107
  let literals: string[] = [];
81
108
  let unexpects: string[] = [];
82
- for (const cscodeFolder of cscodeFolders) {
83
- this.scanCodeInFolder(cscodeFolder, literals, unexpects, trmethod, scanonly, verbose);
84
- }
85
- for (const gameConfigFolder of gameConfigFolders) {
86
- this.scanTablesInFolder(gameConfigFolder, literals, verbose);
109
+
110
+ // 并行处理代码文件夹
111
+ const codeFolderPromises = cscodeFolders.map(async (cscodeFolder) => {
112
+ const folderLiterals: string[] = [];
113
+ const folderUnexpects: string[] = [];
114
+ await this.scanCodeInFolder(cscodeFolder, folderLiterals, folderUnexpects, trmethod, scanonly, verbose);
115
+ return { literals: folderLiterals, unexpects: folderUnexpects };
116
+ });
117
+
118
+ const codeFolderResults = await Promise.all(codeFolderPromises);
119
+ for (const result of codeFolderResults) {
120
+ literals.push(...result.literals);
121
+ unexpects.push(...result.unexpects);
87
122
  }
123
+
124
+ // 并行处理表格文件夹
125
+ const tableFolderPromises = gameConfigFolders.map(async (gameConfigFolder) => {
126
+ await this.scanTablesInFolder(gameConfigFolder, literals, verbose);
127
+ });
128
+ await Promise.all(tableFolderPromises);
129
+
130
+ // 去重和过滤
88
131
  this.filterLiterals(literals);
89
132
 
90
133
  if (verbose) {
@@ -14,55 +14,79 @@ export class TableScanner {
14
14
  }
15
15
  }
16
16
  scanJsonWords(jsonContent: string, fields: string[], literals: string[]) {
17
- let arr = JSON.parse(jsonContent);
18
- for (const jsonRow of arr) {
19
- for (const key of fields) {
20
- let value = jsonRow[key];
21
- if (typeof (value) == "string") {
22
- literals.push(value);
23
- } else if (Array.isArray(value)) {
24
- literals.push(...value);
17
+ try {
18
+ let arr = JSON.parse(jsonContent);
19
+ for (const jsonRow of arr) {
20
+ for (const key of fields) {
21
+ let value = jsonRow[key];
22
+ if (typeof (value) == "string") {
23
+ literals.push(value);
24
+ } else if (Array.isArray(value)) {
25
+ literals.push(...value);
26
+ }
25
27
  }
26
28
  }
29
+ } catch (error) {
30
+ console.error(`解析JSON失败: ${error}`);
27
31
  }
28
32
  }
29
- scanTableLiterals(csFullPath: string, literals: string[], verbose: boolean) {
33
+ async scanTableLiterals(csFullPath: string, literals: string[], verbose: boolean) {
30
34
  // csFullPath = "E:/DATA/Projects/ZhiYou/ProjectFClient/GameClient/Assets/Bundles/GameConfigs/Main/RefinerTable-RefinerEventTable.cs";
31
35
  let jsonFullPath = csFullPath.replace("/Main/", "/Auto/").replace(/\.cs$/, ".json");
32
- if (fs.existsSync(jsonFullPath) && fs.existsSync(csFullPath)) {
33
- let csContent = fs.readFileSync(csFullPath, "utf-8");
34
- let trstrFields = this.parseTrStrFields(csContent);
35
- if (trstrFields.length > 0) {
36
- if (verbose) {
37
- console.log(`扫描表格: ${csFullPath} , 需要翻译字段: ${trstrFields}`);
36
+ try {
37
+ const [csExists, jsonExists] = await Promise.all([
38
+ fs.promises.access(csFullPath).then(() => true).catch(() => false),
39
+ fs.promises.access(jsonFullPath).then(() => true).catch(() => false)
40
+ ]);
41
+
42
+ if (jsonExists && csExists) {
43
+ const [csContent, jsonContent] = await Promise.all([
44
+ fs.promises.readFile(csFullPath, "utf-8"),
45
+ fs.promises.readFile(jsonFullPath, "utf-8")
46
+ ]);
47
+
48
+ let trstrFields = this.parseTrStrFields(csContent);
49
+ if (trstrFields.length > 0) {
50
+ if (verbose) {
51
+ console.log(`扫描表格: ${csFullPath} , 需要翻译字段: ${trstrFields}`);
52
+ }
53
+ this.scanJsonWords(jsonContent, trstrFields, literals);
54
+ } else {
55
+ if (verbose) {
56
+ console.log(`跳过表格: ${csFullPath}`);
57
+ }
38
58
  }
39
- let jsonContent = fs.readFileSync(jsonFullPath, "utf-8");
40
- this.scanJsonWords(jsonContent, trstrFields, literals);
41
59
  } else {
42
60
  if (verbose) {
43
- console.log(`跳过表格: ${csFullPath}`);
44
- }
45
- }
46
- } else {
47
- if (verbose) {
48
- if (fs.existsSync(csFullPath) == false) {
49
- console.warn(`表格 CS 文件不存在: ${jsonFullPath}`);
50
- }
51
- if (fs.existsSync(jsonFullPath) == false) {
52
- console.warn(`表格 JSON 文件不存在: ${csFullPath}`);
61
+ if (!csExists) {
62
+ console.warn(`表格 CS 文件不存在: ${jsonFullPath}`);
63
+ }
64
+ if (!jsonExists) {
65
+ console.warn(`表格 JSON 文件不存在: ${csFullPath}`);
66
+ }
53
67
  }
54
68
  }
69
+ } catch (error) {
70
+ console.error(`处理表格文件失败: ${csFullPath}`, error);
55
71
  }
56
72
  }
57
73
  /**
58
74
  * 扫描
59
75
  */
60
- scanTablesLiterals(folder: string, literals: string[], verbose: boolean) {
76
+ async scanTablesLiterals(folder: string, literals: string[], verbose: boolean) {
61
77
  let dir = folder;
62
78
  let files = glob.sync("*.cs", { cwd: dir });
63
- for (const filePath of files.reverse()) {
64
- let csFullPath = folder + filePath;
65
- this.scanTableLiterals(csFullPath, literals, verbose);
79
+
80
+ // 限制并行处理的文件数量,避免内存占用过高
81
+ const batchSize = 10;
82
+ for (let i = 0; i < files.length; i += batchSize) {
83
+ const batchFiles = files.slice(i, i + batchSize).reverse();
84
+ const batchPromises = batchFiles.map(async (filePath) => {
85
+ let csFullPath = folder + filePath;
86
+ await this.scanTableLiterals(csFullPath, literals, verbose);
87
+ });
88
+
89
+ await Promise.all(batchPromises);
66
90
  }
67
91
  }
68
92
  }