scancscode 1.0.31 → 1.0.34

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.
Files changed (61) hide show
  1. package/.trae/specs/fix-doc-comment-boundary/checklist.md +7 -0
  2. package/.trae/specs/fix-doc-comment-boundary/spec.md +52 -0
  3. package/.trae/specs/fix-doc-comment-boundary/tasks.md +34 -0
  4. package/.trae/specs/fix-interpolated-string-nested-literals/checklist.md +7 -0
  5. package/.trae/specs/fix-interpolated-string-nested-literals/spec.md +55 -0
  6. package/.trae/specs/fix-interpolated-string-nested-literals/tasks.md +25 -0
  7. package/.trae/specs/fix-remaining-interpolated-string-index/checklist.md +9 -0
  8. package/.trae/specs/fix-remaining-interpolated-string-index/spec.md +59 -0
  9. package/.trae/specs/fix-remaining-interpolated-string-index/tasks.md +41 -0
  10. package/.trae/specs/fix-return-interpolated-string/checklist.md +8 -0
  11. package/.trae/specs/fix-return-interpolated-string/spec.md +60 -0
  12. package/.trae/specs/fix-return-interpolated-string/tasks.md +39 -0
  13. package/.trae/specs/handle-anonymous-function-strings/checklist.md +11 -0
  14. package/.trae/specs/handle-anonymous-function-strings/spec.md +137 -0
  15. package/.trae/specs/handle-anonymous-function-strings/tasks.md +65 -0
  16. package/.trae/specs/handle-interpolated-string-double-braces/checklist.md +9 -0
  17. package/.trae/specs/handle-interpolated-string-double-braces/spec.md +61 -0
  18. package/.trae/specs/handle-interpolated-string-double-braces/tasks.md +41 -0
  19. package/.trae/specs/handle-return-statement/checklist.md +11 -0
  20. package/.trae/specs/handle-return-statement/spec.md +76 -0
  21. package/.trae/specs/handle-return-statement/tasks.md +44 -0
  22. package/.trae/specs/handle-special-string-characters/checklist.md +13 -0
  23. package/.trae/specs/handle-special-string-characters/spec.md +94 -0
  24. package/.trae/specs/handle-special-string-characters/tasks.md +74 -0
  25. package/.trae/specs/unify-return-statement-string-extraction/checklist.md +10 -0
  26. package/.trae/specs/unify-return-statement-string-extraction/spec.md +70 -0
  27. package/.trae/specs/unify-return-statement-string-extraction/tasks.md +54 -0
  28. package/bin/scanliterals.js +3 -3
  29. package/bin/slimlangs.js +3 -3
  30. package/dist/debug-arg.js +30 -0
  31. package/dist/debug-args.js +34 -0
  32. package/dist/debug-comment-5.js +25 -0
  33. package/dist/debug-comment-strings.js +24 -0
  34. package/dist/debug-full.js +14 -0
  35. package/dist/debug-template-issue.js +33 -0
  36. package/dist/debug-test-5.js +23 -0
  37. package/dist/debug-test.js +21 -0
  38. package/dist/debug.js +15 -0
  39. package/dist/simple-debug.js +27 -0
  40. package/dist/simple-test.js +61 -0
  41. package/dist/src/CSharpStringExtractor.js +1791 -358
  42. package/dist/src/CmdExecutor.js +6 -8
  43. package/dist/temp-original-source.js +1 -0
  44. package/dist/test/CSharpStringExtractor.test.js +1587 -207
  45. package/dist/test-logic.js +79 -0
  46. package/dist/test-regex.js +13 -0
  47. package/docs/CSharpStringExtractor/344/273/243/347/240/201/347/224/237/346/210/220/346/217/220/347/244/272/350/257/215.txt +73 -0
  48. package/jest.config.js +9 -9
  49. package/package.json +1 -1
  50. package/src/CSCodeScanner.ts +305 -305
  51. package/src/CSVUtils.ts +181 -181
  52. package/src/CSharpStringExtractor.ts +2058 -479
  53. package/src/CmdExecutor.ts +107 -106
  54. package/src/LiteralCollector.ts +143 -143
  55. package/src/RunConvert.ts +3 -3
  56. package/src/RunSlimLangs.ts +3 -3
  57. package/src/TableScanner.ts +92 -92
  58. package/test/CSharpStringExtractor.test.ts +1673 -208
  59. package/test/KeeperDialog.cs +114 -0
  60. package/test/TestSpecialString.cs +24 -0
  61. package/tsconfig.json +109 -109
