scancscode 1.0.55 → 1.0.57

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.
@@ -9,427 +9,563 @@ describe('CSharpStringExtractor', () => {
9
9
  });
10
10
 
11
11
  // 测试从普通函数调用参数中提取字符串表达式信息, 只需要提取参数中的字符串值表达式, 不需要对提取的字符串表达式进行处理
12
- test('should extract plain strings', () => {
13
- const code = 'Console.WriteLine("Hello, world!");';
14
- const snippets = extractor.extractStrings(code);
15
-
16
- expect(snippets.length).toBe(1);
17
- expect(snippets[0].literals).toEqual(['Hello, world!']);
18
- });
19
12
 
20
- // 已经追加 `.TR()` 后缀的字符串表达式不需要重复追加 `.TR()`
21
- test('should handle strings with .TR() already appended', () => {
22
- const code = 'obj.prop = "Hello, world!".TR();';
13
+ describe('should handle .text = format', () => {
14
+ test('should handle .text = format 1', () => {
15
+ const code = `m_text_iwff.text = info ;`;
23
16
  const snippets = extractor.extractStrings(code);
24
-
25
- expect(snippets.length).toBe(1);
26
- expect(snippets[0].originalCode).toBe('"Hello, world!".TR()');
27
- expect(snippets[0].convertedCode).toBe('"Hello, world!".TR()');
28
- expect(snippets[0].isChanged).toBe(false);
29
- });
30
-
31
- // 测试从普通函数调用参数中提取字符串表达式信息, 只需要提取参数中的字符串值表达式, 不需要对提取的字符串表达式进行处理, 也不需要追加 `.TR()`
32
- test('should not add .TR() to function arguments', () => {
33
- const code = 'CallFunc("Hello, world!");';
17
+ {
18
+ let targetSnippet = snippets[0];
19
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`info`));
20
+ expect(targetSnippet.originalCode).toBe(`info`);
21
+ expect(targetSnippet.convertedCode).toBe(`info.TR()`);
22
+ expect(targetSnippet.literals).toEqual([
23
+ ]);
24
+ expect(targetSnippet.isChanged).toBe(true);
25
+ }
26
+ })
27
+ test('should handle .text = format 2', () => {
28
+ const code = `m_text_info.text = info1.member1 + info2.member2;`;
34
29
  const snippets = extractor.extractStrings(code);
35
-
36
- expect(snippets.length).toBe(1);
37
- expect(snippets[0].originalCode).toBe('"Hello, world!"');
38
- expect(snippets[0].convertedCode).toBe('"Hello, world!"');
30
+ {
31
+ let targetSnippet = snippets[0];
32
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`info1.member1 + info2.member2`));
33
+ expect(targetSnippet.originalCode).toBe(`info1.member1 + info2.member2`);
34
+ expect(targetSnippet.convertedCode).toBe(`info1.member1.TR() + info2.member2.TR()`);
35
+ expect(targetSnippet.literals).toEqual([
36
+ ]);
37
+ expect(targetSnippet.isChanged).toBe(true);
38
+ }
39
+ })
39
40
  });
40
41
 
41
- // 测试从普通属性赋值语句中提取字符串表达式信息, 只需要提取赋值表达式中的字符串值表达式, 不需要对提取的字符串表达式进行处理, 也不需要追加 `.TR()`
42
- test('should not add .TR() to regular property assignments', () => {
43
- const code = 'obj.prop = "Hello, world!";';
42
+ describe('should handle .text = with Tr.Format', () => {
43
+ test('should handle .text = with Tr.Format 2', () => {
44
+ const code = 'm_text_lastAward.text = $"[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]";';
44
45
  const snippets = extractor.extractStrings(code);
45
46
 
46
- expect(snippets.length).toBe(1);
47
- expect(snippets[0].originalCode).toBe('"Hello, world!"');
48
- expect(snippets[0].convertedCode).toBe('"Hello, world!"');
47
+ const snippet = snippets[0];
48
+ expect(snippet.originalCode).toBe('$"[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]"');
49
+ expect(snippet.convertedCode).toBe('$"[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]".TR()');
50
+ expect(snippet.literals).toEqual(['[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]']);
51
+ expect(snippet.isChanged).toBe(true);
52
+ })
49
53
  });
50
54
 
51
- // 测试从 $"" 字符串模板(也叫内插字符串)中提取字符串表达式信息, 需要先将字符串模板转换为 `string.Format(...)` 格式, 然后将 `string.Format(...)` 替换为 `Tr.Format(...)`, 之后从 `Tr.Format(...)` 的函数调用参数中提取普通字符串、或进一步递归提取字符串表达式信息
52
- test('should handle $"" string templates', () => {
53
- const code = 'var label1 = $"Hello, {name}!";';
55
+ describe('should handle bracket', () => {
56
+ test('should handle bracket 1', () => {
57
+ const code = `m_text_time.text = $"下一轮神兽出现倒计时: {Date.GetIntweerpolatedTime(ServerTimer.Instance.Time, _startGameStamp)}";`
54
58
  const snippets = extractor.extractStrings(code);
55
59
 
56
- expect(snippets.length).toBe(1);
57
- expect(snippets[0].originalCode).toBe('$"Hello, {name}!"');
58
- expect(snippets[0].literals).toContain('Hello, {0}!');
59
- expect(snippets[0].convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
60
- });
60
+ // 验证提取的片段数量
61
+ expect(snippets.length).toBeGreaterThan(0);
61
62
 
62
- // 测试从普通函数调用参数中提取 $"" 字符串模板(也叫内插字符串), 需要先将字符串模板转换为 `string.Format(...)` 格式, 然后将 `string.Format(...)` 替换为 `Tr.Format(...)`, 之后从 `Tr.Format(...)` 的函数调用参数中提取普通字符串、或进一步递归提取字符串表达式信息
63
- test('should handle $"" string templates in function calls', () => {
64
- const code = 'CallFunc($"Hello, world: {obj.Func1()}");';
63
+ let targetSnippet = snippets[0];
64
+ expect(targetSnippet.originalCode).toBe(`$"下一轮神兽出现倒计时: {Date.GetIntweerpolatedTime(ServerTimer.Instance.Time, _startGameStamp)}"`);
65
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("下一轮神兽出现倒计时: {0}", Date.GetIntweerpolatedTime(ServerTimer.Instance.Time, _startGameStamp))`);
66
+ expect(targetSnippet.literals).toEqual([
67
+ '下一轮神兽出现倒计时: {0}'
68
+ ]);
69
+ expect(targetSnippet.isChanged).toBe(true);
70
+ })
71
+ test('should handle bracket 2', () => {
72
+ const code = `m_text_time.text = $"神兽离去时间: {Date.FeGetInterpolatedTime(ServerTimer.Instance.Time, _endGameStamp)}";`
65
73
  const snippets = extractor.extractStrings(code);
66
74
 
67
- expect(snippets.length).toBe(1);
68
- expect(snippets[0].originalCode).toBe('$"Hello, world: {obj.Func1()}"');
69
- expect(snippets[0].convertedCode).toBe('Tr.Format("Hello, world: {0}", obj.Func1())');
70
- });
75
+ // 验证提取的片段数量
76
+ expect(snippets.length).toBeGreaterThan(0);
71
77
 
72
- // 测试遇到 `string.Format(...)` 形式的字符串表达式, 需要先将 `string.Format(...)` 替换为 `Tr.Format(...)`, 之后从 `Tr.Format(...)` 的函数调用参数中提取普通字符串、或进一步递归提取字符串表达式信息, 内插字符串概念参考: `https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/tokens/interpolated`
73
- test('should convert string.Format to Tr.Format', () => {
74
- const code = 'string.Format("Hello, ", name, "!");';
78
+ let targetSnippet = snippets[0];
79
+ expect(targetSnippet.originalCode).toBe(`$"神兽离去时间: {Date.FeGetInterpolatedTime(ServerTimer.Instance.Time, _endGameStamp)}"`);
80
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("神兽离去时间: {0}", Date.FeGetInterpolatedTime(ServerTimer.Instance.Time, _endGameStamp))`);
81
+ expect(targetSnippet.literals).toEqual([
82
+ '神兽离去时间: {0}'
83
+ ]);
84
+ expect(targetSnippet.isChanged).toBe(true);
85
+ })
86
+ test('should handle bracket 3', () => {
87
+ const code = `desc += $"剩余{ToGetInterpolatedTime(_cardPoolData.FinishTime * 1000, ServerTimer.Instance.Time)}";`
75
88
  const snippets = extractor.extractStrings(code);
76
89
 
77
- expect(snippets.length).toBe(1);
78
- // string.Format(...) 形式的字符串表达式, 不需要对提取的字符串表达式进行处理, 也不需要追加 `.TR()`
79
- // string.Format(...) 形式包含的字符串表达式, 需要特殊处理, 连带 `string.Format()` 一起捕获存入 originalCode 成员
80
- expect(snippets[0].originalCode).toBe('string.Format("Hello, ", name, "!")');
81
- expect(snippets[0].convertedCode).toBe('Tr.Format("Hello, ", name, "!")');
82
- });
90
+ // 验证提取的片段数量
91
+ expect(snippets.length).toBeGreaterThan(0);
83
92
 
84
- // 测试遇到 `string.Format(...)` 形式的字符串表达式, 需要先将 `string.Format(...)` 替换为 `Tr.Format(...)`, 之后从 `Tr.Format(...)` 的函数调用参数中提取普通字符串、或进一步递归提取字符串表达式信息
85
- // 同时测试用 `+` 连接的字符串表达式, 确保用 `+` 符号拼接的字符串表达式被整体处理, 从中提取字符串表达式信息, 而不是分别处理 `+` 两边每个字符串表达式
86
- test('should handle string.Format in .text assignments', () => {
87
- const code = 'label.text = Tr.Format("pre", Func(), "sub") + other;';
93
+ let targetSnippet = snippets[0];
94
+ expect(targetSnippet.originalCode).toBe(`$"剩余{ToGetInterpolatedTime(_cardPoolData.FinishTime * 1000, ServerTimer.Instance.Time)}"`);
95
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("剩余{0}", ToGetInterpolatedTime(_cardPoolData.FinishTime * 1000, ServerTimer.Instance.Time))`);
96
+ expect(targetSnippet.literals).toEqual([
97
+ '剩余{0}'
98
+ ]);
99
+ expect(targetSnippet.isChanged).toBe(true);
100
+ })
101
+ test('should handle bracket 4', () => {
102
+ const code = `desc += $"剩余{ToGetInterpolatedTime(FF(_cardPoolData.FinishTime() * 1000, ServerTimer.Instance.Time()))}";`
88
103
  const snippets = extractor.extractStrings(code);
89
104
 
90
- expect(snippets.length).toBe(1);
91
- expect(snippets[0].originalCode).toBe('Tr.Format("pre", Func(), "sub") + other');
92
- expect(snippets[0].literals).toContain('pre');
93
- expect(snippets[0].literals).toContain('sub');
105
+ // 验证提取的片段数量
106
+ expect(snippets.length).toBeGreaterThan(0);
107
+
108
+ let targetSnippet = snippets[0];
109
+ expect(targetSnippet.originalCode).toBe(`$"剩余{ToGetInterpolatedTime(FF(_cardPoolData.FinishTime() * 1000, ServerTimer.Instance.Time()))}"`);
110
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("剩余{0}", ToGetInterpolatedTime(FF(_cardPoolData.FinishTime() * 1000, ServerTimer.Instance.Time())))`);
111
+ expect(targetSnippet.literals).toEqual([
112
+ '剩余{0}'
113
+ ]);
114
+ expect(targetSnippet.isChanged).toBe(true);
115
+ })
94
116
  });
95
117
 
96
- // 形如 `m_btn_xxx.title = yyy;` 的赋值语句要和形如 `xxx.text = yyy;` 的赋值语句完全等同处理, 其中 `xxx`和`yyy` 代表某段C#字面量, 可以是对象、字符串、或其他表达式, `m_btn_` 为引用符号名固定前缀; 为了便于理解, 用正则表达式表示, 也就是相当于需要同时匹配 `/^m_btn_\w+\.title\s*=/` 形式的表达式和 `/\w+\.text\s*=/` 形式的表达式, 而其中对于 `xxx` 和 `yyy` 部分的处理逻辑是完全一致的
97
- test('should handle m_btn_xxx.title = yyy', () => {
118
+ describe('should handle class member initialization assignment with anonymous function', () => {
119
+ test('should handle class member initialization assignment with anonymous function 1', () => {
98
120
  const code = `
99
- buy.title = "lkwjelkfj1";
100
- m_btn1_buy.title = "lkwjelkfj2";
101
- am_btn_buy.title = "lkwjelkfj3";
102
- m_btn_buy.title = "lkwjelkfj4";
103
- m_btn_wwefHwref.title = $"Hello";
104
- m_btn_fxx_wf.title = $"Hello, {name}!";
121
+ FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
122
+ {
123
+ Title = "提示",
124
+ ConfirmCallback = async () =>
125
+ {
126
+ //灵纹一键下阵
127
+ if (await this.GetModel<CardModel>().DispatchAction(new Rune_Action_CleanRune(_sutraCardData.Card.Id)))
128
+ {
129
+ Toast.Info("卸载成功");
130
+ }
131
+ },
132
+ CancelText = "取消",
133
+ }).Forget();
105
134
  `;
106
135
  const snippets = extractor.extractStrings(code);
107
136
  {
108
- let snippet = snippets[0];
109
- expect(snippet.originalIndex).toBe(code.indexOf('"lkwjelkfj1"'));
110
- expect(snippet.originalCode).toBe('"lkwjelkfj1"');
111
- // `buy` 不符合 `m_btn_` 开头的条件, 不需要强制加 `.TR()`
112
- expect(snippet.convertedCode).toBe('"lkwjelkfj1"');
113
- expect(snippet.literals).toContain('lkwjelkfj1');
114
- expect(snippet.isChanged).toBe(false);
137
+ let targetSnippet = snippets[0];
138
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"提示"`));
139
+ expect(targetSnippet.originalCode).toBe(`"提示"`);
140
+ expect(targetSnippet.convertedCode).toBe(`"提示"`);
141
+ expect(targetSnippet.literals).toEqual([
142
+ '提示'
143
+ ]);
144
+ expect(targetSnippet.isChanged).toBe(false);
115
145
  }
116
146
  {
117
- let snippet = snippets[1];
118
- expect(snippet.originalIndex).toBe(code.indexOf('"lkwjelkfj2"'));
119
- expect(snippet.originalCode).toBe('"lkwjelkfj2"');
120
- // `m_btn1_buy` 不符合 `m_btn_` 开头的条件, 不需要强制加 `.TR()`
121
- expect(snippet.convertedCode).toBe('"lkwjelkfj2"');
122
- expect(snippet.literals).toContain('lkwjelkfj2');
123
- expect(snippet.isChanged).toBe(false);
147
+ let targetSnippet = snippets[1];
148
+ // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
149
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"卸载成功"`));
150
+ expect(targetSnippet.originalCode).toBe(`"卸载成功"`);
151
+ expect(targetSnippet.convertedCode).toBe(`"卸载成功"`);
152
+ expect(targetSnippet.literals).toEqual([
153
+ '卸载成功'
154
+ ]);
155
+ expect(targetSnippet.isChanged).toBe(false);
124
156
  }
125
157
  {
126
- let snippet = snippets[2];
127
- expect(snippet.originalIndex).toBe(code.indexOf('"lkwjelkfj3"'));
128
- expect(snippet.originalCode).toBe('"lkwjelkfj3"');
129
- // `am_btn_buy` 不符合 `m_btn_` 开头的条件, 不需要强制加 `.TR()`
130
- expect(snippet.convertedCode).toBe('"lkwjelkfj3"');
131
- expect(snippet.literals).toContain('lkwjelkfj3');
132
- expect(snippet.isChanged).toBe(false);
158
+ let targetSnippet = snippets[2];
159
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"取消"`));
160
+ expect(targetSnippet.originalCode).toBe(`"取消"`);
161
+ expect(targetSnippet.convertedCode).toBe(`"取消"`);
162
+ expect(targetSnippet.literals).toEqual([
163
+ '取消'
164
+ ]);
165
+ expect(targetSnippet.isChanged).toBe(false);
133
166
  }
167
+ })
168
+ test('should handle class member initialization assignment with anonymous function 2', () => {
169
+ const code = `
170
+ FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
171
+ {
172
+ ConfirmCallback = async () =>
173
+ {
174
+ Toast.Info("卸载成功");
175
+ },
176
+ }).Forget();
177
+ `;
178
+ const snippets = extractor.extractStrings(code);
134
179
  {
135
- let snippet = snippets[3];
136
- expect(snippet.originalIndex).toBe(code.indexOf('"lkwjelkfj4"'));
137
- expect(snippet.originalCode).toBe('"lkwjelkfj4"');
138
- // `m_btn_buy` 符合 `m_btn_` 开头的条件, 需要强制加 `.TR()`
139
- expect(snippet.convertedCode).toBe('"lkwjelkfj4".TR()');
140
- expect(snippet.literals).toContain('lkwjelkfj4');
141
- expect(snippet.isChanged).toBe(true);
180
+ let targetSnippet = snippets[0];
181
+ // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
182
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"卸载成功"`));
183
+ expect(targetSnippet.originalCode).toBe(`"卸载成功"`);
184
+ expect(targetSnippet.convertedCode).toBe(`"卸载成功"`);
185
+ expect(targetSnippet.literals).toEqual([
186
+ '卸载成功'
187
+ ]);
188
+ expect(targetSnippet.isChanged).toBe(false);
142
189
  }
190
+ })
191
+ test('should handle class member initialization assignment with anonymous function 3', () => {
192
+ const code = `
193
+ FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
194
+ {
195
+ ConfirmCallback = (int qwfewe) =>
196
+ {
197
+ Toast.Info($"卸载成功: {qwfewe}");
198
+ },
199
+ }).Forget();
200
+ `;
201
+ const snippets = extractor.extractStrings(code);
143
202
  {
144
- let snippet = snippets[4];
145
- expect(snippet.originalIndex).toBe(code.indexOf('$"Hello"'));
146
- expect(snippet.originalCode).toBe('$"Hello"');
147
- // `m_btn_wwefHwref` 符合 `m_btn_` 开头的条件, 需要强制加 `.TR()`
148
- expect(snippet.convertedCode).toBe('$"Hello".TR()');
149
- expect(snippet.literals).toContain('Hello');
150
- expect(snippet.isChanged).toBe(true);
203
+ let targetSnippet = snippets[0];
204
+ // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
205
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"卸载成功: {qwfewe}"`));
206
+ expect(targetSnippet.originalCode).toBe(`$"卸载成功: {qwfewe}"`);
207
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("卸载成功: {0}", qwfewe)`);
208
+ expect(targetSnippet.literals).toEqual([
209
+ '卸载成功: {0}'
210
+ ]);
211
+ expect(targetSnippet.isChanged).toBe(true);
151
212
  }
213
+ })
214
+ test('should handle class member initialization assignment with anonymous function 4', () => {
215
+ const code = `
216
+ FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
217
+ {
218
+ ConfirmCallback = async () => Toast.Info("卸载成功"),
219
+ }).Forget();
220
+ `;
221
+ const snippets = extractor.extractStrings(code);
152
222
  {
153
- let snippet = snippets[5];
154
- expect(snippet.originalIndex).toBe(code.indexOf('$"Hello, {name}!"'));
155
- expect(snippet.originalCode).toBe('$"Hello, {name}!"');
156
- // `m_btn_fxx_wf` 符合 `m_btn_` 开头的条件
157
- expect(snippet.convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
158
- expect(snippet.literals).toContain('Hello, {0}!');
159
- expect(snippet.isChanged).toBe(true);
223
+ let targetSnippet = snippets[0];
224
+ // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
225
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"卸载成功"`));
226
+ expect(targetSnippet.originalCode).toBe(`"卸载成功"`);
227
+ expect(targetSnippet.convertedCode).toBe(`"卸载成功"`);
228
+ expect(targetSnippet.literals).toEqual([
229
+ '卸载成功'
230
+ ]);
231
+ expect(targetSnippet.isChanged).toBe(false);
160
232
  }
161
- expect(snippets.length).toBe(6);
162
- });
163
-
164
- // 测试用 `+` 连接的字符串表达式, 确保用 `+` 符号拼接的字符串表达式被整体处理, 从中提取字符串表达式信息, 而不是分别处理 `+` 两边每个字符串表达式; 并且给 `+` 连接的每个成分追加 `.TR()` 或者转换为 `Tr.Format(...)` 形式
165
- test('should handle string concatenation', () => {
166
- const code = 'var label2 = "Hello, " + name + "!";';
233
+ })
234
+ test('should handle class member initialization assignment with anonymous function 5', () => {
235
+ const code = `
236
+ FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
237
+ {
238
+ ConfirmCallback = () => Toast.Info("卸载成功"),
239
+ }).Forget();
240
+ `;
167
241
  const snippets = extractor.extractStrings(code);
168
-
169
- expect(snippets.length).toBe(1);
170
- expect(snippets[0].originalCode).toBe('"Hello, " + name + "!"');
171
- expect(snippets[0].convertedCode).toBe('"Hello, ".TR() + name.TR() + "!".TR()');
242
+ {
243
+ let targetSnippet = snippets[0];
244
+ // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
245
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"卸载成功"`));
246
+ expect(targetSnippet.originalCode).toBe(`"卸载成功"`);
247
+ expect(targetSnippet.convertedCode).toBe(`"卸载成功"`);
248
+ expect(targetSnippet.literals).toEqual([
249
+ '卸载成功'
250
+ ]);
251
+ expect(targetSnippet.isChanged).toBe(false);
252
+ }
253
+ })
172
254
  });
173
255
 
