scancscode 1.0.27 → 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.
- package/dist/CSCodeScanner.js +5 -4
- package/dist/LiteralCollector.js +2 -2
- package/dist/TableScanner.js +1 -1
- package/jest.config.js +9 -0
- package/package.json +6 -3
- package/src/CSCodeScanner.ts +174 -150
- package/src/CSVUtils.ts +5 -1
- package/src/CSharpStringExtractor.ts +1069 -0
- package/src/CmdExecutor.ts +9 -1
- package/src/LiteralCollector.ts +74 -31
- package/src/TableScanner.ts +56 -32
- package/test/CSharpStringExtractor.test.ts +1029 -0
- package/test/GuildDonateDialog.cs +194 -0
- package/test/MainSutraDetailDialog.cs +362 -0
- package/test/TestConvert.test.ts +8 -0
- package/src/CodeSnippet.ts +0 -7
- package/src/TestConvert.test.ts +0 -6
- package/src/TestSlimCsv.test.ts +0 -6
- package/src/index.ts +0 -3
package/dist/CSCodeScanner.js
CHANGED
|
@@ -6,7 +6,7 @@ exports.CSCodeScanner = void 0;
|
|
|
6
6
|
*/
|
|
7
7
|
class CSCodeScanner {
|
|
8
8
|
// 正则表达式匹配 uictrl.text = $"..."; 的模式
|
|
9
|
-
static assignmentPattern = /([\
|
|
9
|
+
static assignmentPattern = /(^\s*[\.a-zA-Z0-9_\u4e00-\u9fff]+\s*\+?=(?![=>])\s*|return\s+)([^;]+)\s*;/mg;
|
|
10
10
|
// 正则表达式匹配 匹配每个字符串
|
|
11
11
|
static stringPattern = /\$?"([^"]*)"/mg;
|
|
12
12
|
// 正则表达式匹配 匹配获取成员值的表达式
|
|
@@ -52,9 +52,10 @@ class CSCodeScanner {
|
|
|
52
52
|
const assignMatches = [...content.matchAll(CSCodeScanner.assignmentPattern)];
|
|
53
53
|
for (let j = 0; j < assignMatches.length; j++) {
|
|
54
54
|
const assignMatch = assignMatches[j];
|
|
55
|
-
let assignLine = assignMatch[0];
|
|
56
|
-
let assignHead = assignMatch[1];
|
|
57
|
-
let bodyLine = assignMatch[2];
|
|
55
|
+
// let assignLine = assignMatch[0];
|
|
56
|
+
// let assignHead = assignMatch[1];
|
|
57
|
+
// let bodyLine = assignMatch[2];
|
|
58
|
+
let [assignLine, assignHead, bodyLine] = assignMatch;
|
|
58
59
|
let convertedAssignLine;
|
|
59
60
|
/**
|
|
60
61
|
* 需要翻译的文本
|
package/dist/LiteralCollector.js
CHANGED
|
@@ -46,8 +46,8 @@ class LiteralCollector {
|
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
48
|
let files = glob_1.glob.sync("**/*.cs", { cwd: folder });
|
|
49
|
-
let testFullPath = "@";
|
|
50
|
-
|
|
49
|
+
// let testFullPath = "@";
|
|
50
|
+
let testFullPath = "E:/DATA/Projects/ZhiYou/ProjectFClient/GameClient/Assets/Bundles/FGUI/SutraUI_Detail/MainSutraDetailDialog.cs";
|
|
51
51
|
for (const filePath of files) {
|
|
52
52
|
let fullPath = folder + filePath;
|
|
53
53
|
if (testFullPath != "@") {
|
package/dist/TableScanner.js
CHANGED
|
@@ -38,7 +38,7 @@ const fs = __importStar(require("fs"));
|
|
|
38
38
|
const glob_1 = require("glob");
|
|
39
39
|
class TableScanner {
|
|
40
40
|
parseTrStrFields(content) {
|
|
41
|
-
let m = content.match(/\/\/ NeedTranslateFields\: \[([a-zA-Z_,\
|
|
41
|
+
let m = content.match(/\/\/ NeedTranslateFields\: \[([a-zA-Z_,\s0-9]*)\]$/m);
|
|
42
42
|
if (m != null) {
|
|
43
43
|
let wordsContent = m[1];
|
|
44
44
|
let words = wordsContent.split(", ");
|
package/jest.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scancscode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.29",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"scanliterals":"node bin/scanliterals.js",
|
|
12
12
|
"slimlangs":"node bin/slimlangs.js",
|
|
13
|
-
"test": "
|
|
13
|
+
"test": "jest"
|
|
14
14
|
},
|
|
15
15
|
"keywords": [],
|
|
16
16
|
"author": "",
|
|
@@ -22,8 +22,11 @@
|
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/command-line-args": "^5.2.3",
|
|
25
|
+
"@types/jest": "^30.0.0",
|
|
25
26
|
"@types/node": "^25.0.3",
|
|
27
|
+
"jest": "^30.2.0",
|
|
28
|
+
"ts-jest": "^29.4.6",
|
|
26
29
|
"ts-node": "^10.9.2",
|
|
27
30
|
"typescript": "^5.9.3"
|
|
28
31
|
}
|
|
29
|
-
}
|
|
32
|
+
}
|
package/src/CSCodeScanner.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { CodeSnippet } from "./
|
|
1
|
+
import { CodeSnippet, CSharpStringExtractor } from "./CSharpStringExtractor";
|
|
2
|
+
import { LiteralCollector } from "./LiteralCollector";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* 扫描C#代码, 扫描出其中所有形如 uictrl.text = 其他内容; 的代码片段, 其他内容可以是: $"<font color={colorStr}>{itemConfig.Name}</ font>"; 等等, 其他内容中形如 {变量} 的部分需要提取出来, 转换成 string.Format("<font color={0}>{1}</ font>", colorStr, itemConfig.Name); 的格式
|
|
@@ -7,6 +8,8 @@ import { CodeSnippet } from "./CodeSnippet";
|
|
|
7
8
|
export class CSCodeScanner {
|
|
8
9
|
// 正则表达式匹配 uictrl.text = $"..."; 的模式
|
|
9
10
|
private static readonly assignmentPattern = /([\w\.\u4e00-\u9fff]+\.text\s*\+?=(?![=>])\s*|return\s+)([^;]+)\s*;/mg;
|
|
11
|
+
// 正则表达式匹配 xxx = "..."; 的模式
|
|
12
|
+
private static readonly assignmentPattern2 = /(^\s*[\.a-zA-Z0-9_\u4e00-\u9fff]+\s*\+?=)\s*;/mg;
|
|
10
13
|
|
|
11
14
|
// 正则表达式匹配 匹配每个字符串
|
|
12
15
|
private static readonly stringPattern = /\$?"([^"]*)"/mg;
|
|
@@ -56,166 +59,182 @@ export class CSCodeScanner {
|
|
|
56
59
|
}
|
|
57
60
|
const snippets: CodeSnippet[] = [];
|
|
58
61
|
|
|
59
|
-
const assignMatches = [...content.matchAll(CSCodeScanner.assignmentPattern)];
|
|
60
|
-
for (let j = 0; j < assignMatches.length; j++) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
// const assignMatches = [...content.matchAll(CSCodeScanner.assignmentPattern)];
|
|
63
|
+
// for (let j = 0; j < assignMatches.length; j++) {
|
|
64
|
+
// const assignMatch = assignMatches[j];
|
|
65
|
+
// // let assignLine = assignMatch[0];
|
|
66
|
+
// // let assignHead = assignMatch[1];
|
|
67
|
+
// // let bodyLine = assignMatch[2];
|
|
68
|
+
// let [assignLine, assignHead, bodyLine] = assignMatch;
|
|
69
|
+
// let convertedAssignLine: string;
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
71
|
+
// /**
|
|
72
|
+
// * 需要翻译的文本
|
|
73
|
+
// */
|
|
74
|
+
// let literals: string[] = [];
|
|
75
|
+
// let unexpects: string[] = [];
|
|
76
|
+
// const stringMatchs = [...bodyLine.matchAll(CSCodeScanner.stringPattern)];
|
|
77
|
+
// if (stringMatchs.length > 0) {
|
|
78
|
+
// // 通过是否单行字符串并以 ".TR(); 结尾和判断是否内插字符串来判断是否需要在结尾附加 .TR()
|
|
79
|
+
// let isSingleString = false;
|
|
80
|
+
// if (stringMatchs.length == 1 && stringMatchs[0][0] == bodyLine) {
|
|
81
|
+
// let stringMatchFirst = stringMatchs[0];
|
|
82
|
+
// let stringLine = stringMatchFirst[0];
|
|
83
|
+
// if (stringLine.startsWith("$") || stringLine.startsWith("@$")) {
|
|
84
|
+
// let stringContent = stringMatchFirst[1];
|
|
85
|
+
// const variableMatches0 = [...stringContent.matchAll(CSCodeScanner.interpolationPattern)];
|
|
86
|
+
// isSingleString = variableMatches0.length == 0;
|
|
87
|
+
// } else {
|
|
88
|
+
// isSingleString = true;
|
|
89
|
+
// }
|
|
90
|
+
// }
|
|
87
91
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
92
|
+
// if (isSingleString) {
|
|
93
|
+
// let stringMatchFirst = stringMatchs[0];
|
|
94
|
+
// let stringLineIndex = stringMatchFirst.index;
|
|
95
|
+
// let prefix = bodyLine.substring(0, stringLineIndex);
|
|
96
|
+
// let stringLineFirst = stringMatchFirst[0];
|
|
97
|
+
// if (this.isNativeString(stringLineFirst)) {
|
|
98
|
+
// convertedAssignLine = assignHead + prefix + stringMatchFirst[0] + ";";
|
|
99
|
+
// } else {
|
|
100
|
+
// convertedAssignLine = assignHead + prefix + stringMatchFirst[0] + `.${trmethodname}();`;
|
|
101
|
+
// }
|
|
102
|
+
// } else {
|
|
103
|
+
// let stringLines: string[] = [];
|
|
104
|
+
// stringLines.push(assignHead);
|
|
105
|
+
// let lastIndex = 0;
|
|
106
|
+
// for (let i = 0; i < stringMatchs.length; i++) {
|
|
107
|
+
// let stringMatch = stringMatchs[i];
|
|
108
|
+
// let stringLine = stringMatch[0];
|
|
109
|
+
// let stringContent = stringMatch[1];
|
|
110
|
+
// let stringLineIndex = stringMatch.index;
|
|
111
|
+
// let stringStartIndexInContent = assignMatch.index + assignHead.length + stringMatch.index
|
|
112
|
+
// /**
|
|
113
|
+
// * 转换后的字符串
|
|
114
|
+
// */
|
|
115
|
+
// let convertedString: string;
|
|
116
|
+
// if (stringLine.startsWith("$") || stringLine.startsWith("@$")) {
|
|
117
|
+
// // 开始转换插值
|
|
118
|
+
// // 提取插值表达式中的变量
|
|
119
|
+
// const variableMatches0 = [...stringContent.matchAll(CSCodeScanner.interpolationPattern)];
|
|
120
|
+
// if (variableMatches0.length > 0) {
|
|
121
|
+
// let variableMatches: RegExpExecArray[] = [];
|
|
122
|
+
// let map = new Map<string, RegExpExecArray>();
|
|
123
|
+
// for (const variableMatche of variableMatches0) {
|
|
124
|
+
// if (!map.has(variableMatche[1])) {
|
|
125
|
+
// map.set(variableMatche[1], variableMatche);
|
|
126
|
+
// variableMatches.push(variableMatche);
|
|
127
|
+
// }
|
|
128
|
+
// }
|
|
125
129
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
130
|
+
// // 构建格式化字符串
|
|
131
|
+
// let formatString = stringContent;
|
|
132
|
+
// variableMatches.forEach((variableMatche, index) => {
|
|
133
|
+
// let varName = variableMatche[1];
|
|
134
|
+
// let suffix = variableMatche[2] ?? "";
|
|
135
|
+
// let replaced = formatString.replaceAll(`{${varName}${suffix}}`, `{${index}${suffix}}`);
|
|
136
|
+
// if (replaced == formatString) {
|
|
137
|
+
// let [lineNum, colNum] = CSCodeScanner.getLineIndexFromIndex(content, stringStartIndexInContent);
|
|
138
|
+
// let tip = `可能无法处理的复杂情形1(${filePath}:${lineNum}:${colNum}): ${stringContent}`;
|
|
139
|
+
// console.error(tip);
|
|
140
|
+
// unexpects.push(tip);
|
|
141
|
+
// } else {
|
|
142
|
+
// formatString = replaced;
|
|
143
|
+
// }
|
|
144
|
+
// });
|
|
141
145
|
|
|
142
146
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
// // 构建string.Format调用
|
|
148
|
+
// let formatCall = `string.Format("${formatString}"`;
|
|
149
|
+
// for (const variableMatche of variableMatches) {
|
|
150
|
+
// let varName = variableMatche[1];
|
|
151
|
+
// formatCall += `, ${varName}`;
|
|
152
|
+
// }
|
|
153
|
+
// formatCall += ")";
|
|
150
154
|
|
|
151
|
-
|
|
155
|
+
// convertedString = formatCall;
|
|
152
156
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
157
|
+
// literals.push(formatString);
|
|
158
|
+
// } else {
|
|
159
|
+
// // throw new Error("暂不支持插值字符串转换为 string.Format, 请手动处理");
|
|
160
|
+
// let isValidFormat = true;
|
|
161
|
+
// if (stringContent.indexOf("{") != -1 || stringContent.indexOf("}") != -1) {
|
|
162
|
+
// if (bodyLine.indexOf("{") != -1 && bodyLine.indexOf("}") != -1) {
|
|
163
|
+
// let [lineNum, colNum] = CSCodeScanner.getLineIndexFromIndex(content, stringStartIndexInContent);
|
|
164
|
+
// let tip = `可能无法处理的复杂情形2(${filePath}:${lineNum}:${colNum}): ${stringContent}`;
|
|
165
|
+
// console.error(tip);
|
|
166
|
+
// unexpects.push(tip);
|
|
167
|
+
// isValidFormat = false;
|
|
168
|
+
// }
|
|
169
|
+
// }
|
|
170
|
+
// let formattedStringLine = stringLine;
|
|
171
|
+
// if (isValidFormat) {
|
|
172
|
+
// // let stringStartIndex = stringMatch.index
|
|
173
|
+
// // let stringEndIndex = stringStartIndex + stringLine.length
|
|
174
|
+
// // let prefix = bodyLine.substring(stringStartIndex - 2, stringStartIndex)
|
|
175
|
+
// // let suffix = bodyLine.substring(stringEndIndex, stringEndIndex + ".TR()".length)
|
|
176
|
+
// // if ((stringStartIndex == 0 || prefix == "+ ") && suffix != ".TR()") {
|
|
177
|
+
// // formattedStringLine = formattedStringLine + ".TR()"
|
|
178
|
+
// // }
|
|
179
|
+
// formattedStringLine = this.replaceStringsTR(stringMatch, stringLine, bodyLine, trmethodname);
|
|
180
|
+
// literals.push(stringContent);
|
|
181
|
+
// }
|
|
182
|
+
// convertedString = formattedStringLine;
|
|
183
|
+
// }
|
|
184
|
+
// } else {
|
|
185
|
+
// literals.push(stringContent);
|
|
186
|
+
// convertedString = this.replaceStringsTR(stringMatch, stringLine, bodyLine, trmethodname);
|
|
187
|
+
// }
|
|
184
188
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
189
|
+
// // 串联字符串列表
|
|
190
|
+
// let prefix = bodyLine.substring(lastIndex, stringLineIndex);
|
|
191
|
+
// lastIndex = stringLineIndex + stringLine.length;
|
|
192
|
+
// stringLines.push(prefix);
|
|
193
|
+
// stringLines.push(convertedString);
|
|
194
|
+
// }
|
|
195
|
+
// let matchEnd = stringMatchs[stringMatchs.length - 1];
|
|
196
|
+
// let endIndex = matchEnd.index + matchEnd[0].length;
|
|
197
|
+
// stringLines.push(bodyLine.substring(endIndex));
|
|
198
|
+
// stringLines.push(";");
|
|
199
|
+
// convertedAssignLine = stringLines.join("");
|
|
200
|
+
// }
|
|
201
|
+
// } else {
|
|
202
|
+
// let convertBodyLine = CSCodeScanner.handleMembersConvert(bodyLine, assignHead, trmethodname)
|
|
203
|
+
// if (convertBodyLine != null) {
|
|
204
|
+
// convertedAssignLine = (assignHead ?? "") + convertBodyLine;
|
|
205
|
+
// } else {
|
|
206
|
+
// convertedAssignLine = assignLine
|
|
207
|
+
// }
|
|
208
|
+
// }
|
|
205
209
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
210
|
+
// let convertedAssignLine2 = convertedAssignLine.replaceAll(this.stringFormatPattern, `${trclassname}.Format`);
|
|
211
|
+
// snippets.push({
|
|
212
|
+
// originalIndex: assignMatch.index,
|
|
213
|
+
// originalCode: assignLine,
|
|
214
|
+
// convertedCode: convertedAssignLine2,
|
|
215
|
+
// literals,
|
|
216
|
+
// unexpects,
|
|
217
|
+
// });
|
|
218
|
+
// }
|
|
215
219
|
|
|
220
|
+
let capturer = new CSharpStringExtractor();
|
|
221
|
+
capturer.extractStrings(content, snippets, trclassname, trmethodname);
|
|
216
222
|
|
|
217
223
|
return snippets;
|
|
218
224
|
}
|
|
225
|
+
public static filterSnippets(snippets: CodeSnippet[]) {
|
|
226
|
+
let len = snippets.length;
|
|
227
|
+
for (let i = len - 1; i >= 0; i--) {
|
|
228
|
+
let snippet = snippets[i];
|
|
229
|
+
let needReplace = snippet.literals.some(literal => {
|
|
230
|
+
const needTr = LiteralCollector.needTranslate(literal);
|
|
231
|
+
return needTr;
|
|
232
|
+
});
|
|
233
|
+
if (!needReplace) {
|
|
234
|
+
snippets.splice(i, 1);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
219
238
|
private static handleMembersConvert(bodyLine: string, assignHead: string, trmethodname: string) {
|
|
220
239
|
let convertedAssignLine: string | null
|
|
221
240
|
let memberLines = bodyLine.split("+");
|
|
@@ -274,8 +293,13 @@ export class CSCodeScanner {
|
|
|
274
293
|
let partEnd = content.substring(endSnippet.originalIndex + endSnippet.originalCode.length);
|
|
275
294
|
parts.push(partEnd);
|
|
276
295
|
}
|
|
277
|
-
|
|
278
|
-
|
|
296
|
+
try{
|
|
297
|
+
let convertedContent = parts.join("");
|
|
298
|
+
return convertedContent;
|
|
299
|
+
}catch(err){
|
|
300
|
+
console.error(`替换字符串失败: ${err}`);
|
|
301
|
+
return content;
|
|
302
|
+
}
|
|
279
303
|
}
|
|
280
304
|
|
|
281
305
|
}
|
package/src/CSVUtils.ts
CHANGED
|
@@ -110,7 +110,11 @@ export class CSVUtils {
|
|
|
110
110
|
static async updateToFile(filePath: string, literals: string[], langs: string[]) {
|
|
111
111
|
let csvUtils = new CSVUtils(filePath);
|
|
112
112
|
let rows0 = await csvUtils.parseCsv();
|
|
113
|
-
|
|
113
|
+
|
|
114
|
+
// 优化:使用Set去重,减少重复处理
|
|
115
|
+
const uniqueLiterals = [...new Set(literals)];
|
|
116
|
+
|
|
117
|
+
let rows2 = csvUtils.merge(rows0, uniqueLiterals, langs);
|
|
114
118
|
await CSVUtils.writeCsv(filePath, rows2);
|
|
115
119
|
console.log(`已经更新多语言表: ${filePath} , 共有 ${rows2.length - 1} 条目`);
|
|
116
120
|
}
|