@@ -7,376 +7,448 @@ describe('CSharpStringExtractor', () => {
7
7
  beforeEach(() => {
8
8
  extractor = new CSharpStringExtractor_1.CSharpStringExtractor();
9
9
  });
10
+ // 测试从普通函数调用参数中提取字符串表达式信息, 只需要提取参数中的字符串值表达式, 不需要对提取的字符串表达式进行处理
10
11
  test('should extract plain strings', () => {
11
12
  const code = 'Console.WriteLine("Hello, world!");';
12
13
  const snippets = extractor.extractStrings(code);
13
14
  expect(snippets.length).toBe(1);
14
15
  expect(snippets[0].literals).toEqual(['Hello, world!']);
15
16
  });
17
+ // 已经追加 `.TR()` 后缀的字符串表达式不需要重复追加 `.TR()`
16
18
  test('should handle strings with .TR() already appended', () => {
17
19
  const code = 'obj.prop = "Hello, world!".TR();';
18
20
  const snippets = extractor.extractStrings(code);
19
21
  expect(snippets.length).toBe(1);
20
- expect(snippets[0].originalCode).toBe('obj.prop = "Hello, world!".TR();');
21
- expect(snippets[0].convertedCode).toBe('obj.prop = "Hello, world!".TR();');
22
+ expect(snippets[0].originalCode).toBe('"Hello, world!".TR()');
23
+ expect(snippets[0].convertedCode).toBe('"Hello, world!".TR()');
22
24
  expect(snippets[0].isChanged).toBe(false);
23
25
  });
26
+ // 测试从普通函数调用参数中提取字符串表达式信息, 只需要提取参数中的字符串值表达式, 不需要对提取的字符串表达式进行处理, 也不需要追加 `.TR()`
24
27
  test('should not add .TR() to function arguments', () => {
25
28
  const code = 'CallFunc("Hello, world!");';
26
29
  const snippets = extractor.extractStrings(code);
27
30
  expect(snippets.length).toBe(1);
28
- expect(snippets[0].convertedCode).toBe('CallFunc("Hello, world!");');
31
+ expect(snippets[0].originalCode).toBe('"Hello, world!"');
32
+ expect(snippets[0].convertedCode).toBe('"Hello, world!"');
29
33
  });
34
+ // 测试从普通属性赋值语句中提取字符串表达式信息, 只需要提取赋值表达式中的字符串值表达式, 不需要对提取的字符串表达式进行处理, 也不需要追加 `.TR()`
30
35
  test('should not add .TR() to regular property assignments', () => {
31
36
  const code = 'obj.prop = "Hello, world!";';
32
37
  const snippets = extractor.extractStrings(code);
33
38
  expect(snippets.length).toBe(1);
34
- expect(snippets[0].convertedCode).toBe('obj.prop = "Hello, world!";');
39
+ expect(snippets[0].originalCode).toBe('"Hello, world!"');
40
+ expect(snippets[0].convertedCode).toBe('"Hello, world!"');
35
41
  });
42
+ // 测试从 $"" 字符串模板(也叫内插字符串)中提取字符串表达式信息, 需要先将字符串模板转换为 `string.Format(...)` 格式, 然后将 `string.Format(...)` 替换为 `Tr.Format(...)`, 之后从 `Tr.Format(...)` 的函数调用参数中提取普通字符串、或进一步递归提取字符串表达式信息
36
43
  test('should handle $"" string templates', () => {
37
- const code = '$"Hello, {name}!";';
44
+ const code = 'var label1 = $"Hello, {name}!";';
38
45
  const snippets = extractor.extractStrings(code);
39
46
  expect(snippets.length).toBe(1);
47
+ expect(snippets[0].originalCode).toBe('$"Hello, {name}!"');
40
48
  expect(snippets[0].literals).toContain('Hello, {0}!');
41
- expect(snippets[0].convertedCode).toBe('Tr.Format("Hello, {0}!", name);');
49
+ expect(snippets[0].convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
42
50
  });
51
+ // 测试从普通函数调用参数中提取 $"" 字符串模板(也叫内插字符串), 需要先将字符串模板转换为 `string.Format(...)` 格式, 然后将 `string.Format(...)` 替换为 `Tr.Format(...)`, 之后从 `Tr.Format(...)` 的函数调用参数中提取普通字符串、或进一步递归提取字符串表达式信息
43
52
  test('should handle $"" string templates in function calls', () => {
44
53
  const code = 'CallFunc($"Hello, world: {obj.Func1()}");';
45
54
  const snippets = extractor.extractStrings(code);
46
55
  expect(snippets.length).toBe(1);
47
- expect(snippets[0].convertedCode).toBe('CallFunc(Tr.Format("Hello, world: {0}", obj.Func1()));');
56
+ expect(snippets[0].originalCode).toBe('$"Hello, world: {obj.Func1()}"');
57
+ expect(snippets[0].convertedCode).toBe('Tr.Format("Hello, world: {0}", obj.Func1())');
48
58
  });
59
+ // 测试遇到 `string.Format(...)` 形式的字符串表达式, 需要先将 `string.Format(...)` 替换为 `Tr.Format(...)`, 之后从 `Tr.Format(...)` 的函数调用参数中提取普通字符串、或进一步递归提取字符串表达式信息, 内插字符串概念参考: `https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/tokens/interpolated`
49
60
  test('should convert string.Format to Tr.Format', () => {
50
61
  const code = 'string.Format("Hello, ", name, "!");';
51
62
  const snippets = extractor.extractStrings(code);
52
63
  expect(snippets.length).toBe(1);
53
- expect(snippets[0].convertedCode).toBe('Tr.Format("Hello, ", name, "!");');
64
+ // string.Format(...) 形式的字符串表达式, 不需要对提取的字符串表达式进行处理, 也不需要追加 `.TR()`
65
+ // string.Format(...) 形式包含的字符串表达式, 需要特殊处理, 连带 `string.Format()` 一起捕获存入 originalCode 成员
66
+ expect(snippets[0].originalCode).toBe('string.Format("Hello, ", name, "!")');
67
+ expect(snippets[0].convertedCode).toBe('Tr.Format("Hello, ", name, "!")');
54
68
  });
69
+ // 测试遇到 `string.Format(...)` 形式的字符串表达式, 需要先将 `string.Format(...)` 替换为 `Tr.Format(...)`, 之后从 `Tr.Format(...)` 的函数调用参数中提取普通字符串、或进一步递归提取字符串表达式信息
70
+ // 同时测试用 `+` 连接的字符串表达式, 确保用 `+` 符号拼接的字符串表达式被整体处理, 从中提取字符串表达式信息, 而不是分别处理 `+` 两边每个字符串表达式
55
71
  test('should handle string.Format in .text assignments', () => {
56
72
  const code = 'label.text = Tr.Format("pre", Func(), "sub") + other;';
57
73
  const snippets = extractor.extractStrings(code);
58
74
  expect(snippets.length).toBe(1);
75
+ expect(snippets[0].originalCode).toBe('Tr.Format("pre", Func(), "sub") + other');
59
76
  expect(snippets[0].literals).toContain('pre');
60
77
  expect(snippets[0].literals).toContain('sub');
61
78
  });
79
+ // 测试用 `+` 连接的字符串表达式, 确保用 `+` 符号拼接的字符串表达式被整体处理, 从中提取字符串表达式信息, 而不是分别处理 `+` 两边每个字符串表达式; 并且给 `+` 连接的每个成分追加 `.TR()` 或者转换为 `Tr.Format(...)` 形式
62
80
  test('should handle string concatenation', () => {
63
- const code = '"Hello, " + name + "!";';
81
+ const code = 'var label2 = "Hello, " + name + "!";';
64
82
  const snippets = extractor.extractStrings(code);
65
83
  expect(snippets.length).toBe(1);
66
- expect(snippets[0].convertedCode).toBe('"Hello, ".TR() + name.TR() + "!".TR();');
84
+ expect(snippets[0].originalCode).toBe('"Hello, " + name + "!"');
85
+ expect(snippets[0].convertedCode).toBe('"Hello, ".TR() + name.TR() + "!".TR()');
67
86
  });
87
+ // 测试 `xxx.text = yyy` 形式的赋值语句, 确保将 `yyy` 中的字符串表达式信息提取出来, 并追加 `.TR()` 或者转换为 `Tr.Format(...)` 形式; 其中 `xxx`和`yyy` 代表某段C#字面量, 可以是对象、字符串、或其他表达式
68
88
  test('should handle .text = assignments with function calls', () => {
69
89
  const code = 'label.text = Func();';
70
90
  const snippets = extractor.extractStrings(code);
71
91
  expect(snippets.length).toBe(1);
72
- expect(snippets[0].convertedCode).toBe('label.text = Func().TR();');
92
+ expect(snippets[0].originalCode).toBe('Func()');
93
+ expect(snippets[0].convertedCode).toBe('Func().TR()');
73
94
  });
95
+ // 测试 `xxx.text = xxx + xxx` 形式的赋值语句, 确保将 `xxx.text` 中的 `xxx` 字符串表达式提取出来, 并追加 `.TR()` 或者转换为 `Tr.Format(...)` 形式; 其中 `xxx`和`yyy` 代表某段C#表达式, 可以是对象、字符串、或其他表达式
74
96
  test('should handle .text = assignments with multiple function calls', () => {
75
97
  const code = 'label.text = Func() + Func();';
76
98
  const snippets = extractor.extractStrings(code);
77
99
  expect(snippets.length).toBe(1);
78
- expect(snippets[0].convertedCode).toBe('label.text = Func().TR() + Func().TR();');
100
+ expect(snippets[0].originalCode).toBe('Func() + Func()');
101
+ expect(snippets[0].convertedCode).toBe('Func().TR() + Func().TR()');
79
102
  });
103
+ // 测试 `xxx.text = yyy` 形式的赋值语句, 确保将 `yyy` 中的 `xxx` 内插字符串提取出来, 并转换为 `Tr.Format(...)` 形式; 其中 `xxx`和`yyy` 代表某段C#表达式, 可以是对象、字符串、或其他表达式
80
104
  test('should handle .text = assignments with string templates', () => {
81
105
  const code = 'label.text = $"pre{Func()}sub";';
82
106
  const snippets = extractor.extractStrings(code);
83
107
  expect(snippets.length).toBe(1);
108
+ expect(snippets[0].originalCode).toBe('$"pre{Func()}sub"');
84
109
  expect(snippets[0].literals).toContain('pre{0}sub');
85
- expect(snippets[0].convertedCode).toBe('label.text = Tr.Format("pre{0}sub", Func());');
110
+ expect(snippets[0].convertedCode).toBe('Tr.Format("pre{0}sub", Func())');
86
111
  });
112
+ // 测试从内插字符串中提取字符串表达式信息时, 需要注意转换和捕获内插字符串格式参数, 内插字符串和对应格式参数参考: `https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/tokens/interpolated`
87
113
  test('should handle .text = assignments with string.Format', () => {
88
114
  const code = 'label.text = string.Format("pre{0:F2}{1}", Func(), "sub") + other;';
89
115
  const snippets = extractor.extractStrings(code);
90
116
  expect(snippets.length).toBe(1);
117
+ expect(snippets[0].originalCode).toBe('string.Format("pre{0:F2}{1}", Func(), "sub") + other');
91
118
  expect(snippets[0].literals).toContain('pre{0:F2}{1}');
92
119
  expect(snippets[0].literals).toContain('sub');
93
120
  });
121
+ // 测试用 `+` 连接的字符串表达式, 确保用 `+` 符号拼接的字符串表达式被整体处理, 从中提取字符串表达式信息, 而不是分别处理 `+` 两边每个字符串表达式; 并且给 `+` 连接的每个成分追加 `.TR()` 或者转换为 `Tr.Format(...)` 形式或进一步递归处理
94
122
  test('should handle complex concatenation with existing .TR() calls', () => {
95
- const code = '"Hello, ".TR() + name.TR() + obj2.name.TR() + obj2.nam1_e.Fn1().Prop + "!";';
123
+ const code = 'var hello3 = "Hello, ".TR() + name.TR() + obj2.name.TR() + obj2.nam1_e.Fn1().Prop + "!";';
96
124
  const snippets = extractor.extractStrings(code);
97
125
  expect(snippets.length).toBe(1);
98
- expect(snippets[0].convertedCode).toBe('"Hello, ".TR() + name.TR() + obj2.name.TR() + obj2.nam1_e.Fn1().Prop.TR() + "!".TR();');
126
+ expect(snippets[0].originalCode).toBe('"Hello, ".TR() + name.TR() + obj2.name.TR() + obj2.nam1_e.Fn1().Prop + "!"');
127
+ expect(snippets[0].convertedCode).toBe('"Hello, ".TR() + name.TR() + obj2.name.TR() + obj2.nam1_e.Fn1().Prop.TR() + "!".TR()');
99
128
  });
129
+ // 测试处理包含转义引号的字符串表达式, 确保能正确提取和转换转义引号, 而不会影响字符串边界的正常解析
100
130
  test('should handle escaped quotes in strings', () => {
101
- const code = 'Debug.Log("aaa\\\"bbb\\\"c\\\"d\\\\\"cc");';
131
+ const code = 'Debug.Log("aaa\\\"bbb\\\"c\\\"d\\\\\\"cc");';
102
132
  const snippets = extractor.extractStrings(code);
103
133
  expect(snippets.length).toBe(1);
134
+ expect(snippets[0].originalCode).toBe('"aaa\\\"bbb\\\"c\\\"d\\\\\\"cc"');
135
+ expect(snippets[0].convertedCode).toBe('"aaa\\\"bbb\\\"c\\\"d\\\\\\"cc"');
104
136
  // 由于JavaScript字符串转义的复杂性,我们只检查是否提取了字符串
105
- expect(snippets[0].literals.length).toBeGreaterThan(0);
137
+ expect(snippets[0].literals).toEqual(['aaa\\\"bbb\\\"c\\\"d\\\\\\"cc']);
106
138
  });
139
+ // 测试处理包含 `+` 连接的字符串表达式, 需要给 `+` 连接的每个成分追加 `.TR()` 或者转换为 `Tr.Format(...)` 形式或进一步递归处理
107
140
  test('should capture statement boundaries correctly', () => {
108
141
  const code = 'obj.text = "Test property" + "Test property2";';
109
142
  const snippets = extractor.extractStrings(code);
110
143
  expect(snippets.length).toBe(1);
111
- expect(snippets[0].originalCode).toBe('obj.text = "Test property" + "Test property2";');
144
+ expect(snippets[0].originalCode).toBe('"Test property" + "Test property2"');
145
+ expect(snippets[0].convertedCode).toBe('"Test property".TR() + "Test property2".TR()');
112
146
  });
147
+ // 测试处理包含多个语句的C#代码, 确保能从各个语句中正确提取和转换每个语句中的字符串表达式, 而不会影响其他语句的正常解析
113
148
  test('should handle multiple statements', () => {
114
149
  const code = 'obj1.text = "Hello"; obj2.text = "World";';
115
150
  const snippets = extractor.extractStrings(code);
116
151
  expect(snippets.length).toBe(2);
117
- expect(snippets[0].originalCode).toBe('obj1.text = "Hello";');
118
- expect(snippets[1].originalCode).toBe('obj2.text = "World";');
152
+ expect(snippets[0].originalCode).toBe('"Hello"');
153
+ expect(snippets[0].convertedCode).toBe('"Hello".TR()');
154
+ expect(snippets[1].originalCode).toBe('"World"');
155
+ expect(snippets[1].convertedCode).toBe('"World".TR()');
119
156
  });
157
+ // 测试处理作为函数参数的内插字符串表达式, 确保能从内插字符串中提取字符串表达式信息, 并转换为 `Tr.Format(...)` 形式
120
158
  test('should extract and convert string templates', () => {
121
159
  const code = 'Ljk.Ilk($"Hello, {name}!");';
122
160
  const snippets = extractor.extractStrings(code);
123
161
  expect(snippets.length).toBeGreaterThan(0);
124
162
  const snippet = snippets[0];
125
- expect(snippet.originalCode).toBe('Ljk.Ilk($"Hello, {name}!");');
126
- expect(snippet.convertedCode).toBe('Ljk.Ilk(Tr.Format("Hello, {0}!", name));');
163
+ expect(snippet.originalCode).toBe('$"Hello, {name}!"');
164
+ expect(snippet.convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
127
165
  expect(snippet.literals).toEqual(['Hello, {0}!']);
128
166
  expect(snippet.isChanged).toBe(true);
129
167
  });
168
+ // 测试处理 `string.Format` 调用, 确保能将其转换为 `Tr.Format(...)` 形式, 并正确提取字符串表达式信息
130
169
  test('should convert string.Format to Tr.Format', () => {
131
170
  const code = 'string.Format("Hello, {0}!", name);';
132
171
  const snippets = extractor.extractStrings(code);
133
172
  expect(snippets.length).toBeGreaterThan(0);
134
173
  const snippet = snippets[0];
135
- expect(snippet.originalCode).toBe('string.Format("Hello, {0}!", name);');
136
- expect(snippet.convertedCode).toBe('Tr.Format("Hello, {0}!", name);');
174
+ expect(snippet.originalCode).toBe('string.Format("Hello, {0}!", name)');
175
+ expect(snippet.convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
137
176
  expect(snippet.literals).toEqual(['Hello, {0}!']);
138
177
  expect(snippet.isChanged).toBe(true);
139
178
  });
179
+ // 测试处理 `xxx.text = yyy` 形式赋值语句, 以 `.text =` 给 `text` 成员赋值的表达式中, `yyy` 部分必定是字符串表达式, 需要从 `yyy` 中正确提取字符串表达式信息, 并给普通字符串表达式追加 `.TR()` 或者让内插字符串转换为 `Tr.Format(...)` 形式
140
180
  test('should handle .text = assignments', () => {
141
181
  const code = 'label.text = "Test";';
142
182
  const snippets = extractor.extractStrings(code);
143
183
  expect(snippets.length).toBeGreaterThan(0);
144
184
  const snippet = snippets[0];
145
- expect(snippet.originalCode).toBe('label.text = "Test";');
146
- expect(snippet.convertedCode).toBe('label.text = "Test".TR();');
185
+ expect(snippet.originalCode).toBe('"Test"');
186
+ expect(snippet.convertedCode).toBe('"Test".TR()');
147
187
  expect(snippet.literals).toEqual(['Test']);
148
188
  expect(snippet.isChanged).toBe(true);
149
189
  });
190
+ // 测试处理包含 `+` 连接的字符串表达式, 需要给 `+` 连接的每个成分追加 `.TR()` 或者转换为 `Tr.Format(...)` 形式或进一步递归处理
150
191
  test('should handle string concatenations', () => {
151
- const code = '"Hello, " + name + "!";';
192
+ const code = 'var wkleee = "Hello, " + name + "!";';
152
193
  const snippets = extractor.extractStrings(code);
153
194
  expect(snippets.length).toBeGreaterThan(0);
154
195
  const snippet = snippets[0];
155
- expect(snippet.originalCode).toBe('"Hello, " + name + "!";');
156
- expect(snippet.convertedCode).toBe('"Hello, ".TR() + name.TR() + "!".TR();');
196
+ expect(snippet.originalCode).toBe('"Hello, " + name + "!"');
197
+ expect(snippet.convertedCode).toBe('"Hello, ".TR() + name.TR() + "!".TR()');
157
198
  expect(snippet.literals).toEqual(['Hello, ', '!']);
158
199
  expect(snippet.isChanged).toBe(true);
159
200
  });
201
+ // 测试处理 `+` 连接的字符串表达式时, 确保不会给已经包含 `.TR()` 的字符串表达式再次追加 `.TR()`
160
202
  test('should not add .TR() to strings already having it', () => {
161
- const code = '"Hello".TR();';
203
+ const code = 'var wkle = "Hello".TR();';
162
204
  const snippets = extractor.extractStrings(code);
163
205
  const snippet = snippets[0];
164
- expect(snippet.originalCode).toBe('"Hello".TR();');
165
- expect(snippet.convertedCode).toBe('"Hello".TR();');
206
+ expect(snippet.originalCode).toBe('"Hello".TR()');
207
+ expect(snippet.convertedCode).toBe('"Hello".TR()');
166
208
  expect(snippet.literals).toEqual(['Hello']);
167
209
  expect(snippet.isChanged).toBe(false);
168
210
  });
211
+ // 测试处理复杂的 `.text =` 赋值语句, 确保能正确处理包含 `string.Format` 调用和 `+` 连接的字符串表达式, 并转换为 `Tr.Format(...)` 形式或进一步递归处理
169
212
  test('should handle complex text assignments', () => {
170
213
  const code = 'label.text = string.Format("pre{0}sub", Func()) + other;';
171
214
  const snippets = extractor.extractStrings(code);
172
215
  const snippet = snippets[0];
173
- expect(snippet.originalCode).toBe('label.text = string.Format("pre{0}sub", Func()) + other;');
174
- expect(snippet.convertedCode).toBe('label.text = Tr.Format("pre{0}sub", Func()) + other.TR();');
216
+ expect(snippet.originalCode).toBe('string.Format("pre{0}sub", Func()) + other');
217
+ expect(snippet.convertedCode).toBe('Tr.Format("pre{0}sub", Func()) + other.TR()');
175
218
  expect(snippet.literals).toEqual(['pre{0}sub']);
176
219
  expect(snippet.isChanged).toBe(true);
177
220
  });
221
+ // 测试处理转义字符串, 确保能正确处理包含转义字符的字符串表达式, 并给普通字符串表达式追加 `.TR()` 或者让内插字符串转换为 `Tr.Format(...)` 形式
178
222
  test('should handle escaped strings', () => {
179
223
  const code = 'a.text = "aaa\\"bbb\\"c\\"d\\\\\\"cc";';
180
224
  const snippets = extractor.extractStrings(code);
181
225
  const snippet = snippets[0];
182
- expect(snippet.originalCode).toBe('a.text = "aaa\\"bbb\\"c\\"d\\\\\\"cc";');
183
- expect(snippet.convertedCode).toBe('a.text = "aaa\\"bbb\\"c\\"d\\\\\\"cc".TR();');
226
+ expect(snippet.originalCode).toBe('"aaa\\"bbb\\"c\\"d\\\\\\"cc"');
227
+ expect(snippet.convertedCode).toBe('"aaa\\"bbb\\"c\\"d\\\\\\"cc".TR()');
184
228
  expect(snippet.literals).toEqual(['aaa\\"bbb\\"c\\"d\\\\\\"cc']);
185
229
  expect(snippet.isChanged).toBe(true);
186
230
  });
231
+ // 测试处理 `@$""` 和 `$@""` 格式的字符串表达式, 确保能将其转换为 `Tr.Format(...)` 形式, 并正确提取字符串表达式信息
187
232
  test('should handle @$"" and $@"" formats', () => {
188
233
  const code = 'Fcx.Kjl(@$"Hello, {name}!");';
189
234
  const snippets = extractor.extractStrings(code);
190
235
  const snippet = snippets[0];
191
- expect(snippet.originalCode).toBe('Fcx.Kjl(@$"Hello, {name}!");');
192
- expect(snippet.convertedCode).toBe('Fcx.Kjl(Tr.Format("Hello, {0}!", name));');
236
+ expect(snippet.originalCode).toBe('@$"Hello, {name}!"');
237
+ expect(snippet.convertedCode).toBe('Tr.Format("Hello, {0}!", name)');
193
238
  expect(snippet.literals).toEqual(['Hello, {0}!']);
194
239
  expect(snippet.isChanged).toBe(true);
195
240
  });
241
+ // 测试处理函数调用时, 确保能正确提取参数中的字符串表达式, 不需要给字符串表达式追加 `.TR()` 或 转换为 `Tr.Format(...)` 形式, 除非遇到由 `+` 连接的字符串表达式
196
242
  test('should handle function calls with string arguments', () => {
197
243
  const code = 'CallFunc("Hello", "World");';
198
244
  const snippets = extractor.extractStrings(code);
199
- const snippet = snippets[0];
200
- expect(snippet.originalCode).toBe('CallFunc("Hello", "World");');
201
- expect(snippet.convertedCode).toBe('CallFunc("Hello", "World");');
202
- expect(snippet.literals).toEqual(['Hello', 'World']);
203
- expect(snippet.isChanged).toBe(false);
245
+ {
246
+ const snippet = snippets[0];
247
+ expect(snippet.originalCode).toBe('"Hello"');
248
+ expect(snippet.convertedCode).toBe('"Hello"');
249
+ expect(snippet.literals).toEqual(['Hello']);
250
+ expect(snippet.isChanged).toBe(false);
251
+ }
252
+ {
253
+ const snippet = snippets[1];
254
+ expect(snippet.originalCode).toBe('"World"');
255
+ expect(snippet.convertedCode).toBe('"World"');
256
+ expect(snippet.literals).toEqual(['World']);
257
+ expect(snippet.isChanged).toBe(false);
258
+ }
204
259
  });
260
+ // 测试处理 `.text =` 赋值语句时, 确保能正确处理包含 `Tr.Format(...)` 调用的字符串表达式, 并给普通字符串表达式追加 `.TR()` 或者让内插字符串转换为 `Tr.Format(...)` 形式
205
261
  test('should handle .text = with Tr.Format', () => {
206
262
  const code = 'label.text = Tr.Format("pre", Func(), "sub") + other;';
207
263
  const snippets = extractor.extractStrings(code);
208
264
  const snippet = snippets[0];
209
- expect(snippet.originalCode).toBe('label.text = Tr.Format("pre", Func(), "sub") + other;');
210
- expect(snippet.convertedCode).toBe('label.text = Tr.Format("pre", Func(), "sub") + other.TR();');
265
+ expect(snippet.originalCode).toBe('Tr.Format("pre", Func(), "sub") + other');
266
+ expect(snippet.convertedCode).toBe('Tr.Format("pre", Func(), "sub") + other.TR()');
211
267
  expect(snippet.literals).toEqual(['pre', 'sub']);
212
268
  expect(snippet.isChanged).toBe(true);
213
269
  });
270
+ // 测试处理 `.text =` 赋值语句时, 确保能正确处理包含 `Tr.Format(...)` 调用的字符串表达式, 并给普通字符串表达式追加 `.TR()` 或者让内插字符串转换为 `Tr.Format(...)` 形式, 除非遇到由 `+` 连接的字符串表达式
214
271
  test('should handle .text = with Tr.Format 2', () => {
215
272
  const code = 'm_text_lastAward.text = $"[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]";';
216
273
  const snippets = extractor.extractStrings(code);
217
274
  const snippet = snippets[0];
218
- expect(snippet.originalCode).toBe('m_text_lastAward.text = $"[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]";');
219
- expect(snippet.convertedCode).toBe('m_text_lastAward.text = $"[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]";');
275
+ expect(snippet.originalCode).toBe('$"[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]"');
276
+ expect(snippet.convertedCode).toBe('$"[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]"');
220
277
  expect(snippet.literals).toEqual(['[color=#FFFFFF]上期奖励:[/color][color=#FFE97E][/color][color=#FFFFFF]暂无获奖[/color]']);
221
278
  expect(snippet.isChanged).toBe(false);
222
279
  });
280
+ // 处理C#多行语句
223
281
  test('should handle non string assignment 1', () => {
224
282
  const code = 'var d1 = 12;var d2 = 13;var d3 = d1 + d2;var aa = "aaa";';
225
283
  const snippets = extractor.extractStrings(code);
226
284
  {
227
285
  const snippet = snippets[0];
228
- expect(snippet.originalCode).toBe('var aa = "aaa";');
229
- expect(snippet.convertedCode).toBe('var aa = "aaa";');
286
+ expect(snippet.originalCode).toBe('"aaa"');
287
+ expect(snippet.convertedCode).toBe('"aaa"');
230
288
  expect(snippet.literals).toEqual(['aaa']);
231
289
  expect(snippet.isChanged).toBe(false);
232
290
  }
233
291
  });
292
+ // 处理C#多行语句
234
293
  test('should handle non string assignment 2', () => {
235
294
  const code = 'var d3 = d1 + d2;var aa = "aaa";';
236
295
  const snippets = extractor.extractStrings(code);
237
296
  {
238
297
  const snippet = snippets[0];
239
- expect(snippet.originalCode).toBe('var aa = "aaa";');
240
- expect(snippet.convertedCode).toBe('var aa = "aaa";');
298
+ expect(snippet.originalCode).toBe('"aaa"');
299
+ expect(snippet.convertedCode).toBe('"aaa"');
241
300
  expect(snippet.literals).toEqual(['aaa']);
242
301
  expect(snippet.isChanged).toBe(false);
243
302
  }
244
303
  });
304
+ // 处理C#多行语句
245
305
  test('should handle multilne content1', () => {
246
306
  const code = 'var aa = "aaa";\nvar bb = "bbb";\nvar cc = "ccc";';
247
307
  const snippets = extractor.extractStrings(code);
248
308
  {
249
309
  const snippet = snippets[0];
250
- expect(snippet.originalCode).toBe('var aa = "aaa";');
251
- expect(snippet.convertedCode).toBe('var aa = "aaa";');
310
+ expect(snippet.originalCode).toBe('"aaa"');
311
+ expect(snippet.convertedCode).toBe('"aaa"');
252
312
  expect(snippet.literals).toEqual(['aaa']);
253
313
  expect(snippet.isChanged).toBe(false);
254
314
  }
255
315
  {
256
316
  const snippet = snippets[1];
257
- expect(snippet.originalCode).toBe('var bb = "bbb";');
258
- expect(snippet.convertedCode).toBe('var bb = "bbb";');
317
+ expect(snippet.originalCode).toBe('"bbb"');
318
+ expect(snippet.convertedCode).toBe('"bbb"');
259
319
  expect(snippet.literals).toEqual(['bbb']);
260
320
  expect(snippet.isChanged).toBe(false);
261
321
  }
262
322
  {
263
323
  const snippet = snippets[2];
264
- expect(snippet.originalCode).toBe('var cc = "ccc";');
265
- expect(snippet.convertedCode).toBe('var cc = "ccc";');
324
+ expect(snippet.originalCode).toBe('"ccc"');
325
+ expect(snippet.convertedCode).toBe('"ccc"');
266
326
  expect(snippet.literals).toEqual(['ccc']);
267
327
  expect(snippet.isChanged).toBe(false);
268
328
  }
269
329
  });
330
+ // 处理C#多行语句
270
331
  test('should handle multilne content2', () => {
271
332
  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;';
272
333
  const snippets = extractor.extractStrings(code);
273
334
  {
274
335
  const snippet = snippets[0];
275
- expect(snippet.originalCode).toBe('var aa = "aaa";');
276
- expect(snippet.convertedCode).toBe('var aa = "aaa";');
336
+ expect(snippet.originalCode).toBe('"aaa"');
337
+ expect(snippet.convertedCode).toBe('"aaa"');
277
338
  expect(snippet.literals).toEqual(['aaa']);
278
339
  expect(snippet.isChanged).toBe(false);
279
340
  }
280
341
  {
281
342
  const snippet = snippets[1];
282
- expect(snippet.originalCode).toBe('var bb = "bbb";');
283
- expect(snippet.convertedCode).toBe('var bb = "bbb";');
343
+ expect(snippet.originalCode).toBe('"bbb"');
344
+ expect(snippet.convertedCode).toBe('"bbb"');
284
345
  expect(snippet.literals).toEqual(['bbb']);
285
346
  expect(snippet.isChanged).toBe(false);
286
347
  }
287
348
  {
288
349
  const snippet = snippets[2];
289
- expect(snippet.originalCode).toBe('var hh = aa + bb + "hhh";');
290
- expect(snippet.convertedCode).toBe('var hh = aa.TR() + bb.TR() + "hhh".TR();');
350
+ expect(snippet.originalCode).toBe('aa + bb + "hhh"');
351
+ expect(snippet.convertedCode).toBe('aa.TR() + bb.TR() + "hhh".TR()');
291
352
  expect(snippet.literals).toEqual(['hhh']);
292
353
  expect(snippet.isChanged).toBe(true);
293
354
  }
294
355
  {
295
356
  const snippet = snippets[3];
296
- expect(snippet.originalCode).toBe('cc.text = "ccc" + aa + bb;');
297
- expect(snippet.convertedCode).toBe('cc.text = "ccc".TR() + aa.TR() + bb.TR();');
357
+ expect(snippet.originalCode).toBe('"ccc" + aa + bb');
358
+ expect(snippet.convertedCode).toBe('"ccc".TR() + aa.TR() + bb.TR()');
298
359
  expect(snippet.literals).toEqual(['ccc']);
299
360
  expect(snippet.isChanged).toBe(true);
300
361
  }
301
362
  {
302
363
  const snippet = snippets[4];
303
- expect(snippet.originalCode).toBe('var ii = "iii";');
304
- expect(snippet.convertedCode).toBe('var ii = "iii";');
364
+ expect(snippet.originalCode).toBe('"iii"');
365
+ expect(snippet.convertedCode).toBe('"iii"');
305
366
  expect(snippet.literals).toEqual(['iii']);
306
367
  expect(snippet.isChanged).toBe(false);
307
368
  }
308
369
  {
309
370
  const snippet = snippets[5];
310
- expect(snippet.originalCode).toBe('jj.text = "jjj";');
311
- expect(snippet.convertedCode).toBe('jj.text = "jjj".TR();');
371
+ expect(snippet.originalCode).toBe('"jjj"');
372
+ expect(snippet.convertedCode).toBe('"jjj".TR()');
312
373
  expect(snippet.literals).toEqual(['jjj']);
313
374
  expect(snippet.isChanged).toBe(true);
314
375
  }
315
376
  {
316
377
  const snippet = snippets[6];
317
- expect(snippet.originalCode).toBe('CallFunc("jjj");');
318
- expect(snippet.convertedCode).toBe('CallFunc("jjj");');
378
+ expect(snippet.originalCode).toBe('"jjj"');
379
+ expect(snippet.convertedCode).toBe('"jjj"');
319
380
  expect(snippet.literals).toEqual(['jjj']);
320
381
  expect(snippet.isChanged).toBe(false);
321
382
  }
322
383
  {
323
384
  const snippet = snippets[7];
324
- expect(snippet.originalCode).toBe('CallFunc2("jjj", "kkk");');
325
- expect(snippet.convertedCode).toBe('CallFunc2("jjj", "kkk");');
326
- expect(snippet.literals).toEqual(['jjj', 'kkk']);
385
+ expect(snippet.originalCode).toBe('"jjj"');
386
+ expect(snippet.convertedCode).toBe('"jjj"');
387
+ expect(snippet.literals).toEqual(['jjj']);
327
388
  expect(snippet.isChanged).toBe(false);
328
389
  }
329
390
  {
330
391
  const snippet = snippets[8];
331
- expect(snippet.originalCode).toBe('jj.text = "jjj" + ll;');
332
- expect(snippet.convertedCode).toBe('jj.text = "jjj".TR() + ll.TR();');
392
+ expect(snippet.originalCode).toBe('"kkk"');
393
+ expect(snippet.convertedCode).toBe('"kkk"');
394
+ expect(snippet.literals).toEqual(['kkk']);
395
+ expect(snippet.isChanged).toBe(false);
396
+ }
397
+ {
398
+ const snippet = snippets[9];
399
+ expect(snippet.originalCode).toBe('"jjj" + ll');
400
+ expect(snippet.convertedCode).toBe('"jjj".TR() + ll.TR()');
333
401
  expect(snippet.literals).toEqual(['jjj']);
334
402
  expect(snippet.isChanged).toBe(true);
335
403
  }
336
404
  });
405
+ // 处理C#多行语句
337
406
  test('should handle multilne content3', () => {
338
407
  const code = 'label.text = Tr.Format("pre", Func(), "sub") + other;\nlabel2.text = Tr.Format("pre2", Func(), "sub2") + other2;';
339
408
  const snippets = extractor.extractStrings(code);
340
409
  {
341
410
  const snippet = snippets[0];
342
- expect(snippet.originalCode).toBe('label.text = Tr.Format("pre", Func(), "sub") + other;');
343
- expect(snippet.convertedCode).toBe('label.text = Tr.Format("pre", Func(), "sub") + other.TR();');
411
+ expect(snippet.originalCode).toBe('Tr.Format("pre", Func(), "sub") + other');
412
+ expect(snippet.convertedCode).toBe('Tr.Format("pre", Func(), "sub") + other.TR()');
344
413
  expect(snippet.literals).toEqual(['pre', 'sub']);
345
414
  expect(snippet.isChanged).toBe(true);
346
415
  }
347
416
  {
348
417
  const snippet = snippets[1];
349
- expect(snippet.originalCode).toBe('label2.text = Tr.Format("pre2", Func(), "sub2") + other2;');
350
- expect(snippet.convertedCode).toBe('label2.text = Tr.Format("pre2", Func(), "sub2") + other2.TR();');
418
+ expect(snippet.originalCode).toBe('Tr.Format("pre2", Func(), "sub2") + other2');
419
+ expect(snippet.convertedCode).toBe('Tr.Format("pre2", Func(), "sub2") + other2.TR()');
351
420
  expect(snippet.literals).toEqual(['pre2', 'sub2']);
352
421
  expect(snippet.isChanged).toBe(true);
353
422
  }
354
423
  });
424
+ // 处理C#多行语句
355
425
  test('should handle multilne content4', () => {
356
426
  const code = 'label.text =\n Tr.Format(\n\t"pre", Func(),\n\t\t "sub") + other;';
357
427
  const snippets = extractor.extractStrings(code);
358
428
  {
359
429
  const snippet = snippets[0];
360
- expect(snippet.originalCode).toBe('label.text =\n Tr.Format(\n\t"pre", Func(),\n\t\t "sub") + other;');
361
- expect(snippet.convertedCode).toBe('label.text =\n Tr.Format(\n\t"pre", Func(),\n\t\t "sub") + other.TR();');
430
+ expect(snippet.originalCode).toBe('Tr.Format(\n\t"pre", Func(),\n\t\t "sub") + other');
431
+ expect(snippet.convertedCode).toBe('Tr.Format(\n\t"pre", Func(),\n\t\t "sub") + other.TR()');
362
432
  expect(snippet.literals).toEqual(['pre', 'sub']);
363
433
  expect(snippet.isChanged).toBe(true);
364
434
  }
365
435
  });
436
+ // 处理C#多行语句
366
437
  test('should handle multilne content5', () => {
367
438
  const code = `
368
- //注释不需要包含在捕获部分里
439
+ // 注释中无字符串表达式时, 不需要包含在捕获部分里
369
440
  m_text_name.text = cardTable.Name;
370
441
  `;
371
442
  const snippets = extractor.extractStrings(code);
372
443
  {
373
444
  const snippet = snippets[0];
374
- expect(snippet.originalCode).toBe('m_text_name.text = cardTable.Name;');
375
- expect(snippet.convertedCode).toBe('m_text_name.text = cardTable.Name.TR();');
445
+ expect(snippet.originalCode).toBe('cardTable.Name');
446
+ expect(snippet.convertedCode).toBe('cardTable.Name.TR()');
376
447
  expect(snippet.literals).toEqual([]);
377
448
  expect(snippet.isChanged).toBe(true);
378
449
  }
379
450
  });
451
+ // 处理C#多行语句
380
452
  test('should handle multilne content6', () => {
381
453
  const code = `
382
454
  if (condition)
@@ -387,13 +459,14 @@ describe('CSharpStringExtractor', () => {
387
459
  const snippets = extractor.extractStrings(code);
388
460
  {
389
461
  const snippet = snippets[0];
390
- expect(snippet.originalCode).toBe('Toast.Info("卸载成功");');
391
- expect(snippet.convertedCode).toBe('Toast.Info("卸载成功");');
462
+ expect(snippet.originalCode).toBe('"卸载成功"');
463
+ expect(snippet.convertedCode).toBe('"卸载成功"');
392
464
  expect(snippet.literals).toEqual(['卸载成功']);
393
- expect(snippet.originalIndex).toBe(code.indexOf('Toast.Info("卸载成功");'));
465
+ expect(snippet.originalIndex).toBe(code.indexOf('"卸载成功"'));
394
466
  expect(snippet.isChanged).toBe(false);
395
467
  }
396
468
  });
469
+ // 处理C#多行语句
397
470
  test('should handle multilne content7', () => {
398
471
  const code = `
399
472
  while (condition)
@@ -404,13 +477,14 @@ describe('CSharpStringExtractor', () => {
404
477
  const snippets = extractor.extractStrings(code);
405
478
  {
406
479
  const snippet = snippets[0];
407
- expect(snippet.originalCode).toBe('TT1.Fn1("卸载成功");');
408
- expect(snippet.convertedCode).toBe('TT1.Fn1("卸载成功");');
480
+ expect(snippet.originalCode).toBe('"卸载成功"');
481
+ expect(snippet.convertedCode).toBe('"卸载成功"');
409
482
  expect(snippet.literals).toEqual(['卸载成功']);
410
- expect(snippet.originalIndex).toBe(code.indexOf('TT1.Fn1("卸载成功");'));
483
+ expect(snippet.originalIndex).toBe(code.indexOf('"卸载成功"'));
411
484
  expect(snippet.isChanged).toBe(false);
412
485
  }
413
486
  });
487
+ // 处理C#多行语句
414
488
  test('should handle multilne content8', () => {
415
489
  const code = `
416
490
  for (scope;condition;continuex)
@@ -421,12 +495,13 @@ describe('CSharpStringExtractor', () => {
421
495
  const snippets = extractor.extractStrings(code);
422
496
  {
423
497
  const snippet = snippets[0];
424
- expect(snippet.originalCode).toBe('QR2.Fn2("卸载成功");');
425
- expect(snippet.convertedCode).toBe('QR2.Fn2("卸载成功");');
498
+ expect(snippet.originalCode).toBe('"卸载成功"');
499
+ expect(snippet.convertedCode).toBe('"卸载成功"');
426
500
  expect(snippet.literals).toEqual(['卸载成功']);
427
501
  expect(snippet.isChanged).toBe(false);
428
502
  }
429
503
  });
504
+ // 处理C#多行语句
430
505
  test('should handle multilne content9', () => {
431
506
  const code = `
432
507
  {
@@ -436,12 +511,13 @@ describe('CSharpStringExtractor', () => {
436
511
  const snippets = extractor.extractStrings(code);
437
512
  {
438
513
  const snippet = snippets[0];
439
- expect(snippet.originalCode).toBe('KK3.Ca3("卸载成功");');
440
- expect(snippet.convertedCode).toBe('KK3.Ca3("卸载成功");');
514
+ expect(snippet.originalCode).toBe('"卸载成功"');
515
+ expect(snippet.convertedCode).toBe('"卸载成功"');
441
516
  expect(snippet.literals).toEqual(['卸载成功']);
442
517
  expect(snippet.isChanged).toBe(false);
443
518
  }
444
519
  });
520
+ // 处理C#多行语句
445
521
  test('should handle multilne content10', () => {
446
522
  const code = `
447
523
  var lambda1 = () => {
@@ -451,12 +527,13 @@ describe('CSharpStringExtractor', () => {
451
527
  const snippets = extractor.extractStrings(code);
452
528
  {
453
529
  const snippet = snippets[0];
454
- expect(snippet.originalCode).toBe('LJN4.Fn4("卸载成功");');
455
- expect(snippet.convertedCode).toBe('LJN4.Fn4("卸载成功");');
530
+ expect(snippet.originalCode).toBe('"卸载成功"');
531
+ expect(snippet.convertedCode).toBe('"卸载成功"');
456
532
  expect(snippet.literals).toEqual(['卸载成功']);
457
533
  expect(snippet.isChanged).toBe(false);
458
534
  }
459
535
  });
536
+ // 处理C#多行语句
460
537
  test('should handle multilne content11', () => {
461
538
  const code = `
462
539
  void lambda1() {
@@ -466,12 +543,13 @@ describe('CSharpStringExtractor', () => {
466
543
  const snippets = extractor.extractStrings(code);
467
544
  {
468
545
  const snippet = snippets[0];
469
- expect(snippet.originalCode).toBe('KK5.Call5("卸载成功");');
470
- expect(snippet.convertedCode).toBe('KK5.Call5("卸载成功");');
546
+ expect(snippet.originalCode).toBe('"卸载成功"');
547
+ expect(snippet.convertedCode).toBe('"卸载成功"');
471
548
  expect(snippet.literals).toEqual(['卸载成功']);
472
549
  expect(snippet.isChanged).toBe(false);
473
550
  }
474
551
  });
552
+ // 处理C#多行语句
475
553
  test('should handle multilne content12', () => {
476
554
  const code = `
477
555
  //星级
@@ -492,12 +570,13 @@ describe('CSharpStringExtractor', () => {
492
570
  const snippets = extractor.extractStrings(code);
493
571
  {
494
572
  const snippet = snippets[0];
495
- expect(snippet.originalCode).toBe('m_text_quality.text = Tr.Format("{0}阶", _sutraCardData.Quality);');
496
- expect(snippet.convertedCode).toBe('m_text_quality.text = Tr.Format("{0}阶", _sutraCardData.Quality);');
573
+ expect(snippet.originalCode).toBe('Tr.Format("{0}阶", _sutraCardData.Quality)');
574
+ expect(snippet.convertedCode).toBe('Tr.Format("{0}阶", _sutraCardData.Quality)');
497
575
  expect(snippet.literals).toEqual(['{0}阶']);
498
576
  expect(snippet.isChanged).toBe(false);
499
577
  }
500
578
  });
579
+ // 处理C#多行语句
501
580
  test('should handle multilne content13', () => {
502
581
  const code = `
503
582
  Toast.Info("卸载成功");
@@ -506,21 +585,22 @@ describe('CSharpStringExtractor', () => {
506
585
  const snippets = extractor.extractStrings(code);
507
586
  {
508
587
  const snippet = snippets[0];
509
- expect(snippet.originalIndex).toBe(code.indexOf('Toast.Info("卸载成功");'));
510
- expect(snippet.originalCode).toBe('Toast.Info("卸载成功");');
511
- expect(snippet.convertedCode).toBe('Toast.Info("卸载成功");');
588
+ expect(snippet.originalIndex).toBe(code.indexOf('"卸载成功"'));
589
+ expect(snippet.originalCode).toBe('"卸载成功"');
590
+ expect(snippet.convertedCode).toBe('"卸载成功"');
512
591
  expect(snippet.literals).toEqual(['卸载成功']);
513
592
  expect(snippet.isChanged).toBe(false);
514
593
  }
515
594
  {
516
595
  const snippet = snippets[1];
517
- expect(snippet.originalIndex).toBe(code.indexOf('Toast.Info("卸载成功");', snippets[0].originalIndex + 1));
518
- expect(snippet.originalCode).toBe('Toast.Info("卸载成功");');
519
- expect(snippet.convertedCode).toBe('Toast.Info("卸载成功");');
596
+ expect(snippet.originalIndex).toBe(code.indexOf('"卸载成功"', snippets[0].originalIndex + 1));
597
+ expect(snippet.originalCode).toBe('"卸载成功"');
598
+ expect(snippet.convertedCode).toBe('"卸载成功"');
520
599
  expect(snippet.literals).toEqual(['卸载成功']);
521
600
  expect(snippet.isChanged).toBe(false);
522
601
  }
523
602
  });
603
+ // 处理C#多行语句
524
604
  test('should handle multilne content14', () => {
525
605
  const code = (0, fs_1.readFileSync)('./test/MainSutraDetailDialog.cs', 'utf8');
526
606
  const snippets = extractor.extractStrings(code);
@@ -528,112 +608,156 @@ describe('CSharpStringExtractor', () => {
528
608
  expect(snippets.length).toBeGreaterThan(0);
529
609
  // 针对每个snippet展开对每个属性值的断言
530
610
  // Snippet 1
531
- expect(snippets[0].originalIndex).toBe(2807);
532
- expect(snippets[0].originalCode).toBe('m_text_name.text = cardTable.Name.TR();');
533
- expect(snippets[0].convertedCode).toBe('m_text_name.text = cardTable.Name.TR();');
611
+ expect(snippets[0].originalIndex).toBe(code.indexOf('cardTable.Name.TR()'));
612
+ expect(snippets[0].originalCode).toBe('cardTable.Name.TR()');
613
+ expect(snippets[0].convertedCode).toBe('cardTable.Name.TR()');
534
614
  expect(snippets[0].literals).toEqual([]);
535
615
  expect(snippets[0].isChanged).toBe(false);
536
616
  // Snippet 2
537
- expect(snippets[1].originalIndex).toBe(3550);
538
- expect(snippets[1].originalCode).toBe('m_text_potrem1.text = sutraConfig.Poetry[0].TR();');
539
- expect(snippets[1].convertedCode).toBe('m_text_potrem1.text = sutraConfig.Poetry[0].TR();');
617
+ expect(snippets[1].originalIndex).toBe(code.indexOf('sutraConfig.Poetry[0].TR()'));
618
+ expect(snippets[1].originalCode).toBe('sutraConfig.Poetry[0].TR()');
619
+ expect(snippets[1].convertedCode).toBe('sutraConfig.Poetry[0].TR()');
540
620
  expect(snippets[1].literals).toEqual([]);
541
621
  expect(snippets[1].isChanged).toBe(false);
542
622
  // Snippet 3
543
- expect(snippets[2].originalIndex).toBe(3612);
544
- expect(snippets[2].originalCode).toBe('m_text_potrem2.text = sutraConfig.Poetry[1].TR();');
545
- expect(snippets[2].convertedCode).toBe('m_text_potrem2.text = sutraConfig.Poetry[1].TR();');
623
+ expect(snippets[2].originalIndex).toBe(code.indexOf('sutraConfig.Poetry[1].TR()'));
624
+ expect(snippets[2].originalCode).toBe('sutraConfig.Poetry[1].TR()');
625
+ expect(snippets[2].convertedCode).toBe('sutraConfig.Poetry[1].TR()');
546
626
  expect(snippets[2].literals).toEqual([]);
547
627
  expect(snippets[2].isChanged).toBe(false);
548
628
  // Snippet 4
549
- expect(snippets[3].originalIndex).toBe(3912);
550
- expect(snippets[3].originalCode).toBe('m_text_atkAdd.text = (_sutraCardData.AttackUp() / 100).ToString("0.0") + "%".TR();');
551
- expect(snippets[3].convertedCode).toBe('m_text_atkAdd.text = (_sutraCardData.AttackUp() / 100).ToString("0.0").TR() + "%".TR();');
629
+ expect(snippets[3].originalIndex).toBe(code.indexOf('(_sutraCardData.AttackUp() / 100).ToString("0.0") + "%".TR()'));
630
+ expect(snippets[3].originalCode).toBe('(_sutraCardData.AttackUp() / 100).ToString("0.0") + "%".TR()');
631
+ expect(snippets[3].convertedCode).toBe('(_sutraCardData.AttackUp() / 100).ToString("0.0").TR() + "%".TR()');
552
632
  expect(snippets[3].literals).toEqual(['0.0', '%']);
553
633
  expect(snippets[3].isChanged).toBe(true);
554
634
  // Snippet 5
555
- expect(snippets[4].originalIndex).toBe(4007);
556
- expect(snippets[4].originalCode).toBe('m_text_hpAdd.text = (_sutraCardData.HpUp() / 100).ToString("0.0") + "%".TR();');
557
- expect(snippets[4].convertedCode).toBe('m_text_hpAdd.text = (_sutraCardData.HpUp() / 100).ToString("0.0").TR() + "%".TR();');
635
+ expect(snippets[4].originalIndex).toBe(code.indexOf('(_sutraCardData.HpUp() / 100).ToString("0.0") + "%".TR()'));
636
+ expect(snippets[4].originalCode).toBe('(_sutraCardData.HpUp() / 100).ToString("0.0") + "%".TR()');
637
+ expect(snippets[4].convertedCode).toBe('(_sutraCardData.HpUp() / 100).ToString("0.0").TR() + "%".TR()');
558
638
  expect(snippets[4].literals).toEqual(['0.0', '%']);
559
639
  expect(snippets[4].isChanged).toBe(true);
560
640
  // Snippet 6
561
- expect(snippets[5].originalIndex).toBe(4187);
562
- expect(snippets[5].originalCode).toBe('m_text_skillName.text = skillConfig.Name.TR();');
563
- expect(snippets[5].convertedCode).toBe('m_text_skillName.text = skillConfig.Name.TR();');
641
+ expect(snippets[5].originalIndex).toBe(code.indexOf('skillConfig.Name.TR()'));
642
+ expect(snippets[5].originalCode).toBe('skillConfig.Name.TR()');
643
+ expect(snippets[5].convertedCode).toBe('skillConfig.Name.TR()');
564
644
  expect(snippets[5].literals).toEqual([]);
565
645
  expect(snippets[5].isChanged).toBe(false);
566
646
  // Snippet 7
567
- expect(snippets[6].originalIndex).toBe(4324);
568
- expect(snippets[6].originalCode).toBe('m_text_skill.text = passiveSkillConfig != null ? passiveSkillConfig.Description.TR() : "被动技能未解锁".TR();');
569
- expect(snippets[6].convertedCode).toBe('m_text_skill.text = passiveSkillConfig != null ? passiveSkillConfig.Description.TR() : "被动技能未解锁".TR();');
647
+ expect(snippets[6].originalIndex).toBe(code.indexOf('passiveSkillConfig != null ? passiveSkillConfig.Description.TR() : "被动技能未解锁".TR()'));
648
+ expect(snippets[6].originalCode).toBe('passiveSkillConfig != null ? passiveSkillConfig.Description.TR() : "被动技能未解锁".TR()');
649
+ expect(snippets[6].convertedCode).toBe('passiveSkillConfig != null ? passiveSkillConfig.Description.TR() : "被动技能未解锁".TR()');
570
650
  expect(snippets[6].literals).toEqual(['被动技能未解锁']);
571
651
  expect(snippets[6].isChanged).toBe(false);
572
652
  // Snippet 8
573
- expect(snippets[7].originalIndex).toBe(4505);
574
- expect(snippets[7].originalCode).toBe('m_effect_skillUnlock.ShowEffect("Effect_FaBao_Unlock");');
575
- expect(snippets[7].convertedCode).toBe('m_effect_skillUnlock.ShowEffect("Effect_FaBao_Unlock");');
653
+ expect(snippets[7].originalIndex).toBe(code.indexOf('"Effect_FaBao_Unlock"'));
654
+ expect(snippets[7].originalCode).toBe('"Effect_FaBao_Unlock"');
655
+ expect(snippets[7].convertedCode).toBe('"Effect_FaBao_Unlock"');
576
656
  expect(snippets[7].literals).toEqual(['Effect_FaBao_Unlock']);
577
657
  expect(snippets[7].isChanged).toBe(false);
578
658
  // Snippet 9
579
- expect(snippets[8].originalIndex).toBe(4952);
580
- expect(snippets[8].originalCode).toBe('m_text_quality.text = Tr.Format("{0}阶", _sutraCardData.Quality);');
581
- expect(snippets[8].convertedCode).toBe('m_text_quality.text = Tr.Format("{0}阶", _sutraCardData.Quality);');
659
+ expect(snippets[8].originalIndex).toBe(code.indexOf('Tr.Format("{0}阶", _sutraCardData.Quality)'));
660
+ expect(snippets[8].originalCode).toBe('Tr.Format("{0}阶", _sutraCardData.Quality)');
661
+ expect(snippets[8].convertedCode).toBe('Tr.Format("{0}阶", _sutraCardData.Quality)');
582
662
  expect(snippets[8].literals).toEqual(['{0}阶']);
583
663
  expect(snippets[8].isChanged).toBe(false);
584
664
  // Snippet 10
585
- expect(snippets[9].originalIndex).toBe(5050);
586
- expect(snippets[9].originalCode).toBe('m_text_tongXuan.text = "通玄:".TR() + (_sutraCardData.InheritAtkPercent / 100).ToString("0.0") + "%".TR();');
587
- expect(snippets[9].convertedCode).toBe('m_text_tongXuan.text = "通玄:".TR() + (_sutraCardData.InheritAtkPercent / 100).ToString("0.0").TR() + "%".TR();');
665
+ expect(snippets[9].originalIndex).toBe(code.indexOf('"通玄:".TR() + (_sutraCardData.InheritAtkPercent / 100).ToString("0.0") + "%".TR()'));
666
+ expect(snippets[9].originalCode).toBe('"通玄:".TR() + (_sutraCardData.InheritAtkPercent / 100).ToString("0.0") + "%".TR()');
667
+ expect(snippets[9].convertedCode).toBe('"通玄:".TR() + (_sutraCardData.InheritAtkPercent / 100).ToString("0.0").TR() + "%".TR()');
588
668
  expect(snippets[9].literals).toEqual(['通玄:', '0.0', '%']);
589
669
  expect(snippets[9].isChanged).toBe(true);
590
670
  // Snippet 11
591
- expect(snippets[10].originalIndex).toBe(5943);
592
- expect(snippets[10].originalCode).toBe(`m_text_cost.text = enough
671
+ expect(snippets[10].originalIndex).toBe(code.indexOf(`enough
672
+ ? Tr.Format("[color=#1B8049]{0}/{1}[/color]", curCount, costCount)
673
+ : Tr.Format("[color=#E55E5A]{0}/{1}[/color]", curCount, costCount)`));
674
+ expect(snippets[10].originalCode).toBe(`enough
593
675
  ? Tr.Format("[color=#1B8049]{0}/{1}[/color]", curCount, costCount)
594
- : Tr.Format("[color=#E55E5A]{0}/{1}[/color]", curCount, costCount);`);
595
- expect(snippets[10].convertedCode).toBe(`m_text_cost.text = enough
676
+ : Tr.Format("[color=#E55E5A]{0}/{1}[/color]", curCount, costCount)`);
677
+ expect(snippets[10].convertedCode).toBe(`enough
596
678
  ? Tr.Format("[color=#1B8049]{0}/{1}[/color]", curCount, costCount)
597
- : Tr.Format("[color=#E55E5A]{0}/{1}[/color]", curCount, costCount);`);
679
+ : Tr.Format("[color=#E55E5A]{0}/{1}[/color]", curCount, costCount)`);
598
680
  expect(snippets[10].literals).toEqual(['[color=#1B8049]{0}/{1}[/color]', '[color=#E55E5A]{0}/{1}[/color]']);
599
681
  expect(snippets[10].isChanged).toBe(false);
600
682
  // Snippet 12
601
- expect(snippets[11].originalIndex).toBe(6370);
602
- expect(snippets[11].originalCode).toBe('m_text_upgradeTip.text = dependLockInfo.Item2.TR();');
603
- expect(snippets[11].convertedCode).toBe('m_text_upgradeTip.text = dependLockInfo.Item2.TR();');
683
+ expect(snippets[11].originalIndex).toBe(code.indexOf('dependLockInfo.Item2.TR()'));
684
+ expect(snippets[11].originalCode).toBe('dependLockInfo.Item2.TR()');
685
+ expect(snippets[11].convertedCode).toBe('dependLockInfo.Item2.TR()');
604
686
  expect(snippets[11].literals).toEqual([]);
605
687
  expect(snippets[11].isChanged).toBe(false);
606
688
  // Snippet 13
607
- expect(snippets[12].originalIndex).toBe(7951);
608
- expect(snippets[12].originalCode).toBe('m_effect_fateUnlock.ShowEffect("Effect_FaBao_Unlock");');
609
- expect(snippets[12].convertedCode).toBe('m_effect_fateUnlock.ShowEffect("Effect_FaBao_Unlock");');
689
+ expect(snippets[12].originalIndex).toBe(code.indexOf('"Effect_FaBao_Unlock"', code.indexOf('"Effect_FaBao_Unlock"') + 1));
690
+ expect(snippets[12].originalCode).toBe('"Effect_FaBao_Unlock"');
691
+ expect(snippets[12].convertedCode).toBe('"Effect_FaBao_Unlock"');
610
692
  expect(snippets[12].literals).toEqual(['Effect_FaBao_Unlock']);
611
693
  expect(snippets[12].isChanged).toBe(false);
612
694
  // Snippet 14
613
- expect(snippets[13].originalIndex).toBe(8033);
614
- expect(snippets[13].originalCode).toBe('#region 灵纹信息\n\n m_text_runeSlot.text = Tr.Format("({0}/6)", _sutraCardData.Card.RuneOpenCount);');
615
- expect(snippets[13].convertedCode).toBe('#region 灵纹信息\n\n m_text_runeSlot.text = Tr.Format("({0}/6)", _sutraCardData.Card.RuneOpenCount);');
616
- expect(snippets[13].literals).toEqual([]);
695
+ expect(snippets[13].originalIndex).toBe(code.indexOf('Tr.Format("({0}/6)", _sutraCardData.Card.RuneOpenCount)'));
696
+ expect(snippets[13].originalCode).toBe('Tr.Format("({0}/6)", _sutraCardData.Card.RuneOpenCount)');
697
+ expect(snippets[13].convertedCode).toBe('Tr.Format("({0}/6)", _sutraCardData.Card.RuneOpenCount)');
698
+ expect(snippets[13].literals).toEqual(['({0}/6)']);
617
699
  expect(snippets[13].isChanged).toBe(false);
618
700
  // Snippet 15
619
- expect(snippets[14].originalIndex).toBe(9680);
620
- expect(snippets[14].originalCode).toBe('Log.Error($"Can not find tagId in sutra : {_sutraCardData.Card.Id}");');
621
- expect(snippets[14].convertedCode).toBe('Log.Error(Tr.Format("Can not find tagId in sutra : {0}", _sutraCardData.Card.Id));');
701
+ expect(snippets[14].originalIndex).toBe(code.indexOf('$"Can not find tagId in sutra : {_sutraCardData.Card.Id}"'));
702
+ expect(snippets[14].originalCode).toBe('$"Can not find tagId in sutra : {_sutraCardData.Card.Id}"');
703
+ expect(snippets[14].convertedCode).toBe('Tr.Format("Can not find tagId in sutra : {0}", _sutraCardData.Card.Id)');
622
704
  expect(snippets[14].literals).toEqual(['Can not find tagId in sutra : {0}']);
623
705
  expect(snippets[14].isChanged).toBe(true);
706
+ //#region 需要捕获类成员赋值表达式中, 出现在赋值操作符`=`右侧的字符串值表达式
624
707
  // Snippet 16
625
- expect(snippets[15].originalIndex).toBe(11955);
626
- expect(snippets[15].originalCode).toBe('Toast.Info("卸载成功");');
627
- expect(snippets[15].convertedCode).toBe('Toast.Info("卸载成功");');
628
- expect(snippets[15].literals).toEqual(['卸载成功']);
708
+ expect(snippets[15].originalIndex).toBeGreaterThan(0);
709
+ expect(snippets[15].originalIndex).toBe(code.indexOf('"提示"'));
710
+ expect(snippets[15].originalCode).toBe('"提示"');
711
+ expect(snippets[15].convertedCode).toBe('"提示"');
712
+ expect(snippets[15].literals).toEqual(['提示']);
629
713
  expect(snippets[15].isChanged).toBe(false);
630
714
  // Snippet 17
631
- expect(snippets[16].originalIndex).toBe(12549);
632
- expect(snippets[16].originalCode).toBe('Toast.Info("卸载成功");');
633
- expect(snippets[16].convertedCode).toBe('Toast.Info("卸载成功");');
634
- expect(snippets[16].literals).toEqual(['卸载成功']);
715
+ expect(snippets[16].originalIndex).toBeGreaterThan(0);
716
+ expect(snippets[16].originalIndex).toBe(code.indexOf('"是否一键卸下法宝当前镶嵌灵纹"'));
717
+ expect(snippets[16].originalCode).toBe('"是否一键卸下法宝当前镶嵌灵纹"');
718
+ expect(snippets[16].convertedCode).toBe('"是否一键卸下法宝当前镶嵌灵纹"');
719
+ expect(snippets[16].literals).toEqual(['是否一键卸下法宝当前镶嵌灵纹']);
635
720
  expect(snippets[16].isChanged).toBe(false);
721
+ // Snippet 18
722
+ expect(snippets[17].originalIndex).toBeGreaterThan(0);
723
+ expect(snippets[17].originalIndex).toBe(code.indexOf('"确认"'));
724
+ expect(snippets[17].originalCode).toBe('"确认"');
725
+ expect(snippets[17].convertedCode).toBe('"确认"');
726
+ expect(snippets[17].literals).toEqual(['确认']);
727
+ expect(snippets[17].isChanged).toBe(false);
728
+ //#endregion 需要捕获类成员赋值句式中, 出现在赋值操作符`=`右侧的字符串值表达式
729
+ // Snippet 19
730
+ expect(snippets[18].originalIndex).toBeGreaterThan(0);
731
+ expect(snippets[18].originalIndex).toBe(code.indexOf('"卸载成功"'));
732
+ expect(snippets[18].originalCode).toBe('"卸载成功"');
733
+ expect(snippets[18].convertedCode).toBe('"卸载成功"');
734
+ expect(snippets[18].literals).toEqual(['卸载成功']);
735
+ expect(snippets[18].isChanged).toBe(false);
736
+ //#region 需要捕获类成员赋值句式中, 出现在赋值操作符`=`右侧的字符串值表达式
737
+ // Snippet 20
738
+ expect(snippets[19].originalIndex).toBeGreaterThan(0);
739
+ expect(snippets[19].originalIndex).toBe(code.indexOf('"取消"'));
740
+ expect(snippets[19].originalCode).toBe('"取消"');
741
+ expect(snippets[19].convertedCode).toBe('"取消"');
742
+ expect(snippets[19].literals).toEqual(['取消']);
743
+ expect(snippets[19].isChanged).toBe(false);
744
+ // Snippet 21
745
+ expect(snippets[20].originalIndex).toBeGreaterThan(0);
746
+ expect(snippets[20].originalIndex).toBe(code.indexOf('"本次登录不再提示"'));
747
+ expect(snippets[20].originalCode).toBe('"本次登录不再提示"');
748
+ expect(snippets[20].convertedCode).toBe('"本次登录不再提示"');
749
+ expect(snippets[20].literals).toEqual(['本次登录不再提示']);
750
+ expect(snippets[20].isChanged).toBe(false);
751
+ //#endregion 需要捕获类成员赋值句式中, 出现在赋值操作符`=`右侧的字符串值表达式
752
+ // Snippet 22
753
+ expect(snippets[21].originalIndex).toBeGreaterThan(0);
754
+ expect(snippets[21].originalIndex).toBe(code.indexOf('"卸载成功"', code.indexOf('"卸载成功"') + 1));
755
+ expect(snippets[21].originalCode).toBe('"卸载成功"');
756
+ expect(snippets[21].convertedCode).toBe('"卸载成功"');
757
+ expect(snippets[21].literals).toEqual(['卸载成功']);
758
+ expect(snippets[21].isChanged).toBe(false);
636
759
  });
760
+ // 处理C#多行语句
637
761
  test('should handle multilne content15', () => {
638
762
  const code = (0, fs_1.readFileSync)('./test/GuildDonateDialog.cs', 'utf8');
639
763
  const snippets = extractor.extractStrings(code);
@@ -644,35 +768,38 @@ describe('CSharpStringExtractor', () => {
644
768
  const targetSnippet = snippets.find(snippet => snippet.originalCode.includes('ui://a0w66rlc7bhfusff'));
645
769
  expect(targetSnippet).toBeDefined();
646
770
  if (targetSnippet) {
647
- expect(targetSnippet.originalIndex).toBe(2685);
648
- expect(targetSnippet.originalCode).toBe(`m_btn_paid.text = $"<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{paidConfig.Quantity}";`);
649
- expect(targetSnippet.convertedCode).toBe(`m_btn_paid.text = Tr.Format("<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{0}", paidConfig.Quantity);`);
771
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{paidConfig.Quantity}"`));
772
+ expect(targetSnippet.originalCode).toBe(`$"<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{paidConfig.Quantity}"`);
773
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{0}", paidConfig.Quantity)`);
650
774
  expect(targetSnippet.literals).toEqual(["<img src='ui://a0w66rlc7bhfusff'/ width = '70' height = '70'>{0}"]);
651
775
  expect(targetSnippet.isChanged).toBe(true);
652
776
  }
653
777
  });
654
- test('should handle multilne content16', () => {
778
+ // 处理C#普通字符串包含 `//` 的情形
779
+ test('should handle string with `//`', () => {
655
780
  const code = `m_btn_paid.text = "//";`;
656
781
  const snippets = extractor.extractStrings(code);
657
782
  // 验证提取的片段数量
658
783
  expect(snippets.length).toBeGreaterThan(0);
659
784
  let targetSnippet = snippets[0];
660
- expect(targetSnippet.originalCode).toBe(`m_btn_paid.text = "//";`);
661
- expect(targetSnippet.convertedCode).toBe(`m_btn_paid.text = "//".TR();`);
785
+ expect(targetSnippet.originalCode).toBe(`"//"`);
786
+ expect(targetSnippet.convertedCode).toBe(`"//".TR()`);
662
787
  expect(targetSnippet.literals).toEqual(['//']);
663
788
  expect(targetSnippet.isChanged).toBe(true);
664
789
  });
790
+ // 处理C# `+=` 形式赋值语句
665
791
  test('should handle string template with format specifier', () => {
666
792
  const code = `infoStr += $"最终抗性: {resistReduce:F}\\n";`;
667
793
  const snippets = extractor.extractStrings(code);
668
794
  // 验证提取的片段数量
669
795
  expect(snippets.length).toBeGreaterThan(0);
670
796
  let targetSnippet = snippets[0];
671
- expect(targetSnippet.originalCode).toBe(`infoStr += $"最终抗性: {resistReduce:F}\\n";`);
672
- expect(targetSnippet.convertedCode).toBe(`infoStr += Tr.Format("最终抗性: {0:F}\\n", resistReduce);`);
797
+ expect(targetSnippet.originalCode).toBe(`$"最终抗性: {resistReduce:F}\\n"`);
798
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("最终抗性: {0:F}\\n", resistReduce)`);
673
799
  expect(targetSnippet.literals).toEqual(['最终抗性: {0:F}\\n']);
674
800
  expect(targetSnippet.isChanged).toBe(true);
675
801
  });
802
+ // 处理C#多行语句, 特别是包含 `\n` 的字符串
676
803
  test('should handle multilne content17', () => {
677
804
  const code = `
678
805
  infoStr += $"aaa: {aa}\n" +
@@ -682,16 +809,17 @@ describe('CSharpStringExtractor', () => {
682
809
  // 验证提取的片段数量
683
810
  expect(snippets.length).toBeGreaterThan(0);
684
811
  let targetSnippet = snippets[0];
685
- expect(targetSnippet.originalCode).toBe(`infoStr += $"aaa: {aa}\n" +
686
- $"bbb = {bb}";`);
687
- expect(targetSnippet.convertedCode).toBe(`infoStr += Tr.Format("aaa: {0}\n", aa) +
688
- Tr.Format("bbb = {0}", bb);`);
812
+ expect(targetSnippet.originalCode).toBe(`$"aaa: {aa}\n" +
813
+ $"bbb = {bb}"`);
814
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("aaa: {0}\n", aa) +
815
+ Tr.Format("bbb = {0}", bb)`);
689
816
  expect(targetSnippet.literals).toEqual([
690
817
  'aaa: {0}\n',
691
818
  'bbb = {0}'
692
819
  ]);
693
820
  expect(targetSnippet.isChanged).toBe(true);
694
821
  });
822
+ // 处理C#多行语句, 特别是包含 `\\n` 的内插字符串
695
823
  test('should handle multilne content19', () => {
696
824
  const code = `
697
825
  infoStr += $"aaa: {aa}\\n" +
@@ -701,16 +829,17 @@ describe('CSharpStringExtractor', () => {
701
829
  // 验证提取的片段数量
702
830
  expect(snippets.length).toBeGreaterThan(0);
703
831
  let targetSnippet = snippets[0];
704
- expect(targetSnippet.originalCode).toBe(`infoStr += $"aaa: {aa}\\n" +
705
- $"bbb = {bb}";`);
706
- expect(targetSnippet.convertedCode).toBe(`infoStr += Tr.Format("aaa: {0}\\n", aa) +
707
- Tr.Format("bbb = {0}", bb);`);
832
+ expect(targetSnippet.originalCode).toBe(`$"aaa: {aa}\\n" +
833
+ $"bbb = {bb}"`);
834
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("aaa: {0}\\n", aa) +
835
+ Tr.Format("bbb = {0}", bb)`);
708
836
  expect(targetSnippet.literals).toEqual([
709
837
  'aaa: {0}\\n',
710
838
  'bbb = {0}'
711
839
  ]);
712
840
  expect(targetSnippet.isChanged).toBe(true);
713
841
  });
842
+ // 处理C#中多行字符串拼接成的字符串表达式
714
843
  test('should handle multilne content18', () => {
715
844
  const code = `
716
845
  infoStr += "伤害公式: \\n" +
@@ -726,22 +855,22 @@ describe('CSharpStringExtractor', () => {
726
855
  // 验证提取的片段数量
727
856
  expect(snippets.length).toBeGreaterThan(0);
728
857
  let targetSnippet = snippets[0];
729
- expect(targetSnippet.originalCode).toBe(`infoStr += "伤害公式: \\n" +
858
+ expect(targetSnippet.originalCode).toBe(`"伤害公式: \\n" +
730
859
  $"最终伤害[color={colorCode}][{(float)damageValue:F}][/color] = \\n" +
731
860
  $"基础伤害[b][{baseValue:F}][/b] X \\n" +
732
861
  $"暴击伤害加成[b][{damageInfo.CritDamageRatio:F}][/b] X \\n" +
733
862
  $"最终伤害加成[b][{1 + damageInfo.FinalDamageRatio:F}][/b] X \\n" +
734
863
  $"最终承伤加成[b][{1 + damageInfo.FinalInjuryRatio:F}][/b] / \\n" +
735
864
  $"最终伤害减免[b][{1 + damageInfo.FinalDamageReduce:F}][/b] X \\n" +
736
- $"抗性减免[b][{resistReduce:F}]";`);
737
- expect(targetSnippet.convertedCode).toBe(`infoStr += "伤害公式: \\n".TR() +
865
+ $"抗性减免[b][{resistReduce:F}]"`);
866
+ expect(targetSnippet.convertedCode).toBe(`"伤害公式: \\n".TR() +
738
867
  Tr.Format("最终伤害[color={0}][{1:F}][/color] = \\n", colorCode, (float)damageValue) +
739
868
  Tr.Format("基础伤害[b][{0:F}][/b] X \\n", baseValue) +
740
869
  Tr.Format("暴击伤害加成[b][{0:F}][/b] X \\n", damageInfo.CritDamageRatio) +
741
870
  Tr.Format("最终伤害加成[b][{0:F}][/b] X \\n", 1 + damageInfo.FinalDamageRatio) +
742
871
  Tr.Format("最终承伤加成[b][{0:F}][/b] / \\n", 1 + damageInfo.FinalInjuryRatio) +
743
872
  Tr.Format("最终伤害减免[b][{0:F}][/b] X \\n", 1 + damageInfo.FinalDamageReduce) +
744
- Tr.Format("抗性减免[b][{0:F}]", resistReduce);`);
873
+ Tr.Format("抗性减免[b][{0:F}]", resistReduce)`);
745
874
  expect(targetSnippet.literals).toEqual([
746
875
  '伤害公式: \\n',
747
876
  '最终伤害[color={0}][{1:F}][/color] = \\n',
@@ -754,134 +883,1385 @@ describe('CSharpStringExtractor', () => {
754
883
  ]);
755
884
  expect(targetSnippet.isChanged).toBe(true);
756
885
  });
757
- test('should handle lack bracket 1', () => {
886
+ // 处理C#中包含括号的内插字符串
887
+ test('should handle bracket 1', () => {
758
888
  const code = `m_text_time.text = $"下一轮神兽出现倒计时: {Date.GetIntweerpolatedTime(ServerTimer.Instance.Time, _startGameStamp)}";`;
759
889
  const snippets = extractor.extractStrings(code);
760
890
  // 验证提取的片段数量
761
891
  expect(snippets.length).toBeGreaterThan(0);
762
892
  let targetSnippet = snippets[0];
763
- expect(targetSnippet.originalCode).toBe(`m_text_time.text = $"下一轮神兽出现倒计时: {Date.GetIntweerpolatedTime(ServerTimer.Instance.Time, _startGameStamp)}";`);
764
- expect(targetSnippet.convertedCode).toBe(`m_text_time.text = Tr.Format("下一轮神兽出现倒计时: {0}", Date.GetIntweerpolatedTime(ServerTimer.Instance.Time, _startGameStamp));`);
893
+ expect(targetSnippet.originalCode).toBe(`$"下一轮神兽出现倒计时: {Date.GetIntweerpolatedTime(ServerTimer.Instance.Time, _startGameStamp)}"`);
894
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("下一轮神兽出现倒计时: {0}", Date.GetIntweerpolatedTime(ServerTimer.Instance.Time, _startGameStamp))`);
765
895
  expect(targetSnippet.literals).toEqual([
766
896
  '下一轮神兽出现倒计时: {0}'
767
897
  ]);
768
898
  expect(targetSnippet.isChanged).toBe(true);
769
899
  });
770
- test('should handle lack bracket 2', () => {
900
+ // 处理C#中包含括号的内插字符串
901
+ test('should handle bracket 2', () => {
771
902
  const code = `m_text_time.text = $"神兽离去时间: {Date.FeGetInterpolatedTime(ServerTimer.Instance.Time, _endGameStamp)}";`;
772
903
  const snippets = extractor.extractStrings(code);
773
904
  // 验证提取的片段数量
774
905
  expect(snippets.length).toBeGreaterThan(0);
775
906
  let targetSnippet = snippets[0];
776
- expect(targetSnippet.originalCode).toBe(`m_text_time.text = $"神兽离去时间: {Date.FeGetInterpolatedTime(ServerTimer.Instance.Time, _endGameStamp)}";`);
777
- expect(targetSnippet.convertedCode).toBe(`m_text_time.text = Tr.Format("神兽离去时间: {0}", Date.FeGetInterpolatedTime(ServerTimer.Instance.Time, _endGameStamp));`);
907
+ expect(targetSnippet.originalCode).toBe(`$"神兽离去时间: {Date.FeGetInterpolatedTime(ServerTimer.Instance.Time, _endGameStamp)}"`);
908
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("神兽离去时间: {0}", Date.FeGetInterpolatedTime(ServerTimer.Instance.Time, _endGameStamp))`);
778
909
  expect(targetSnippet.literals).toEqual([
779
910
  '神兽离去时间: {0}'
780
911
  ]);
781
912
  expect(targetSnippet.isChanged).toBe(true);
782
913
  });
783
- test('should handle lack bracket 3', () => {
914
+ // 处理C#中包含括号的内插字符串
915
+ test('should handle bracket 3', () => {
784
916
  const code = `desc += $"剩余{ToGetInterpolatedTime(_cardPoolData.FinishTime * 1000, ServerTimer.Instance.Time)}";`;
785
917
  const snippets = extractor.extractStrings(code);
786
918
  // 验证提取的片段数量
787
919
  expect(snippets.length).toBeGreaterThan(0);
788
920
  let targetSnippet = snippets[0];
789
- expect(targetSnippet.originalCode).toBe(`desc += $"剩余{ToGetInterpolatedTime(_cardPoolData.FinishTime * 1000, ServerTimer.Instance.Time)}";`);
790
- expect(targetSnippet.convertedCode).toBe(`desc += Tr.Format("剩余{0}", ToGetInterpolatedTime(_cardPoolData.FinishTime * 1000, ServerTimer.Instance.Time));`);
921
+ expect(targetSnippet.originalCode).toBe(`$"剩余{ToGetInterpolatedTime(_cardPoolData.FinishTime * 1000, ServerTimer.Instance.Time)}"`);
922
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("剩余{0}", ToGetInterpolatedTime(_cardPoolData.FinishTime * 1000, ServerTimer.Instance.Time))`);
791
923
  expect(targetSnippet.literals).toEqual([
792
924
  '剩余{0}'
793
925
  ]);
794
926
  expect(targetSnippet.isChanged).toBe(true);
795
927
  });
796
- test('should handle lack bracket 4', () => {
928
+ // 处理C#中包含括号的内插字符串
929
+ test('should handle bracket 4', () => {
797
930
  const code = `desc += $"剩余{ToGetInterpolatedTime(FF(_cardPoolData.FinishTime() * 1000, ServerTimer.Instance.Time()))}";`;
798
931
  const snippets = extractor.extractStrings(code);
799
932
  // 验证提取的片段数量
800
933
  expect(snippets.length).toBeGreaterThan(0);
801
934
  let targetSnippet = snippets[0];
802
- expect(targetSnippet.originalCode).toBe(`desc += $"剩余{ToGetInterpolatedTime(FF(_cardPoolData.FinishTime() * 1000, ServerTimer.Instance.Time()))}";`);
803
- expect(targetSnippet.convertedCode).toBe(`desc += Tr.Format("剩余{0}", ToGetInterpolatedTime(FF(_cardPoolData.FinishTime() * 1000, ServerTimer.Instance.Time())));`);
935
+ expect(targetSnippet.originalCode).toBe(`$"剩余{ToGetInterpolatedTime(FF(_cardPoolData.FinishTime() * 1000, ServerTimer.Instance.Time()))}"`);
936
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("剩余{0}", ToGetInterpolatedTime(FF(_cardPoolData.FinishTime() * 1000, ServerTimer.Instance.Time())))`);
804
937
  expect(targetSnippet.literals).toEqual([
805
938
  '剩余{0}'
806
939
  ]);
807
940
  expect(targetSnippet.isChanged).toBe(true);
808
941
  });
942
+ // 处理C#中包含`+=`符号的内插字符串
809
943
  test('should handle duplicate tr handle 1', () => {
810
944
  const code = `infoStr = $"+={colorCode}";`;
811
945
  const snippets = extractor.extractStrings(code);
812
946
  // 验证提取的片段数量
813
947
  expect(snippets.length).toBeGreaterThan(0);
814
948
  let targetSnippet = snippets[0];
815
- expect(targetSnippet.originalCode).toBe(`infoStr = $"+={colorCode}";`);
816
- expect(targetSnippet.convertedCode).toBe(`infoStr = Tr.Format("+={0}", colorCode);`);
949
+ expect(targetSnippet.originalCode).toBe(`$"+={colorCode}"`);
950
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("+={0}", colorCode)`);
817
951
  expect(targetSnippet.literals).toEqual([
818
952
  '+={0}'
819
953
  ]);
820
954
  expect(targetSnippet.isChanged).toBe(true);
821
955
  });
956
+ // 处理C# `+=` 形式的赋值语句后接 包含 `=` 符号的内插字符串
822
957
  test('should handle duplicate tr handle 2', () => {
823
958
  const code = `infoStr += $"={colorCode}";`;
824
959
  const snippets = extractor.extractStrings(code);
825
960
  // 验证提取的片段数量
826
961
  expect(snippets.length).toBeGreaterThan(0);
827
962
  let targetSnippet = snippets[0];
828
- expect(targetSnippet.originalCode).toBe(`infoStr += $"={colorCode}";`);
829
- expect(targetSnippet.convertedCode).toBe(`infoStr += Tr.Format("={0}", colorCode);`);
963
+ expect(targetSnippet.originalCode).toBe(`$"={colorCode}"`);
964
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("={0}", colorCode)`);
830
965
  expect(targetSnippet.literals).toEqual([
831
966
  '={0}'
832
967
  ]);
833
968
  expect(targetSnippet.isChanged).toBe(true);
834
969
  });
970
+ // 处理C# `+=` 形式的赋值语句后接 包含 `+=` 符号的内插字符串
835
971
  test('should handle duplicate tr handle 3', () => {
836
972
  const code = `infoStr += $"+={colorCode}";`;
837
973
  const snippets = extractor.extractStrings(code);
838
974
  // 验证提取的片段数量
839
975
  expect(snippets.length).toBeGreaterThan(0);
840
976
  let targetSnippet = snippets[0];
841
- expect(targetSnippet.originalCode).toBe(`infoStr += $"+={colorCode}";`);
842
- expect(targetSnippet.convertedCode).toBe(`infoStr += Tr.Format("+={0}", colorCode);`);
977
+ expect(targetSnippet.originalCode).toBe(`$"+={colorCode}"`);
978
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("+={0}", colorCode)`);
843
979
  expect(targetSnippet.literals).toEqual([
844
980
  '+={0}'
845
981
  ]);
846
982
  expect(targetSnippet.isChanged).toBe(true);
847
983
  });
984
+ // 处理C# `+=` 形式的赋值语句后接包含 `=`、`[`、`]`、`{`、`}`、`=` 等特殊符号的内插字符串
848
985
  test('should handle duplicate tr handle 4', () => {
849
986
  const code = `infoStr += $"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n";`;
850
987
  const snippets = extractor.extractStrings(code);
851
988
  // 验证提取的片段数量
852
989
  expect(snippets.length).toBeGreaterThan(0);
853
990
  let targetSnippet = snippets[0];
854
- expect(targetSnippet.originalCode).toBe(`infoStr += $"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n";`);
855
- expect(targetSnippet.convertedCode).toBe(`infoStr += Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType);`);
991
+ expect(targetSnippet.originalCode).toBe(`$"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n"`);
992
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`);
856
993
  expect(targetSnippet.literals).toEqual([
857
994
  '伤害类型: [color={0}][b]{1}[/b][/color]\n'
858
995
  ]);
859
996
  expect(targetSnippet.isChanged).toBe(true);
860
997
  });
998
+ // 处理C#中函数调用参数中包含普通字符串的情况, 函数参数需要拆分, 逐个参数捕获
861
999
  test('should handle para 1', () => {
862
1000
  const code = `SetData("等级", level + 1);`;
863
1001
  const snippets = extractor.extractStrings(code);
864
1002
  // 验证提取的片段数量
865
1003
  expect(snippets.length).toBeGreaterThan(0);
866
1004
  let targetSnippet = snippets[0];
867
- expect(targetSnippet.originalCode).toBe(`SetData("等级", level + 1);`);
868
- expect(targetSnippet.convertedCode).toBe(`SetData("等级", level + 1);`);
1005
+ // 函数参数需要拆分, 逐个参数捕获
1006
+ expect(targetSnippet.originalCode).toBe(`"等级"`);
1007
+ expect(targetSnippet.convertedCode).toBe(`"等级"`);
869
1008
  expect(targetSnippet.literals).toEqual([
870
1009
  "等级"
871
1010
  ]);
872
1011
  expect(targetSnippet.isChanged).toBe(false);
873
1012
  });
1013
+ // 处理C#中函数调用参数中包含普通字符串的情况
874
1014
  test('should handle para 2', () => {
875
1015
  const code = `bbb.Func2("等级", level, level + 1, false, isMax);`;
876
1016
  const snippets = extractor.extractStrings(code);
877
1017
  // 验证提取的片段数量
878
1018
  expect(snippets.length).toBeGreaterThan(0);
879
1019
  let targetSnippet = snippets[0];
880
- expect(targetSnippet.originalCode).toBe(`bbb.Func2("等级", level, level + 1, false, isMax);`);
881
- expect(targetSnippet.convertedCode).toBe(`bbb.Func2("等级", level, level + 1, false, isMax);`);
1020
+ expect(targetSnippet.originalCode).toBe(`"等级"`);
1021
+ expect(targetSnippet.convertedCode).toBe(`"等级"`);
882
1022
  expect(targetSnippet.literals).toEqual([
883
1023
  "等级"
884
1024
  ]);
885
1025
  expect(targetSnippet.isChanged).toBe(false);
886
1026
  });
1027
+ // 处理C#中switch语句中包含普通字符串的情况
1028
+ test('should handle switch 1', () => {
1029
+ const code = `
1030
+ switch(condition){
1031
+ default:
1032
+ Log.Warning("实时更新自:" + rankData.Type);
1033
+ break;
1034
+ }`;
1035
+ const snippets = extractor.extractStrings(code);
1036
+ // 验证提取的片段数量
1037
+ expect(snippets.length).toBeGreaterThan(0);
1038
+ let targetSnippet = snippets[0];
1039
+ expect(targetSnippet.originalCode).toBe(`"实时更新自:" + rankData.Type`);
1040
+ // 普通函数参数不需要追加 `.TR()`, 除非包含由 `+` 符号连接字符串等的情况
1041
+ expect(targetSnippet.convertedCode).toBe(`"实时更新自:" + rankData.Type`);
1042
+ expect(targetSnippet.literals).toEqual([
1043
+ "实时更新自:"
1044
+ ]);
1045
+ expect(targetSnippet.isChanged).toBe(false);
1046
+ });
1047
+ // 处理C#中switch语句中包含普通字符串的情况
1048
+ test('should handle switch 2', () => {
1049
+ const code = `
1050
+ switch(kwjkwlje){
1051
+ case (int)RANK_TYPE.天梯段位:
1052
+ Debug.Log1("jkwhfehwfjkh:" + rank2Data.T4zype);
1053
+ break;
1054
+ }`;
1055
+ const snippets = extractor.extractStrings(code);
1056
+ // 验证提取的片段数量, switch 语句中包含普通字符串的情况
1057
+ expect(snippets.length).toBeGreaterThan(0);
1058
+ let targetSnippet = snippets[0];
1059
+ expect(targetSnippet.originalCode).toBe(`"jkwhfehwfjkh:" + rank2Data.T4zype`);
1060
+ expect(targetSnippet.convertedCode).toBe(`"jkwhfehwfjkh:" + rank2Data.T4zype`);
1061
+ expect(targetSnippet.literals).toEqual([
1062
+ "jkwhfehwfjkh:"
1063
+ ]);
1064
+ expect(targetSnippet.isChanged).toBe(false);
1065
+ });
1066
+ // 处理C#中switch语句中包含普通字符串的情况
1067
+ test('should handle switch 3', () => {
1068
+ const code = `
1069
+ switch(lkw){
1070
+ case V434:
1071
+ {
1072
+ Action2("wegwfw:" + varnws);
1073
+ break;
1074
+ }
1075
+ }`;
1076
+ const snippets = extractor.extractStrings(code);
1077
+ // 验证提取的片段数量
1078
+ expect(snippets.length).toBeGreaterThan(0);
1079
+ let targetSnippet = snippets[0];
1080
+ expect(targetSnippet.originalCode).toBe(`"wegwfw:" + varnws`);
1081
+ expect(targetSnippet.convertedCode).toBe(`"wegwfw:" + varnws`);
1082
+ expect(targetSnippet.literals).toEqual([
1083
+ "wegwfw:"
1084
+ ]);
1085
+ expect(targetSnippet.isChanged).toBe(false);
1086
+ });
1087
+ // 处理C#中switch语句中包含普通字符串的情况
1088
+ test('should handle switch 4', () => {
1089
+ const code = `
1090
+ case V434:
1091
+ Action2("wegwfw:" + varnws);
1092
+ break;`;
1093
+ const snippets = extractor.extractStrings(code);
1094
+ // 验证提取的片段数量
1095
+ expect(snippets.length).toBeGreaterThan(0);
1096
+ let targetSnippet = snippets[0];
1097
+ expect(targetSnippet.originalCode).toBe(`"wegwfw:" + varnws`);
1098
+ expect(targetSnippet.convertedCode).toBe(`"wegwfw:" + varnws`);
1099
+ expect(targetSnippet.literals).toEqual([
1100
+ "wegwfw:"
1101
+ ]);
1102
+ expect(targetSnippet.isChanged).toBe(false);
1103
+ });
1104
+ // 处理 C#内容中存在多个相同的包含字符串的语句时, 要每个都提取出来
1105
+ test('should handle lost 1', () => {
1106
+ const code = (0, fs_1.readFileSync)('./test/KeeperDialog.cs', 'utf8');
1107
+ const snippets = extractor.extractStrings(code);
1108
+ let targetSnippet = snippets[3];
1109
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"已购买";
1110
+ m_btn_buy.enabled = false;
1111
+
1112
+ //购买后自动启用`));
1113
+ expect(targetSnippet.originalCode).toBe(`"已购买"`);
1114
+ expect(targetSnippet.convertedCode).toBe(`"已购买".TR()`);
1115
+ expect(targetSnippet.literals).toEqual([
1116
+ "已购买"
1117
+ ]);
1118
+ expect(targetSnippet.isChanged).toBe(true);
1119
+ // 验证提取的片段数量
1120
+ expect(snippets.length).toBeGreaterThanOrEqual(5);
1121
+ });
1122
+ // 字符串中包含 `)` 符号时, 也需要捕获该字符串
1123
+ test('should handle lost 2', () => {
1124
+ const code = `m_text_runeSlot.text = Tr.Format(")", _sutraCardData.Card.RuneOpenCount);`;
1125
+ const snippets = extractor.extractStrings(code);
1126
+ let targetSnippet = snippets[0];
1127
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format(")", _sutraCardData.Card.RuneOpenCount)`));
1128
+ expect(targetSnippet.originalCode).toBe(`Tr.Format(")", _sutraCardData.Card.RuneOpenCount)`);
1129
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format(")", _sutraCardData.Card.RuneOpenCount)`);
1130
+ // 字符串中包含 `)` 符号时, 也需要捕获该字符串
1131
+ expect(targetSnippet.literals).toEqual([
1132
+ ')'
1133
+ ]);
1134
+ expect(targetSnippet.isChanged).toBe(false);
1135
+ });
1136
+ // 处理 C#内容时, 需要匹配出包含 `(` 符号的字符串表达式
1137
+ test('should handle lost 3', () => {
1138
+ const code = `m_text_runeSlot.text = ")";`;
1139
+ const snippets = extractor.extractStrings(code);
1140
+ let targetSnippet = snippets[0];
1141
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`")"`));
1142
+ expect(targetSnippet.originalCode).toBe(`")"`);
1143
+ expect(targetSnippet.convertedCode).toBe(`")".TR()`);
1144
+ expect(targetSnippet.literals).toEqual([
1145
+ ')'
1146
+ ]);
1147
+ expect(targetSnippet.isChanged).toBe(true);
1148
+ });
1149
+ // 测试处理C# `return` 语句中的字符串表达式, 提取的字符串表达式中不需要包含 `return` 关键字, 只需要包含字符串表达式
1150
+ test('should handle return statement 1', () => {
1151
+ const code = `return "参数错误";`;
1152
+ const snippets = extractor.extractStrings(code);
1153
+ let targetSnippet = snippets[0];
1154
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"参数错误"`));
1155
+ expect(targetSnippet.originalCode).toBe(`"参数错误"`);
1156
+ expect(targetSnippet.convertedCode).toBe(`"参数错误"`);
1157
+ expect(targetSnippet.literals).toEqual([
1158
+ '参数错误'
1159
+ ]);
1160
+ expect(targetSnippet.isChanged).toBe(false);
1161
+ });
1162
+ // 测试处理C# `return` 语句中的字符串表达式, 提取的字符串表达式中不需要包含 `return` 关键字, 只需要包含字符串表达式
1163
+ test('should handle return statement 2', () => {
1164
+ const code = `return "";`;
1165
+ const snippets = extractor.extractStrings(code);
1166
+ let targetSnippet = snippets[0];
1167
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`""`));
1168
+ expect(targetSnippet.originalCode).toBe(`""`);
1169
+ expect(targetSnippet.convertedCode).toBe(`""`);
1170
+ expect(targetSnippet.literals).toEqual([
1171
+ ''
1172
+ ]);
1173
+ expect(targetSnippet.isChanged).toBe(false);
1174
+ });
1175
+ // 测试处理C# `return` 语句中的字符串表达式, 提取的字符串表达式中不需要包含 `return` 关键字, 只需要包含字符串表达式
1176
+ test('should handle return statement 3', () => {
1177
+ const code = `return $"";`;
1178
+ const snippets = extractor.extractStrings(code);
1179
+ let targetSnippet = snippets[0];
1180
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$""`));
1181
+ expect(targetSnippet.originalCode).toBe(`$""`);
1182
+ expect(targetSnippet.convertedCode).toBe(`$""`);
1183
+ expect(targetSnippet.literals).toEqual([
1184
+ ''
1185
+ ]);
1186
+ expect(targetSnippet.isChanged).toBe(false);
1187
+ });
1188
+ // 测试处理C# `return` 语句中的字符串表达式, 提取的字符串表达式中不需要包含 `return` 关键字, 只需要包含字符串表达式
1189
+ test('should handle return statement 4', () => {
1190
+ const code = `return $"fwefwe";`;
1191
+ const snippets = extractor.extractStrings(code);
1192
+ let targetSnippet = snippets[0];
1193
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"fwefwe"`));
1194
+ expect(targetSnippet.originalCode).toBe(`$"fwefwe"`);
1195
+ expect(targetSnippet.convertedCode).toBe(`$"fwefwe"`);
1196
+ expect(targetSnippet.literals).toEqual([
1197
+ 'fwefwe'
1198
+ ]);
1199
+ expect(targetSnippet.isChanged).toBe(false);
1200
+ });
1201
+ // 测试处理C# `return` 语句中的字符串表达式, 提取的字符串表达式中不需要包含 `return` 关键字, 只需要包含字符串表达式
1202
+ test('should handle return statement 5', () => {
1203
+ const code = `return $"wefwf{fwef}";`;
1204
+ const snippets = extractor.extractStrings(code);
1205
+ let targetSnippet = snippets[0];
1206
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"wefwf{fwef}"`));
1207
+ expect(targetSnippet.originalCode).toBe(`$"wefwf{fwef}"`);
1208
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("wefwf{0}", fwef)`);
1209
+ expect(targetSnippet.literals).toEqual([
1210
+ 'wefwf{0}'
1211
+ ]);
1212
+ expect(targetSnippet.isChanged).toBe(true);
1213
+ });
1214
+ // 测试处理C#字符串表达式中包含各种特殊字符的情况
1215
+ test('should handle special characters in string expression 1', () => {
1216
+ const code = `return "abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\";`;
1217
+ const snippets = extractor.extractStrings(code);
1218
+ let targetSnippet = snippets[0];
1219
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\"`));
1220
+ expect(targetSnippet.originalCode).toBe(`"abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\"`);
1221
+ expect(targetSnippet.convertedCode).toBe(`"abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\"`);
1222
+ expect(targetSnippet.literals).toEqual([
1223
+ 'abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+{}|:\\"<>?1234567890\\\\'
1224
+ ]);
1225
+ expect(targetSnippet.isChanged).toBe(false);
1226
+ });
1227
+ // 测试处理在C#类成员初始赋值语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#字符串边界识别和捕获
1228
+ test('should handle member initial assignment', () => {
1229
+ const code = (0, fs_1.readFileSync)("test/TestSpecialString.cs", "utf8");
1230
+ const snippets = extractor.extractStrings(code);
1231
+ {
1232
+ let targetSnippet = snippets[0];
1233
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"\\\\"`));
1234
+ expect(targetSnippet.originalCode).toBe(`"\\\\"`);
1235
+ expect(targetSnippet.convertedCode).toBe(`"\\\\"`);
1236
+ expect(targetSnippet.literals).toEqual([
1237
+ '\\\\'
1238
+ ]);
1239
+ expect(targetSnippet.isChanged).toBe(false);
1240
+ }
1241
+ {
1242
+ let targetSnippet = snippets[1];
1243
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"\\n"`));
1244
+ expect(targetSnippet.originalCode).toBe(`"\\n"`);
1245
+ expect(targetSnippet.convertedCode).toBe(`"\\n"`);
1246
+ expect(targetSnippet.literals).toEqual([
1247
+ '\\n'
1248
+ ]);
1249
+ expect(targetSnippet.isChanged).toBe(false);
1250
+ }
1251
+ {
1252
+ let targetSnippet = snippets[2];
1253
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"\\t"`));
1254
+ expect(targetSnippet.originalCode).toBe(`$"\\t"`);
1255
+ expect(targetSnippet.convertedCode).toBe(`$"\\t"`);
1256
+ expect(targetSnippet.literals).toEqual([
1257
+ '\\t'
1258
+ ]);
1259
+ expect(targetSnippet.isChanged).toBe(false);
1260
+ }
1261
+ });
1262
+ // 测试处理在C#各种语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#字符串边界识别和捕获
1263
+ test('should handle special characters in string expression 3', () => {
1264
+ const code = (0, fs_1.readFileSync)("test/TestSpecialString.cs", "utf8");
1265
+ const snippets = extractor.extractStrings(code);
1266
+ {
1267
+ let targetSnippet = snippets[3];
1268
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"1. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1269
+ expect(targetSnippet.originalCode).toBe(`"1. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1270
+ expect(targetSnippet.convertedCode).toBe(`"1. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1271
+ expect(targetSnippet.literals).toEqual([
1272
+ '1. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1273
+ ]);
1274
+ expect(targetSnippet.isChanged).toBe(false);
1275
+ }
1276
+ {
1277
+ let targetSnippet = snippets[4];
1278
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"2. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1279
+ expect(targetSnippet.originalCode).toBe(`"2. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1280
+ expect(targetSnippet.convertedCode).toBe(`"2. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1281
+ expect(targetSnippet.literals).toEqual([
1282
+ '2. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1283
+ ]);
1284
+ expect(targetSnippet.isChanged).toBe(false);
1285
+ }
1286
+ {
1287
+ let targetSnippet = snippets[6];
1288
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"4. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1289
+ expect(targetSnippet.originalCode).toBe(`"4. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1290
+ expect(targetSnippet.convertedCode).toBe(`"4. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1291
+ expect(targetSnippet.literals).toEqual([
1292
+ '4. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1293
+ ]);
1294
+ expect(targetSnippet.isChanged).toBe(false);
1295
+ }
1296
+ });
1297
+ // 测试处理在C#各种语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#字符串边界识别和捕获
1298
+ test('should handle special characters in string expression 3.1', () => {
1299
+ const code = (0, fs_1.readFileSync)("test/TestSpecialString.cs", "utf8");
1300
+ const snippets = extractor.extractStrings(code);
1301
+ {
1302
+ let targetSnippet = snippets[3];
1303
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"1. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1304
+ expect(targetSnippet.originalCode).toBe(`"1. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1305
+ expect(targetSnippet.convertedCode).toBe(`"1. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1306
+ expect(targetSnippet.literals).toEqual([
1307
+ '1. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1308
+ ]);
1309
+ expect(targetSnippet.isChanged).toBe(false);
1310
+ }
1311
+ });
1312
+ // 测试处理在C#各种语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#字符串边界识别和捕获
1313
+ test('should handle special characters in string expression of return sentence', () => {
1314
+ const code = (0, fs_1.readFileSync)("test/TestSpecialString.cs", "utf8");
1315
+ const snippets = extractor.extractStrings(code);
1316
+ {
1317
+ let targetSnippet = snippets[7];
1318
+ // 需要统一匹配 `return` 语句中的字符串表达式
1319
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"5. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1320
+ expect(targetSnippet.originalCode).toBe(`"5. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1321
+ expect(targetSnippet.convertedCode).toBe(`"5. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1322
+ expect(targetSnippet.literals).toEqual([
1323
+ '5. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1324
+ ]);
1325
+ expect(targetSnippet.isChanged).toBe(false);
1326
+ }
1327
+ });
1328
+ // 测试处理在C#各种语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#字符串边界识别和捕获
1329
+ test('should handle special characters in string expression 3.2', () => {
1330
+ const code = (0, fs_1.readFileSync)("test/TestSpecialString.cs", "utf8");
1331
+ const snippets = extractor.extractStrings(code);
1332
+ {
1333
+ let targetSnippet = snippets[8];
1334
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"6. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1335
+ expect(targetSnippet.originalCode).toBe(`"6. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1336
+ expect(targetSnippet.convertedCode).toBe(`"6. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1337
+ expect(targetSnippet.literals).toEqual([
1338
+ '6. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1339
+ ]);
1340
+ expect(targetSnippet.isChanged).toBe(false);
1341
+ }
1342
+ {
1343
+ let targetSnippet = snippets[9];
1344
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"7. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1345
+ expect(targetSnippet.originalCode).toBe(`"7. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1346
+ expect(targetSnippet.convertedCode).toBe(`"7. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1347
+ expect(targetSnippet.literals).toEqual([
1348
+ '7. {}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1349
+ ]);
1350
+ expect(targetSnippet.isChanged).toBe(false);
1351
+ }
1352
+ });
1353
+ // 测试处理在C#各种语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#字符串边界识别和捕获
1354
+ test('should handle special characters in string expression 4', () => {
1355
+ const code = (0, fs_1.readFileSync)("test/TestSpecialString.cs", "utf8");
1356
+ const snippets = extractor.extractStrings(code);
1357
+ {
1358
+ let targetSnippet = snippets[5];
1359
+ // 需要支持内插字符串中的特殊转义字符组合: `{{` 表示 `{`, `}}` 表示 `}`, 但是 `{{`和`}}` 从内插字符串转 `Tr.Format(...)` 形式时, 不需要转为 `{`和`}`, `{xxx}` 表示内插表达式
1360
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"3. {wef}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1361
+ expect(targetSnippet.originalCode).toBe(`$"3. {wef}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1362
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("3. {0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\", wef)`);
1363
+ expect(targetSnippet.literals).toEqual([
1364
+ '3. {0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1365
+ ]);
1366
+ expect(targetSnippet.isChanged).toBe(true);
1367
+ }
1368
+ });
1369
+ // 测试处理在C#各种形式语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#内插字符串边界识别和捕获
1370
+ test('should handle special characters in string expression 5', () => {
1371
+ const code = (0, fs_1.readFileSync)("test/TestSpecialString.cs", "utf8");
1372
+ const snippets = extractor.extractStrings(code);
1373
+ {
1374
+ let targetSnippet = snippets[10];
1375
+ // 需要支持内插字符串中的特殊转义字符组合: `{{` 表示 `{`, `}}` 表示 `}`, 但是 `{{`和`}}` 从内插字符串转 `Tr.Format(...)` 形式时, 不需要转为 `{`和`}`, `{xxx}` 表示内插表达式
1376
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"8. {wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1377
+ expect(targetSnippet.originalCode).toBe(`$"8. {wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1378
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("8. {0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\", wefff)`);
1379
+ expect(targetSnippet.literals).toEqual([
1380
+ '8. {0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1381
+ ]);
1382
+ expect(targetSnippet.isChanged).toBe(true);
1383
+ }
1384
+ });
1385
+ // 测试处理在C#各种形式语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#内插字符串边界识别和捕获
1386
+ test('should handle special characters in string expression 6', () => {
1387
+ const code = (0, fs_1.readFileSync)("test/TestSpecialString.cs", "utf8");
1388
+ const snippets = extractor.extractStrings(code);
1389
+ {
1390
+ let targetSnippet = snippets[11];
1391
+ // 需要支持内插字符串中的特殊转义字符组合: `{{` 表示 `{`, `}}` 表示 `}`, 但是 `{{`和`}}` 从内插字符串转 `Tr.Format(...)` 形式时, 不需要转为 `{`和`}`, `{xxx}` 表示内插表达式
1392
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"9. {wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1393
+ expect(targetSnippet.originalCode).toBe(`$"9. {wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1394
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("9. {0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\", wefff)`);
1395
+ expect(targetSnippet.literals).toEqual([
1396
+ '9. {0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1397
+ ]);
1398
+ expect(targetSnippet.isChanged).toBe(true);
1399
+ }
1400
+ });
1401
+ // 测试处理在C#各种形式语句中, 字符串表达式中包含各种特殊字符的情况, 工具中需要统一处理C#内插字符串边界识别和捕获
1402
+ test('should handle special characters in string expression 7', () => {
1403
+ const code = (0, fs_1.readFileSync)("test/TestSpecialString.cs", "utf8");
1404
+ const snippets = extractor.extractStrings(code);
1405
+ {
1406
+ let targetSnippet = snippets[12];
1407
+ // 需要支持内插字符串中的特殊转义字符组合: `{{` 表示 `{`, `}}` 表示 `}`, 但是 `{{`和`}}` 从内插字符串转 `Tr.Format(...)` 形式时, 不需要转为 `{`和`}`, `{xxx}` 表示内插表达式
1408
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"10. {wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1409
+ expect(targetSnippet.originalCode).toBe(`$"10. {wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1410
+ // 需要统一匹配 `return` 语句中的字符串表达式
1411
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("10. {0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\", wefff)`);
1412
+ expect(targetSnippet.literals).toEqual([
1413
+ '10. {0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1414
+ ]);
1415
+ expect(targetSnippet.isChanged).toBe(true);
1416
+ }
1417
+ });
1418
+ test('should handle optional value assignment', () => {
1419
+ const code = `m_text_otherName.text = battleModel.TeammatePlayerData?.Name ?? "";`;
1420
+ const snippets = extractor.extractStrings(code);
1421
+ {
1422
+ let targetSnippet = snippets[0];
1423
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`battleModel.TeammatePlayerData?.Name ?? ""`));
1424
+ expect(targetSnippet.originalCode).toBe(`battleModel.TeammatePlayerData?.Name ?? ""`);
1425
+ expect(targetSnippet.convertedCode).toBe(`battleModel.TeammatePlayerData?.Name ?? "".TR()`);
1426
+ expect(targetSnippet.literals).toEqual([
1427
+ ''
1428
+ ]);
1429
+ expect(targetSnippet.isChanged).toBe(true);
1430
+ }
1431
+ });
1432
+ // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1433
+ test('should handle string in comment 1', () => {
1434
+ const code = `
1435
+ protected override void OnShow(object param)
1436
+ {
1437
+ // Log.Info("AAA:ChooseSutraLayer显示1");
1438
+ base.OnShow(param);
1439
+ }`;
1440
+ const snippets = extractor.extractStrings(code);
1441
+ {
1442
+ let targetSnippet = snippets[0];
1443
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"AAA:ChooseSutraLayer显示1"`));
1444
+ expect(targetSnippet.originalCode).toBe(`"AAA:ChooseSutraLayer显示1"`);
1445
+ expect(targetSnippet.convertedCode).toBe(`"AAA:ChooseSutraLayer显示1"`);
1446
+ expect(targetSnippet.literals).toEqual([
1447
+ 'AAA:ChooseSutraLayer显示1'
1448
+ ]);
1449
+ expect(targetSnippet.isChanged).toBe(false);
1450
+ }
1451
+ });
1452
+ // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1453
+ test('should handle string in comment 2', () => {
1454
+ const code = `
1455
+ protected override void OnShow(object param)
1456
+ {
1457
+ // Log.Info($"BBB:Jowikwf");
1458
+ base.OnShow(param);
1459
+ }`;
1460
+ const snippets = extractor.extractStrings(code);
1461
+ {
1462
+ let targetSnippet = snippets[0];
1463
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"BBB:Jowikwf"`));
1464
+ expect(targetSnippet.originalCode).toBe(`$"BBB:Jowikwf"`);
1465
+ expect(targetSnippet.convertedCode).toBe(`$"BBB:Jowikwf"`);
1466
+ expect(targetSnippet.literals).toEqual([
1467
+ 'BBB:Jowikwf'
1468
+ ]);
1469
+ expect(targetSnippet.isChanged).toBe(false);
1470
+ }
1471
+ });
1472
+ // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1473
+ test('should handle string in comment 3', () => {
1474
+ const code = `
1475
+ protected override void OnShow(object param)
1476
+ {
1477
+ // Log.Info($"BBB:{wlek}Jowikwf");
1478
+ base.OnShow(param);
1479
+ }`;
1480
+ const snippets = extractor.extractStrings(code);
1481
+ {
1482
+ let targetSnippet = snippets[0];
1483
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"BBB:{wlek}Jowikwf"`));
1484
+ expect(targetSnippet.originalCode).toBe(`$"BBB:{wlek}Jowikwf"`);
1485
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("BBB:{0}Jowikwf", wlek)`);
1486
+ expect(targetSnippet.literals).toEqual([
1487
+ 'BBB:{0}Jowikwf'
1488
+ ]);
1489
+ expect(targetSnippet.isChanged).toBe(true);
1490
+ }
1491
+ });
1492
+ // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1493
+ test('should handle string in comment 4', () => {
1494
+ const code = `
1495
+ protected override void OnShow(object param)
1496
+ {
1497
+ // Log.Info("{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\");
1498
+ base.OnShow(param);
1499
+ }`;
1500
+ const snippets = extractor.extractStrings(code);
1501
+ {
1502
+ let targetSnippet = snippets[0];
1503
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1504
+ expect(targetSnippet.originalCode).toBe(`"{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1505
+ expect(targetSnippet.convertedCode).toBe(`"{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1506
+ expect(targetSnippet.literals).toEqual([
1507
+ '{}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1508
+ ]);
1509
+ expect(targetSnippet.isChanged).toBe(false);
1510
+ }
1511
+ });
1512
+ // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1513
+ test('should handle string in comment 5', () => {
1514
+ const code = `
1515
+ protected override void OnShow(object param)
1516
+ {
1517
+ // Log.Info($"{wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\");
1518
+ base.OnShow(param);
1519
+ }`;
1520
+ const snippets = extractor.extractStrings(code);
1521
+ {
1522
+ let targetSnippet = snippets[0];
1523
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"{wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`));
1524
+ expect(targetSnippet.originalCode).toBe(`$"{wefff}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\"`);
1525
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\", wefff)`);
1526
+ expect(targetSnippet.literals).toEqual([
1527
+ '{0}{{}}abcdefghijklmnopqrstuvwxyz\`-=[];\',./~!@#$%^&*()_+|:\\"<>?1234567890\\\\'
1528
+ ]);
1529
+ expect(targetSnippet.isChanged).toBe(true);
1530
+ }
1531
+ });
1532
+ // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1533
+ test('should handle complex string 1', () => {
1534
+ const code = `
1535
+ infoStr += $"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n";
1536
+ infoStr += $"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n";
1537
+ `;
1538
+ const snippets = extractor.extractStrings(code);
1539
+ {
1540
+ let targetSnippet = snippets[0];
1541
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n"`));
1542
+ expect(targetSnippet.originalCode).toBe(`$"伤害类型: [color={colorCode}][b]{_damageInfo.DamageType}[/b][/color]\n"`);
1543
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`);
1544
+ expect(targetSnippet.literals).toEqual([
1545
+ '伤害类型: [color={0}][b]{1}[/b][/color]\n'
1546
+ ]);
1547
+ expect(targetSnippet.isChanged).toBe(true);
1548
+ }
1549
+ });
1550
+ // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1551
+ test('should handle complex string 2', () => {
1552
+ const code = `
1553
+ infoStr += Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType);
1554
+ infoStr += $"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n";
1555
+ `;
1556
+ const snippets = extractor.extractStrings(code);
1557
+ {
1558
+ let targetSnippet = snippets[0];
1559
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`));
1560
+ expect(targetSnippet.originalCode).toBe(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`);
1561
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("伤害类型: [color={0}][b]{1}[/b][/color]\n", colorCode, _damageInfo.DamageType)`);
1562
+ expect(targetSnippet.literals).toEqual([
1563
+ '伤害类型: [color={0}][b]{1}[/b][/color]\n'
1564
+ ]);
1565
+ expect(targetSnippet.isChanged).toBe(false);
1566
+ }
1567
+ });
1568
+ // 正确处理C# 字符串表达式中递归内嵌字符串表达式的情况: 需要正确转换内插字符串格式
1569
+ test('should handle fix interpolated string nested literals', () => {
1570
+ const code = `infoStr += $"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n";`;
1571
+ const snippets = extractor.extractStrings(code);
1572
+ {
1573
+ let targetSnippet = snippets[0];
1574
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n"`));
1575
+ expect(targetSnippet.originalCode).toBe(`$"是否暴击: [b]{(_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否")}[/b]\n"`);
1576
+ // 需要正确转换内插字符串格式
1577
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("是否暴击: [b]{0}[/b]\n", (_damageInfo.IsCritical ? "[color=#00B000]是[/color]" : "否"))`);
1578
+ expect(targetSnippet.literals).toEqual([
1579
+ '是否暴击: [b]{0}[/b]\n'
1580
+ ]);
1581
+ expect(targetSnippet.isChanged).toBe(true);
1582
+ }
1583
+ });
1584
+ // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1585
+ test('should handle complex string with optional value 3', () => {
1586
+ const code = `
1587
+ else if (battleModel.CurGameType == BattleModel.GameType.Teamwork)
1588
+ {
1589
+ //合作模式显示队友名称
1590
+ m_text_otherName.text = battleModel.TeammatePlayerData?.Name ?? "";
1591
+ }
1592
+ `;
1593
+ const snippets = extractor.extractStrings(code);
1594
+ {
1595
+ let targetSnippet = snippets[0];
1596
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`battleModel.TeammatePlayerData?.Name ?? ""`));
1597
+ expect(targetSnippet.originalCode).toBe(`battleModel.TeammatePlayerData?.Name ?? ""`);
1598
+ expect(targetSnippet.convertedCode).toBe(`battleModel.TeammatePlayerData?.Name ?? "".TR()`);
1599
+ expect(targetSnippet.literals).toEqual([
1600
+ ''
1601
+ ]);
1602
+ expect(targetSnippet.isChanged).toBe(true);
1603
+ }
1604
+ });
1605
+ // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1606
+ test('should handle complex string 4', () => {
1607
+ const code = `
1608
+ private void OnBtnIaa(EventContext context)
1609
+ {
1610
+ var iaaConfig = IAAConfigTable.GetConfigById((int)IAAId.境界失败_加速冷却);
1611
+ if (iaaConfig == null)
1612
+ {
1613
+ return;
1614
+ }
1615
+
1616
+ string des = $"观看视频后\n等待时间减少{iaaConfig.EffectValue / 60}分钟";
1617
+ this.GetModel<IAAModel>().ShowAdWithDialog(IAAId.境界失败_加速冷却, "加速时间", des, null);
1618
+ }
1619
+ `;
1620
+ const snippets = extractor.extractStrings(code);
1621
+ {
1622
+ let targetSnippet = snippets[0];
1623
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"观看视频后\n等待时间减少{iaaConfig.EffectValue / 60}分钟"`));
1624
+ expect(targetSnippet.originalCode).toBe(`$"观看视频后\n等待时间减少{iaaConfig.EffectValue / 60}分钟"`);
1625
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("观看视频后\n等待时间减少{0}分钟", iaaConfig.EffectValue / 60)`);
1626
+ expect(targetSnippet.literals).toEqual([
1627
+ '观看视频后\n等待时间减少{0}分钟'
1628
+ ]);
1629
+ expect(targetSnippet.isChanged).toBe(true);
1630
+ }
1631
+ });
1632
+ // 需要正确识别函数调用参数中每个参数的边界, 并识别每个参数中的字符串表达式
1633
+ test('should handle strings in function call arguments', () => {
1634
+ const code = `
1635
+ private void OnBtnIaa(EventContext context)
1636
+ {
1637
+ var iaaConfig = IAAConfigTable.GetConfigById((int)IAAId.境界失败_加速冷却);
1638
+ if (iaaConfig == null)
1639
+ {
1640
+ return;
1641
+ }
1642
+
1643
+ string des = $"观看视频后\n等待时间减少{iaaConfig.EffectValue / 60}分钟";
1644
+ this.GetModel<IAAModel>().ShowAdWithDialog(IAAId.境界失败_加速冷却, "加速时间", des, null);
1645
+ }
1646
+ `;
1647
+ const snippets = extractor.extractStrings(code);
1648
+ {
1649
+ let targetSnippet = snippets[1];
1650
+ // 需要正确识别函数调用参数中每个参数的边界, 并识别每个参数中的字符串表达式
1651
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"加速时间"`));
1652
+ expect(targetSnippet.originalCode).toBe(`"加速时间"`);
1653
+ expect(targetSnippet.convertedCode).toBe(`"加速时间"`);
1654
+ expect(targetSnippet.literals).toEqual([
1655
+ '加速时间'
1656
+ ]);
1657
+ expect(targetSnippet.isChanged).toBe(false);
1658
+ }
1659
+ });
1660
+ // 正确处理C#注释中的字符串表达式 - 同样需要从字符串中提取字符串表达式信息
1661
+ test('should handle string in comment 5', () => {
1662
+ const code = `
1663
+ m_text_percent.text = $"{curGoodsConfig.RebateRate}%";
1664
+ m_name_holder.url = FUISys.Instance.GetIconUrl(_curShopDetail.ShopConfig.Name);
1665
+ m_thumbnail_holder.url = FUISys.Instance.GetIconUrl(_curShopDetail.ShopConfig.Thumbnail);
1666
+ m_btn_buy.text = $"¥ {curGoodsConfig.Price}";
1667
+ m_text_timeleft.text = curShop.TimeLimitData.RemainTime().TR() + "后消失".TR();
1668
+ `;
1669
+ const snippets = extractor.extractStrings(code);
1670
+ {
1671
+ let targetSnippet = snippets[2];
1672
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`curShop.TimeLimitData.RemainTime().TR() + "后消失".TR()`));
1673
+ expect(targetSnippet.originalCode).toBe(`curShop.TimeLimitData.RemainTime().TR() + "后消失".TR()`);
1674
+ expect(targetSnippet.convertedCode).toBe(`curShop.TimeLimitData.RemainTime().TR() + "后消失".TR()`);
1675
+ expect(targetSnippet.literals).toEqual([
1676
+ '后消失'
1677
+ ]);
1678
+ expect(targetSnippet.isChanged).toBe(false);
1679
+ }
1680
+ });
1681
+ // 正确处理C# `switch` 表达式形式中的字符串表达式
1682
+ test('should handle switch expression string', () => {
1683
+ const code = `
1684
+ case (int)State.Lock:
1685
+ Toast.Info($"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁");
1686
+ break;
1687
+ `;
1688
+ const snippets = extractor.extractStrings(code);
1689
+ {
1690
+ let targetSnippet = snippets[0];
1691
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`));
1692
+ expect(targetSnippet.originalCode).toBe(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`);
1693
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("灵田{0}级解锁", _model.GetFarmLandUnlockLevel(_landId))`);
1694
+ expect(targetSnippet.literals).toEqual([
1695
+ '灵田{0}级解锁'
1696
+ ]);
1697
+ expect(targetSnippet.isChanged).toBe(true);
1698
+ }
1699
+ });
1700
+ // 正确识别C# 行注释语句边界, 行注释不能影响上下行的字符串提取
1701
+ test('should handle comment boundary 1', () => {
1702
+ const code = `
1703
+ //上锁
1704
+ case (int)State.Lock:
1705
+ Toast.Info($"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁");
1706
+ break;
1707
+ `;
1708
+ const snippets = extractor.extractStrings(code);
1709
+ {
1710
+ let targetSnippet = snippets[0];
1711
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`));
1712
+ expect(targetSnippet.originalCode).toBe(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`);
1713
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("灵田{0}级解锁", _model.GetFarmLandUnlockLevel(_landId))`);
1714
+ expect(targetSnippet.literals).toEqual([
1715
+ '灵田{0}级解锁'
1716
+ ]);
1717
+ expect(targetSnippet.isChanged).toBe(true);
1718
+ }
1719
+ });
1720
+ // 正确识别C# 行注释语句边界, 行注释不能影响上下行的字符串提取
1721
+ test('should handle comment boundary 2', () => {
1722
+ const code = `
1723
+ // klwjfe
1724
+ namespace TestNamespace{
1725
+ // lkwjfe
1726
+ public class FK{
1727
+ // klwf
1728
+ public void TestM(){
1729
+ // 模拟状态变量
1730
+ var _state = (int)State.Lock;
1731
+ // 模拟土地ID变量
1732
+ switch (_state){
1733
+ //上锁
1734
+ case (int)State.Lock:
1735
+ // lkwjefl
1736
+ Toast.Info($"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁");
1737
+ // klwejf
1738
+ break;
1739
+ // lkwjf
1740
+ }
1741
+ // klwjfel
1742
+ }
1743
+ }
1744
+ }
1745
+ `;
1746
+ const snippets = extractor.extractStrings(code);
1747
+ {
1748
+ let targetSnippet = snippets[0];
1749
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`));
1750
+ expect(targetSnippet.originalCode).toBe(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`);
1751
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("灵田{0}级解锁", _model.GetFarmLandUnlockLevel(_landId))`);
1752
+ expect(targetSnippet.literals).toEqual([
1753
+ '灵田{0}级解锁'
1754
+ ]);
1755
+ expect(targetSnippet.isChanged).toBe(true);
1756
+ }
1757
+ });
1758
+ // 正确识别C# 行注释语句边界, 行注释不能影响上下行的字符串提取
1759
+ test('should handle comment boundary 2', () => {
1760
+ const code = `
1761
+ // klwjfe
1762
+ namespace TestNamespace{
1763
+ // lkwjfe
1764
+ public class FK{
1765
+ // wlkjelj
1766
+ private int Llkwe = 23;
1767
+ // lkjlkj
1768
+ private int Dwekl { get; set; } = 23;
1769
+ // jklwef
1770
+ private static int Dwekl { get; set; } = 23;
1771
+ // lkwjeflk
1772
+ public static void TestM(){}
1773
+ // wesd
1774
+ public static void TestM()
1775
+ {
1776
+ }
1777
+ // wesd
1778
+ public static void TestM(){
1779
+ }
1780
+ // klwf
1781
+ public void TestM(){
1782
+ // 模拟状态变量
1783
+ var _state = (int)State.Lock;
1784
+ // 模拟土地ID变量
1785
+ switch (_state){
1786
+ //上锁
1787
+ case (int)State.Lock:
1788
+ // lkwjefl
1789
+ Toast.Info($"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁");
1790
+ // klwejf
1791
+ break;
1792
+ // lkwjf
1793
+ }
1794
+ // klwjfel
1795
+ }
1796
+ }
1797
+ }
1798
+ `;
1799
+ const snippets = extractor.extractStrings(code);
1800
+ {
1801
+ let targetSnippet = snippets[0];
1802
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`));
1803
+ expect(targetSnippet.originalCode).toBe(`$"灵田{_model.GetFarmLandUnlockLevel(_landId)}级解锁"`);
1804
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("灵田{0}级解锁", _model.GetFarmLandUnlockLevel(_landId))`);
1805
+ expect(targetSnippet.literals).toEqual([
1806
+ '灵田{0}级解锁'
1807
+ ]);
1808
+ expect(targetSnippet.isChanged).toBe(true);
1809
+ }
1810
+ });
1811
+ // 正确识别C#文档注释边界, 类、方法、类成员的文档注释需要直接忽略捕获, 不参与字符串表达式提取; 文档注释通常位于类、方法、类成员的定义上方, 文档注释的格式形如: ` /// <xxx> yyy\n /// </xxx>` 或 ` /// <xxx yyy/>`, 其中xxx为标签, yyy为注释内容, `<xxx>`和`</xxx>` 不一定在同一行或不同行, ` /// <xxx> yyy\n` 不一定只有一行; 文档注释通常以`<xxx>`标签开始, 以`</xxx>`标签结束, 或者以 `<xxx ` 开始, 以 `/>` 结束。
1812
+ test('should handle doc comment boundary for class/method/members', () => {
1813
+ const code = `
1814
+ /// <summary>
1815
+ /// "fwef 类注释1"
1816
+ /// $"fwef 类注释2"
1817
+ /// $"fwef 类注释2 {wef}"
1818
+ /// wef $"fwef 类注释2 {wef}" wef
1819
+ /// </summary>
1820
+ /// <sumary "lkwjfelj"/>
1821
+ public partial class TimeLimitedChargeDialog
1822
+ {
1823
+ /// <summary>
1824
+ /// $" Property成员注释 dsvdf {wlpoe}"
1825
+ /// </summary>
1826
+ private int Ljfw { get; set; } = 342;
1827
+
1828
+ /// <summary>
1829
+ /// $" Field成员注释 wfewe {vvwe}"
1830
+ /// $" Field成员注释 wfewe {vvwe}" wfe
1831
+ /// </summary>
1832
+ private int Ljfw = 342;
1833
+
1834
+ /// <summary>
1835
+ ///</summary>
1836
+ private int Ljfw = 342;
1837
+
1838
+ /// <summary>
1839
+ /// " wef方法注释 wef"
1840
+ /// $" wef方法注释 wef"
1841
+ /// $" wef方法注释 wef{wef}"
1842
+ /// wfe $" wef方法注释 wef{wef}"
1843
+ /// wfe $" wef方法注释 wef{wef}" wef
1844
+ ///wfe $" wef方法注释 wef{wef}" wef
1845
+ /// wefw $" wef方法注释 wef{wef}" we
1846
+ /// </summary>
1847
+ /// <sumary wf $"klwf"/>
1848
+ /// <param name="force">是否重新创建页签列表</param>
1849
+ private void RefreshGoodsInfo()
1850
+ {
1851
+ m_text_timeleft.text = curShop.TimeLimitData.RemainTime() + "后消失";
1852
+ }
1853
+ }
1854
+ `;
1855
+ const snippets = extractor.extractStrings(code);
1856
+ {
1857
+ let targetSnippet = snippets[0];
1858
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1859
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`curShop.TimeLimitData.RemainTime() + "后消失"`));
1860
+ expect(targetSnippet.originalCode).toBe(`curShop.TimeLimitData.RemainTime() + "后消失"`);
1861
+ expect(targetSnippet.convertedCode).toBe(`curShop.TimeLimitData.RemainTime().TR() + "后消失".TR()`);
1862
+ expect(targetSnippet.literals).toEqual([
1863
+ '后消失'
1864
+ ]);
1865
+ expect(targetSnippet.isChanged).toBe(true);
1866
+ }
1867
+ });
1868
+ // 正确识别C#方法参数中的字符串表达式, 支持1到多个形参有默认值的情形
1869
+ test('should handle string expression in method call parameter 1', () => {
1870
+ const code = `
1871
+ namespace FaBao.UI.Comp
1872
+ {
1873
+ public partial class ItemCommonComp
1874
+ {
1875
+ public void BindData(bool needCompare = false)
1876
+ {
1877
+ m_text_level.text = Tr.Format("{0}阶", _itemConfig.PillLevel);
1878
+ }
1879
+ }
1880
+ }
1881
+ `;
1882
+ const snippets = extractor.extractStrings(code);
1883
+ {
1884
+ let targetSnippet = snippets[0];
1885
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1886
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}阶", _itemConfig.PillLevel)`));
1887
+ expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1888
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1889
+ expect(targetSnippet.literals).toEqual([
1890
+ '{0}阶'
1891
+ ]);
1892
+ expect(targetSnippet.isChanged).toBe(false);
1893
+ }
1894
+ expect(snippets.length).toBe(1);
1895
+ });
1896
+ // 正确识别C#方法参数中的字符串表达式, 支持1到多个形参有默认值的情形
1897
+ test('should handle string expression in method call parameter 2', () => {
1898
+ const code = `
1899
+ namespace FaBao.UI.Comp
1900
+ {
1901
+ public partial class ItemCommonComp
1902
+ {
1903
+ public void BindData(bool needCompare = false, long needCompare2 = 23, float needCompare2 = 324.0)
1904
+ {
1905
+ m_text_level.text = Tr.Format("{0}阶", _itemConfig.PillLevel);
1906
+ }
1907
+ }
1908
+ }
1909
+ `;
1910
+ const snippets = extractor.extractStrings(code);
1911
+ {
1912
+ let targetSnippet = snippets[0];
1913
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1914
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}阶", _itemConfig.PillLevel)`));
1915
+ expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1916
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1917
+ expect(targetSnippet.literals).toEqual([
1918
+ '{0}阶'
1919
+ ]);
1920
+ expect(targetSnippet.isChanged).toBe(false);
1921
+ }
1922
+ expect(snippets.length).toBe(1);
1923
+ });
1924
+ // 正确识别C#方法参数中的字符串表达式, 支持1到多个形参有默认值的情形
1925
+ test('should handle string expression in method call parameter 3', () => {
1926
+ const code = `
1927
+ namespace FaBao.UI.Comp
1928
+ {
1929
+ public partial class ItemCommonComp
1930
+ {
1931
+ public void BindData(string wkle, bool needCompare = false, int needCompare2 = false)
1932
+ {
1933
+ m_text_level.text = Tr.Format("{0}阶", _itemConfig.PillLevel);
1934
+ }
1935
+ }
1936
+ }
1937
+ `;
1938
+ const snippets = extractor.extractStrings(code);
1939
+ {
1940
+ let targetSnippet = snippets[0];
1941
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1942
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}阶", _itemConfig.PillLevel)`));
1943
+ expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1944
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
1945
+ expect(targetSnippet.literals).toEqual([
1946
+ '{0}阶'
1947
+ ]);
1948
+ expect(targetSnippet.isChanged).toBe(false);
1949
+ }
1950
+ expect(snippets.length).toBe(1);
1951
+ });
1952
+ // 正确提取C#方法参数中的字符串表达式信息, 支持1到多个形参有默认值的情形
1953
+ test('should handle string expression in method call parameter 3', () => {
1954
+ const code = `
1955
+ namespace FaBao.UI.Comp
1956
+ {
1957
+ public partial class ItemCommonComp
1958
+ {
1959
+ public void BindData(string wkle = "11111", bool needCompare = false, int needCompare2 = false)
1960
+ {
1961
+ }
1962
+
1963
+ public void BindData(string wkle = "22", string wkle = "werwer", bool needCompare = false, string wkle = "wefwewef31f", int needCompare2 = false, string wkle = "df223")
1964
+ {
1965
+ }
1966
+
1967
+ public void BindData(string wkle = "(*&%\\\\*(@Fwfe))&(")
1968
+ {
1969
+ }
1970
+
1971
+ public void BindData(string we, string wkle = "aaaaa", bool needCompare = false, int needCompare2 = false)
1972
+ {
1973
+ m_text_level.text = Tr.Format("{0}阶", _itemConfig.PillLevel);
1974
+ }
1975
+ }
1976
+ }
1977
+ `;
1978
+ const snippets = extractor.extractStrings(code);
1979
+ {
1980
+ let targetSnippet = snippets[0];
1981
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1982
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"11111"`));
1983
+ expect(targetSnippet.originalCode).toBe(`"11111"`);
1984
+ expect(targetSnippet.convertedCode).toBe(`"11111"`);
1985
+ expect(targetSnippet.literals).toEqual([
1986
+ '11111'
1987
+ ]);
1988
+ expect(targetSnippet.isChanged).toBe(false);
1989
+ }
1990
+ {
1991
+ let targetSnippet = snippets[1];
1992
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
1993
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"22"`));
1994
+ expect(targetSnippet.originalCode).toBe(`"22"`);
1995
+ expect(targetSnippet.convertedCode).toBe(`"22"`);
1996
+ expect(targetSnippet.literals).toEqual([
1997
+ '22'
1998
+ ]);
1999
+ expect(targetSnippet.isChanged).toBe(false);
2000
+ }
2001
+ {
2002
+ let targetSnippet = snippets[2];
2003
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2004
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"werwer"`));
2005
+ expect(targetSnippet.originalCode).toBe(`"werwer"`);
2006
+ expect(targetSnippet.convertedCode).toBe(`"werwer"`);
2007
+ expect(targetSnippet.literals).toEqual([
2008
+ 'werwer'
2009
+ ]);
2010
+ expect(targetSnippet.isChanged).toBe(false);
2011
+ }
2012
+ {
2013
+ let targetSnippet = snippets[3];
2014
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2015
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"wefwewef31f"`));
2016
+ expect(targetSnippet.originalCode).toBe(`"wefwewef31f"`);
2017
+ expect(targetSnippet.convertedCode).toBe(`"wefwewef31f"`);
2018
+ expect(targetSnippet.literals).toEqual([
2019
+ 'wefwewef31f'
2020
+ ]);
2021
+ expect(targetSnippet.isChanged).toBe(false);
2022
+ }
2023
+ {
2024
+ let targetSnippet = snippets[4];
2025
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2026
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"df223"`));
2027
+ expect(targetSnippet.originalCode).toBe(`"df223"`);
2028
+ expect(targetSnippet.convertedCode).toBe(`"df223"`);
2029
+ expect(targetSnippet.literals).toEqual([
2030
+ 'df223'
2031
+ ]);
2032
+ expect(targetSnippet.isChanged).toBe(false);
2033
+ }
2034
+ {
2035
+ let targetSnippet = snippets[5];
2036
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2037
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"(*&%\\\\*(@Fwfe))&("`));
2038
+ expect(targetSnippet.originalCode).toBe(`"(*&%\\\\*(@Fwfe))&("`);
2039
+ expect(targetSnippet.convertedCode).toBe(`"(*&%\\\\*(@Fwfe))&("`);
2040
+ expect(targetSnippet.literals).toEqual([
2041
+ '(*&%\\\\*(@Fwfe))&('
2042
+ ]);
2043
+ expect(targetSnippet.isChanged).toBe(false);
2044
+ }
2045
+ {
2046
+ let targetSnippet = snippets[6];
2047
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2048
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"aaaaa"`));
2049
+ expect(targetSnippet.originalCode).toBe(`"aaaaa"`);
2050
+ expect(targetSnippet.convertedCode).toBe(`"aaaaa"`);
2051
+ expect(targetSnippet.literals).toEqual([
2052
+ 'aaaaa'
2053
+ ]);
2054
+ expect(targetSnippet.isChanged).toBe(false);
2055
+ }
2056
+ {
2057
+ let targetSnippet = snippets[7];
2058
+ // 类注释和方法注释不参与字符串表达式提取, 不影响字符串提取结果
2059
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}阶", _itemConfig.PillLevel)`));
2060
+ expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
2061
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}阶", _itemConfig.PillLevel)`);
2062
+ expect(targetSnippet.literals).toEqual([
2063
+ '{0}阶'
2064
+ ]);
2065
+ expect(targetSnippet.isChanged).toBe(false);
2066
+ }
2067
+ });
2068
+ // 需要正确识别C#代码中 `if` 语句边界 和 创建对象表达式的边界, 识别 `if` 语句前、中、后部分中的字符串表达式
2069
+ test('should handle if border and object creation expression border', () => {
2070
+ const code = `
2071
+ namespace FaBao.UI.MainUI
2072
+ {
2073
+ public partial class SpellUpgradeDialog
2074
+ {
2075
+ private async void OnBtnUpgrade()
2076
+ {
2077
+ // new SpellCard_Action_UpgradeSpellCard(_symbolCard.Id) 被方法调用传参的 () 包裹, 因此已经构成了完整的对象创建表达式
2078
+ if (await this.GetModel<SpellCardModel>().DispatchAction(new SpellCard_Action_UpgradeSpellCard(_symbolCard.Id)))
2079
+ {
2080
+ //升级成功后刷新界面
2081
+ m_text_level.text = Tr.Format("{0}级", _symbolCard.Level);
2082
+ }
2083
+ }
2084
+ }
2085
+ }
2086
+ `;
2087
+ const snippets = extractor.extractStrings(code);
2088
+ {
2089
+ let targetSnippet = snippets[0];
2090
+ // 需要正确识别 `if` 语句边界, 识别 `if` 语句前、中、后部分中的字符串表达式
2091
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`Tr.Format("{0}级", _symbolCard.Level)`));
2092
+ expect(targetSnippet.originalCode).toBe(`Tr.Format("{0}级", _symbolCard.Level)`);
2093
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("{0}级", _symbolCard.Level)`);
2094
+ expect(targetSnippet.literals).toEqual([
2095
+ '{0}级'
2096
+ ]);
2097
+ expect(targetSnippet.isChanged).toBe(false);
2098
+ }
2099
+ expect(snippets.length).toBe(1);
2100
+ });
2101
+ // 需要正确识别C#代码中的匿名函数, 匿名函数中的字符串表达式也同样需要提取; 匿名函数通常以 `0到多个修饰词 (可选参数列表) => { ... }` 或者 `0到多个修饰词 (可选参数列表) => 一句表达式` 形式定义实现.
2102
+ test('should handle class member initialization assignment with anonymous function 1', () => {
2103
+ const code = `
2104
+ FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
2105
+ {
2106
+ Title = "提示",
2107
+ ConfirmCallback = async () =>
2108
+ {
2109
+ //灵纹一键下阵
2110
+ if (await this.GetModel<CardModel>().DispatchAction(new Rune_Action_CleanRune(_sutraCardData.Card.Id)))
2111
+ {
2112
+ Toast.Info("卸载成功");
2113
+ }
2114
+ },
2115
+ CancelText = "取消",
2116
+ }).Forget();
2117
+ `;
2118
+ const snippets = extractor.extractStrings(code);
2119
+ {
2120
+ let targetSnippet = snippets[0];
2121
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"提示"`));
2122
+ expect(targetSnippet.originalCode).toBe(`"提示"`);
2123
+ expect(targetSnippet.convertedCode).toBe(`"提示"`);
2124
+ expect(targetSnippet.literals).toEqual([
2125
+ '提示'
2126
+ ]);
2127
+ expect(targetSnippet.isChanged).toBe(false);
2128
+ }
2129
+ {
2130
+ let targetSnippet = snippets[1];
2131
+ // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
2132
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"卸载成功"`));
2133
+ expect(targetSnippet.originalCode).toBe(`"卸载成功"`);
2134
+ expect(targetSnippet.convertedCode).toBe(`"卸载成功"`);
2135
+ expect(targetSnippet.literals).toEqual([
2136
+ '卸载成功'
2137
+ ]);
2138
+ expect(targetSnippet.isChanged).toBe(false);
2139
+ }
2140
+ {
2141
+ let targetSnippet = snippets[2];
2142
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"取消"`));
2143
+ expect(targetSnippet.originalCode).toBe(`"取消"`);
2144
+ expect(targetSnippet.convertedCode).toBe(`"取消"`);
2145
+ expect(targetSnippet.literals).toEqual([
2146
+ '取消'
2147
+ ]);
2148
+ expect(targetSnippet.isChanged).toBe(false);
2149
+ }
2150
+ });
2151
+ // 需要正确识别C#代码中的匿名函数, 匿名函数中的字符串表达式也同样需要提取; 匿名函数通常以 `0到多个修饰词 (可选参数列表) => { ... }` 或者 `0到多个修饰词 (可选参数列表) => 一句表达式` 形式定义实现.
2152
+ test('should handle class member initialization assignment with anonymous function 2', () => {
2153
+ const code = `
2154
+ FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
2155
+ {
2156
+ ConfirmCallback = async () =>
2157
+ {
2158
+ Toast.Info("卸载成功");
2159
+ },
2160
+ }).Forget();
2161
+ `;
2162
+ const snippets = extractor.extractStrings(code);
2163
+ {
2164
+ let targetSnippet = snippets[0];
2165
+ // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
2166
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"卸载成功"`));
2167
+ expect(targetSnippet.originalCode).toBe(`"卸载成功"`);
2168
+ expect(targetSnippet.convertedCode).toBe(`"卸载成功"`);
2169
+ expect(targetSnippet.literals).toEqual([
2170
+ '卸载成功'
2171
+ ]);
2172
+ expect(targetSnippet.isChanged).toBe(false);
2173
+ }
2174
+ });
2175
+ // 需要正确识别C#代码中的匿名函数, 匿名函数中的字符串表达式也同样需要提取; 匿名函数通常以 `0到多个修饰词 (可选参数列表) => { ... }` 或者 `0到多个修饰词 (可选参数列表) => 一句表达式` 形式定义实现.
2176
+ test('should handle class member initialization assignment with anonymous function 2', () => {
2177
+ const code = `
2178
+ FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
2179
+ {
2180
+ ConfirmCallback = (int qwfewe) =>
2181
+ {
2182
+ Toast.Info($"卸载成功: {qwfewe}");
2183
+ },
2184
+ }).Forget();
2185
+ `;
2186
+ const snippets = extractor.extractStrings(code);
2187
+ {
2188
+ let targetSnippet = snippets[0];
2189
+ // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
2190
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`$"卸载成功: {qwfewe}"`));
2191
+ expect(targetSnippet.originalCode).toBe(`$"卸载成功: {qwfewe}"`);
2192
+ expect(targetSnippet.convertedCode).toBe(`Tr.Format("卸载成功: {0}", qwfewe)`);
2193
+ expect(targetSnippet.literals).toEqual([
2194
+ '卸载成功: {0}'
2195
+ ]);
2196
+ expect(targetSnippet.isChanged).toBe(true);
2197
+ }
2198
+ });
2199
+ // 需要正确识别C#代码中的匿名函数, 匿名函数中的字符串表达式也同样需要提取; 匿名函数通常以 `0到多个修饰词 (可选参数列表) => { ... }` 或者 `0到多个修饰词 (可选参数列表) => 一句表达式` 形式定义实现.
2200
+ test('should handle class member initialization assignment with anonymous function 3', () => {
2201
+ const code = `
2202
+ FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
2203
+ {
2204
+ ConfirmCallback = async () => Toast.Info("卸载成功"),
2205
+ }).Forget();
2206
+ `;
2207
+ const snippets = extractor.extractStrings(code);
2208
+ {
2209
+ let targetSnippet = snippets[0];
2210
+ // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
2211
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"卸载成功"`));
2212
+ expect(targetSnippet.originalCode).toBe(`"卸载成功"`);
2213
+ expect(targetSnippet.convertedCode).toBe(`"卸载成功"`);
2214
+ expect(targetSnippet.literals).toEqual([
2215
+ '卸载成功'
2216
+ ]);
2217
+ expect(targetSnippet.isChanged).toBe(false);
2218
+ }
2219
+ });
2220
+ // 需要正确识别C#代码中的匿名函数, 匿名函数中的字符串表达式也同样需要提取; 匿名函数通常以 `0到多个修饰词 (可选参数列表) => { ... }` 或者 `0到多个修饰词 (可选参数列表) => 一句表达式` 形式定义实现.
2221
+ test('should handle class member initialization assignment with anonymous function 4', () => {
2222
+ const code = `
2223
+ FUISys.Instance.ShowLayer<MainConfirmDialog>(UISceneType.Main, new MainConfirmDialog.MainConfirmDialogParam()
2224
+ {
2225
+ ConfirmCallback = () => Toast.Info("卸载成功"),
2226
+ }).Forget();
2227
+ `;
2228
+ const snippets = extractor.extractStrings(code);
2229
+ {
2230
+ let targetSnippet = snippets[0];
2231
+ // 需要正确识别C#代码中类成员初始化赋值时, 给成员赋值匿名函数时, 匿名函数中的字符串表达式也需要提取
2232
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`"卸载成功"`));
2233
+ expect(targetSnippet.originalCode).toBe(`"卸载成功"`);
2234
+ expect(targetSnippet.convertedCode).toBe(`"卸载成功"`);
2235
+ expect(targetSnippet.literals).toEqual([
2236
+ '卸载成功'
2237
+ ]);
2238
+ expect(targetSnippet.isChanged).toBe(false);
2239
+ }
2240
+ });
2241
+ // 测试处理 `xxx.text = yyy` 形式赋值语句, 以 `.text =` 给 `text` 成员赋值的表达式中, `yyy` 部分必定是字符串表达式; 如果`yyy`中不存在字符串, 则`yyy` 中以 `+` 连接的表达式需要加上 `.TR()`; 如果 `yyy` 是作为值表达式整体(必定返回字符串类型值), 也需要追加 `.TR()`。
2242
+ test('should handle .text = format 1', () => {
2243
+ const code = `m_text_iwff.text = info ;`;
2244
+ const snippets = extractor.extractStrings(code);
2245
+ {
2246
+ let targetSnippet = snippets[0];
2247
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`info`));
2248
+ expect(targetSnippet.originalCode).toBe(`info`);
2249
+ expect(targetSnippet.convertedCode).toBe(`info.TR()`);
2250
+ expect(targetSnippet.literals).toEqual([]);
2251
+ expect(targetSnippet.isChanged).toBe(true);
2252
+ }
2253
+ });
2254
+ // 测试处理 `xxx.text = yyy` 形式赋值语句, 以 `.text =` 给 `text` 成员赋值的表达式中, `yyy` 部分必定是字符串表达式; 如果`yyy`中不存在字符串, 则`yyy` 中以 `+` 连接的表达式需要加上 `.TR()`; 如果 `yyy` 是作为值表达式整体(必定返回字符串类型值), 也需要追加 `.TR()`。
2255
+ test('should handle .text = format 1', () => {
2256
+ const code = `m_text_info.text = info1.member1 + info2.member2;`;
2257
+ const snippets = extractor.extractStrings(code);
2258
+ {
2259
+ let targetSnippet = snippets[0];
2260
+ expect(targetSnippet.originalIndex).toBe(code.indexOf(`info1.member1 + info2.member2`));
2261
+ expect(targetSnippet.originalCode).toBe(`info1.member1 + info2.member2`);
2262
+ expect(targetSnippet.convertedCode).toBe(`info1.member1.TR() + info2.member2.TR()`);
2263
+ expect(targetSnippet.literals).toEqual([]);
2264
+ expect(targetSnippet.isChanged).toBe(true);
2265
+ }
2266
+ });
887
2267
  });