174
- // 测试 `xxx.text = yyy;` 形式的赋值语句, 确保将 `yyy` 中的字符串表达式信息提取出来, 并追加 `.TR()` 或者转换为 `Tr.Format(...)` 形式; 其中 `xxx`和`yyy` 代表某段C#字面量, 可以是对象、字符串、或其他表达式
175
- test('should handle .text = assignments with function calls', () => {
176
- const code = 'label.text = Func();';
256
+ describe('should handle comment boundary', () => {
257
+ test('should handle comment boundary 1', () => {
258
+ const code = `
259
+ //上锁
260
+ case (int)State.Lock:
261
+ Toast.Info($"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁");
262
+ break;
263
+ `;
177
264
  const snippets = extractor.extractStrings(code);
178
-
179
- expect(snippets.length).toBe(1);
180
- expect(snippets[0].originalCode).toBe('Func()');
181
- expect(snippets[0].convertedCode).toBe('Func().TR()');
182
- });
183
-
184
- // 测试 `xxx.text = xxx + xxx;` 形式的赋值语句, 确保将 `xxx.text` 中的 `xxx` 字符串表达式提取出来, 并追加 `.TR()` 或者转换为 `Tr.Format(...)` 形式; 其中 `xxx`和`yyy` 代表某段C#表达式, 可以是对象、字符串、或其他表达式
185
- test('should handle .text = assignments with multiple function calls', () => {
186
- const code = 'label.text = Func() + Func();';
265
+ {
266
+ let targetSnippet = snippets[0];
267
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`));
268
+ expect(targetSnippet.originalCode).toBe(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`);
269
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("灵田{0}级解锁", _model.GetFarmLandUnlockLevel(_landId))`);
270
+ expect(targetSnippet.literals).toEqual([
271
+ '灵田{0}级解锁'
272
+ ]);
273
+ expect(targetSnippet.isChanged).toBe(true);
274
+ }
275
+ })
276
+ test('should handle comment boundary 2', () => {
277
+ const code = `
278
+ // klwjfe
279
+ namespace TestNamespace{
280
+ // lkwjfe
281
+ public class FK{
282
+ // klwf
283
+ public void TestM(){
284
+ // 模拟状态变量
285
+ var _state = (int)State.Lock;
286
+ // 模拟土地ID变量
287
+ switch (_state){
288
+ //上锁
289
+ case (int)State.Lock:
290
+ // lkwjefl
291
+ Toast.Info($"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁");
292
+ // klwejf
293
+ break;
294
+ // lkwjf
295
+ }
296
+ // klwjfel
297
+ }
298
+ }
299
+ }
300
+ `;
187
301
  const snippets = extractor.extractStrings(code);
188
-
189
- expect(snippets.length).toBe(1);
190
- expect(snippets[0].originalCode).toBe('Func() + Func()');
191
- expect(snippets[0].convertedCode).toBe('Func().TR() + Func().TR()');
192
- });
193
-
194
- // 测试 `xxx.text = yyy;` 形式的赋值语句, 确保将 `yyy` 中的 `xxx` 内插字符串提取出来, 并转换为 `Tr.Format(...)` 形式; 其中 `xxx`和`yyy` 代表某段C#表达式, 可以是对象、字符串、或其他表达式
195
- test('should handle .text = assignments with string templates', () => {
196
- const code = 'label.text = $"pre{Func()}sub";';
302
+ {
303
+ let targetSnippet = snippets[0];
304
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`));
305
+ expect(targetSnippet.originalCode).toBe(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`);
306
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("灵田{0}级解锁", _model.GetFarmLandUnlockLevel(_landId))`);
307
+ expect(targetSnippet.literals).toEqual([
308
+ '灵田{0}级解锁'
309
+ ]);
310
+ expect(targetSnippet.isChanged).toBe(true);
311
+ }
312
+ })
313
+ test('should handle comment boundary 3', () => {
314
+ const code = `
315
+ // klwjfe
316
+ namespace TestNamespace{
317
+ // lkwjfe
318
+ public class FK{
319
+ // wlkjelj
320
+ private int Llkwe = 23;
321
+ // lkjlkj
322
+ private int Dwekl { get; set; } = 23;
323
+ // jklwef
324
+ private static int Dwekl { get; set; } = 23;
325
+ // lkwjeflk
326
+ public static void TestM(){}
327
+ // wesd
328
+ public static void TestM()
329
+ {
330
+ }
331
+ // wesd
332
+ public static void TestM(){
333
+ }
334
+ // klwf
335
+ public void TestM(){
336
+ // 模拟状态变量
337
+ var _state = (int)State.Lock;
338
+ // 模拟土地ID变量
339
+ switch (_state){
340
+ //上锁
341
+ case (int)State.Lock:
342
+ // lkwjefl
343
+ Toast.Info($"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁");
344
+ // klwejf
345
+ break;
346
+ // lkwjf
347
+ }
348
+ // klwjfel
349
+ }
350
+ }
351
+ }
352
+ `;
197
353
  const snippets = extractor.extractStrings(code);
198
-
199
- expect(snippets.length).toBe(1);
200
- expect(snippets[0].originalCode).toBe('$"pre{Func()}sub"');
201
- expect(snippets[0].literals).toContain('pre{0}sub');
202
- expect(snippets[0].convertedCode).toBe('Tr.Format("pre{0}sub", Func())');
354
+ {
355
+ let targetSnippet = snippets[0];
356
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`));
357
+ expect(targetSnippet.originalCode).toBe(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`);
358
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("灵田{0}级解锁", _model.GetFarmLandUnlockLevel(_landId))`);
359
+ expect(targetSnippet.literals).toEqual([
360
+ '灵田{0}级解锁'
361
+ ]);
362
+ expect(targetSnippet.isChanged).toBe(true);
363
+ }
364
+ })
203
365
  });
204
366
 
205
- // 测试从内插字符串中提取字符串表达式信息时, 需要注意转换和捕获内插字符串格式参数, 内插字符串和对应格式参数参考: `https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/tokens/interpolated`
206
- test('should handle .text = assignments with string.Format', () => {
207
- const code = 'label.text = string.Format("pre{0:F2}{1}", Func(), "sub") + other;';
367
+ describe('should handle complex string', () => {
368
+ test('should handle complex string 1', () => {
369
+ const code = `
370
+ infoStr += $"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n";
371
+ infoStr += $"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n";
372
+ `;
208
373
  const snippets = extractor.extractStrings(code);
209
-
210
- expect(snippets.length).toBe(1);
211
- expect(snippets[0].originalCode).toBe('string.Format("pre{0:F2}{1}", Func(), "sub") + other');
212
- expect(snippets[0].literals).toContain('pre{0:F2}{1}');
213
- expect(snippets[0].literals).toContain('sub');
214
- });
215
-
216
- // 测试用 `+` 连接的字符串表达式, 确保用 `+` 符号拼接的字符串表达式被整体处理, 从中提取字符串表达式信息, 而不是分别处理 `+` 两边每个字符串表达式; 并且给 `+` 连接的每个成分追加 `.TR()` 或者转换为 `Tr.Format(...)` 形式或进一步递归处理
217
- test('should handle complex concatenation with existing .TR() calls', () => {
218
- const code = 'var hello3 = "Hello, ".TR() + name.TR() + obj2.name.TR() + obj2.nam1_e.Fn1().Prop + "!";';
374
+ {
375
+ let targetSnippet = snippets[0];
376
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n"`));
377
+ expect(targetSnippet.originalCode).toBe(`$"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n"`);
378
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`);
379
+ expect(targetSnippet.literals).toEqual([
380
+ '伤害类型: [color={0}][b]{1}[/b][/color]\n'
381
+ ]);
382
+ expect(targetSnippet.isChanged).toBe(true);
383
+ }
384
+ })
385
+ test('should handle complex string 2', () => {
386
+ const code = `
387
+ infoStr += Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType);
388
+ infoStr += $"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n";
389
+ `;
219
390
  const snippets = extractor.extractStrings(code);
391
+ {
392
+ let targetSnippet = snippets[0];
393
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`));
394
+ expect(targetSnippet.originalCode).toBe(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`);
395
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`);
396
+ expect(targetSnippet.literals).toEqual([
397
+ '伤害类型: [color={0}][b]{1}[/b][/color]\n'
398
+ ]);
399
+ expect(targetSnippet.isChanged).toBe(false);
400
+ }
401
+ })
402
+ test('should handle complex string 4', () => {
403
+ const code = `
404
+ private void OnBtnIaa(EventContext context)
405
+ {
406
+ var iaaConfig = IAAConfigTable.GetConfigById((int)IAAId.境界失败_加速冷却);
407
+ if (iaaConfig == null)
408
+ {
409
+ return;
410
+ }
220
411
 
221
- expect(snippets.length).toBe(1);
222
- expect(snippets[0].originalCode).toBe('"Hello, ".TR() + name.TR() + obj2.name.TR() + obj2.nam1_e.Fn1().Prop + "!"');
223
- expect(snippets[0].convertedCode).toBe('"Hello, ".TR() + name.TR() + obj2.name.TR() + obj2.nam1_e.Fn1().Prop.TR() + "!".TR()');
224
- });
225
-
226
- // 测试处理包含转义引号的字符串表达式, 确保能正确提取和转换转义引号, 而不会影响字符串边界的正常解析
227
- test('should handle escaped quotes in strings', () => {
228
- const code = 'Debug.Log("aaa\\\"bbb\\\"c\\\"d\\\\\\"cc");';
412
+ string des = $"观看视频后\n等待时间减少{iaaConfig.EffectValue / 60}分钟";
413
+ this.GetModel<IAAModel>().ShowAdWithDialog(IAAId.境界失败_加速冷却, "加速时间", des, null);
414
+ }
415
+ `;
229
416
  const snippets = extractor.extractStrings(code);
230
-
231
- expect(snippets.length).toBe(1);
232
- expect(snippets[0].originalCode).toBe('"aaa\\\"bbb\\\"c\\\"d\\\\\\"cc"');
233
- expect(snippets[0].convertedCode).toBe('"aaa\\\"bbb\\\"c\\\"d\\\\\\"cc"');
234
- // 由于JavaScript字符串转义的复杂性,我们只检查是否提取了字符串
235
- expect(snippets[0].literals).toEqual(['aaa\\\"bbb\\\"c\\\"d\\\\\\"cc']);
417
+ {
418
+ let targetSnippet = snippets[0];
419
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"观看视频后\n等待时间减少{iaaConfig.EffectValue / 60}分钟"`));
420
+ expect(targetSnippet.originalCode).toBe(`$"观看视频后\n等待时间减少{iaaConfig.EffectValue / 60}分钟"`);
421
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("观看视频后\n等待时间减少{0}分钟", iaaConfig.EffectValue / 60)`);
422
+ expect(targetSnippet.literals).toEqual([
423
+ '观看视频后\n等待时间减少{0}分钟'
424
+ ]);
425
+ expect(targetSnippet.isChanged).toBe(true);
426
+ }
427
+ })
236
428
  });
237
429
 
238
- // 测试处理包含 `+` 连接的字符串表达式, 需要给 `+` 连接的每个成分追加 `.TR()` 或者转换为 `Tr.Format(...)` 形式或进一步递归处理
239
- test('should capture statement boundaries correctly', () => {
240
- const code = 'obj.text = "Test property" + "Test property2";';
430
+ describe('should handle complex string with optional value', () => {
431
+ test('should handle complex string with optional value 3', () => {
432
+ const code = `
433
+ else if (battleModel.CurGameType == BattleModel.GameType.Teamwork)
434
+ {
435
+ //合作模式显示队友名称
436
+ m_text_otherName.text = battleModel.TeammatePlayerData?.Name ?? "";
437
+ }
438
+ `;
241
439
  const snippets = extractor.extractStrings(code);
242
-
243
- expect(snippets.length).toBe(1);
244
- expect(snippets[0].originalCode).toBe('"Test property" + "Test property2"');
245
- expect(snippets[0].convertedCode).toBe('"Test property".TR() + "Test property2".TR()');
440
+ {
441
+ let targetSnippet = snippets[0];
442
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`battleModel.TeammatePlayerData?.Name ?? ""`));
443
+ expect(targetSnippet.originalCode).toBe(`battleModel.TeammatePlayerData?.Name ?? ""`);
444
+ expect(targetSnippet.convertedCode).toBe(`battleModel.TeammatePlayerData?.Name ?? "".TR()`);
445
+ expect(targetSnippet.literals).toEqual([
446
+ ''
447
+ ]);
448
+ expect(targetSnippet.isChanged).toBe(true);
449
+ }
450
+ })
246
451
  });
247
452
 
248
- // 测试处理包含多个语句的C#代码, 确保能从各个语句中正确提取和转换每个语句中的字符串表达式, 而不会影响其他语句的正常解析
249
- test('should handle multiple statements', () => {
250
- const code = 'obj1.text = "Hello"; obj2.text = "World";';
453
+ describe('should handle duplicate tr handle', () => {
454
+ test('should handle duplicate tr handle 1', () => {
455
+ const code = `infoStr = $"+={colorCode}";`
251
456
  const snippets = extractor.extractStrings(code);
252
457
 
253
- expect(snippets.length).toBe(2);
254
- expect(snippets[0].originalCode).toBe('"Hello"');
255
- expect(snippets[0].convertedCode).toBe('"Hello".TR()');
256
- expect(snippets[1].originalCode).toBe('"World"');
257
- expect(snippets[1].convertedCode).toBe('"World".TR()');
258
- });
458
+ // 验证提取的片段数量
459
+ expect(snippets.length).toBeGreaterThan(0);
259
460
 
260
- // 测试处理作为函数参数的内插字符串表达式, 确保能从内插字符串中提取字符串表达式信息, 并转换为 `Tr.Format(...)` 形式
261
- test('should extract and convert string templates', () => {
262
- const code = 'Ljk.Ilk($"Hello, {name}!");';
461
+ let targetSnippet = snippets[0];
462
+ expect(targetSnippet.originalCode).toBe(`$"+={colorCode}"`);
463
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("+={0}", colorCode)`);
464
+ expect(targetSnippet.literals).toEqual([
465
+ '+={0}'
466
+ ]);
467
+ expect(targetSnippet.isChanged).toBe(true);
468
+ })
469
+ test('should handle duplicate tr handle 2', () => {
470
+ const code = `infoStr += $"={colorCode}";`
263
471
  const snippets = extractor.extractStrings(code);
264
472
 
473
+ // 验证提取的片段数量
265
474
  expect(snippets.length).toBeGreaterThan(0);
266
- const snippet = snippets[0];
267
- expect(snippet.originalCode).toBe('$"Hello, {name}!"');
268
- expect(snippet.convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
269
- expect(snippet.literals).toEqual(['Hello, {0}!']);
270
- expect(snippet.isChanged).toBe(true);
271
- });
272
-
273
- // 测试处理 `string.Format` 调用, 确保能将其转换为 `Tr.Format(...)` 形式, 并正确提取字符串表达式信息
274
- test('should convert string.Format to Tr.Format', () => {
275
- const code = 'string.Format("Hello, {0}!", name);';
276
- const snippets = extractor.extractStrings(code);
277
-
278
- expect(snippets.length).toBeGreaterThan(0);
279
- const snippet = snippets[0];
280
- expect(snippet.originalCode).toBe('string.Format("Hello, {0}!", name)');
281
- expect(snippet.convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
282
- expect(snippet.literals).toEqual(['Hello, {0}!']);
283
- expect(snippet.isChanged).toBe(true);
284
- });
285
475
 
286
- // 测试处理 `xxx.text = yyy;` 形式赋值语句, 以 `.text =` 给 `text` 成员赋值的表达式中, `yyy` 部分必定是字符串表达式, 需要从 `yyy` 中正确提取字符串表达式信息, 并给普通字符串表达式追加 `.TR()` 或者让内插字符串转换为 `Tr.Format(...)` 形式
287
- test('should handle .text = assignments', () => {
288
- const code = 'label.text = "Test";';
476
+ let targetSnippet = snippets[0];
477
+ expect(targetSnippet.originalCode).toBe(`$"={colorCode}"`);
478
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("={0}", colorCode)`);
479
+ expect(targetSnippet.literals).toEqual([
480
+ '={0}'
481
+ ]);
482
+ expect(targetSnippet.isChanged).toBe(true);
483
+ })
484
+ test('should handle duplicate tr handle 3', () => {
485
+ const code = `infoStr += $"+={colorCode}";`
289
486
  const snippets = extractor.extractStrings(code);
290
487
 
488
+ // 验证提取的片段数量
291
489
  expect(snippets.length).toBeGreaterThan(0);
292
- const snippet = snippets[0];
293
- expect(snippet.originalCode).toBe('"Test"');
294
- expect(snippet.convertedCode).toBe('"Test".TR()');
295
- expect(snippet.literals).toEqual(['Test']);
296
- expect(snippet.isChanged).toBe(true);
297
- });
298
490
 
299
- // 测试处理包含 `+` 连接的字符串表达式, 需要给 `+` 连接的每个成分追加 `.TR()` 或者转换为 `Tr.Format(...)` 形式或进一步递归处理
300
- test('should handle string concatenations', () => {
301
- const code = 'var wkleee = "Hello, " + name + "!";';
491
+ let targetSnippet = snippets[0];
492
+ expect(targetSnippet.originalCode).toBe(`$"+={colorCode}"`);
493
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("+={0}", colorCode)`);
494
+ expect(targetSnippet.literals).toEqual([
495
+ '+={0}'
496
+ ]);
497
+ expect(targetSnippet.isChanged).toBe(true);
498
+ })
499
+ test('should handle duplicate tr handle 4', () => {
500
+ const code = `infoStr += $"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n";`
302
501
  const snippets = extractor.extractStrings(code);
303
502
 
503
+ // 验证提取的片段数量
304
504
  expect(snippets.length).toBeGreaterThan(0);
305
- const snippet = snippets[0];
306
- expect(snippet.originalCode).toBe('"Hello, " + name + "!"');
307
- expect(snippet.convertedCode).toBe('"Hello, ".TR() + name.TR() + "!".TR()');
308
- expect(snippet.literals).toEqual(['Hello, ', '!']);
309
- expect(snippet.isChanged).toBe(true);
310
- });
311
-
312
- // 测试处理 `+` 连接的字符串表达式时, 确保不会给已经包含 `.TR()` 的字符串表达式再次追加 `.TR()`
313
- test('should not add .TR() to strings already having it', () => {
314
- const code = 'var wkle = "Hello".TR();';
315
- const snippets = extractor.extractStrings(code);
316
-
317
- const snippet = snippets[0];
318
- expect(snippet.originalCode).toBe('"Hello".TR()');
319
- expect(snippet.convertedCode).toBe('"Hello".TR()');
320
- expect(snippet.literals).toEqual(['Hello']);
321
- expect(snippet.isChanged).toBe(false);
322
- });
323
-
324
- // 测试处理复杂的 `.text =` 赋值语句, 确保能正确处理包含 `string.Format` 调用和 `+` 连接的字符串表达式, 并转换为 `Tr.Format(...)` 形式或进一步递归处理
325
- test('should handle complex text assignments', () => {
326
- const code = 'label.text = string.Format("pre{0}sub", Func()) + other;';
327
- const snippets = extractor.extractStrings(code);
328
-
329
- const snippet = snippets[0];
330
- expect(snippet.originalCode).toBe('string.Format("pre{0}sub", Func()) + other');
331
- expect(snippet.convertedCode).toBe('Tr.Format("pre{0}sub", Func()) + other.TR()');
332
- expect(snippet.literals).toEqual(['pre{0}sub']);
333
- expect(snippet.isChanged).toBe(true);
334
- });
335
-
336
- // 测试处理转义字符串, 确保能正确处理包含转义字符的字符串表达式, 并给普通字符串表达式追加 `.TR()` 或者让内插字符串转换为 `Tr.Format(...)` 形式
337
- test('should handle escaped strings', () => {
338
- const code = 'a.text = "aaa\\"bbb\\"c\\"d\\\\\\"cc";';
339
- const snippets = extractor.extractStrings(code);
340
505
 
341
- const snippet = snippets[0];
342
- expect(snippet.originalCode).toBe('"aaa\\"bbb\\"c\\"d\\\\\\"cc"');
343
- expect(snippet.convertedCode).toBe('"aaa\\"bbb\\"c\\"d\\\\\\"cc".TR()');
344
- expect(snippet.literals).toEqual(['aaa\\"bbb\\"c\\"d\\\\\\"cc']);
345
- expect(snippet.isChanged).toBe(true);
506
+ let targetSnippet = snippets[0];
507
+ expect(targetSnippet.originalCode).toBe(`$"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n"`);
508
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`);
509
+ expect(targetSnippet.literals).toEqual([
510
+ '伤害类型: [color={0}][b]{1}[/b][/color]\n'
511
+ ]);
512
+ expect(targetSnippet.isChanged).toBe(true);
513
+ })
346
514
  });
347
515
 
348
- // 测试处理 `@$""` 和 `$@""` 格式的字符串表达式, 确保能将其转换为 `Tr.Format(...)` 形式, 并正确提取字符串表达式信息
349
- test('should handle @$"" and $@"" formats', () => {
350
- const code = 'Fcx.Kjl(@$"Hello, {name}!");';
516
+ describe('should handle lost', () => {
517
+ test('should handle lost 1', () => {
518
+ const code = readFileSync('./test/KeeperDialog.cs', 'utf8');
351
519
  const snippets = extractor.extractStrings(code);
352
520
 
353
- const snippet = snippets[0];
354
- expect(snippet.originalCode).toBe('@$"Hello, {name}!"');
355
- expect(snippet.convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
356
- expect(snippet.literals).toEqual(['Hello, {0}!']);
357
- expect(snippet.isChanged).toBe(true);
358
- });
359
-
360
- // 测试处理函数调用时, 确保能正确提取参数中的字符串表达式, 不需要给字符串表达式追加 `.TR()` 或 转换为 `Tr.Format(...)` 形式, 除非遇到由 `+` 连接的字符串表达式
361
- test('should handle function calls with string arguments', () => {
362
- const code = 'CallFunc("Hello", "World");';
363
- const snippets = extractor.extractStrings(code);
364
- {
365
- const snippet = snippets[0];
366
- expect(snippet.originalCode).toBe('"Hello"');
367
- expect(snippet.convertedCode).toBe('"Hello"');
368
- expect(snippet.literals).toEqual(['Hello']);
369
- expect(snippet.isChanged).toBe(false);
370
- }
371
- {
521
+ let targetSnippet = snippets[3];
522
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"已购买";
523
+ m_btn_buy.enabled = false;
372
524
 
373
- const snippet = snippets[1];
374
- expect(snippet.originalCode).toBe('"World"');
375
- expect(snippet.convertedCode).toBe('"World"');
376
- expect(snippet.literals).toEqual(['World']);
377
- expect(snippet.isChanged).toBe(false);
378
- }
379
- });
525
+ //购买后自动启用`));
526
+ expect(targetSnippet.originalCode).toBe(`"已购买"`);
527
+ expect(targetSnippet.convertedCode).toBe(`"已购买".TR()`);
528
+ expect(targetSnippet.literals).toEqual([
529
+ "已购买"
530
+ ]);
531
+ expect(targetSnippet.isChanged).toBe(true);
380
532
 
381
- // 测试处理 `.text =` 赋值语句时, 确保能正确处理包含 `Tr.Format(...)` 调用的字符串表达式, 并给普通字符串表达式追加 `.TR()` 或者让内插字符串转换为 `Tr.Format(...)` 形式
382
- test('should handle .text = with Tr.Format', () => {
383
- const code = 'label.text = Tr.Format("pre", Func(), "sub") + other;';
533
+ // 验证提取的片段数量
534
+ expect(snippets.length).toBeGreaterThanOrEqual(5)
535
+ })
536
+ test('should handle lost 2', () => {
537
+ const code = `m_text_runeSlot.text = Tr.Format(")", _sutraCardData.Card.RuneOpenCount);`;
384
538
  const snippets = extractor.extractStrings(code);
385
539
 
386
- const snippet = snippets[0];
387
- expect(snippet.originalCode).toBe('Tr.Format("pre", Func(), "sub") + other');
388
- expect(snippet.convertedCode).toBe('Tr.Format("pre", Func(), "sub") + other.TR()');
389
- expect(snippet.literals).toEqual(['pre', 'sub']);
390
- expect(snippet.isChanged).toBe(true);
391
- });
540
+ let targetSnippet = snippets[0];
541
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format(")", _sutraCardData.Card.RuneOpenCount)`));
542
+ expect(targetSnippet.originalCode).toBe(`Tr.Format(")", _sutraCardData.Card.RuneOpenCount)`);
543
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format(")", _sutraCardData.Card.RuneOpenCount)`);
544
+ // 字符串中包含 `)` 符号时, 也需要捕获该字符串
545
+ expect(targetSnippet.literals).toEqual([
546
+ ')'
547
+ ]);
548
+ expect(targetSnippet.isChanged).toBe(false);
392
549
 
393
- // 测试处理 `.text =` 赋值语句时, 确保能正确处理包含 `Tr.Format(...)` 调用的字符串表达式, 并给普通字符串表达式追加 `.TR()` 或者让内插字符串转换为 `Tr.Format(...)` 形式, 除非遇到由 `+` 连接的字符串表达式
394
- test('should handle .text = with Tr.Format 2', () => {
395
- const code = 'm_text_lastAward.text = $"[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]";';
550
+ })
551
+ test('should handle lost 3', () => {
552
+ const code = `m_text_runeSlot.text = ")";`;
396
553
  const snippets = extractor.extractStrings(code);
397
554
 
398
- const snippet = snippets[0];
399
- expect(snippet.originalCode).toBe('$"[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]"');
400
- expect(snippet.convertedCode).toBe('$"[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]".TR()');
401
- expect(snippet.literals).toEqual(['[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]']);
402
- expect(snippet.isChanged).toBe(true);
403
- });
404
-
405
- // 处理C#多行语句
406
- test('should handle non string assignment 1', () => {
407
- const code = 'var d1 = 12;var d2 = 13;var d3 = d1 + d2;var aa = "aaa";';
408
- const snippets = extractor.extractStrings(code);
409
- {
410
- const snippet = snippets[0];
411
- expect(snippet.originalCode).toBe('"aaa"');
412
- expect(snippet.convertedCode).toBe('"aaa"');
413
- expect(snippet.literals).toEqual(['aaa']);
414
- expect(snippet.isChanged).toBe(false);
415
- }
416
- });
555
+ let targetSnippet = snippets[0];
556
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`")"`));
557
+ expect(targetSnippet.originalCode).toBe(`")"`);
558
+ expect(targetSnippet.convertedCode).toBe(`")".TR()`);
559
+ expect(targetSnippet.literals).toEqual([
560
+ ')'
561
+ ]);
562
+ expect(targetSnippet.isChanged).toBe(true);
417
563
 
418
- // 处理C#多行语句
419
- test('should handle non string assignment 2', () => {
420
- const code = 'var d3 = d1 + d2;var aa = "aaa";';
421
- const snippets = extractor.extractStrings(code);
422
- {
423
- const snippet = snippets[0];
424
- expect(snippet.originalCode).toBe('"aaa"');
425
- expect(snippet.convertedCode).toBe('"aaa"');
426
- expect(snippet.literals).toEqual(['aaa']);
427
- expect(snippet.isChanged).toBe(false);
428
- }
564
+ })
429
565
  });
430
566
 
431
- // 处理C#多行语句
432
- test('should handle multilne content1', () => {
567
+ describe('should handle multilne content', () => {
568
+ test('should handle multilne content 1', () => {
433
569
  const code = 'var aa = "aaa";\nvar bb = "bbb";\nvar cc = "ccc";';
434
570
  const snippets = extractor.extractStrings(code);
435
571
  {
@@ -453,10 +589,8 @@ describe('CSharpStringExtractor', () => {
453
589
  expect(snippet.literals).toEqual(['ccc']);
454
590
  expect(snippet.isChanged).toBe(false);
455
591
  }
456
- });
457
-
458
- // 处理C#多行语句
459
- test('should handle multilne content2', () => {
592
+ })
593
+ test('should handle multilne content 2', () => {
460
594
  const code = 'var d1 = 12;var d2 = 13;var d3 = d1 + d2;var aa = "aaa";\nvar bb = "bbb";\nvar dd = aa + bb;\nvar hh = aa + bb + "hhh";\ncc.text = "ccc" + aa + bb;var ii = "iii";jj.text = "jjj";CallFunc("jjj");CallFunc2("jjj", "kkk");jj.text = "jjj" + ll;';
461
595
  const snippets = extractor.extractStrings(code);
462
596
  {
@@ -529,10 +663,8 @@ describe('CSharpStringExtractor', () => {
529
663
  expect(snippet.literals).toEqual(['jjj']);
530
664
  expect(snippet.isChanged).toBe(true);
531
665
  }
532
- });
533
-
534
- // 处理C#多行语句
535
- test('should handle multilne content3', () => {
666
+ })
667
+ test('should handle multilne content 3', () => {
536
668
  const code = 'label.text = Tr.Format("pre", Func(), "sub") + other;\nlabel2.text = Tr.Format("pre2", Func(), "sub2") + other2;';
537
669
  const snippets = extractor.extractStrings(code);
538
670
  {
@@ -549,10 +681,8 @@ describe('CSharpStringExtractor', () => {
549
681
  expect(snippet.literals).toEqual(['pre2', 'sub2']);
550
682
  expect(snippet.isChanged).toBe(true);
551
683
  }
552
- });
553
-
554
- // 处理C#多行语句
555
- test('should handle multilne content4', () => {
684
+ })
685
+ test('should handle multilne content 4', () => {
556
686
  const code = 'label.text =\n Tr.Format(\n\t"pre", Func(),\n\t\t "sub") + other;';
557
687
  const snippets = extractor.extractStrings(code);
558
688
  {
@@ -562,10 +692,8 @@ describe('CSharpStringExtractor', () => {
562
692
  expect(snippet.literals).toEqual(['pre', 'sub']);
563
693
  expect(snippet.isChanged).toBe(true);
564
694
  }
565
- });
566
-
567
- // 处理C#多行语句
568
- test('should handle multilne content5', () => {
695
+ })
696
+ test('should handle multilne content 5', () => {
569
697
  const code = `
570
698
  // 注释中无字符串表达式时, 不需要包含在捕获部分里
571
699
  m_text_name.text = cardTable.Name;
@@ -578,10 +706,8 @@ describe('CSharpStringExtractor', () => {
578
706
  expect(snippet.literals).toEqual([]);
579
707
  expect(snippet.isChanged).toBe(true);
580
708
  }
581
- });
582
-
583
- // 处理C#多行语句
584
- test('should handle multilne content6', () => {
709
+ })
710
+ test('should handle multilne content 6', () => {
585
711
  const code = `
586
712
  if (condition)
587
713
  {
@@ -597,10 +723,8 @@ describe('CSharpStringExtractor', () => {
597
723
  expect(snippet.originalIndex).toBe(code.indexOf('"卸载成功"'));
598
724
  expect(snippet.isChanged).toBe(false);
599
725
  }
600
- });
601
-
602
- // 处理C#多行语句
603
- test('should handle multilne content7', () => {
726
+ })
727
+ test('should handle multilne content 7', () => {
604
728
  const code = `
605
729
  while (condition)
606
730
  {
@@ -616,10 +740,8 @@ describe('CSharpStringExtractor', () => {
616
740
  expect(snippet.originalIndex).toBe(code.indexOf('"卸载成功"'));
617
741
  expect(snippet.isChanged).toBe(false);
618
742
  }
619
- });
620
-
621
- // 处理C#多行语句
622
- test('should handle multilne content8', () => {
743
+ })
744
+ test('should handle multilne content 8', () => {
623
745
  const code = `
624
746
  for (scope;condition;continuex)
625
747
  {
@@ -634,10 +756,8 @@ describe('CSharpStringExtractor', () => {
634
756
  expect(snippet.literals).toEqual(['卸载成功']);
635
757
  expect(snippet.isChanged).toBe(false);
636
758
  }
637
- });
638
-
639
- // 处理C#多行语句
640
- test('should handle multilne content9', () => {
759
+ })
760
+ test('should handle multilne content 9', () => {
641
761
  const code = `
642
762
  {
643
763
  KK3.Ca3("卸载成功");
@@ -651,10 +771,8 @@ describe('CSharpStringExtractor', () => {
651
771
  expect(snippet.literals).toEqual(['卸载成功']);
652
772
  expect(snippet.isChanged).toBe(false);
653
773
  }
654
- });
655
-
656
- // 处理C#多行语句
657
- test('should handle multilne content10', () => {
774
+ })
775
+ test('should handle multilne content 10', () => {
658
776
  const code = `
659
777
  var lambda1 = () => {
660
778
  LJN4.Fn4("卸载成功");
@@ -668,10 +786,8 @@ describe('CSharpStringExtractor', () => {
668
786
  expect(snippet.literals).toEqual(['卸载成功']);
669
787
  expect(snippet.isChanged).toBe(false);
670
788
  }
671
- });
672
-
673
- // 处理C#多行语句
674
- test('should handle multilne content11', () => {
789
+ })
790
+ test('should handle multilne content 11', () => {
675
791
  const code = `
676
792
  void lambda1() {
677
793
  KK5.Call5("卸载成功");
@@ -685,10 +801,8 @@ describe('CSharpStringExtractor', () => {
685
801
  expect(snippet.literals).toEqual(['卸载成功']);
686
802
  expect(snippet.isChanged).toBe(false);
687
803
  }
688
- });
689
-
690
- // 处理C#多行语句
691
- test('should handle multilne content12', () => {
804
+ })
805
+ test('should handle multilne content 12', () => {
692
806
  const code = `
693
807
  //星级
694
808
  m_list_star.RemoveChildrenToPool();
@@ -713,10 +827,8 @@ describe('CSharpStringExtractor', () => {
713
827
  expect(snippet.literals).toEqual(['{0}阶']);
714
828
  expect(snippet.isChanged).toBe(false);
715
829
  }
716
- });
717
-
718
- // 处理C#多行语句
719
- test('should handle multilne content13', () => {
830
+ })
831
+ test('should handle multilne content 13', () => {
720
832
  const code = `
721
833
  Toast.Info("卸载成功");
722
834
  Toast.Info("卸载成功");
@@ -738,10 +850,8 @@ describe('CSharpStringExtractor', () => {
738
850
  expect(snippet.literals).toEqual(['卸载成功']);
739
851
  expect(snippet.isChanged).toBe(false);
740
852
  }
741
- });
742
-
743
- // 处理C#多行语句
744
- test('should handle multilne content14', () => {
853
+ })
854
+ test('should handle multilne content 14', () => {
745
855
  const code = readFileSync('./test/MainSutraDetailDialog.cs', 'utf8');
746
856
  const snippets = extractor.extractStrings(code);
747
857
 
@@ -920,10 +1030,8 @@ describe('CSharpStringExtractor', () => {
920
1030
  expect(snippets[21].convertedCode).toBe('"卸载成功"');
921
1031
  expect(snippets[21].literals).toEqual(['卸载成功']);
922
1032
  expect(snippets[21].isChanged).toBe(false);
923
- });
924
-
925
- // 处理C#多行语句
926
- test('should handle multilne content15', () => {
1033
+ })
1034
+ test('should handle multilne content 15', () => {
927
1035
  const code = readFileSync('./test/GuildDonateDialog.cs', 'utf8');
928
1036
  const snippets = extractor.extractStrings(code);
929
1037
 
@@ -944,41 +1052,8 @@ describe('CSharpStringExtractor', () => {
944
1052
  expect(targetSnippet.isChanged).toBe(true);
945
1053
  }
946
1054
 
947
- });
948
-
949
- // 处理C#普通字符串包含 `//` 的情形
950
- test('should handle string with `//`', () => {
951
- const code = `m_btn_paid.text = "//";`
952
- const snippets = extractor.extractStrings(code);
953
-
954
- // 验证提取的片段数量
955
- expect(snippets.length).toBeGreaterThan(0);
956
-
957
- let targetSnippet = snippets[0];
958
- expect(targetSnippet.originalCode).toBe(`"//"`);
959
- expect(targetSnippet.convertedCode).toBe(`"//".TR()`);
960
- expect(targetSnippet.literals).toEqual(['//']);
961
- expect(targetSnippet.isChanged).toBe(true);
962
-
963
- });
964
-
965
- // 处理C# `+=` 形式赋值语句
966
- test('should handle string template with format specifier', () => {
967
- const code = `infoStr += $"最终抗性: {resistReduce:F}\\n";`
968
- const snippets = extractor.extractStrings(code);
969
-
970
- // 验证提取的片段数量
971
- expect(snippets.length).toBeGreaterThan(0);
972
-
973
- let targetSnippet = snippets[0];
974
- expect(targetSnippet.originalCode).toBe(`$"最终抗性: {resistReduce:F}\\n"`);
975
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("最终抗性: {0:F}\\n", resistReduce)`);
976
- expect(targetSnippet.literals).toEqual(['最终抗性: {0:F}\\n']);
977
- expect(targetSnippet.isChanged).toBe(true);
978
- });
979
-
980
- // 处理C#多行语句, 特别是包含 `\n` 的字符串
981
- test('should handle multilne content17', () => {
1055
+ })
1056
+ test('should handle multilne content 17', () => {
982
1057
  const code = `
983
1058
  infoStr += $"aaa: {aa}\n" +
984
1059
  $"bbb = {bb}";
@@ -998,10 +1073,8 @@ describe('CSharpStringExtractor', () => {
998
1073
  'bbb = {0}'
999
1074
  ]);
1000
1075
  expect(targetSnippet.isChanged).toBe(true);
1001
- });
1002
-
1003
- // 处理C#多行语句, 特别是包含 `\\n` 的内插字符串
1004
- test('should handle multilne content19', () => {
1076
+ })
1077
+ test('should handle multilne content 19', () => {
1005
1078
  const code = `
1006
1079
  infoStr += $"aaa: {aa}\\n" +
1007
1080
  $"bbb = {bb}";
@@ -1021,10 +1094,8 @@ describe('CSharpStringExtractor', () => {
1021
1094
  'bbb = {0}'
1022
1095
  ]);
1023
1096
  expect(targetSnippet.isChanged).toBe(true);
1024
- });
1025
-
1026
- // 处理C#中多行字符串拼接成的字符串表达式
1027
- test('should handle multilne content18', () => {
1097
+ })
1098
+ test('should handle multilne content 18', () => {
1028
1099
  const code = `
1029
1100
  infoStr += "伤害公式: \\n" +
1030
1101
  $"最终伤害[color={colorCode}][{(float)damageValue:F}][/color] = \\n" +
@@ -1068,146 +1139,58 @@ describe('CSharpStringExtractor', () => {
1068
1139
  '抗性减免[b][{7:F}]'
1069
1140
  ]);
1070
1141
  expect(targetSnippet.isChanged).toBe(true);
1142
+ })
1071
1143
  });
1072
1144
 
1073
- // 处理C#中包含括号的内插字符串
1074
- test('should handle bracket 1', () => {
1075
- const code = `m_text_time.text = $"下一轮神兽出现倒计时: {Date.GetIntweerpolatedTime(ServerTimer.Instance.Time, _startGameStamp)}";`
1145
+ describe('should handle non string assignment', () => {
1146
+ test('should handle non string assignment 1', () => {
1147
+ const code = 'var d1 = 12;var d2 = 13;var d3 = d1 + d2;var aa = "aaa";';
1076
1148
  const snippets = extractor.extractStrings(code);
1149
+ {
1150
+ const snippet = snippets[0];
1151
+ expect(snippet.originalCode).toBe('"aaa"');
1152
+ expect(snippet.convertedCode).toBe('"aaa"');
1153
+ expect(snippet.literals).toEqual(['aaa']);
1154
+ expect(snippet.isChanged).toBe(false);
1155
+ }
1156
+ })
1157
+ test('should handle non string assignment 2', () => {
1158
+ const code = 'var d3 = d1 + d2;var aa = "aaa";';
1159
+ const snippets = extractor.extractStrings(code);
1160
+ {
1161
+ const snippet = snippets[0];
1162
+ expect(snippet.originalCode).toBe('"aaa"');
1163
+ expect(snippet.convertedCode).toBe('"aaa"');
1164
+ expect(snippet.literals).toEqual(['aaa']);
1165
+ expect(snippet.isChanged).toBe(false);
1166
+ }
1167
+ })
1168
+ });
1077
1169
 
1078
- // 验证提取的片段数量
1079
- expect(snippets.length).toBeGreaterThan(0);
1080
-
1081
- let targetSnippet = snippets[0];
1082
- expect(targetSnippet.originalCode).toBe(`$"下一轮神兽出现倒计时: {Date.GetIntweerpolatedTime(ServerTimer.Instance.Time, _startGameStamp)}"`);
1083
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("下一轮神兽出现倒计时: {0}", Date.GetIntweerpolatedTime(ServerTimer.Instance.Time, _startGameStamp))`);
1084
- expect(targetSnippet.literals).toEqual([
1085
- '下一轮神兽出现倒计时: {0}'
1086
- ]);
1087
- expect(targetSnippet.isChanged).toBe(true);
1088
- });
1089
-
1090
- // 处理C#中包含括号的内插字符串
1091
- test('should handle bracket 2', () => {
1092
- const code = `m_text_time.text = $"神兽离去时间: {Date.FeGetInterpolatedTime(ServerTimer.Instance.Time, _endGameStamp)}";`
1093
- const snippets = extractor.extractStrings(code);
1094
-
1095
- // 验证提取的片段数量
1096
- expect(snippets.length).toBeGreaterThan(0);
1097
-
1098
- let targetSnippet = snippets[0];
1099
- expect(targetSnippet.originalCode).toBe(`$"神兽离去时间: {Date.FeGetInterpolatedTime(ServerTimer.Instance.Time, _endGameStamp)}"`);
1100
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("神兽离去时间: {0}", Date.FeGetInterpolatedTime(ServerTimer.Instance.Time, _endGameStamp))`);
1101
- expect(targetSnippet.literals).toEqual([
1102
- '神兽离去时间: {0}'
1103
- ]);
1104
- expect(targetSnippet.isChanged).toBe(true);
1105
- });
1106
-
1107
- // 处理C#中包含括号的内插字符串
1108
- test('should handle bracket 3', () => {
1109
- const code = `desc += $"剩余{ToGetInterpolatedTime(_cardPoolData.FinishTime * 1000, ServerTimer.Instance.Time)}";`
1110
- const snippets = extractor.extractStrings(code);
1111
-
1112
- // 验证提取的片段数量
1113
- expect(snippets.length).toBeGreaterThan(0);
1114
-
1115
- let targetSnippet = snippets[0];
1116
- expect(targetSnippet.originalCode).toBe(`$"剩余{ToGetInterpolatedTime(_cardPoolData.FinishTime * 1000, ServerTimer.Instance.Time)}"`);
1117
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("剩余{0}", ToGetInterpolatedTime(_cardPoolData.FinishTime * 1000, ServerTimer.Instance.Time))`);
1118
- expect(targetSnippet.literals).toEqual([
1119
- '剩余{0}'
1120
- ]);
1121
- expect(targetSnippet.isChanged).toBe(true);
1122
- });
1123
-
1124
- // 处理C#中包含括号的内插字符串
1125
- test('should handle bracket 4', () => {
1126
- const code = `desc += $"剩余{ToGetInterpolatedTime(FF(_cardPoolData.FinishTime() * 1000, ServerTimer.Instance.Time()))}";`
1127
- const snippets = extractor.extractStrings(code);
1128
-
1129
- // 验证提取的片段数量
1130
- expect(snippets.length).toBeGreaterThan(0);
1131
-
1132
- let targetSnippet = snippets[0];
1133
- expect(targetSnippet.originalCode).toBe(`$"剩余{ToGetInterpolatedTime(FF(_cardPoolData.FinishTime() * 1000, ServerTimer.Instance.Time()))}"`);
1134
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("剩余{0}", ToGetInterpolatedTime(FF(_cardPoolData.FinishTime() * 1000, ServerTimer.Instance.Time())))`);
1135
- expect(targetSnippet.literals).toEqual([
1136
- '剩余{0}'
1137
- ]);
1138
- expect(targetSnippet.isChanged).toBe(true);
1139
- });
1140
-
1141
- // 处理C#中包含`+=`符号的内插字符串
1142
- test('should handle duplicate tr handle 1', () => {
1143
- const code = `infoStr = $"+={colorCode}";`
1144
- const snippets = extractor.extractStrings(code);
1145
-
1146
- // 验证提取的片段数量
1147
- expect(snippets.length).toBeGreaterThan(0);
1148
-
1149
- let targetSnippet = snippets[0];
1150
- expect(targetSnippet.originalCode).toBe(`$"+={colorCode}"`);
1151
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("+={0}", colorCode)`);
1152
- expect(targetSnippet.literals).toEqual([
1153
- '+={0}'
1154
- ]);
1155
- expect(targetSnippet.isChanged).toBe(true);
1156
- });
1157
-
1158
- // 处理C# `+=` 形式的赋值语句后接 包含 `=` 符号的内插字符串
1159
- test('should handle duplicate tr handle 2', () => {
1160
- const code = `infoStr += $"={colorCode}";`
1161
- const snippets = extractor.extractStrings(code);
1162
-
1163
- // 验证提取的片段数量
1164
- expect(snippets.length).toBeGreaterThan(0);
1165
-
1166
- let targetSnippet = snippets[0];
1167
- expect(targetSnippet.originalCode).toBe(`$"={colorCode}"`);
1168
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("={0}", colorCode)`);
1169
- expect(targetSnippet.literals).toEqual([
1170
- '={0}'
1171
- ]);
1172
- expect(targetSnippet.isChanged).toBe(true);
1173
- });
1174
-
1175
- // 处理C# `+=` 形式的赋值语句后接 包含 `+=` 符号的内插字符串
1176
- test('should handle duplicate tr handle 3', () => {
1177
- const code = `infoStr += $"+={colorCode}";`
1170
+ describe('should handle null', () => {
1171
+ test('should handle null 1', () => {
1172
+ const code = `m_text_notice.text = null;`;
1178
1173
  const snippets = extractor.extractStrings(code);
1179
-
1180
- // 验证提取的片段数量
1181
- expect(snippets.length).toBeGreaterThan(0);
1182
-
1183
- let targetSnippet = snippets[0];
1184
- expect(targetSnippet.originalCode).toBe(`$"+={colorCode}"`);
1185
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("+={0}", colorCode)`);
1186
- expect(targetSnippet.literals).toEqual([
1187
- '+={0}'
1188
- ]);
1189
- expect(targetSnippet.isChanged).toBe(true);
1190
- });
1191
-
1192
- // 处理C# `+=` 形式的赋值语句后接包含 `=`、`[`、`]`、`{`、`}`、`=` 等特殊符号的内插字符串
1193
- test('should handle duplicate tr handle 4', () => {
1194
- const code = `infoStr += $"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n";`
1174
+ {
1175
+ let targetSnippet = snippets[0];
1176
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`null`));
1177
+ expect(targetSnippet.originalCode).toBe(`null`);
1178
+ expect(targetSnippet.convertedCode).toBe(`null`);
1179
+ expect(targetSnippet.literals).toEqual([
1180
+ ]);
1181
+ expect(targetSnippet.isChanged).toBe(false);
1182
+ }
1183
+ expect(snippets.length).toBe(1);
1184
+ })
1185
+ test('should handle null 2', () => {
1186
+ const code = `m_text_notice.wfefe = null;`;
1195
1187
  const snippets = extractor.extractStrings(code);
1196
-
1197
- // 验证提取的片段数量
1198
- expect(snippets.length).toBeGreaterThan(0);
1199
-
1200
- let targetSnippet = snippets[0];
1201
- expect(targetSnippet.originalCode).toBe(`$"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n"`);
1202
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`);
1203
- expect(targetSnippet.literals).toEqual([
1204
- '伤害类型: [color={0}][b]{1}[/b][/color]\n'
1205
- ]);
1206
- expect(targetSnippet.isChanged).toBe(true);
1188
+ expect(snippets.length).toBe(0);
1189
+ })
1207
1190
  });
1208
1191
 
1209
- // 处理C#中函数调用参数中包含普通字符串的情况, 函数参数需要拆分, 逐个参数捕获
1210
- test('should handle para 1', () => {
1192
+ describe('should handle para', () => {
1193
+ test('should handle para 1', () => {
1211
1194
  const code = `SetData("等级", level + 1);`
1212
1195
  const snippets = extractor.extractStrings(code);
1213
1196
 
@@ -1222,10 +1205,8 @@ describe('CSharpStringExtractor', () => {
1222
1205
  "等级"
1223
1206
  ]);
1224
1207
  expect(targetSnippet.isChanged).toBe(false);
1225
- });
1226
-
1227
- // 处理C#中函数调用参数中包含普通字符串的情况
1228
- test('should handle para 2', () => {
1208
+ })
1209
+ test('should handle para 2', () => {
1229
1210
  const code = `bbb.Func2("等级", level, level + 1, false, isMax);`
1230
1211
  const snippets = extractor.extractStrings(code);
1231
1212
 
@@ -1239,284 +1220,151 @@ describe('CSharpStringExtractor', () => {
1239
1220
  "等级"
1240
1221
  ]);
1241
1222
  expect(targetSnippet.isChanged).toBe(false);
1223
+ })
1242
1224
  });
1243
1225
 
1244
- // 处理C#中switch语句中包含普通字符串的情况
1245
- test('should handle switch 1', () => {
1246
- const code = `
1247
- switch(condition){
1248
- default:
1249
- Log.Warning("实时更新自:" + rankData.Type);
1250
- break;
1251
- }`
1252
- const snippets = extractor.extractStrings(code);
1253
-
1254
- // 验证提取的片段数量
1255
- expect(snippets.length).toBeGreaterThan(0);
1256
-
1257
- let targetSnippet = snippets[0];
1258
- expect(targetSnippet.originalCode).toBe(`"实时更新自:" + rankData.Type`);
1259
- // 普通函数参数不需要追加 `.TR()`, 除非包含由 `+` 符号连接字符串等的情况
1260
- expect(targetSnippet.convertedCode).toBe(`"实时更新自:" + rankData.Type`);
1261
- expect(targetSnippet.literals).toEqual([
1262
- "实时更新自:"
1263
- ]);
1264
- expect(targetSnippet.isChanged).toBe(false);
1265
- });
1266
-
1267
- // 处理C#中switch语句中包含普通字符串的情况
1268
- test('should handle switch 2', () => {
1269
- const code = `
1270
- switch(kwjkwlje){
1271
- case (int)RANK_TYPE.天梯段位:
1272
- Debug.Log1("jkwhfehwfjkh:" + rank2Data.T4zype);
1273
- break;
1274
- }`
1226
+ describe('should handle return statement', () => {
1227
+ test('should handle return statement 1', () => {
1228
+ const code = `return "参数错误";`;
1275
1229
  const snippets = extractor.extractStrings(code);
1276
1230
 
1277
- // 验证提取的片段数量, switch 语句中包含普通字符串的情况
1278
- expect(snippets.length).toBeGreaterThan(0);
1279
-
1280
1231
  let targetSnippet = snippets[0];
1281
- expect(targetSnippet.originalCode).toBe(`"jkwhfehwfjkh:" + rank2Data.T4zype`);
1282
- expect(targetSnippet.convertedCode).toBe(`"jkwhfehwfjkh:" + rank2Data.T4zype`);
1232
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"参数错误"`));
1233
+ expect(targetSnippet.originalCode).toBe(`"参数错误"`);
1234
+ expect(targetSnippet.convertedCode).toBe(`"参数错误"`);
1283
1235
  expect(targetSnippet.literals).toEqual([
1284
- "jkwhfehwfjkh:"
1236
+ '参数错误'
1285
1237
  ]);
1286
1238
  expect(targetSnippet.isChanged).toBe(false);
1287
- });
1288
1239
 
1289
- // 处理C#中switch语句中包含普通字符串的情况
1290
- test('should handle switch 3', () => {
1291
- const code = `
1292
- switch(lkw){
1293
- case V434:
1294
- {
1295
- Action2("wegwfw:" + varnws);
1296
- break;
1297
- }
1298
- }`
1240
+ })
1241
+ test('should handle return statement 2', () => {
1242
+ const code = `return "";`;
1299
1243
  const snippets = extractor.extractStrings(code);
1300
1244
 
1301
- // 验证提取的片段数量
1302
- expect(snippets.length).toBeGreaterThan(0);
1303
-
1304
1245
  let targetSnippet = snippets[0];
1305
- expect(targetSnippet.originalCode).toBe(`"wegwfw:" + varnws`);
1306
- expect(targetSnippet.convertedCode).toBe(`"wegwfw:" + varnws`);
1246
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`""`));
1247
+ expect(targetSnippet.originalCode).toBe(`""`);
1248
+ expect(targetSnippet.convertedCode).toBe(`""`);
1307
1249
  expect(targetSnippet.literals).toEqual([
1308
- "wegwfw:"
1250
+ ''
1309
1251
  ]);
1310
1252
  expect(targetSnippet.isChanged).toBe(false);
1311
- });
1312
1253
 
1313
- // 处理C#中switch语句中包含普通字符串的情况
1314
- test('should handle switch 4', () => {
1315
- const code = `
1316
- case V434:
1317
- Action2("wegwfw:" + varnws);
1318
- break;`
1254
+ })
1255
+ test('should handle return statement 3', () => {
1256
+ const code = `return $"";`;
1319
1257
  const snippets = extractor.extractStrings(code);
1320
1258
 
1321
- // 验证提取的片段数量
1322
- expect(snippets.length).toBeGreaterThan(0);
1323
-
1324
1259
  let targetSnippet = snippets[0];
1325
- expect(targetSnippet.originalCode).toBe(`"wegwfw:" + varnws`);
1326
- expect(targetSnippet.convertedCode).toBe(`"wegwfw:" + varnws`);
1260
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$""`));
1261
+ expect(targetSnippet.originalCode).toBe(`$""`);
1262
+ expect(targetSnippet.convertedCode).toBe(`$""`);
1327
1263
  expect(targetSnippet.literals).toEqual([
1328
- "wegwfw:"
1264
+ ''
1329
1265
  ]);
1330
1266
  expect(targetSnippet.isChanged).toBe(false);
1331
- });
1332
-
1333
- // 处理 C#内容中存在多个相同的包含字符串的语句时, 要每个都提取出来
1334
- test('should handle lost 1', () => {
1335
- const code = readFileSync('./test/KeeperDialog.cs', 'utf8');
1336
- const snippets = extractor.extractStrings(code);
1337
-
1338
- let targetSnippet = snippets[3];
1339
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"已购买";
1340
- m_btn_buy.enabled = false;
1341
-
1342
- //购买后自动启用`));
1343
- expect(targetSnippet.originalCode).toBe(`"已购买"`);
1344
- expect(targetSnippet.convertedCode).toBe(`"已购买".TR()`);
1345
- expect(targetSnippet.literals).toEqual([
1346
- "已购买"
1347
- ]);
1348
- expect(targetSnippet.isChanged).toBe(true);
1349
-
1350
- // 验证提取的片段数量
1351
- expect(snippets.length).toBeGreaterThanOrEqual(5)
1352
- });
1353
1267
 
1354
- // 字符串中包含 `)` 符号时, 也需要捕获该字符串
1355
- test('should handle lost 2', () => {
1356
- const code = `m_text_runeSlot.text = Tr.Format(")", _sutraCardData.Card.RuneOpenCount);`;
1268
+ })
1269
+ test('should handle return statement 4', () => {
1270
+ const code = `return $"fwefwe";`;
1357
1271
  const snippets = extractor.extractStrings(code);
1358
1272
 
1359
1273
  let targetSnippet = snippets[0];
1360
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format(")", _sutraCardData.Card.RuneOpenCount)`));
1361
- expect(targetSnippet.originalCode).toBe(`Tr.Format(")", _sutraCardData.Card.RuneOpenCount)`);
1362
- expect(targetSnippet.convertedCode).toBe(`Tr.Format(")", _sutraCardData.Card.RuneOpenCount)`);
1363
- // 字符串中包含 `)` 符号时, 也需要捕获该字符串
1274
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"fwefwe"`));
1275
+ expect(targetSnippet.originalCode).toBe(`$"fwefwe"`);
1276
+ expect(targetSnippet.convertedCode).toBe(`$"fwefwe"`);
1364
1277
  expect(targetSnippet.literals).toEqual([
1365
- ')'
1278
+ 'fwefwe'
1366
1279
  ]);
1367
1280
  expect(targetSnippet.isChanged).toBe(false);
1368
1281
 
1369
- });
1370
-
1371
- // 处理 C#内容时, 需要匹配出包含 `(` 符号的字符串表达式
1372
- test('should handle lost 3', () => {
1373
- const code = `m_text_runeSlot.text = ")";`;
1282
+ })
1283
+ test('should handle return statement 5', () => {
1284
+ const code = `return $"wefwf{fwef}";`;
1374
1285
  const snippets = extractor.extractStrings(code);
1375
1286
 
1376
1287
  let targetSnippet = snippets[0];
1377
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`")"`));
1378
- expect(targetSnippet.originalCode).toBe(`")"`);
1379
- expect(targetSnippet.convertedCode).toBe(`")".TR()`);
1288
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"wefwf{fwef}"`));
1289
+ expect(targetSnippet.originalCode).toBe(`$"wefwf{fwef}"`);
1290
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("wefwf{0}", fwef)`);
1380
1291
  expect(targetSnippet.literals).toEqual([
1381
- ')'
1292
+ 'wefwf{0}'
1382
1293
  ]);
1383
1294
  expect(targetSnippet.isChanged).toBe(true);
1384
1295
 
1296
+ })
1385
1297
  });
1386
1298
 
1387
- // 测试处理C# `return` 语句中的字符串表达式, 提取的字符串表达式中不需要包含 `return` 关键字, 只需要包含字符串表达式
1388
- test('should handle return statement 1', () => {
1389
- const code = `return "参数错误";`;
1390
- const snippets = extractor.extractStrings(code);
1391
-
1392
- let targetSnippet = snippets[0];
1393
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"参数错误"`));
1394
- expect(targetSnippet.originalCode).toBe(`"参数错误"`);
1395
- expect(targetSnippet.convertedCode).toBe(`"参数错误"`);
1396
- expect(targetSnippet.literals).toEqual([
1397
- '参数错误'
1398
- ]);
1399
- expect(targetSnippet.isChanged).toBe(false);
1400
-
1401
- });
1402
-
1403
- // 测试处理C# `return` 语句中的字符串表达式, 提取的字符串表达式中不需要包含 `return` 关键字, 只需要包含字符串表达式
1404
- test('should handle return statement 2', () => {
1405
- const code = `return "";`;
1406
- const snippets = extractor.extractStrings(code);
1407
-
1408
- let targetSnippet = snippets[0];
1409
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`""`));
1410
- expect(targetSnippet.originalCode).toBe(`""`);
1411
- expect(targetSnippet.convertedCode).toBe(`""`);
1412
- expect(targetSnippet.literals).toEqual([
1413
- ''
1414
- ]);
1415
- expect(targetSnippet.isChanged).toBe(false);
1416
-
1417
- });
1418
-
1419
- // 测试处理C# `return` 语句中的字符串表达式, 提取的字符串表达式中不需要包含 `return` 关键字, 只需要包含字符串表达式
1420
- test('should handle return statement 3', () => {
1421
- const code = `return $"";`;
1422
- const snippets = extractor.extractStrings(code);
1423
-
1424
- let targetSnippet = snippets[0];
1425
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$""`));
1426
- expect(targetSnippet.originalCode).toBe(`$""`);
1427
- expect(targetSnippet.convertedCode).toBe(`$""`);
1428
- expect(targetSnippet.literals).toEqual([
1429
- ''
1430
- ]);
1431
- expect(targetSnippet.isChanged).toBe(false);
1432
-
1433
- });
1434
-
1435
- // 测试处理C# `return` 语句中的字符串表达式, 提取的字符串表达式中不需要包含 `return` 关键字, 只需要包含字符串表达式
1436
- test('should handle return statement 4', () => {
1437
- const code = `return $"fwefwe";`;
1438
- const snippets = extractor.extractStrings(code);
1439
-
1440
- let targetSnippet = snippets[0];
1441
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"fwefwe"`));
1442
- expect(targetSnippet.originalCode).toBe(`$"fwefwe"`);
1443
- expect(targetSnippet.convertedCode).toBe(`$"fwefwe"`);
1444
- expect(targetSnippet.literals).toEqual([
1445
- 'fwefwe'
1446
- ]);
1447
- expect(targetSnippet.isChanged).toBe(false);
1448
-
1449
- });
1450
-
1451
- // 测试处理C# `return` 语句中的字符串表达式, 提取的字符串表达式中不需要包含 `return` 关键字, 只需要包含字符串表达式
1452
- test('should handle return statement 5', () => {
1453
- const code = `return $"wefwf{fwef}";`;
1454
- const snippets = extractor.extractStrings(code);
1455
-
1456
- let targetSnippet = snippets[0];
1457
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"wefwf{fwef}"`));
1458
- expect(targetSnippet.originalCode).toBe(`$"wefwf{fwef}"`);
1459
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("wefwf{0}", fwef)`);
1460
- expect(targetSnippet.literals).toEqual([
1461
- 'wefwf{0}'
1462
- ]);
1463
- expect(targetSnippet.isChanged).toBe(true);
1464
-
1465
- });
1466
-
1467
- // 测试处理C#字符串表达式中包含各种特殊字符的情况
1468
- test('should handle special characters in string expression 1', () => {
1469
- const code = `return "abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\";`;
1470
- const snippets = extractor.extractStrings(code);
1471
-
1472
- let targetSnippet = snippets[0];
1473
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\"`));
1474
- expect(targetSnippet.originalCode).toBe(`"abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\"`);
1475
- expect(targetSnippet.convertedCode).toBe(`"abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\"`);
1476
- expect(targetSnippet.literals).toEqual([
1477
- 'abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\'
1478
- ]);
1479
- expect(targetSnippet.isChanged).toBe(false);
1480
- });
1481
-
1482
- // 测试处理在C#类成员初始赋值语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#字符串边界识别和捕获
1483
- test('should handle member initial assignment', () => {
1484
- const code = readFileSync("test/TestSpecialString.cs", "utf8");
1299
+ describe('should handle special characters in string', () => {
1300
+ test('should handle special characters in string 8', () => {
1301
+ const code = `
1302
+ m_btn_paid.text = $"<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{paidConfig.Quantity}";
1303
+ `;
1485
1304
  const snippets = extractor.extractStrings(code);
1486
1305
  {
1487
1306
  let targetSnippet = snippets[0];
1488
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"\\\\"`));
1489
- expect(targetSnippet.originalCode).toBe(`"\\\\"`);
1490
- expect(targetSnippet.convertedCode).toBe(`"\\\\"`);
1307
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{paidConfig.Quantity}"`));
1308
+ expect(targetSnippet.originalCode).toBe(`$"<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{paidConfig.Quantity}"`);
1309
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{0}", paidConfig.Quantity)`);
1491
1310
  expect(targetSnippet.literals).toEqual([
1492
- '\\\\'
1311
+ `<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{0}`
1493
1312
  ]);
1494
- expect(targetSnippet.isChanged).toBe(false);
1313
+ expect(targetSnippet.isChanged).toBe(true);
1495
1314
  }
1315
+ expect(snippets.length).toBe(1);
1316
+ })
1317
+ test('should handle special characters in string 9', () => {
1318
+ const code = `
1319
+ (GetChild($"m_textAnime{GetNextNumber()}") as TurtleTextAnimeComp)?.SetText(word);
1320
+ `;
1321
+ const snippets = extractor.extractStrings(code);
1496
1322
  {
1497
- let targetSnippet = snippets[1];
1498
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"\\n"`));
1499
- expect(targetSnippet.originalCode).toBe(`"\\n"`);
1500
- expect(targetSnippet.convertedCode).toBe(`"\\n"`);
1323
+ let targetSnippet = snippets[0];
1324
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"m_textAnime{GetNextNumber()}"`));
1325
+ expect(targetSnippet.originalCode).toBe(`$"m_textAnime{GetNextNumber()}"`);
1326
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("m_textAnime{0}", GetNextNumber())`);
1501
1327
  expect(targetSnippet.literals).toEqual([
1502
- '\\n'
1328
+ `m_textAnime{0}`
1503
1329
  ]);
1504
- expect(targetSnippet.isChanged).toBe(false);
1330
+ expect(targetSnippet.isChanged).toBe(true);
1505
1331
  }
1332
+ expect(snippets.length).toBe(1);
1333
+ })
1334
+ test('should handle special characters in string 10', () => {
1335
+ const code = `
1336
+ (GetChild($"m_textAnime{GetNextNumber()}") as TurtleTextAnimeComp)?.SetText(word);
1337
+ `;
1338
+ const snippets = extractor.extractStrings(code);
1506
1339
  {
1507
- let targetSnippet = snippets[2];
1508
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"\\t"`));
1509
- expect(targetSnippet.originalCode).toBe(`$"\\t"`);
1510
- expect(targetSnippet.convertedCode).toBe(`$"\\t"`);
1340
+ let targetSnippet = snippets[0];
1341
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"m_textAnime{GetNextNumber()}"`));
1342
+ expect(targetSnippet.originalCode).toBe(`$"m_textAnime{GetNextNumber()}"`);
1343
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("m_textAnime{0}", GetNextNumber())`);
1511
1344
  expect(targetSnippet.literals).toEqual([
1512
- '\\t'
1345
+ `m_textAnime{0}`
1513
1346
  ]);
1514
- expect(targetSnippet.isChanged).toBe(false);
1347
+ expect(targetSnippet.isChanged).toBe(true);
1515
1348
  }
1349
+ expect(snippets.length).toBe(1);
1350
+ })
1516
1351
  });
1517
1352
 
1518
- // 测试处理在C#各种语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#字符串边界识别和捕获
1519
- test('should handle special characters in string expression 3', () => {
1353
+ describe('should handle special characters in string expression', () => {
1354
+ test('should handle special characters in string expression 1', () => {
1355
+ const code = `return "abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\";`;
1356
+ const snippets = extractor.extractStrings(code);
1357
+
1358
+ let targetSnippet = snippets[0];
1359
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\"`));
1360
+ expect(targetSnippet.originalCode).toBe(`"abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\"`);
1361
+ expect(targetSnippet.convertedCode).toBe(`"abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\"`);
1362
+ expect(targetSnippet.literals).toEqual([
1363
+ 'abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\'
1364
+ ]);
1365
+ expect(targetSnippet.isChanged).toBe(false);
1366
+ })
1367
+ test('should handle special characters in string expression 3', () => {
1520
1368
  const code = readFileSync("test/TestSpecialString.cs", "utf8");
1521
1369
  const snippets = extractor.extractStrings(code);
1522
1370
  {
@@ -1549,10 +1397,8 @@ describe('CSharpStringExtractor', () => {
1549
1397
  ]);
1550
1398
  expect(targetSnippet.isChanged).toBe(false);
1551
1399
  }
1552
- });
1553
-
1554
- // 测试处理在C#各种语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#字符串边界识别和捕获
1555
- test('should handle special characters in string expression 3.1', () => {
1400
+ })
1401
+ test('should handle special characters in string expression 3.1', () => {
1556
1402
  const code = readFileSync("test/TestSpecialString.cs", "utf8");
1557
1403
  const snippets = extractor.extractStrings(code);
1558
1404
  {
@@ -1565,27 +1411,8 @@ describe('CSharpStringExtractor', () => {
1565
1411
  ]);
1566
1412
  expect(targetSnippet.isChanged).toBe(false);
1567
1413
  }
1568
- });
1569
-
1570
- // 测试处理在C#各种语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#字符串边界识别和捕获
1571
- test('should handle special characters in string expression of return sentence', () => {
1572
- const code = readFileSync("test/TestSpecialString.cs", "utf8");
1573
- const snippets = extractor.extractStrings(code);
1574
- {
1575
- let targetSnippet = snippets[7];
1576
- // 需要统一匹配 `return` 语句中的字符串表达式
1577
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"5. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1578
- expect(targetSnippet.originalCode).toBe(`"5. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1579
- expect(targetSnippet.convertedCode).toBe(`"5. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1580
- expect(targetSnippet.literals).toEqual([
1581
- '5. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1582
- ]);
1583
- expect(targetSnippet.isChanged).toBe(false);
1584
- }
1585
- });
1586
-
1587
- // 测试处理在C#各种语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#字符串边界识别和捕获
1588
- test('should handle special characters in string expression 3.2', () => {
1414
+ })
1415
+ test('should handle special characters in string expression 3.2', () => {
1589
1416
  const code = readFileSync("test/TestSpecialString.cs", "utf8");
1590
1417
  const snippets = extractor.extractStrings(code);
1591
1418
  {
@@ -1608,10 +1435,8 @@ describe('CSharpStringExtractor', () => {
1608
1435
  ]);
1609
1436
  expect(targetSnippet.isChanged).toBe(false);
1610
1437
  }
1611
- });
1612
-
1613
- // 测试处理在C#各种语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#字符串边界识别和捕获
1614
- test('should handle special characters in string expression 4', () => {
1438
+ })
1439
+ test('should handle special characters in string expression 4', () => {
1615
1440
  const code = readFileSync("test/TestSpecialString.cs", "utf8");
1616
1441
  const snippets = extractor.extractStrings(code);
1617
1442
  {
@@ -1625,10 +1450,8 @@ describe('CSharpStringExtractor', () => {
1625
1450
  ]);
1626
1451
  expect(targetSnippet.isChanged).toBe(true);
1627
1452
  }
1628
- });
1629
-
1630
- // 测试处理在C#各种形式语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#内插字符串边界识别和捕获
1631
- test('should handle special characters in string expression 5', () => {
1453
+ })
1454
+ test('should handle special characters in string expression 5', () => {
1632
1455
  const code = readFileSync("test/TestSpecialString.cs", "utf8");
1633
1456
  const snippets = extractor.extractStrings(code);
1634
1457
  {
@@ -1642,10 +1465,8 @@ describe('CSharpStringExtractor', () => {
1642
1465
  ]);
1643
1466
  expect(targetSnippet.isChanged).toBe(true);
1644
1467
  }
1645
- });
1646
-
1647
- // 测试处理在C#各种形式语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#内插字符串边界识别和捕获
1648
- test('should handle special characters in string expression 6', () => {
1468
+ })
1469
+ test('should handle special characters in string expression 6', () => {
1649
1470
  const code = readFileSync("test/TestSpecialString.cs", "utf8");
1650
1471
  const snippets = extractor.extractStrings(code);
1651
1472
  {
@@ -1659,10 +1480,8 @@ describe('CSharpStringExtractor', () => {
1659
1480
  ]);
1660
1481
  expect(targetSnippet.isChanged).toBe(true);
1661
1482
  }
1662
- });
1663
-
1664
- // 测试处理在C#各种形式语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#内插字符串边界识别和捕获
1665
- test('should handle special characters in string expression 7', () => {
1483
+ })
1484
+ test('should handle special characters in string expression 7', () => {
1666
1485
  const code = readFileSync("test/TestSpecialString.cs", "utf8");
1667
1486
  const snippets = extractor.extractStrings(code);
1668
1487
  {
@@ -1677,1075 +1496,1150 @@ describe('CSharpStringExtractor', () => {
1677
1496
  ]);
1678
1497
  expect(targetSnippet.isChanged).toBe(true);
1679
1498
  }
1499
+ })
1680
1500
  });
1681
1501
 
1682
- test('should handle optional value assignment', () => {
1683
- const code = `m_text_otherName.text = battleModel.TeammatePlayerData?.Name ?? "";`;
1502
+ describe('should handle string expression capture range', () => {
1503
+ test('should handle string expression capture range 1', () => {
1504
+ const code = `
1505
+ (GetChild($"vwvwe{index + 1}") as LargeLotterySpellCardComp)?.InitData(spellCardId, true);
1506
+ `;
1684
1507
  const snippets = extractor.extractStrings(code);
1685
1508
  {
1686
1509
  let targetSnippet = snippets[0];
1687
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`battleModel.TeammatePlayerData?.Name ?? ""`));
1688
- expect(targetSnippet.originalCode).toBe(`battleModel.TeammatePlayerData?.Name ?? ""`);
1689
- expect(targetSnippet.convertedCode).toBe(`battleModel.TeammatePlayerData?.Name ?? "".TR()`);
1510
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"vwvwe{index + 1}"`));
1511
+ expect(targetSnippet.originalCode).toBe(`$"vwvwe{index + 1}"`);
1512
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("vwvwe{0}", index + 1)`);
1690
1513
  expect(targetSnippet.literals).toEqual([
1691
- ''
1514
+ `vwvwe{0}`
1692
1515
  ]);
1693
1516
  expect(targetSnippet.isChanged).toBe(true);
1694
1517
  }
1695
- });
1696
-
1697
- // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1698
- test('should handle string in comment 1', () => {
1518
+ expect(snippets.length).toBe(1);
1519
+ })
1520
+ test('should handle string expression capture range 2', () => {
1699
1521
  const code = `
1700
- protected override void OnShow(object param)
1701
- {
1702
- // Log.Info("AAA:ChooseSutraLayer显示1");
1703
- base.OnShow(param);
1704
- }`;
1522
+ (GetChild($"brrr_{index + 1}") as LargeLotterySpellCardComp)?.InitData(spellCardId, true);
1523
+ `;
1705
1524
  const snippets = extractor.extractStrings(code);
1706
1525
  {
1707
1526
  let targetSnippet = snippets[0];
1708
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"AAA:ChooseSutraLayer显示1"`));
1709
- expect(targetSnippet.originalCode).toBe(`"AAA:ChooseSutraLayer显示1"`);
1710
- expect(targetSnippet.convertedCode).toBe(`"AAA:ChooseSutraLayer显示1"`);
1527
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"brrr_{index + 1}"`));
1528
+ expect(targetSnippet.originalCode).toBe(`$"brrr_{index + 1}"`);
1529
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("brrr_{0}", index + 1)`);
1711
1530
  expect(targetSnippet.literals).toEqual([
1712
- 'AAA:ChooseSutraLayer显示1'
1531
+ `brrr_{0}`
1713
1532
  ]);
1714
- expect(targetSnippet.isChanged).toBe(false);
1533
+ expect(targetSnippet.isChanged).toBe(true);
1715
1534
  }
1716
- });
1717
-
1718
- // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1719
- test('should handle string in comment 2', () => {
1535
+ expect(snippets.length).toBe(1);
1536
+ })
1537
+ test('should handle string expression capture range 3', () => {
1720
1538
  const code = `
1721
- protected override void OnShow(object param)
1722
- {
1723
- // Log.Info($"BBB:Jowikwf");
1724
- base.OnShow(param);
1725
- }`;
1539
+ (GetChild($"m_card_{index}") as LargeLotterySpellCardComp)?.PlayEff();
1540
+ `;
1726
1541
  const snippets = extractor.extractStrings(code);
1727
1542
  {
1728
1543
  let targetSnippet = snippets[0];
1729
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"BBB:Jowikwf"`));
1730
- expect(targetSnippet.originalCode).toBe(`$"BBB:Jowikwf"`);
1731
- expect(targetSnippet.convertedCode).toBe(`$"BBB:Jowikwf"`);
1544
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"m_card_{index}"`));
1545
+ expect(targetSnippet.originalCode).toBe(`$"m_card_{index}"`);
1546
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("m_card_{0}", index)`);
1732
1547
  expect(targetSnippet.literals).toEqual([
1733
- 'BBB:Jowikwf'
1548
+ `m_card_{0}`
1734
1549
  ]);
1735
- expect(targetSnippet.isChanged).toBe(false);
1550
+ expect(targetSnippet.isChanged).toBe(true);
1736
1551
  }
1552
+ expect(snippets.length).toBe(1);
1553
+ })
1737
1554
  });
1738
1555
 
1739
- // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1740
- test('should handle string in comment 3', () => {
1556
+ describe('should handle string expression in method call parameter', () => {
1557
+ test('should handle string expression in method call parameter 1', () => {
1741
1558
  const code = `
1742
- protected override void OnShow(object param)
1559
+ namespace FaBao.UI.Comp
1560
+ {
1561
+ public partial class ItemCommonComp
1562
+ {
1563
+ public void BindData(bool needCompare = false)
1743
1564
  {
1744
- // Log.Info($"BBB:{wlek}Jowikwf");
1745
- base.OnShow(param);
1746
- }`;
1565
+ m_text_level.text = Tr.Format("{0}", _itemConfig.PillLevel);
1566
+ }
1567
+ }
1568
+ }
1569
+ `;
1747
1570
  const snippets = extractor.extractStrings(code);
1748
1571
  {
1749
1572
  let targetSnippet = snippets[0];
1750
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"BBB:{wlek}Jowikwf"`));
1751
- expect(targetSnippet.originalCode).toBe(`$"BBB:{wlek}Jowikwf"`);
1752
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("BBB:{0}Jowikwf", wlek)`);
1573
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1574
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}", _itemConfig.PillLevel)`));
1575
+ expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}", _itemConfig.PillLevel)`);
1576
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1753
1577
  expect(targetSnippet.literals).toEqual([
1754
- 'BBB:{0}Jowikwf'
1578
+ '{0}'
1755
1579
  ]);
1756
- expect(targetSnippet.isChanged).toBe(true);
1580
+ expect(targetSnippet.isChanged).toBe(false);
1757
1581
  }
1758
- });
1759
-
1760
- // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1761
- test('should handle string in comment 4', () => {
1582
+ expect(snippets.length).toBe(1);
1583
+ })
1584
+ test('should handle string expression in method call parameter 2', () => {
1762
1585
  const code = `
1763
- protected override void OnShow(object param)
1586
+ namespace FaBao.UI.Comp
1587
+ {
1588
+ public partial class ItemCommonComp
1589
+ {
1590
+ public void BindData(bool needCompare = false, long needCompare2 = 23, float needCompare2 = 324.0)
1764
1591
  {
1765
- // Log.Info("{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\");
1766
- base.OnShow(param);
1767
- }`;
1592
+ m_text_level.text = Tr.Format("{0}", _itemConfig.PillLevel);
1593
+ }
1594
+ }
1595
+ }
1596
+ `;
1768
1597
  const snippets = extractor.extractStrings(code);
1769
1598
  {
1770
1599
  let targetSnippet = snippets[0];
1771
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1772
- expect(targetSnippet.originalCode).toBe(`"{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1773
- expect(targetSnippet.convertedCode).toBe(`"{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1774
- expect(targetSnippet.literals).toEqual([
1775
- '{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1600
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1601
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}阶", _itemConfig.PillLevel)`));
1602
+ expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1603
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1604
+ expect(targetSnippet.literals).toEqual([
1605
+ '{0}阶'
1776
1606
  ]);
1777
1607
  expect(targetSnippet.isChanged).toBe(false);
1778
1608
  }
1779
- });
1780
-
1781
- // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1782
- test('should handle string in comment 5', () => {
1609
+ expect(snippets.length).toBe(1);
1610
+ })
1611
+ test('should handle string expression in method call parameter 3', () => {
1783
1612
  const code = `
1784
- protected override void OnShow(object param)
1613
+ namespace FaBao.UI.Comp
1614
+ {
1615
+ public partial class ItemCommonComp
1616
+ {
1617
+ public void BindData(string wkle, bool needCompare = false, int needCompare2 = false)
1785
1618
  {
1786
- // Log.Info($"{wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\");
1787
- base.OnShow(param);
1788
- }`;
1619
+ m_text_level.text = Tr.Format("{0}", _itemConfig.PillLevel);
1620
+ }
1621
+ }
1622
+ }
1623
+ `;
1789
1624
  const snippets = extractor.extractStrings(code);
1790
1625
  {
1791
1626
  let targetSnippet = snippets[0];
1792
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"{wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1793
- expect(targetSnippet.originalCode).toBe(`$"{wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1794
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\", wefff)`);
1627
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1628
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}阶", _itemConfig.PillLevel)`));
1629
+ expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}", _itemConfig.PillLevel)`);
1630
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1795
1631
  expect(targetSnippet.literals).toEqual([
1796
- '{0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1632
+ '{0}'
1797
1633
  ]);
1798
- expect(targetSnippet.isChanged).toBe(true);
1634
+ expect(targetSnippet.isChanged).toBe(false);
1799
1635
  }
1800
- });
1801
-
1802
- // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1803
- test('should handle complex string 1', () => {
1636
+ expect(snippets.length).toBe(1);
1637
+ })
1638
+ test('should handle string expression in method call parameter 4', () => {
1804
1639
  const code = `
1805
- infoStr += $"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n";
1806
- infoStr += $"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n";
1807
- `;
1808
- const snippets = extractor.extractStrings(code);
1640
+ namespace FaBao.UI.Comp
1641
+ {
1642
+ public partial class ItemCommonComp
1643
+ {
1644
+ public void BindData(string wkle = "11111", bool needCompare = false, int needCompare2 = false)
1809
1645
  {
1810
- let targetSnippet = snippets[0];
1811
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n"`));
1812
- expect(targetSnippet.originalCode).toBe(`$"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n"`);
1813
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`);
1814
- expect(targetSnippet.literals).toEqual([
1815
- '伤害类型: [color={0}][b]{1}[/b][/color]\n'
1816
- ]);
1817
- expect(targetSnippet.isChanged).toBe(true);
1818
1646
  }
1819
- });
1820
1647
 
1821
- // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1822
- test('should handle complex string 2', () => {
1823
- const code = `
1824
- infoStr += Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType);
1825
- infoStr += $"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "")}[/b]\n";
1648
+ public void BindData(string wkle = "22", string wkle = "werwer", bool needCompare = false, string wkle = "wefwewef31f", int needCompare2 = false, string wkle = "df223")
1649
+ {
1650
+ }
1651
+
1652
+ public void BindData(string wkle = "(*&%\\\\*(@Fwfe))&(")
1653
+ {
1654
+ }
1655
+
1656
+ public void BindData(string we, string wkle = "aaaaa", bool needCompare = false, int needCompare2 = false)
1657
+ {
1658
+ m_text_level.text = Tr.Format("{0}阶", _itemConfig.PillLevel);
1659
+ }
1660
+ }
1661
+ }
1826
1662
  `;
1827
1663
  const snippets = extractor.extractStrings(code);
1828
1664
  {
1829
1665
  let targetSnippet = snippets[0];
1830
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`));
1831
- expect(targetSnippet.originalCode).toBe(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`);
1832
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`);
1666
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1667
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"11111"`));
1668
+ expect(targetSnippet.originalCode).toBe(`"11111"`);
1669
+ expect(targetSnippet.convertedCode).toBe(`"11111"`);
1833
1670
  expect(targetSnippet.literals).toEqual([
1834
- '伤害类型: [color={0}][b]{1}[/b][/color]\n'
1671
+ '11111'
1835
1672
  ]);
1836
1673
  expect(targetSnippet.isChanged).toBe(false);
1837
1674
  }
1838
- });
1839
-
1840
- // 正确处理C# 字符串表达式中递归内嵌字符串表达式的情况: 需要正确转换内插字符串格式
1841
- test('should handle fix interpolated string nested literals', () => {
1842
- const code = `infoStr += $"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n";`;
1843
- const snippets = extractor.extractStrings(code);
1844
1675
  {
1845
- let targetSnippet = snippets[0];
1846
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n"`));
1847
- expect(targetSnippet.originalCode).toBe(`$"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n"`);
1848
- // 需要正确转换内插字符串格式
1849
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("是否暴击: [b]{0}[/b]\n", (_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否"))`);
1676
+ let targetSnippet = snippets[1];
1677
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1678
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"22"`));
1679
+ expect(targetSnippet.originalCode).toBe(`"22"`);
1680
+ expect(targetSnippet.convertedCode).toBe(`"22"`);
1850
1681
  expect(targetSnippet.literals).toEqual([
1851
- '是否暴击: [b]{0}[/b]\n'
1682
+ '22'
1852
1683
  ]);
1853
- expect(targetSnippet.isChanged).toBe(true);
1684
+ expect(targetSnippet.isChanged).toBe(false);
1854
1685
  }
1855
- });
1856
-
1857
- // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1858
- test('should handle complex string with optional value 3', () => {
1859
- const code = `
1860
- else if (battleModel.CurGameType == BattleModel.GameType.Teamwork)
1861
- {
1862
- //合作模式显示队友名称
1863
- m_text_otherName.text = battleModel.TeammatePlayerData?.Name ?? "";
1864
- }
1865
- `;
1866
- const snippets = extractor.extractStrings(code);
1867
1686
  {
1868
- let targetSnippet = snippets[0];
1869
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`battleModel.TeammatePlayerData?.Name ?? ""`));
1870
- expect(targetSnippet.originalCode).toBe(`battleModel.TeammatePlayerData?.Name ?? ""`);
1871
- expect(targetSnippet.convertedCode).toBe(`battleModel.TeammatePlayerData?.Name ?? "".TR()`);
1687
+ let targetSnippet = snippets[2];
1688
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1689
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"werwer"`));
1690
+ expect(targetSnippet.originalCode).toBe(`"werwer"`);
1691
+ expect(targetSnippet.convertedCode).toBe(`"werwer"`);
1872
1692
  expect(targetSnippet.literals).toEqual([
1873
- ''
1693
+ 'werwer'
1874
1694
  ]);
1875
- expect(targetSnippet.isChanged).toBe(true);
1695
+ expect(targetSnippet.isChanged).toBe(false);
1876
1696
  }
1877
- });
1878
-
1879
- // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1880
- test('should handle complex string 4', () => {
1881
- const code = `
1882
- private void OnBtnIaa(EventContext context)
1883
1697
  {
1884
- var iaaConfig = IAAConfigTable.GetConfigById((int)IAAId.境界失败_加速冷却);
1885
- if (iaaConfig == null)
1886
- {
1887
- return;
1888
- }
1889
-
1890
- string des = $"观看视频后\n等待时间减少{iaaConfig.EffectValue / 60}分钟";
1891
- this.GetModel<IAAModel>().ShowAdWithDialog(IAAId.境界失败_加速冷却, "加速时间", des, null);
1698
+ let targetSnippet = snippets[3];
1699
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1700
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"wefwewef31f"`));
1701
+ expect(targetSnippet.originalCode).toBe(`"wefwewef31f"`);
1702
+ expect(targetSnippet.convertedCode).toBe(`"wefwewef31f"`);
1703
+ expect(targetSnippet.literals).toEqual([
1704
+ 'wefwewef31f'
1705
+ ]);
1706
+ expect(targetSnippet.isChanged).toBe(false);
1892
1707
  }
1893
- `;
1894
- const snippets = extractor.extractStrings(code);
1895
1708
  {
1896
- let targetSnippet = snippets[0];
1897
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"观看视频后\n等待时间减少{iaaConfig.EffectValue / 60}分钟"`));
1898
- expect(targetSnippet.originalCode).toBe(`$"观看视频后\n等待时间减少{iaaConfig.EffectValue / 60}分钟"`);
1899
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("观看视频后\n等待时间减少{0}分钟", iaaConfig.EffectValue / 60)`);
1709
+ let targetSnippet = snippets[4];
1710
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1711
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"df223"`));
1712
+ expect(targetSnippet.originalCode).toBe(`"df223"`);
1713
+ expect(targetSnippet.convertedCode).toBe(`"df223"`);
1900
1714
  expect(targetSnippet.literals).toEqual([
1901
- '观看视频后\n等待时间减少{0}分钟'
1715
+ 'df223'
1902
1716
  ]);
1903
- expect(targetSnippet.isChanged).toBe(true);
1717
+ expect(targetSnippet.isChanged).toBe(false);
1904
1718
  }
1905
- });
1906
-
1907
- // 需要正确识别函数调用参数中每个参数的边界, 并识别每个参数中的字符串表达式
1908
- test('should handle strings in function call arguments', () => {
1909
- const code = `
1910
- private void OnBtnIaa(EventContext context)
1911
1719
  {
1912
- var iaaConfig = IAAConfigTable.GetConfigById((int)IAAId.境界失败_加速冷却);
1913
- if (iaaConfig == null)
1914
- {
1915
- return;
1916
- }
1917
-
1918
- string des = $"观看视频后\n等待时间减少{iaaConfig.EffectValue / 60}分钟";
1919
- this.GetModel<IAAModel>().ShowAdWithDialog(IAAId.境界失败_加速冷却, "加速时间", des, null);
1720
+ let targetSnippet = snippets[5];
1721
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1722
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"(*&%\\\\*(@Fwfe))&("`));
1723
+ expect(targetSnippet.originalCode).toBe(`"(*&%\\\\*(@Fwfe))&("`);
1724
+ expect(targetSnippet.convertedCode).toBe(`"(*&%\\\\*(@Fwfe))&("`);
1725
+ expect(targetSnippet.literals).toEqual([
1726
+ '(*&%\\\\*(@Fwfe))&('
1727
+ ]);
1728
+ expect(targetSnippet.isChanged).toBe(false);
1920
1729
  }
1921
- `;
1922
- const snippets = extractor.extractStrings(code);
1923
1730
  {
1924
- let targetSnippet = snippets[1];
1925
- // 需要正确识别函数调用参数中每个参数的边界, 并识别每个参数中的字符串表达式
1926
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"加速时间"`));
1927
- expect(targetSnippet.originalCode).toBe(`"加速时间"`);
1928
- expect(targetSnippet.convertedCode).toBe(`"加速时间"`);
1731
+ let targetSnippet = snippets[6];
1732
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1733
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"aaaaa"`));
1734
+ expect(targetSnippet.originalCode).toBe(`"aaaaa"`);
1735
+ expect(targetSnippet.convertedCode).toBe(`"aaaaa"`);
1929
1736
  expect(targetSnippet.literals).toEqual([
1930
- '加速时间'
1737
+ 'aaaaa'
1931
1738
  ]);
1932
1739
  expect(targetSnippet.isChanged).toBe(false);
1933
1740
  }
1934
- });
1935
-
1936
- // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1937
- test('should handle string in comment 5', () => {
1938
- const code = `
1939
- m_text_percent.text = $"{curGoodsConfig.RebateRate}%";
1940
- m_name_holder.url = FUISys.Instance.GetIconUrl(_curShopDetail.ShopConfig.Name);
1941
- m_thumbnail_holder.url = FUISys.Instance.GetIconUrl(_curShopDetail.ShopConfig.Thumbnail);
1942
- m_btn_buy.text = $"¥ {curGoodsConfig.Price}";
1943
- m_text_timeleft.text = curShop.TimeLimitData.RemainTime().TR() + "后消失".TR();
1944
- `;
1945
- const snippets = extractor.extractStrings(code);
1946
1741
  {
1947
- let targetSnippet = snippets[2];
1948
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`curShop.TimeLimitData.RemainTime().TR() + "后消失".TR()`));
1949
- expect(targetSnippet.originalCode).toBe(`curShop.TimeLimitData.RemainTime().TR() + "后消失".TR()`);
1950
- expect(targetSnippet.convertedCode).toBe(`curShop.TimeLimitData.RemainTime().TR() + "后消失".TR()`);
1742
+ let targetSnippet = snippets[7];
1743
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1744
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}阶", _itemConfig.PillLevel)`));
1745
+ expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1746
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1951
1747
  expect(targetSnippet.literals).toEqual([
1952
- '后消失'
1748
+ '{0}阶'
1953
1749
  ]);
1954
1750
  expect(targetSnippet.isChanged).toBe(false);
1955
1751
  }
1752
+ })
1956
1753
  });
1957
1754
 
1958
- // 正确处理C# `switch` 表达式形式中的字符串表达式
1959
- test('should handle switch expression string', () => {
1755
+ describe('should handle string in comment', () => {
1756
+ test('should handle string in comment 1', () => {
1960
1757
  const code = `
1961
- case (int)State.Lock:
1962
- Toast.Info($"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁");
1963
- break;
1964
- `;
1758
+ protected override void OnShow(object param)
1759
+ {
1760
+ // Log.Info("AAA:ChooseSutraLayer显示1");
1761
+ base.OnShow(param);
1762
+ }`;
1965
1763
  const snippets = extractor.extractStrings(code);
1966
1764
  {
1967
1765
  let targetSnippet = snippets[0];
1968
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`));
1969
- expect(targetSnippet.originalCode).toBe(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`);
1970
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("灵田{0}级解锁", _model.GetFarmLandUnlockLevel(_landId))`);
1766
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"AAA:ChooseSutraLayer显示1"`));
1767
+ expect(targetSnippet.originalCode).toBe(`"AAA:ChooseSutraLayer显示1"`);
1768
+ expect(targetSnippet.convertedCode).toBe(`"AAA:ChooseSutraLayer显示1"`);
1971
1769
  expect(targetSnippet.literals).toEqual([
1972
- '灵田{0}级解锁'
1770
+ 'AAA:ChooseSutraLayer显示1'
1973
1771
  ]);
1974
- expect(targetSnippet.isChanged).toBe(true);
1772
+ expect(targetSnippet.isChanged).toBe(false);
1975
1773
  }
1976
- });
1977
-
1978
- // 正确识别C# 行注释语句边界, 行注释不能影响上下行的字符串提取
1979
- test('should handle comment boundary 1', () => {
1774
+ })
1775
+ test('should handle string in comment 2', () => {
1980
1776
  const code = `
1981
- //上锁
1982
- case (int)State.Lock:
1983
- Toast.Info($"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁");
1984
- break;
1985
- `;
1777
+ protected override void OnShow(object param)
1778
+ {
1779
+ // Log.Info($"BBB:Jowikwf");
1780
+ base.OnShow(param);
1781
+ }`;
1986
1782
  const snippets = extractor.extractStrings(code);
1987
1783
  {
1988
1784
  let targetSnippet = snippets[0];
1989
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`));
1990
- expect(targetSnippet.originalCode).toBe(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`);
1991
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("灵田{0}级解锁", _model.GetFarmLandUnlockLevel(_landId))`);
1785
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"BBB:Jowikwf"`));
1786
+ expect(targetSnippet.originalCode).toBe(`$"BBB:Jowikwf"`);
1787
+ expect(targetSnippet.convertedCode).toBe(`$"BBB:Jowikwf"`);
1992
1788
  expect(targetSnippet.literals).toEqual([
1993
- '灵田{0}级解锁'
1789
+ 'BBB:Jowikwf'
1994
1790
  ]);
1995
- expect(targetSnippet.isChanged).toBe(true);
1791
+ expect(targetSnippet.isChanged).toBe(false);
1996
1792
  }
1997
- });
1998
-
1999
- // 正确识别C# 行注释语句边界, 行注释不能影响上下行的字符串提取
2000
- test('should handle comment boundary 2', () => {
1793
+ })
1794
+ test('should handle string in comment 3', () => {
2001
1795
  const code = `
2002
- // klwjfe
2003
- namespace TestNamespace{
2004
- // lkwjfe
2005
- public class FK{
2006
- // klwf
2007
- public void TestM(){
2008
- // 模拟状态变量
2009
- var _state = (int)State.Lock;
2010
- // 模拟土地ID变量
2011
- switch (_state){
2012
- //上锁
2013
- case (int)State.Lock:
2014
- // lkwjefl
2015
- Toast.Info($"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁");
2016
- // klwejf
2017
- break;
2018
- // lkwjf
2019
- }
2020
- // klwjfel
2021
- }
2022
- }
2023
- }
2024
- `;
1796
+ protected override void OnShow(object param)
1797
+ {
1798
+ // Log.Info($"BBB:{wlek}Jowikwf");
1799
+ base.OnShow(param);
1800
+ }`;
2025
1801
  const snippets = extractor.extractStrings(code);
2026
1802
  {
2027
1803
  let targetSnippet = snippets[0];
2028
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`));
2029
- expect(targetSnippet.originalCode).toBe(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`);
2030
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("灵田{0}级解锁", _model.GetFarmLandUnlockLevel(_landId))`);
1804
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"BBB:{wlek}Jowikwf"`));
1805
+ expect(targetSnippet.originalCode).toBe(`$"BBB:{wlek}Jowikwf"`);
1806
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("BBB:{0}Jowikwf", wlek)`);
2031
1807
  expect(targetSnippet.literals).toEqual([
2032
- '灵田{0}级解锁'
1808
+ 'BBB:{0}Jowikwf'
2033
1809
  ]);
2034
1810
  expect(targetSnippet.isChanged).toBe(true);
2035
1811
  }
2036
- });
2037
- // 正确识别C# 行注释语句边界, 行注释不能影响上下行的字符串提取
2038
- test('should handle comment boundary 3', () => {
1812
+ })
1813
+ test('should handle string in comment 4', () => {
2039
1814
  const code = `
2040
- // klwjfe
2041
- namespace TestNamespace{
2042
- // lkwjfe
2043
- public class FK{
2044
- // wlkjelj
2045
- private int Llkwe = 23;
2046
- // lkjlkj
2047
- private int Dwekl { get; set; } = 23;
2048
- // jklwef
2049
- private static int Dwekl { get; set; } = 23;
2050
- // lkwjeflk
2051
- public static void TestM(){}
2052
- // wesd
2053
- public static void TestM()
1815
+ protected override void OnShow(object param)
2054
1816
  {
2055
- }
2056
- // wesd
2057
- public static void TestM(){
2058
- }
2059
- // klwf
2060
- public void TestM(){
2061
- // 模拟状态变量
2062
- var _state = (int)State.Lock;
2063
- // 模拟土地ID变量
2064
- switch (_state){
2065
- //上锁
2066
- case (int)State.Lock:
2067
- // lkwjefl
2068
- Toast.Info($"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁");
2069
- // klwejf
2070
- break;
2071
- // lkwjf
2072
- }
2073
- // klwjfel
2074
- }
2075
- }
2076
- }
2077
- `;
1817
+ // Log.Info("{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\");
1818
+ base.OnShow(param);
1819
+ }`;
2078
1820
  const snippets = extractor.extractStrings(code);
2079
1821
  {
2080
1822
  let targetSnippet = snippets[0];
2081
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`));
2082
- expect(targetSnippet.originalCode).toBe(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`);
2083
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("灵田{0}级解锁", _model.GetFarmLandUnlockLevel(_landId))`);
1823
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1824
+ expect(targetSnippet.originalCode).toBe(`"{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1825
+ expect(targetSnippet.convertedCode).toBe(`"{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
2084
1826
  expect(targetSnippet.literals).toEqual([
2085
- '灵田{0}级解锁'
1827
+ '{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
2086
1828
  ]);
2087
- expect(targetSnippet.isChanged).toBe(true);
1829
+ expect(targetSnippet.isChanged).toBe(false);
2088
1830
  }
2089
- });
2090
-
2091
- // 正确识别C#文档注释边界, 类、方法、类成员的文档注释需要直接忽略捕获, 不参与字符串表达式提取; 文档注释通常位于类、方法、类成员的定义上方, 文档注释的格式形如: ` /// <xxx> yyy\n /// </xxx>` 或 ` /// <xxx yyy/>`, 其中xxx为标签, yyy为注释内容, `<xxx>`和`</xxx>` 不一定在同一行或不同行, ` /// <xxx> yyy\n` 不一定只有一行; 文档注释通常以`<xxx>`标签开始, 以`</xxx>`标签结束, 或者以 `<xxx ` 开始, 以 `/>` 结束。
2092
- test('should handle doc comment boundary for class/method/members', () => {
1831
+ })
1832
+ test('should handle string in comment 5', () => {
2093
1833
  const code = `
2094
- /// <summary>
2095
- /// "fwef 类注释1"
2096
- /// $"fwef 类注释2"
2097
- /// $"fwef 类注释2 {wef}"
2098
- /// wef $"fwef 类注释2 {wef}" wef
2099
- /// </summary>
2100
- /// <sumary "lkwjfelj"/>
2101
- public partial class TimeLimitedChargeDialog
2102
- {
2103
- /// <summary>
2104
- /// $" Property成员注释 dsvdf {wlpoe}"
2105
- /// </summary>
2106
- private int Ljfw { get; set; } = 342;
2107
-
2108
- /// <summary>
2109
- /// $" Field成员注释 wfewe {vvwe}"
2110
- /// $" Field成员注释 wfewe {vvwe}" wfe
2111
- /// </summary>
2112
- private int Ljfw = 342;
2113
-
2114
- /// <summary>
2115
- ///</summary>
2116
- private int Ljfw = 342;
2117
-
2118
- /// <summary>
2119
- /// " wef方法注释 wef"
2120
- /// $" wef方法注释 wef"
2121
- /// $" wef方法注释 wef{wef}"
2122
- /// wfe $" wef方法注释 wef{wef}"
2123
- /// wfe $" wef方法注释 wef{wef}" wef
2124
- ///wfe $" wef方法注释 wef{wef}" wef
2125
- /// wefw $" wef方法注释 wef{wef}" we
2126
- /// </summary>
2127
- /// <sumary wf $"klwf"/>
2128
- /// <param name="force">是否重新创建页签列表</param>
2129
- private void RefreshGoodsInfo()
1834
+ protected override void OnShow(object param)
2130
1835
  {
2131
- m_text_timeleft.text = curShop.TimeLimitData.RemainTime() + "后消失";
2132
- }
2133
- }
2134
- `;
1836
+ // Log.Info($"{wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\");
1837
+ base.OnShow(param);
1838
+ }`;
2135
1839
  const snippets = extractor.extractStrings(code);
2136
1840
  {
2137
1841
  let targetSnippet = snippets[0];
2138
- // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2139
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`curShop.TimeLimitData.RemainTime() + "后消失"`));
2140
- expect(targetSnippet.originalCode).toBe(`curShop.TimeLimitData.RemainTime() + "后消失"`);
2141
- expect(targetSnippet.convertedCode).toBe(`curShop.TimeLimitData.RemainTime().TR() + "后消失".TR()`);
1842
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"{wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1843
+ expect(targetSnippet.originalCode).toBe(`$"{wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1844
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\", wefff)`);
2142
1845
  expect(targetSnippet.literals).toEqual([
2143
- '后消失'
1846
+ '{0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
2144
1847
  ]);
2145
1848
  expect(targetSnippet.isChanged).toBe(true);
2146
1849
  }
2147
- });
2148
-
2149
- // 正确识别C#方法参数中的字符串表达式, 支持1到多个形参有默认值的情形
2150
- test('should handle string expression in method call parameter 1', () => {
1850
+ })
1851
+ test('should handle string in comment 5', () => {
2151
1852
  const code = `
2152
- namespace FaBao.UI.Comp
2153
- {
2154
- public partial class ItemCommonComp
2155
- {
2156
- public void BindData(bool needCompare = false)
2157
- {
2158
- m_text_level.text = Tr.Format("{0}阶", _itemConfig.PillLevel);
2159
- }
2160
- }
2161
- }
1853
+ m_text_percent.text = $"{curGoodsConfig.RebateRate}%";
1854
+ m_name_holder.url = FUISys.Instance.GetIconUrl(_curShopDetail.ShopConfig.Name);
1855
+ m_thumbnail_holder.url = FUISys.Instance.GetIconUrl(_curShopDetail.ShopConfig.Thumbnail);
1856
+ m_btn_buy.text = $"¥ {curGoodsConfig.Price}";
1857
+ m_text_timeleft.text = curShop.TimeLimitData.RemainTime().TR() + "后消失".TR();
2162
1858
  `;
2163
1859
  const snippets = extractor.extractStrings(code);
2164
1860
  {
2165
- let targetSnippet = snippets[0];
2166
- // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2167
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}阶", _itemConfig.PillLevel)`));
2168
- expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
2169
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1861
+ let targetSnippet = snippets[2];
1862
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`curShop.TimeLimitData.RemainTime().TR() + "后消失".TR()`));
1863
+ expect(targetSnippet.originalCode).toBe(`curShop.TimeLimitData.RemainTime().TR() + "后消失".TR()`);
1864
+ expect(targetSnippet.convertedCode).toBe(`curShop.TimeLimitData.RemainTime().TR() + "后消失".TR()`);
2170
1865
  expect(targetSnippet.literals).toEqual([
2171
- '{0}阶'
1866
+ '后消失'
2172
1867
  ]);
2173
1868
  expect(targetSnippet.isChanged).toBe(false);
2174
1869
  }
2175
- expect(snippets.length).toBe(1);
1870
+ })
2176
1871
  });
2177
1872
 
2178
- // 正确识别C#方法参数中的字符串表达式, 支持1到多个形参有默认值的情形
2179
- test('should handle string expression in method call parameter 2', () => {
1873
+ describe('should handle switch', () => {
1874
+ test('should handle switch 1', () => {
2180
1875
  const code = `
2181
- namespace FaBao.UI.Comp
2182
- {
2183
- public partial class ItemCommonComp
2184
- {
2185
- public void BindData(bool needCompare = false, long needCompare2 = 23, float needCompare2 = 324.0)
2186
- {
2187
- m_text_level.text = Tr.Format("{0}阶", _itemConfig.PillLevel);
2188
- }
2189
- }
2190
- }
2191
- `;
1876
+ switch(condition){
1877
+ default:
1878
+ Log.Warning("实时更新自:" + rankData.Type);
1879
+ break;
1880
+ }`
2192
1881
  const snippets = extractor.extractStrings(code);
2193
- {
2194
- let targetSnippet = snippets[0];
2195
- // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2196
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}阶", _itemConfig.PillLevel)`));
2197
- expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
2198
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
2199
- expect(targetSnippet.literals).toEqual([
2200
- '{0}阶'
2201
- ]);
2202
- expect(targetSnippet.isChanged).toBe(false);
2203
- }
2204
- expect(snippets.length).toBe(1);
2205
- });
2206
1882
 
2207
- // 正确识别C#方法参数中的字符串表达式, 支持1到多个形参有默认值的情形
2208
- test('should handle string expression in method call parameter 3', () => {
1883
+ // 验证提取的片段数量
1884
+ expect(snippets.length).toBeGreaterThan(0);
1885
+
1886
+ let targetSnippet = snippets[0];
1887
+ expect(targetSnippet.originalCode).toBe(`"实时更新自:" + rankData.Type`);
1888
+ // 普通函数参数不需要追加 `.TR()`, 除非包含由 `+` 符号连接字符串等的情况
1889
+ expect(targetSnippet.convertedCode).toBe(`"实时更新自:" + rankData.Type`);
1890
+ expect(targetSnippet.literals).toEqual([
1891
+ "实时更新自:"
1892
+ ]);
1893
+ expect(targetSnippet.isChanged).toBe(false);
1894
+ })
1895
+ test('should handle switch 2', () => {
2209
1896
  const code = `
2210
- namespace FaBao.UI.Comp
2211
- {
2212
- public partial class ItemCommonComp
2213
- {
2214
- public void BindData(string wkle, bool needCompare = false, int needCompare2 = false)
2215
- {
2216
- m_text_level.text = Tr.Format("{0}阶", _itemConfig.PillLevel);
2217
- }
2218
- }
2219
- }
2220
- `;
1897
+ switch(kwjkwlje){
1898
+ case (int)RANK_TYPE.天梯段位:
1899
+ Debug.Log1("jkwhfehwfjkh:" + rank2Data.T4zype);
1900
+ break;
1901
+ }`
2221
1902
  const snippets = extractor.extractStrings(code);
2222
- {
2223
- let targetSnippet = snippets[0];
2224
- // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2225
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}阶", _itemConfig.PillLevel)`));
2226
- expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
2227
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
2228
- expect(targetSnippet.literals).toEqual([
2229
- '{0}阶'
2230
- ]);
2231
- expect(targetSnippet.isChanged).toBe(false);
2232
- }
2233
- expect(snippets.length).toBe(1);
2234
- });
2235
1903
 
2236
- // 正确提取C#方法参数中的字符串表达式信息, 支持1到多个形参有默认值的情形
2237
- test('should handle string expression in method call parameter 4', () => {
1904
+ // 验证提取的片段数量, switch 语句中包含普通字符串的情况
1905
+ expect(snippets.length).toBeGreaterThan(0);
1906
+
1907
+ let targetSnippet = snippets[0];
1908
+ expect(targetSnippet.originalCode).toBe(`"jkwhfehwfjkh:" + rank2Data.T4zype`);
1909
+ expect(targetSnippet.convertedCode).toBe(`"jkwhfehwfjkh:" + rank2Data.T4zype`);
1910
+ expect(targetSnippet.literals).toEqual([
1911
+ "jkwhfehwfjkh:"
1912
+ ]);
1913
+ expect(targetSnippet.isChanged).toBe(false);
1914
+ })
1915
+ test('should handle switch 3', () => {
2238
1916
  const code = `
2239
- namespace FaBao.UI.Comp
2240
- {
2241
- public partial class ItemCommonComp
2242
- {
2243
- public void BindData(string wkle = "11111", bool needCompare = false, int needCompare2 = false)
2244
- {
2245
- }
1917
+ switch(lkw){
1918
+ case V434:
1919
+ {
1920
+ Action2("wegwfw:" + varnws);
1921
+ break;
1922
+ }
1923
+ }`
1924
+ const snippets = extractor.extractStrings(code);
2246
1925
 
2247
- public void BindData(string wkle = "22", string wkle = "werwer", bool needCompare = false, string wkle = "wefwewef31f", int needCompare2 = false, string wkle = "df223")
2248
- {
2249
- }
1926
+ // 验证提取的片段数量
1927
+ expect(snippets.length).toBeGreaterThan(0);
2250
1928
 
2251
- public void BindData(string wkle = "(*&%\\\\*(@Fwfe))&(")
2252
- {
2253
- }
1929
+ let targetSnippet = snippets[0];
1930
+ expect(targetSnippet.originalCode).toBe(`"wegwfw:" + varnws`);
1931
+ expect(targetSnippet.convertedCode).toBe(`"wegwfw:" + varnws`);
1932
+ expect(targetSnippet.literals).toEqual([
1933
+ "wegwfw:"
1934
+ ]);
1935
+ expect(targetSnippet.isChanged).toBe(false);
1936
+ })
1937
+ test('should handle switch 4', () => {
1938
+ const code = `
1939
+ case V434:
1940
+ Action2("wegwfw:" + varnws);
1941
+ break;`
1942
+ const snippets = extractor.extractStrings(code);
2254
1943
 
2255
- public void BindData(string we, string wkle = "aaaaa", bool needCompare = false, int needCompare2 = false)
2256
- {
2257
- m_text_level.text = Tr.Format("{0}阶", _itemConfig.PillLevel);
2258
- }
2259
- }
2260
- }
2261
- `;
1944
+ // 验证提取的片段数量
1945
+ expect(snippets.length).toBeGreaterThan(0);
1946
+
1947
+ let targetSnippet = snippets[0];
1948
+ expect(targetSnippet.originalCode).toBe(`"wegwfw:" + varnws`);
1949
+ expect(targetSnippet.convertedCode).toBe(`"wegwfw:" + varnws`);
1950
+ expect(targetSnippet.literals).toEqual([
1951
+ "wegwfw:"
1952
+ ]);
1953
+ expect(targetSnippet.isChanged).toBe(false);
1954
+ })
1955
+ });
1956
+
1957
+ describe('should handle thriple expression with string expression', () => {
1958
+ test('should handle thriple expression with string expression 1', () => {
1959
+ const code = `m_btn_confirm.title = isUsed ? "使用中" : "使用";`;
2262
1960
  const snippets = extractor.extractStrings(code);
2263
1961
  {
2264
- let targetSnippet = snippets[0];
2265
- // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2266
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"11111"`));
2267
- expect(targetSnippet.originalCode).toBe(`"11111"`);
2268
- expect(targetSnippet.convertedCode).toBe(`"11111"`);
2269
- expect(targetSnippet.literals).toEqual([
2270
- '11111'
2271
- ]);
2272
- expect(targetSnippet.isChanged).toBe(false);
2273
- }
2274
- {
2275
- let targetSnippet = snippets[1];
2276
- // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2277
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"22"`));
2278
- expect(targetSnippet.originalCode).toBe(`"22"`);
2279
- expect(targetSnippet.convertedCode).toBe(`"22"`);
2280
- expect(targetSnippet.literals).toEqual([
2281
- '22'
2282
- ]);
2283
- expect(targetSnippet.isChanged).toBe(false);
2284
- }
2285
- {
2286
- let targetSnippet = snippets[2];
2287
- // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2288
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"werwer"`));
2289
- expect(targetSnippet.originalCode).toBe(`"werwer"`);
2290
- expect(targetSnippet.convertedCode).toBe(`"werwer"`);
2291
- expect(targetSnippet.literals).toEqual([
2292
- 'werwer'
2293
- ]);
2294
- expect(targetSnippet.isChanged).toBe(false);
2295
- }
2296
- {
2297
- let targetSnippet = snippets[3];
2298
- // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2299
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"wefwewef31f"`));
2300
- expect(targetSnippet.originalCode).toBe(`"wefwewef31f"`);
2301
- expect(targetSnippet.convertedCode).toBe(`"wefwewef31f"`);
2302
- expect(targetSnippet.literals).toEqual([
2303
- 'wefwewef31f'
2304
- ]);
2305
- expect(targetSnippet.isChanged).toBe(false);
2306
- }
2307
- {
2308
- let targetSnippet = snippets[4];
2309
- // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2310
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"df223"`));
2311
- expect(targetSnippet.originalCode).toBe(`"df223"`);
2312
- expect(targetSnippet.convertedCode).toBe(`"df223"`);
2313
- expect(targetSnippet.literals).toEqual([
2314
- 'df223'
1962
+ let snippet = snippets[0];
1963
+ expect(snippet.originalCode).toBe('isUsed ? "使用中" : "使用"');
1964
+ expect(snippet.convertedCode).toBe('isUsed ? "使用中".TR() : "使用".TR()');
1965
+ expect(snippet.literals).toEqual([
1966
+ '使用中',
1967
+ '使用'
2315
1968
  ]);
2316
- expect(targetSnippet.isChanged).toBe(false);
2317
1969
  }
1970
+ })
1971
+ test('should handle thriple expression with string expression 2', () => {
1972
+ const code = `wefe.text = isUsed ? "使用中" : "使用";`;
1973
+ const snippets = extractor.extractStrings(code);
2318
1974
  {
2319
- let targetSnippet = snippets[5];
2320
- // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2321
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"(*&%\\\\*(@Fwfe))&("`));
2322
- expect(targetSnippet.originalCode).toBe(`"(*&%\\\\*(@Fwfe))&("`);
2323
- expect(targetSnippet.convertedCode).toBe(`"(*&%\\\\*(@Fwfe))&("`);
2324
- expect(targetSnippet.literals).toEqual([
2325
- '(*&%\\\\*(@Fwfe))&('
1975
+ let snippet = snippets[0];
1976
+ expect(snippet.originalCode).toBe('isUsed ? "使用中" : "使用"');
1977
+ expect(snippet.convertedCode).toBe('isUsed ? "使用中".TR() : "使用".TR()');
1978
+ expect(snippet.literals).toEqual([
1979
+ '使用中',
1980
+ '使用'
2326
1981
  ]);
2327
- expect(targetSnippet.isChanged).toBe(false);
2328
1982
  }
1983
+ })
1984
+ test('should handle thriple expression with string expression 3', () => {
1985
+ const code = `wefetext = isUsed ? "使用中" : "使用";`;
1986
+ const snippets = extractor.extractStrings(code);
2329
1987
  {
2330
- let targetSnippet = snippets[6];
2331
- // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2332
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"aaaaa"`));
2333
- expect(targetSnippet.originalCode).toBe(`"aaaaa"`);
2334
- expect(targetSnippet.convertedCode).toBe(`"aaaaa"`);
2335
- expect(targetSnippet.literals).toEqual([
2336
- 'aaaaa'
1988
+ let snippet = snippets[0];
1989
+ expect(snippet.originalCode).toBe('isUsed ? "使用中" : "使用"');
1990
+ expect(snippet.convertedCode).toBe('isUsed ? "使用中" : "使用"');
1991
+ expect(snippet.literals).toEqual([
1992
+ '使用中',
1993
+ '使用'
2337
1994
  ]);
2338
- expect(targetSnippet.isChanged).toBe(false);
2339
1995
  }
1996
+ })
1997
+ test('should handle thriple expression with string expression 4', () => {
1998
+ const code = `wefetext(isUsed ? "使用中" : "使用");`;
1999
+ const snippets = extractor.extractStrings(code);
2340
2000
  {
2341
- let targetSnippet = snippets[7];
2342
- // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2343
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}阶", _itemConfig.PillLevel)`));
2344
- expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
2345
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
2346
- expect(targetSnippet.literals).toEqual([
2347
- '{0}阶'
2001
+ let snippet = snippets[0];
2002
+ expect(snippet.originalCode).toBe('isUsed ? "使用中" : "使用"');
2003
+ expect(snippet.convertedCode).toBe('isUsed ? "使用中" : "使用"');
2004
+ expect(snippet.literals).toEqual([
2005
+ '使用中',
2006
+ '使用'
2348
2007
  ]);
2349
- expect(targetSnippet.isChanged).toBe(false);
2350
2008
  }
2009
+ })
2351
2010
  });
2352
2011
 
2353
- // 需要正确识别C#代码中 `if` 语句边界 和 创建对象表达式的边界, 识别 `if` 语句前、中、后部分中的字符串表达式
2354
- test('should handle if border and object creation expression border', () => {
2355
- const code = `
2356
- namespace FaBao.UI.MainUI
2357
- {
2358
- public partial class SpellUpgradeDialog
2359
- {
2360
- private async void OnBtnUpgrade()
2361
- {
2362
- // new SpellCard_Action_UpgradeSpellCard(_symbolCard.Id) 被方法调用传参的 () 包裹, 因此已经构成了完整的对象创建表达式
2363
- if (await this.GetModel<SpellCardModel>().DispatchAction(new SpellCard_Action_UpgradeSpellCard(_symbolCard.Id)))
2364
- {
2365
- //升级成功后刷新界面
2366
- m_text_level.text = Tr.Format("{0}级", _symbolCard.Level);
2367
- }
2368
- }
2369
- }
2370
- }
2371
- `;
2012
+ describe('基本字符串提取', () => {
2013
+ test('should extract plain strings', () => {
2014
+ const code = 'Console.WriteLine("Hello, world!");';
2015
+ const snippets = extractor.extractStrings(code);
2016
+
2017
+ expect(snippets.length).toBe(1);
2018
+ expect(snippets[0].literals).toEqual(['Hello, world!']);
2019
+ })
2020
+ });
2021
+
2022
+ describe('已带.TR()后缀的字符串处理', () => {
2023
+ test('should handle strings with .TR() already appended', () => {
2024
+ const code = 'obj.prop = "Hello, world!".TR();';
2025
+ const snippets = extractor.extractStrings(code);
2026
+
2027
+ expect(snippets.length).toBe(1);
2028
+ expect(snippets[0].originalCode).toBe('"Hello, world!".TR()');
2029
+ expect(snippets[0].convertedCode).toBe('"Hello, world!".TR()');
2030
+ expect(snippets[0].isChanged).toBe(false);
2031
+ })
2032
+ test('should not add .TR() to function arguments', () => {
2033
+ const code = 'CallFunc("Hello, world!");';
2034
+ const snippets = extractor.extractStrings(code);
2035
+
2036
+ expect(snippets.length).toBe(1);
2037
+ expect(snippets[0].originalCode).toBe('"Hello, world!"');
2038
+ expect(snippets[0].convertedCode).toBe('"Hello, world!"');
2039
+ })
2040
+ test('should not add .TR() to regular property assignments', () => {
2041
+ const code = 'obj.prop = "Hello, world!";';
2042
+ const snippets = extractor.extractStrings(code);
2043
+
2044
+ expect(snippets.length).toBe(1);
2045
+ expect(snippets[0].originalCode).toBe('"Hello, world!"');
2046
+ expect(snippets[0].convertedCode).toBe('"Hello, world!"');
2047
+ })
2048
+ test('should handle complex concatenation with existing .TR() calls', () => {
2049
+ const code = 'var hello3 = "Hello, ".TR() + name.TR() + obj2.name.TR() + obj2.nam1_e.Fn1().Prop + "!";';
2050
+ const snippets = extractor.extractStrings(code);
2051
+
2052
+ expect(snippets.length).toBe(1);
2053
+ expect(snippets[0].originalCode).toBe('"Hello, ".TR() + name.TR() + obj2.name.TR() + obj2.nam1_e.Fn1().Prop + "!"');
2054
+ expect(snippets[0].convertedCode).toBe('"Hello, ".TR() + name.TR() + obj2.name.TR() + obj2.nam1_e.Fn1().Prop.TR() + "!".TR()');
2055
+ })
2056
+ test('should not add .TR() to strings already having it', () => {
2057
+ const code = 'var wkle = "Hello".TR();';
2058
+ const snippets = extractor.extractStrings(code);
2059
+
2060
+ const snippet = snippets[0];
2061
+ expect(snippet.originalCode).toBe('"Hello".TR()');
2062
+ expect(snippet.convertedCode).toBe('"Hello".TR()');
2063
+ expect(snippet.literals).toEqual(['Hello']);
2064
+ expect(snippet.isChanged).toBe(false);
2065
+ })
2066
+ });
2067
+
2068
+ describe('字符串模板/内插字符串处理', () => {
2069
+ test('should handle $"" string templates', () => {
2070
+ const code = 'var label1 = $"Hello, {name}!";';
2071
+ const snippets = extractor.extractStrings(code);
2072
+
2073
+ expect(snippets.length).toBe(1);
2074
+ expect(snippets[0].originalCode).toBe('$"Hello, {name}!"');
2075
+ expect(snippets[0].literals).toContain('Hello, {0}!');
2076
+ expect(snippets[0].convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
2077
+ })
2078
+ test('should handle $"" string templates in function calls', () => {
2079
+ const code = 'CallFunc($"Hello, world: {obj.Func1()}");';
2080
+ const snippets = extractor.extractStrings(code);
2081
+
2082
+ expect(snippets.length).toBe(1);
2083
+ expect(snippets[0].originalCode).toBe('$"Hello, world: {obj.Func1()}"');
2084
+ expect(snippets[0].convertedCode).toBe('Tr.Format("Hello, world: {0}", obj.Func1())');
2085
+ })
2086
+ test('should handle .text = assignments with string templates', () => {
2087
+ const code = 'label.text = $"pre{Func()}sub";';
2088
+ const snippets = extractor.extractStrings(code);
2089
+
2090
+ expect(snippets.length).toBe(1);
2091
+ expect(snippets[0].originalCode).toBe('$"pre{Func()}sub"');
2092
+ expect(snippets[0].literals).toContain('pre{0}sub');
2093
+ expect(snippets[0].convertedCode).toBe('Tr.Format("pre{0}sub", Func())');
2094
+ })
2095
+ test('should extract and convert string templates', () => {
2096
+ const code = 'Ljk.Ilk($"Hello, {name}!");';
2097
+ const snippets = extractor.extractStrings(code);
2098
+
2099
+ expect(snippets.length).toBeGreaterThan(0);
2100
+ const snippet = snippets[0];
2101
+ expect(snippet.originalCode).toBe('$"Hello, {name}!"');
2102
+ expect(snippet.convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
2103
+ expect(snippet.literals).toEqual(['Hello, {0}!']);
2104
+ expect(snippet.isChanged).toBe(true);
2105
+ })
2106
+ test('should handle @$"" and $@"" formats', () => {
2107
+ const code = 'Fcx.Kjl(@$"Hello, {name}!");';
2108
+ const snippets = extractor.extractStrings(code);
2109
+
2110
+ const snippet = snippets[0];
2111
+ expect(snippet.originalCode).toBe('@$"Hello, {name}!"');
2112
+ expect(snippet.convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
2113
+ expect(snippet.literals).toEqual(['Hello, {0}!']);
2114
+ expect(snippet.isChanged).toBe(true);
2115
+ })
2116
+ test('should handle string template with format specifier', () => {
2117
+ const code = `infoStr += $"最终抗性: {resistReduce:F}\\n";`
2118
+ const snippets = extractor.extractStrings(code);
2119
+
2120
+ // 验证提取的片段数量
2121
+ expect(snippets.length).toBeGreaterThan(0);
2122
+
2123
+ let targetSnippet = snippets[0];
2124
+ expect(targetSnippet.originalCode).toBe(`$"最终抗性: {resistReduce:F}\\n"`);
2125
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("最终抗性: {0:F}\\n", resistReduce)`);
2126
+ expect(targetSnippet.literals).toEqual(['最终抗性: {0:F}\\n']);
2127
+ expect(targetSnippet.isChanged).toBe(true);
2128
+ })
2129
+ test('should handle fix interpolated string nested literals', () => {
2130
+ const code = `infoStr += $"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n";`;
2372
2131
  const snippets = extractor.extractStrings(code);
2373
2132
  {
2374
2133
  let targetSnippet = snippets[0];
2375
- // 需要正确识别 `if` 语句边界, 识别 `if` 语句前、中、后部分中的字符串表达式
2376
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}级", _symbolCard.Level)`));
2377
- expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}级", _symbolCard.Level)`);
2378
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}", _symbolCard.Level)`);
2134
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n"`));
2135
+ expect(targetSnippet.originalCode).toBe(`$"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n"`);
2136
+ // 需要正确转换内插字符串格式
2137
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("是否暴击: [b]{0}[/b]\n", (_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否"))`);
2379
2138
  expect(targetSnippet.literals).toEqual([
2380
- '{0}'
2139
+ '是否暴击: [b]{0}[/b]\n'
2381
2140
  ]);
2382
- expect(targetSnippet.isChanged).toBe(false);
2141
+ expect(targetSnippet.isChanged).toBe(true);
2383
2142
  }
2143
+ })
2144
+ });
2145
+
2146
+ describe('string.Format和Tr.Format处理', () => {
2147
+ test('should convert string.Format to Tr.Format', () => {
2148
+ const code = 'string.Format("Hello, ", name, "!");';
2149
+ const snippets = extractor.extractStrings(code);
2150
+
2384
2151
  expect(snippets.length).toBe(1);
2152
+ // string.Format(...) 形式的字符串表达式, 不需要对提取的字符串表达式进行处理, 也不需要追加 `.TR()`
2153
+ // string.Format(...) 形式包含的字符串表达式, 需要特殊处理, 连带 `string.Format()` 一起捕获存入 originalCode 成员
2154
+ expect(snippets[0].originalCode).toBe('string.Format("Hello, ", name, "!")');
2155
+ expect(snippets[0].convertedCode).toBe('Tr.Format("Hello, ", name, "!")');
2156
+ })
2157
+ test('should convert string.Format to Tr.Format', () => {
2158
+ const code = 'string.Format("Hello, {0}!", name);';
2159
+ const snippets = extractor.extractStrings(code);
2160
+
2161
+ expect(snippets.length).toBeGreaterThan(0);
2162
+ const snippet = snippets[0];
2163
+ expect(snippet.originalCode).toBe('string.Format("Hello, {0}!", name)');
2164
+ expect(snippet.convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
2165
+ expect(snippet.literals).toEqual(['Hello, {0}!']);
2166
+ expect(snippet.isChanged).toBe(true);
2167
+ })
2385
2168
  });
2386
2169
 
2387
- // 需要正确识别C#代码中的匿名函数, 匿名函数中的字符串表达式也同样需要提取; 匿名函数通常以 `0到多个修饰词 (可选参数列表) => { ... }` 或者 `0到多个修饰词 (可选参数列表) => 一句表达式` 形式定义实现.
2388
- test('should handle class member initialization assignment with anonymous function 1', () => {
2170
+ describe('.text赋值语句处理', () => {
2171
+ test('should handle string.Format in .text assignments', () => {
2172
+ const code = 'label.text = Tr.Format("pre", Func(), "sub") + other;';
2173
+ const snippets = extractor.extractStrings(code);
2174
+
2175
+ expect(snippets.length).toBe(1);
2176
+ expect(snippets[0].originalCode).toBe('Tr.Format("pre", Func(), "sub") + other');
2177
+ expect(snippets[0].literals).toContain('pre');
2178
+ expect(snippets[0].literals).toContain('sub');
2179
+ })
2180
+ test('should handle .text = assignments with function calls', () => {
2181
+ const code = 'label.text = Func();';
2182
+ const snippets = extractor.extractStrings(code);
2183
+
2184
+ expect(snippets.length).toBe(1);
2185
+ expect(snippets[0].originalCode).toBe('Func()');
2186
+ expect(snippets[0].convertedCode).toBe('Func().TR()');
2187
+ })
2188
+ test('should handle .text = assignments with multiple function calls', () => {
2189
+ const code = 'label.text = Func() + Func();';
2190
+ const snippets = extractor.extractStrings(code);
2191
+
2192
+ expect(snippets.length).toBe(1);
2193
+ expect(snippets[0].originalCode).toBe('Func() + Func()');
2194
+ expect(snippets[0].convertedCode).toBe('Func().TR() + Func().TR()');
2195
+ })
2196
+ test('should handle .text = assignments with string.Format', () => {
2197
+ const code = 'label.text = string.Format("pre{0:F2}{1}", Func(), "sub") + other;';
2198
+ const snippets = extractor.extractStrings(code);
2199
+
2200
+ expect(snippets.length).toBe(1);
2201
+ expect(snippets[0].originalCode).toBe('string.Format("pre{0:F2}{1}", Func(), "sub") + other');
2202
+ expect(snippets[0].literals).toContain('pre{0:F2}{1}');
2203
+ expect(snippets[0].literals).toContain('sub');
2204
+ })
2205
+ test('should handle .text = assignments', () => {
2206
+ const code = 'label.text = "Test";';
2207
+ const snippets = extractor.extractStrings(code);
2208
+
2209
+ expect(snippets.length).toBeGreaterThan(0);
2210
+ const snippet = snippets[0];
2211
+ expect(snippet.originalCode).toBe('"Test"');
2212
+ expect(snippet.convertedCode).toBe('"Test".TR()');
2213
+ expect(snippet.literals).toEqual(['Test']);
2214
+ expect(snippet.isChanged).toBe(true);
2215
+ })
2216
+ test('should handle .text = with Tr.Format', () => {
2217
+ const code = 'label.text = Tr.Format("pre", Func(), "sub") + other;';
2218
+ const snippets = extractor.extractStrings(code);
2219
+
2220
+ const snippet = snippets[0];
2221
+ expect(snippet.originalCode).toBe('Tr.Format("pre", Func(), "sub") + other');
2222
+ expect(snippet.convertedCode).toBe('Tr.Format("pre", Func(), "sub") + other.TR()');
2223
+ expect(snippet.literals).toEqual(['pre', 'sub']);
2224
+ expect(snippet.isChanged).toBe(true);
2225
+ })
2226
+ test('should handle .text = assignments contains chinese', () => {
2389
2227
  const code = `
2390
- FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
2391
- {
2392
- Title = "提示",
2393
- ConfirmCallback = async () =>
2394
- {
2395
- //灵纹一键下阵
2396
- if (await this.GetModel<CardModel>().DispatchAction(new Rune_Action_CleanRune(_sutraCardData.Card.Id)))
2397
- {
2398
- Toast.Info("卸载成功");
2399
- }
2400
- },
2401
- CancelText = "取消",
2402
- }).Forget();
2228
+ 为栓饭cxs12.text = 南方eflkj.d文件 + "完善ew";
2229
+ m_btn_为栓饭cxs12.title = bw尅kljekl.完善 + "栏栏nfc";
2403
2230
  `;
2404
2231
  const snippets = extractor.extractStrings(code);
2405
2232
  {
2406
- let targetSnippet = snippets[0];
2407
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"提示"`));
2408
- expect(targetSnippet.originalCode).toBe(`"提示"`);
2409
- expect(targetSnippet.convertedCode).toBe(`"提示"`);
2410
- expect(targetSnippet.literals).toEqual([
2411
- '提示'
2412
- ]);
2413
- expect(targetSnippet.isChanged).toBe(false);
2414
- }
2415
- {
2416
- let targetSnippet = snippets[1];
2417
- // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
2418
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"卸载成功"`));
2419
- expect(targetSnippet.originalCode).toBe(`"卸载成功"`);
2420
- expect(targetSnippet.convertedCode).toBe(`"卸载成功"`);
2421
- expect(targetSnippet.literals).toEqual([
2422
- '卸载成功'
2233
+ let snippet = snippets[0];
2234
+ expect(snippet.originalCode).toBe('南方eflkj.d文件 + "完善ew"');
2235
+ expect(snippet.convertedCode).toBe('南方eflkj.d文件.TR() + "完善ew".TR()');
2236
+ expect(snippet.literals).toEqual([
2237
+ '完善ew'
2423
2238
  ]);
2424
- expect(targetSnippet.isChanged).toBe(false);
2425
2239
  }
2426
2240
  {
2427
- let targetSnippet = snippets[2];
2428
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"取消"`));
2429
- expect(targetSnippet.originalCode).toBe(`"取消"`);
2430
- expect(targetSnippet.convertedCode).toBe(`"取消"`);
2431
- expect(targetSnippet.literals).toEqual([
2432
- '取消'
2241
+ let snippet = snippets[1];
2242
+ expect(snippet.originalCode).toBe('bw尅kljekl.完善 + "栏栏nfc"');
2243
+ expect(snippet.convertedCode).toBe('bw尅kljekl.完善.TR() + "栏栏nfc".TR()');
2244
+ expect(snippet.literals).toEqual([
2245
+ '栏栏nfc'
2433
2246
  ]);
2434
- expect(targetSnippet.isChanged).toBe(false);
2435
2247
  }
2248
+ })
2436
2249
  });
2437
2250
 
2438
- // 需要正确识别C#代码中的匿名函数, 匿名函数中的字符串表达式也同样需要提取; 匿名函数通常以 `0到多个修饰词 (可选参数列表) => { ... }` 或者 `0到多个修饰词 (可选参数列表) => 一句表达式` 形式定义实现.
2439
- test('should handle class member initialization assignment with anonymous function 2', () => {
2251
+ describe('.title赋值语句处理', () => {
2252
+ test('should handle m_btn_xxx.title = yyy', () => {
2440
2253
  const code = `
2441
- FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
2442
- {
2443
- ConfirmCallback = async () =>
2444
- {
2445
- Toast.Info("卸载成功");
2446
- },
2447
- }).Forget();
2254
+ buy.title = "lkwjelkfj1";
2255
+ m_btn1_buy.title = "lkwjelkfj2";
2256
+ am_btn_buy.title = "lkwjelkfj3";
2257
+ m_btn_buy.title = "lkwjelkfj4";
2258
+ m_btn_wwefHwref.title = $"Hello";
2259
+ m_btn_fxx_wf.title = $"Hello, {name}!";
2448
2260
  `;
2449
2261
  const snippets = extractor.extractStrings(code);
2450
2262
  {
2451
- let targetSnippet = snippets[0];
2452
- // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
2453
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"卸载成功"`));
2454
- expect(targetSnippet.originalCode).toBe(`"卸载成功"`);
2455
- expect(targetSnippet.convertedCode).toBe(`"卸载成功"`);
2456
- expect(targetSnippet.literals).toEqual([
2457
- '卸载成功'
2458
- ]);
2459
- expect(targetSnippet.isChanged).toBe(false);
2263
+ let snippet = snippets[0];
2264
+ expect(snippet.originalIndex).toBe(code.indexOf('"lkwjelkfj1"'));
2265
+ expect(snippet.originalCode).toBe('"lkwjelkfj1"');
2266
+ // `buy` 不符合 `m_btn_` 开头的条件, 不需要强制加 `.TR()`
2267
+ expect(snippet.convertedCode).toBe('"lkwjelkfj1"');
2268
+ expect(snippet.literals).toContain('lkwjelkfj1');
2269
+ expect(snippet.isChanged).toBe(false);
2460
2270
  }
2461
- });
2462
-
2463
- // 需要正确识别C#代码中的匿名函数, 匿名函数中的字符串表达式也同样需要提取; 匿名函数通常以 `0到多个修饰词 (可选参数列表) => { ... }` 或者 `0到多个修饰词 (可选参数列表) => 一句表达式` 形式定义实现.
2464
- test('should handle class member initialization assignment with anonymous function 3', () => {
2271
+ {
2272
+ let snippet = snippets[1];
2273
+ expect(snippet.originalIndex).toBe(code.indexOf('"lkwjelkfj2"'));
2274
+ expect(snippet.originalCode).toBe('"lkwjelkfj2"');
2275
+ // `m_btn1_buy` 不符合 `m_btn_` 开头的条件, 不需要强制加 `.TR()`
2276
+ expect(snippet.convertedCode).toBe('"lkwjelkfj2"');
2277
+ expect(snippet.literals).toContain('lkwjelkfj2');
2278
+ expect(snippet.isChanged).toBe(false);
2279
+ }
2280
+ {
2281
+ let snippet = snippets[2];
2282
+ expect(snippet.originalIndex).toBe(code.indexOf('"lkwjelkfj3"'));
2283
+ expect(snippet.originalCode).toBe('"lkwjelkfj3"');
2284
+ // `am_btn_buy` 不符合 `m_btn_` 开头的条件, 不需要强制加 `.TR()`
2285
+ expect(snippet.convertedCode).toBe('"lkwjelkfj3"');
2286
+ expect(snippet.literals).toContain('lkwjelkfj3');
2287
+ expect(snippet.isChanged).toBe(false);
2288
+ }
2289
+ {
2290
+ let snippet = snippets[3];
2291
+ expect(snippet.originalIndex).toBe(code.indexOf('"lkwjelkfj4"'));
2292
+ expect(snippet.originalCode).toBe('"lkwjelkfj4"');
2293
+ // `m_btn_buy` 符合 `m_btn_` 开头的条件, 需要强制加 `.TR()`
2294
+ expect(snippet.convertedCode).toBe('"lkwjelkfj4".TR()');
2295
+ expect(snippet.literals).toContain('lkwjelkfj4');
2296
+ expect(snippet.isChanged).toBe(true);
2297
+ }
2298
+ {
2299
+ let snippet = snippets[4];
2300
+ expect(snippet.originalIndex).toBe(code.indexOf('$"Hello"'));
2301
+ expect(snippet.originalCode).toBe('$"Hello"');
2302
+ // `m_btn_wwefHwref` 符合 `m_btn_` 开头的条件, 需要强制加 `.TR()`
2303
+ expect(snippet.convertedCode).toBe('$"Hello".TR()');
2304
+ expect(snippet.literals).toContain('Hello');
2305
+ expect(snippet.isChanged).toBe(true);
2306
+ }
2307
+ {
2308
+ let snippet = snippets[5];
2309
+ expect(snippet.originalIndex).toBe(code.indexOf('$"Hello, {name}!"'));
2310
+ expect(snippet.originalCode).toBe('$"Hello, {name}!"');
2311
+ // `m_btn_fxx_wf` 符合 `m_btn_` 开头的条件
2312
+ expect(snippet.convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
2313
+ expect(snippet.literals).toContain('Hello, {0}!');
2314
+ expect(snippet.isChanged).toBe(true);
2315
+ }
2316
+ expect(snippets.length).toBe(6);
2317
+ })
2318
+ test('should handle m_btn_xxx.title = yyy assignments contains chinese', () => {
2465
2319
  const code = `
2466
- FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
2320
+ switch (_roomData.RoomState)
2321
+ {
2322
+ case Data.Match.RoomState.IsDismiss:
2323
+ m_btn_join.title = "已解散";
2324
+ m_btn_join.enabled = false;
2325
+ grayed = true;
2326
+ break;
2327
+ case Data.Match.RoomState.Rejected:
2467
2328
  {
2468
- ConfirmCallback = (int qwfewe) =>
2469
- {
2470
- Toast.Info($"卸载成功: {qwfewe}");
2471
- },
2472
- }).Forget();
2329
+ m_btn_join.title = $"被拒绝{Kff}";
2330
+ m_btn_join.enabled = false;
2331
+ break;
2332
+ }
2333
+ case Data.Match.RoomState.OutOfDate:
2334
+ m_dd_join.text = "已到期";
2335
+ break;
2336
+ default:
2337
+ m_btn_join.title = "申请";
2338
+ m_btn_joi23n.title = $"申请{Kjf}";
2339
+ break;
2340
+ }
2473
2341
  `;
2474
2342
  const snippets = extractor.extractStrings(code);
2475
2343
  {
2476
- let targetSnippet = snippets[0];
2477
- // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
2478
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"卸载成功: {qwfewe}"`));
2479
- expect(targetSnippet.originalCode).toBe(`$"卸载成功: {qwfewe}"`);
2480
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("卸载成功: {0}", qwfewe)`);
2481
- expect(targetSnippet.literals).toEqual([
2482
- '卸载成功: {0}'
2344
+ let snippet = snippets[0];
2345
+ expect(snippet.originalCode).toBe('"已解散"');
2346
+ expect(snippet.convertedCode).toBe('"已解散".TR()');
2347
+ expect(snippet.literals).toEqual([
2348
+ '已解散'
2349
+ ]);
2350
+ }
2351
+ {
2352
+ let snippet = snippets[1];
2353
+ expect(snippet.originalCode).toBe('$"被拒绝{Kff}"');
2354
+ expect(snippet.convertedCode).toBe('Tr.Format("被拒绝{0}", Kff)');
2355
+ expect(snippet.literals).toEqual([
2356
+ '被拒绝{0}'
2483
2357
  ]);
2484
- expect(targetSnippet.isChanged).toBe(true);
2485
2358
  }
2486
- });
2487
-
2488
- // 需要正确识别C#代码中的匿名函数, 匿名函数中的字符串表达式也同样需要提取; 匿名函数通常以 `0到多个修饰词 (可选参数列表) => { ... }` 或者 `0到多个修饰词 (可选参数列表) => 一句表达式` 形式定义实现.
2489
- test('should handle class member initialization assignment with anonymous function 4', () => {
2490
- const code = `
2491
- FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
2492
- {
2493
- ConfirmCallback = async () => Toast.Info("卸载成功"),
2494
- }).Forget();
2495
- `;
2496
- const snippets = extractor.extractStrings(code);
2497
2359
  {
2498
- let targetSnippet = snippets[0];
2499
- // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
2500
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"卸载成功"`));
2501
- expect(targetSnippet.originalCode).toBe(`"卸载成功"`);
2502
- expect(targetSnippet.convertedCode).toBe(`"卸载成功"`);
2503
- expect(targetSnippet.literals).toEqual([
2504
- '卸载成功'
2360
+ let snippet = snippets[2];
2361
+ expect(snippet.originalCode).toBe('"已到期"');
2362
+ expect(snippet.convertedCode).toBe('"已到期".TR()');
2363
+ expect(snippet.literals).toEqual([
2364
+ '已到期'
2505
2365
  ]);
2506
- expect(targetSnippet.isChanged).toBe(false);
2507
2366
  }
2508
- });
2509
-
2510
- // 需要正确识别C#代码中的匿名函数, 匿名函数中的字符串表达式也同样需要提取; 匿名函数通常以 `0到多个修饰词 (可选参数列表) => { ... }` 或者 `0到多个修饰词 (可选参数列表) => 一句表达式` 形式定义实现.
2511
- test('should handle class member initialization assignment with anonymous function 5', () => {
2512
- const code = `
2513
- FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
2514
- {
2515
- ConfirmCallback = () => Toast.Info("卸载成功"),
2516
- }).Forget();
2517
- `;
2518
- const snippets = extractor.extractStrings(code);
2519
2367
  {
2520
- let targetSnippet = snippets[0];
2521
- // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
2522
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`"卸载成功"`));
2523
- expect(targetSnippet.originalCode).toBe(`"卸载成功"`);
2524
- expect(targetSnippet.convertedCode).toBe(`"卸载成功"`);
2525
- expect(targetSnippet.literals).toEqual([
2526
- '卸载成功'
2368
+ let snippet = snippets[3];
2369
+ expect(snippet.originalCode).toBe('"申请"');
2370
+ expect(snippet.convertedCode).toBe('"申请".TR()');
2371
+ expect(snippet.literals).toEqual([
2372
+ '申请'
2527
2373
  ]);
2528
- expect(targetSnippet.isChanged).toBe(false);
2529
2374
  }
2530
- });
2531
-
2532
- // 测试处理 `xxx.text = yyy;` 形式赋值语句, 以 `.text =` 给 `text` 成员赋值的表达式中, `yyy` 部分必定是字符串表达式; 如果`yyy`中不存在字符串, 则`yyy` 中以 `+` 连接的表达式需要加上 `.TR()`; 如果 `yyy` 是作为值表达式整体(必定返回字符串类型值), 也需要追加 `.TR()`。
2533
- test('should handle .text = format 1', () => {
2534
- const code = `m_text_iwff.text = info ;`;
2535
- const snippets = extractor.extractStrings(code);
2536
2375
  {
2537
- let targetSnippet = snippets[0];
2538
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`info`));
2539
- expect(targetSnippet.originalCode).toBe(`info`);
2540
- expect(targetSnippet.convertedCode).toBe(`info.TR()`);
2541
- expect(targetSnippet.literals).toEqual([
2376
+ let snippet = snippets[4];
2377
+ expect(snippet.originalCode).toBe('$"申请{Kjf}"');
2378
+ expect(snippet.convertedCode).toBe('Tr.Format("申请{0}", Kjf)');
2379
+ expect(snippet.literals).toEqual([
2380
+ '申请{0}'
2542
2381
  ]);
2543
- expect(targetSnippet.isChanged).toBe(true);
2544
2382
  }
2383
+ })
2545
2384
  });
2546
2385
 
2547
- // 测试处理 `xxx.text = yyy;` 形式赋值语句, 以 `.text =` 给 `text` 成员赋值的表达式中, `yyy` 部分必定是字符串表达式; 如果`yyy`中不存在字符串, 则`yyy` 中以 `+` 连接的表达式需要加上 `.TR()`; 如果 `yyy` 是作为值表达式整体(必定返回字符串类型值), 也需要追加 `.TR()`。
2548
- test('should handle .text = format 2', () => {
2549
- const code = `m_text_info.text = info1.member1 + info2.member2;`;
2386
+ describe('字符串拼接处理', () => {
2387
+ test('should handle string concatenation', () => {
2388
+ const code = 'var label2 = "Hello, " + name + "!";';
2550
2389
  const snippets = extractor.extractStrings(code);
2551
- {
2552
- let targetSnippet = snippets[0];
2553
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`info1.member1 + info2.member2`));
2554
- expect(targetSnippet.originalCode).toBe(`info1.member1 + info2.member2`);
2555
- expect(targetSnippet.convertedCode).toBe(`info1.member1.TR() + info2.member2.TR()`);
2556
- expect(targetSnippet.literals).toEqual([
2557
- ]);
2558
- expect(targetSnippet.isChanged).toBe(true);
2559
- }
2390
+
2391
+ expect(snippets.length).toBe(1);
2392
+ expect(snippets[0].originalCode).toBe('"Hello, " + name + "!"');
2393
+ expect(snippets[0].convertedCode).toBe('"Hello, ".TR() + name.TR() + "!".TR()');
2394
+ })
2395
+ test('should handle string concatenations', () => {
2396
+ const code = 'var wkleee = "Hello, " + name + "!";';
2397
+ const snippets = extractor.extractStrings(code);
2398
+
2399
+ expect(snippets.length).toBeGreaterThan(0);
2400
+ const snippet = snippets[0];
2401
+ expect(snippet.originalCode).toBe('"Hello, " + name + "!"');
2402
+ expect(snippet.convertedCode).toBe('"Hello, ".TR() + name.TR() + "!".TR()');
2403
+ expect(snippet.literals).toEqual(['Hello, ', '!']);
2404
+ expect(snippet.isChanged).toBe(true);
2405
+ })
2560
2406
  });
2561
2407
 
2562
- // 处理字符串出现在赋值表达式的 `=` 左边(左值表达式)的情况
2563
- test('should handle right value expression', () => {
2408
+ describe('switch case语句处理', () => {
2409
+ test('should handle switch expression string', () => {
2564
2410
  const code = `
2565
- ((GLoader)GetChild($"m_loader_dailyItem{i + 1}")).url = FUISys.Instance.GetIconUrl(ItemTable.GetConfigById(_cardConfig.EveryDayAwards[i].ResId).Icon);
2411
+ case (int)State.Lock:
2412
+ Toast.Info($"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁");
2413
+ break;
2566
2414
  `;
2567
2415
  const snippets = extractor.extractStrings(code);
2568
2416
  {
2569
2417
  let targetSnippet = snippets[0];
2570
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"m_loader_dailyItem{i + 1}"`));
2571
- expect(targetSnippet.originalCode).toBe(`$"m_loader_dailyItem{i + 1}"`); // 左边表达式函数调用参数中的字符串表达式
2572
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("m_loader_dailyItem{0}", i + 1)`);
2418
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`));
2419
+ expect(targetSnippet.originalCode).toBe(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`);
2420
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("灵田{0}级解锁", _model.GetFarmLandUnlockLevel(_landId))`);
2573
2421
  expect(targetSnippet.literals).toEqual([
2574
- `m_loader_dailyItem{0}`
2422
+ '灵田{0}级解锁'
2575
2423
  ]);
2576
2424
  expect(targetSnippet.isChanged).toBe(true);
2577
2425
  }
2578
- expect(snippets.length).toBe(1);
2426
+ })
2579
2427
  });
2580
2428
 
2581
- // 支持处理字符串里出现各种特殊符号的情况
2582
- test('should handle special characters in string 8', () => {
2583
- const code = `
2584
- m_btn_paid.text = $"<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{paidConfig.Quantity}";
2585
- `;
2429
+ describe('转义字符与特殊字符串处理', () => {
2430
+ test('should handle escaped quotes in strings', () => {
2431
+ const code = 'Debug.Log("aaa\\\"bbb\\\"c\\\"d\\\\\\"cc");';
2432
+ const snippets = extractor.extractStrings(code);
2433
+
2434
+ expect(snippets.length).toBe(1);
2435
+ expect(snippets[0].originalCode).toBe('"aaa\\\"bbb\\\"c\\\"d\\\\\\"cc"');
2436
+ expect(snippets[0].convertedCode).toBe('"aaa\\\"bbb\\\"c\\\"d\\\\\\"cc"');
2437
+ // 由于JavaScript字符串转义的复杂性,我们只检查是否提取了字符串
2438
+ expect(snippets[0].literals).toEqual(['aaa\\\"bbb\\\"c\\\"d\\\\\\"cc']);
2439
+ })
2440
+ test('should handle escaped strings', () => {
2441
+ const code = 'a.text = "aaa\\"bbb\\"c\\"d\\\\\\"cc";';
2442
+ const snippets = extractor.extractStrings(code);
2443
+
2444
+ const snippet = snippets[0];
2445
+ expect(snippet.originalCode).toBe('"aaa\\"bbb\\"c\\"d\\\\\\"cc"');
2446
+ expect(snippet.convertedCode).toBe('"aaa\\"bbb\\"c\\"d\\\\\\"cc".TR()');
2447
+ expect(snippet.literals).toEqual(['aaa\\"bbb\\"c\\"d\\\\\\"cc']);
2448
+ expect(snippet.isChanged).toBe(true);
2449
+ })
2450
+ test('should handle special characters in string expression of return sentence', () => {
2451
+ const code = readFileSync("test/TestSpecialString.cs", "utf8");
2586
2452
  const snippets = extractor.extractStrings(code);
2587
2453
  {
2588
- let targetSnippet = snippets[0];
2589
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{paidConfig.Quantity}"`));
2590
- expect(targetSnippet.originalCode).toBe(`$"<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{paidConfig.Quantity}"`);
2591
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{0}", paidConfig.Quantity)`);
2454
+ let targetSnippet = snippets[7];
2455
+ // 需要统一匹配 `return` 语句中的字符串表达式
2456
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"5. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
2457
+ expect(targetSnippet.originalCode).toBe(`"5. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
2458
+ expect(targetSnippet.convertedCode).toBe(`"5. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
2592
2459
  expect(targetSnippet.literals).toEqual([
2593
- `<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{0}`
2460
+ '5. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
2594
2461
  ]);
2595
- expect(targetSnippet.isChanged).toBe(true);
2462
+ expect(targetSnippet.isChanged).toBe(false);
2596
2463
  }
2597
- expect(snippets.length).toBe(1);
2464
+ })
2598
2465
  });
2599
2466
 
2600
- // 处理赋值表达式 `=` 左右两边(左值表达式和右值表达式)都存在字符串的情况
2601
- test('should handle assignment expression with both sides strings', () => {
2467
+ describe('多行语句与注释处理', () => {
2468
+ test('should handle doc comment boundary for class/method/members', () => {
2602
2469
  const code = `
2603
- ((GTextField)GetChild($"m_text_dailyCount{i + 1}")).text = $"x{_cardConfig.EveryDayAwards[i].Count}";
2470
+ /// <summary>
2471
+ /// "fwef 类注释1"
2472
+ /// $"fwef 类注释2"
2473
+ /// $"fwef 类注释2 {wef}"
2474
+ /// wef $"fwef 类注释2 {wef}" wef
2475
+ /// </summary>
2476
+ /// <sumary "lkwjfelj"/>
2477
+ public partial class TimeLimitedChargeDialog
2478
+ {
2479
+ /// <summary>
2480
+ /// $" Property成员注释 dsvdf {wlpoe}"
2481
+ /// </summary>
2482
+ private int Ljfw { get; set; } = 342;
2483
+
2484
+ /// <summary>
2485
+ /// $" Field成员注释 wfewe {vvwe}"
2486
+ /// $" Field成员注释 wfewe {vvwe}" wfe
2487
+ /// </summary>
2488
+ private int Ljfw = 342;
2489
+
2490
+ /// <summary>
2491
+ ///</summary>
2492
+ private int Ljfw = 342;
2493
+
2494
+ /// <summary>
2495
+ /// " wef方法注释 wef"
2496
+ /// $" wef方法注释 wef"
2497
+ /// $" wef方法注释 wef{wef}"
2498
+ /// wfe $" wef方法注释 wef{wef}"
2499
+ /// wfe $" wef方法注释 wef{wef}" wef
2500
+ ///wfe $" wef方法注释 wef{wef}" wef
2501
+ /// wefw $" wef方法注释 wef{wef}" we
2502
+ /// </summary>
2503
+ /// <sumary wf $"klwf"/>
2504
+ /// <param name="force">是否重新创建页签列表</param>
2505
+ private void RefreshGoodsInfo()
2506
+ {
2507
+ m_text_timeleft.text = curShop.TimeLimitData.RemainTime() + "后消失";
2508
+ }
2509
+ }
2604
2510
  `;
2605
2511
  const snippets = extractor.extractStrings(code);
2606
2512
  {
2607
2513
  let targetSnippet = snippets[0];
2608
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"m_text_dailyCount{i + 1}"`));
2609
- expect(targetSnippet.originalCode).toBe(`$"m_text_dailyCount{i + 1}"`);
2610
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("m_text_dailyCount{0}", i + 1)`);
2611
- expect(targetSnippet.literals).toEqual([
2612
- `m_text_dailyCount{0}`
2613
- ]);
2614
- expect(targetSnippet.isChanged).toBe(true);
2615
- }
2616
- {
2617
- let targetSnippet = snippets[1];
2618
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"x{_cardConfig.EveryDayAwards[i].Count}"`));
2619
- expect(targetSnippet.originalCode).toBe(`$"x{_cardConfig.EveryDayAwards[i].Count}"`);
2620
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("x{0}", _cardConfig.EveryDayAwards[i].Count)`);
2514
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2515
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`curShop.TimeLimitData.RemainTime() + "后消失"`));
2516
+ expect(targetSnippet.originalCode).toBe(`curShop.TimeLimitData.RemainTime() + "后消失"`);
2517
+ expect(targetSnippet.convertedCode).toBe(`curShop.TimeLimitData.RemainTime().TR() + "后消失".TR()`);
2621
2518
  expect(targetSnippet.literals).toEqual([
2622
- `x{0}`
2519
+ '后消失'
2623
2520
  ]);
2624
2521
  expect(targetSnippet.isChanged).toBe(true);
2625
2522
  }
2626
- expect(snippets.length).toBe(2);
2523
+ })
2627
2524
  });
2628
2525
 
2629
- // 支持处理字符串里出现各种特殊符号的情况
2630
- test('should handle special characters in string 9', () => {
2631
- const code = `
2632
- (GetChild($"m_textAnime{GetNextNumber()}") as TurtleTextAnimeComp)?.SetText(word);
2633
- `;
2526
+ describe('边界情况与复杂场景处理', () => {
2527
+ test('should capture statement boundaries correctly', () => {
2528
+ const code = 'obj.text = "Test property" + "Test property2";';
2529
+ const snippets = extractor.extractStrings(code);
2530
+
2531
+ expect(snippets.length).toBe(1);
2532
+ expect(snippets[0].originalCode).toBe('"Test property" + "Test property2"');
2533
+ expect(snippets[0].convertedCode).toBe('"Test property".TR() + "Test property2".TR()');
2534
+ })
2535
+ test('should handle complex text assignments', () => {
2536
+ const code = 'label.text = string.Format("pre{0}sub", Func()) + other;';
2537
+ const snippets = extractor.extractStrings(code);
2538
+
2539
+ const snippet = snippets[0];
2540
+ expect(snippet.originalCode).toBe('string.Format("pre{0}sub", Func()) + other');
2541
+ expect(snippet.convertedCode).toBe('Tr.Format("pre{0}sub", Func()) + other.TR()');
2542
+ expect(snippet.literals).toEqual(['pre{0}sub']);
2543
+ expect(snippet.isChanged).toBe(true);
2544
+ })
2545
+ test('should handle member initial assignment', () => {
2546
+ const code = readFileSync("test/TestSpecialString.cs", "utf8");
2634
2547
  const snippets = extractor.extractStrings(code);
2635
2548
  {
2636
2549
  let targetSnippet = snippets[0];
2637
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"m_textAnime{GetNextNumber()}"`));
2638
- expect(targetSnippet.originalCode).toBe(`$"m_textAnime{GetNextNumber()}"`);
2639
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("m_textAnime{0}", GetNextNumber())`);
2550
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"\\\\"`));
2551
+ expect(targetSnippet.originalCode).toBe(`"\\\\"`);
2552
+ expect(targetSnippet.convertedCode).toBe(`"\\\\"`);
2640
2553
  expect(targetSnippet.literals).toEqual([
2641
- `m_textAnime{0}`
2554
+ '\\\\'
2642
2555
  ]);
2643
- expect(targetSnippet.isChanged).toBe(true);
2556
+ expect(targetSnippet.isChanged).toBe(false);
2644
2557
  }
2645
- expect(snippets.length).toBe(1);
2646
- });
2647
-
2648
- // 支持处理字符串里出现各种特殊符号的情况
2649
- test('should handle special characters in string 10', () => {
2650
- const code = `
2651
- (GetChild($"m_textAnime{GetNextNumber()}") as TurtleTextAnimeComp)?.SetText(word);
2652
- `;
2653
- const snippets = extractor.extractStrings(code);
2654
2558
  {
2655
- let targetSnippet = snippets[0];
2656
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"m_textAnime{GetNextNumber()}"`));
2657
- expect(targetSnippet.originalCode).toBe(`$"m_textAnime{GetNextNumber()}"`);
2658
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("m_textAnime{0}", GetNextNumber())`);
2559
+ let targetSnippet = snippets[1];
2560
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"\\n"`));
2561
+ expect(targetSnippet.originalCode).toBe(`"\\n"`);
2562
+ expect(targetSnippet.convertedCode).toBe(`"\\n"`);
2659
2563
  expect(targetSnippet.literals).toEqual([
2660
- `m_textAnime{0}`
2564
+ '\\n'
2661
2565
  ]);
2662
- expect(targetSnippet.isChanged).toBe(true);
2566
+ expect(targetSnippet.isChanged).toBe(false);
2663
2567
  }
2664
- expect(snippets.length).toBe(1);
2665
- });
2666
-
2667
- // 修正字符串表达式捕获范围
2668
- test('should handle string expression capture range 1', () => {
2669
- const code = `
2670
- (GetChild($"vwvwe{index + 1}") as LargeLotterySpellCardComp)?.InitData(spellCardId, true);
2671
- `;
2672
- const snippets = extractor.extractStrings(code);
2673
2568
  {
2674
- let targetSnippet = snippets[0];
2675
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"vwvwe{index + 1}"`));
2676
- expect(targetSnippet.originalCode).toBe(`$"vwvwe{index + 1}"`);
2677
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("vwvwe{0}", index + 1)`);
2569
+ let targetSnippet = snippets[2];
2570
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"\\t"`));
2571
+ expect(targetSnippet.originalCode).toBe(`$"\\t"`);
2572
+ expect(targetSnippet.convertedCode).toBe(`$"\\t"`);
2678
2573
  expect(targetSnippet.literals).toEqual([
2679
- `vwvwe{0}`
2574
+ '\\t'
2680
2575
  ]);
2681
- expect(targetSnippet.isChanged).toBe(true);
2576
+ expect(targetSnippet.isChanged).toBe(false);
2682
2577
  }
2683
- expect(snippets.length).toBe(1);
2684
- });
2685
-
2686
- // 修正字符串表达式捕获范围
2687
- test('should handle string expression capture range 2', () => {
2688
- const code = `
2689
- (GetChild($"brrr_{index + 1}") as LargeLotterySpellCardComp)?.InitData(spellCardId, true);
2690
- `;
2578
+ })
2579
+ test('should handle optional value assignment', () => {
2580
+ const code = `m_text_otherName.text = battleModel.TeammatePlayerData?.Name ?? "";`;
2691
2581
  const snippets = extractor.extractStrings(code);
2692
2582
  {
2693
2583
  let targetSnippet = snippets[0];
2694
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"brrr_{index + 1}"`));
2695
- expect(targetSnippet.originalCode).toBe(`$"brrr_{index + 1}"`);
2696
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("brrr_{0}", index + 1)`);
2584
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`battleModel.TeammatePlayerData?.Name ?? ""`));
2585
+ expect(targetSnippet.originalCode).toBe(`battleModel.TeammatePlayerData?.Name ?? ""`);
2586
+ expect(targetSnippet.convertedCode).toBe(`battleModel.TeammatePlayerData?.Name ?? "".TR()`);
2697
2587
  expect(targetSnippet.literals).toEqual([
2698
- `brrr_{0}`
2588
+ ''
2699
2589
  ]);
2700
2590
  expect(targetSnippet.isChanged).toBe(true);
2701
2591
  }
2702
- expect(snippets.length).toBe(1);
2703
- });
2704
-
2705
- // 修正字符串表达式捕获范围
2706
- test('should handle string expression capture range 3', () => {
2592
+ })
2593
+ test('should handle if border and object creation expression border', () => {
2707
2594
  const code = `
2708
- (GetChild($"m_card_{index}") as LargeLotterySpellCardComp)?.PlayEff();
2595
+ namespace FaBao.UI.MainUI
2596
+ {
2597
+ public partial class SpellUpgradeDialog
2598
+ {
2599
+ private async void OnBtnUpgrade()
2600
+ {
2601
+ // new SpellCard_Action_UpgradeSpellCard(_symbolCard.Id) 被方法调用传参的 () 包裹, 因此已经构成了完整的对象创建表达式
2602
+ if (await this.GetModel<SpellCardModel>().DispatchAction(new SpellCard_Action_UpgradeSpellCard(_symbolCard.Id)))
2603
+ {
2604
+ //升级成功后刷新界面
2605
+ m_text_level.text = Tr.Format("{0}级", _symbolCard.Level);
2606
+ }
2607
+ }
2608
+ }
2609
+ }
2709
2610
  `;
2710
2611
  const snippets = extractor.extractStrings(code);
2711
2612
  {
2712
2613
  let targetSnippet = snippets[0];
2713
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"m_card_{index}"`));
2714
- expect(targetSnippet.originalCode).toBe(`$"m_card_{index}"`);
2715
- expect(targetSnippet.convertedCode).toBe(`Tr.Format("m_card_{0}", index)`);
2614
+ // 需要正确识别 `if` 语句边界, 识别 `if` 语句前、中、后部分中的字符串表达式
2615
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}", _symbolCard.Level)`));
2616
+ expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}", _symbolCard.Level)`);
2617
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}级", _symbolCard.Level)`);
2716
2618
  expect(targetSnippet.literals).toEqual([
2717
- `m_card_{0}`
2619
+ '{0}级'
2718
2620
  ]);
2719
- expect(targetSnippet.isChanged).toBe(true);
2621
+ expect(targetSnippet.isChanged).toBe(false);
2720
2622
  }
2721
2623
  expect(snippets.length).toBe(1);
2722
- });
2723
-
2724
- // 字符串表达式字面量直接为null时, 无需转换null
2725
- test('should handle null 1', () => {
2726
- const code = `m_text_notice.text = null;`;
2624
+ })
2625
+ test('should handle right value expression', () => {
2626
+ const code = `
2627
+ ((GLoader)GetChild($"m_loader_dailyItem{i + 1}")).url = FUISys.Instance.GetIconUrl(ItemTable.GetConfigById(_cardConfig.EveryDayAwards[i].ResId).Icon);
2628
+ `;
2727
2629
  const snippets = extractor.extractStrings(code);
2728
2630
  {
2729
2631
  let targetSnippet = snippets[0];
2730
- expect(targetSnippet.originalIndex).toBe(code.indexOf(`null`));
2731
- expect(targetSnippet.originalCode).toBe(`null`);
2732
- expect(targetSnippet.convertedCode).toBe(`null`);
2632
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"m_loader_dailyItem{i + 1}"`));
2633
+ expect(targetSnippet.originalCode).toBe(`$"m_loader_dailyItem{i + 1}"`); // 左边表达式函数调用参数中的字符串表达式
2634
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("m_loader_dailyItem{0}", i + 1)`);
2733
2635
  expect(targetSnippet.literals).toEqual([
2636
+ `m_loader_dailyItem{0}`
2734
2637
  ]);
2735
- expect(targetSnippet.isChanged).toBe(false);
2638
+ expect(targetSnippet.isChanged).toBe(true);
2736
2639
  }
2737
2640
  expect(snippets.length).toBe(1);
2738
- });
2739
-
2740
- // 字符串表达式字面量直接为null时, 无需转换null
2741
- test('should handle null 2', () => {
2742
- const code = `m_text_notice.wfefe = null;`;
2743
- const snippets = extractor.extractStrings(code);
2744
- expect(snippets.length).toBe(0);
2745
- });
2746
-
2747
- // 需要正确获取 `originalIndex`, `originalIndex` 的定义为 `originalIndex=code.indexOf(originalCode)`, 其中 `code` 表示原始代码, `originalCode` 表示匹配出的原始代码中的字符串表达式
2748
- test('should handle calculate originalIndex', () => {
2641
+ })
2642
+ test('should handle calculate originalIndex', () => {
2749
2643
  const code = `
2750
2644
  namespace FaBao
2751
2645
  {
@@ -2775,159 +2669,109 @@ namespace FaBao
2775
2669
  ]);
2776
2670
  expect(targetSnippet.isChanged).toBe(false);
2777
2671
  }
2672
+ })
2778
2673
  });
2779
2674
 
2780
- // 测试 `xxx.text = yyy;` 和 `m_btn_xxx.title = yyy;` 形式的赋值语句都需要支持中文, 包括字符串表达式中也要支持包含中文的情况
2781
- test('should handle .text = assignments contains chinese', () => {
2782
- const code = `
2783
- 为栓饭cxs12.text = 南方eflkj.d文件 + "完善ew";
2784
- m_btn_为栓饭cxs12.title = bw尅kljekl.完善 + "栏栏nfc";
2785
- `;
2675
+ describe('其他测试', () => {
2676
+ test('should handle multiple statements', () => {
2677
+ const code = 'obj1.text = "Hello"; obj2.text = "World";';
2678
+ const snippets = extractor.extractStrings(code);
2679
+
2680
+ expect(snippets.length).toBe(2);
2681
+ expect(snippets[0].originalCode).toBe('"Hello"');
2682
+ expect(snippets[0].convertedCode).toBe('"Hello".TR()');
2683
+ expect(snippets[1].originalCode).toBe('"World"');
2684
+ expect(snippets[1].convertedCode).toBe('"World".TR()');
2685
+ })
2686
+ test('should handle function calls with string arguments', () => {
2687
+ const code = 'CallFunc("Hello", "World");';
2786
2688
  const snippets = extractor.extractStrings(code);
2787
2689
  {
2788
- let snippet = snippets[0];
2789
- expect(snippet.originalCode).toBe('南方eflkj.d文件 + "完善ew"');
2790
- expect(snippet.convertedCode).toBe('南方eflkj.d文件.TR() + "完善ew".TR()');
2791
- expect(snippet.literals).toEqual([
2792
- '完善ew'
2793
- ]);
2690
+ const snippet = snippets[0];
2691
+ expect(snippet.originalCode).toBe('"Hello"');
2692
+ expect(snippet.convertedCode).toBe('"Hello"');
2693
+ expect(snippet.literals).toEqual(['Hello']);
2694
+ expect(snippet.isChanged).toBe(false);
2794
2695
  }
2795
2696
  {
2796
- let snippet = snippets[1];
2797
- expect(snippet.originalCode).toBe('bw尅kljekl.完善 + "栏栏nfc"');
2798
- expect(snippet.convertedCode).toBe('bw尅kljekl.完善.TR() + "栏栏nfc".TR()');
2799
- expect(snippet.literals).toEqual([
2800
- '栏栏nfc'
2801
- ]);
2697
+
2698
+ const snippet = snippets[1];
2699
+ expect(snippet.originalCode).toBe('"World"');
2700
+ expect(snippet.convertedCode).toBe('"World"');
2701
+ expect(snippet.literals).toEqual(['World']);
2702
+ expect(snippet.isChanged).toBe(false);
2802
2703
  }
2803
- });
2704
+ })
2705
+ test('should handle string with `//`', () => {
2706
+ const code = `m_btn_paid.text = "//";`
2707
+ const snippets = extractor.extractStrings(code);
2804
2708
 
2805
- // 测试`m_btn_xxx.title = yyy;` 形式的赋值语句要和`xxx.text = yyy;`形式的赋值语句完全等同处理
2806
- test('should handle m_btn_xxx.title = yyy assignments contains chinese', () => {
2709
+ // 验证提取的片段数量
2710
+ expect(snippets.length).toBeGreaterThan(0);
2711
+
2712
+ let targetSnippet = snippets[0];
2713
+ expect(targetSnippet.originalCode).toBe(`"//"`);
2714
+ expect(targetSnippet.convertedCode).toBe(`"//".TR()`);
2715
+ expect(targetSnippet.literals).toEqual(['//']);
2716
+ expect(targetSnippet.isChanged).toBe(true);
2717
+
2718
+ })
2719
+ test('should handle strings in function call arguments', () => {
2807
2720
  const code = `
2808
- switch (_roomData.RoomState)
2721
+ private void OnBtnIaa(EventContext context)
2722
+ {
2723
+ var iaaConfig = IAAConfigTable.GetConfigById((int)IAAId.境界失败_加速冷却);
2724
+ if (iaaConfig == null)
2809
2725
  {
2810
- case Data.Match.RoomState.IsDismiss:
2811
- m_btn_join.title = "已解散";
2812
- m_btn_join.enabled = false;
2813
- grayed = true;
2814
- break;
2815
- case Data.Match.RoomState.Rejected:
2816
- {
2817
- m_btn_join.title = $"被拒绝{Kff}";
2818
- m_btn_join.enabled = false;
2819
- break;
2820
- }
2821
- case Data.Match.RoomState.OutOfDate:
2822
- m_dd_join.text = "已到期";
2823
- break;
2824
- default:
2825
- m_btn_join.title = "申请";
2826
- m_btn_joi23n.title = $"申请{Kjf}";
2827
- break;
2726
+ return;
2828
2727
  }
2829
- `;
2830
- const snippets = extractor.extractStrings(code);
2831
- {
2832
- let snippet = snippets[0];
2833
- expect(snippet.originalCode).toBe('"已解散"');
2834
- expect(snippet.convertedCode).toBe('"已解散".TR()');
2835
- expect(snippet.literals).toEqual([
2836
- '已解散'
2837
- ]);
2838
- }
2839
- {
2840
- let snippet = snippets[1];
2841
- expect(snippet.originalCode).toBe('$"被拒绝{Kff}"');
2842
- expect(snippet.convertedCode).toBe('Tr.Format("被拒绝{0}", Kff)');
2843
- expect(snippet.literals).toEqual([
2844
- '被拒绝{0}'
2845
- ]);
2846
- }
2847
- {
2848
- let snippet = snippets[2];
2849
- expect(snippet.originalCode).toBe('"已到期"');
2850
- expect(snippet.convertedCode).toBe('"已到期".TR()');
2851
- expect(snippet.literals).toEqual([
2852
- '已到期'
2853
- ]);
2854
- }
2855
- {
2856
- let snippet = snippets[3];
2857
- expect(snippet.originalCode).toBe('"申请"');
2858
- expect(snippet.convertedCode).toBe('"申请".TR()');
2859
- expect(snippet.literals).toEqual([
2860
- '申请'
2861
- ]);
2862
- }
2863
- {
2864
- let snippet = snippets[4];
2865
- expect(snippet.originalCode).toBe('$"申请{Kjf}"');
2866
- expect(snippet.convertedCode).toBe('Tr.Format("申请{0}", Kjf)');
2867
- expect(snippet.literals).toEqual([
2868
- '申请{0}'
2869
- ]);
2870
- }
2871
- });
2872
2728
 
2873
- // 测试三元表达式中的字符串表达式处理
2874
- test('should handle thriple expression with string expression 1', () => {
2875
- const code = `m_btn_confirm.title = isUsed ? "使用中" : "使用";`;
2876
- const snippets = extractor.extractStrings(code);
2877
- {
2878
- let snippet = snippets[0];
2879
- expect(snippet.originalCode).toBe('isUsed ? "使用中" : "使用"');
2880
- expect(snippet.convertedCode).toBe('isUsed ? "使用中".TR() : "使用".TR()');
2881
- expect(snippet.literals).toEqual([
2882
- '使用中',
2883
- '使用'
2884
- ]);
2729
+ string des = $"观看视频后\n等待时间减少{iaaConfig.EffectValue / 60}分钟";
2730
+ this.GetModel<IAAModel>().ShowAdWithDialog(IAAId.境界失败_加速冷却, "加速时间", des, null);
2885
2731
  }
2886
- });
2887
-
2888
- // 测试三元表达式中的字符串表达式处理
2889
- test('should handle thriple expression with string expression 2', () => {
2890
- const code = `wefe.text = isUsed ? "使用中" : "使用";`;
2732
+ `;
2891
2733
  const snippets = extractor.extractStrings(code);
2892
2734
  {
2893
- let snippet = snippets[0];
2894
- expect(snippet.originalCode).toBe('isUsed ? "使用中" : "使用"');
2895
- expect(snippet.convertedCode).toBe('isUsed ? "使用中".TR() : "使用".TR()');
2896
- expect(snippet.literals).toEqual([
2897
- '使用中',
2898
- '使用'
2735
+ let targetSnippet = snippets[1];
2736
+ // 需要正确识别函数调用参数中每个参数的边界, 并识别每个参数中的字符串表达式
2737
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"加速时间"`));
2738
+ expect(targetSnippet.originalCode).toBe(`"加速时间"`);
2739
+ expect(targetSnippet.convertedCode).toBe(`"加速时间"`);
2740
+ expect(targetSnippet.literals).toEqual([
2741
+ '加速时间'
2899
2742
  ]);
2743
+ expect(targetSnippet.isChanged).toBe(false);
2900
2744
  }
2901
- });
2902
-
2903
- // 测试三元表达式中的字符串表达式处理
2904
- test('should handle thriple expression with string expression 3', () => {
2905
- const code = `wefetext = isUsed ? "使用中" : "使用";`;
2745
+ })
2746
+ test('should handle assignment expression with both sides strings', () => {
2747
+ const code = `
2748
+ ((GTextField)GetChild($"m_text_dailyCount{i + 1}")).text = $"x{_cardConfig.EveryDayAwards[i].Count}";
2749
+ `;
2906
2750
  const snippets = extractor.extractStrings(code);
2907
2751
  {
2908
- let snippet = snippets[0];
2909
- expect(snippet.originalCode).toBe('isUsed ? "使用中" : "使用"');
2910
- expect(snippet.convertedCode).toBe('isUsed ? "使用中" : "使用"');
2911
- expect(snippet.literals).toEqual([
2912
- '使用中',
2913
- '使用'
2752
+ let targetSnippet = snippets[0];
2753
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"m_text_dailyCount{i + 1}"`));
2754
+ expect(targetSnippet.originalCode).toBe(`$"m_text_dailyCount{i + 1}"`);
2755
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("m_text_dailyCount{0}", i + 1)`);
2756
+ expect(targetSnippet.literals).toEqual([
2757
+ `m_text_dailyCount{0}`
2914
2758
  ]);
2759
+ expect(targetSnippet.isChanged).toBe(true);
2915
2760
  }
2916
- });
2917
-
2918
- // 测试三元表达式中的字符串表达式处理
2919
- test('should handle thriple expression with string expression 4', () => {
2920
- const code = `wefetext(isUsed ? "使用中" : "使用");`;
2921
- const snippets = extractor.extractStrings(code);
2922
2761
  {
2923
- let snippet = snippets[0];
2924
- expect(snippet.originalCode).toBe('isUsed ? "使用中" : "使用"');
2925
- expect(snippet.convertedCode).toBe('isUsed ? "使用中" : "使用"');
2926
- expect(snippet.literals).toEqual([
2927
- '使用中',
2928
- '使用'
2762
+ let targetSnippet = snippets[1];
2763
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"x{_cardConfig.EveryDayAwards[i].Count}"`));
2764
+ expect(targetSnippet.originalCode).toBe(`$"x{_cardConfig.EveryDayAwards[i].Count}"`);
2765
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("x{0}", _cardConfig.EveryDayAwards[i].Count)`);
2766
+ expect(targetSnippet.literals).toEqual([
2767
+ `x{0}`
2929
2768
  ]);
2769
+ expect(targetSnippet.isChanged).toBe(true);
2930
2770
  }
2771
+ expect(snippets.length).toBe(2);
2772
+ })
2931
2773
  });
2932
2774
 
2775
+ ;
2776
+
2933
2777
  });