apphx 2.0.1 → 2.1.0

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 (49) hide show
  1. package/README.md +10 -8
  2. package/dist/cli.js +41 -11
  3. package/dist/cli.js.map +1 -1
  4. package/dist/config.js +4 -2
  5. package/dist/config.js.map +1 -1
  6. package/dist/integrations.js +154 -95
  7. package/dist/integrations.js.map +1 -1
  8. package/dist/notify.js +267 -0
  9. package/dist/notify.js.map +1 -0
  10. package/dist/runner.js +119 -20
  11. package/dist/runner.js.map +1 -1
  12. package/dist/schemas.js +57 -2
  13. package/dist/schemas.js.map +1 -1
  14. package/dist/vendor/obfuscator/dist/config.js +119 -6
  15. package/dist/vendor/obfuscator/dist/config.js.map +1 -1
  16. package/dist/vendor/obfuscator/dist/dfa.js +528 -0
  17. package/dist/vendor/obfuscator/dist/dfa.js.map +1 -0
  18. package/dist/vendor/obfuscator/dist/flutter.js +3266 -0
  19. package/dist/vendor/obfuscator/dist/flutter.js.map +1 -0
  20. package/dist/vendor/obfuscator/dist/image-utils.js +335 -0
  21. package/dist/vendor/obfuscator/dist/image-utils.js.map +1 -0
  22. package/dist/vendor/obfuscator/dist/junk.js +1501 -0
  23. package/dist/vendor/obfuscator/dist/junk.js.map +1 -0
  24. package/dist/vendor/obfuscator/dist/lexicon-data.js +972 -0
  25. package/dist/vendor/obfuscator/dist/lexicon-data.js.map +1 -0
  26. package/dist/vendor/obfuscator/dist/obfuscate.js +51 -2
  27. package/dist/vendor/obfuscator/dist/obfuscate.js.map +1 -1
  28. package/dist/vendor/obfuscator/dist/objc-symbols.js +1819 -0
  29. package/dist/vendor/obfuscator/dist/objc-symbols.js.map +1 -0
  30. package/dist/vendor/obfuscator/dist/project-identity.js +852 -0
  31. package/dist/vendor/obfuscator/dist/project-identity.js.map +1 -0
  32. package/dist/vendor/obfuscator/dist/string-encrypt.js +330 -0
  33. package/dist/vendor/obfuscator/dist/string-encrypt.js.map +1 -0
  34. package/examples/android-java.factory.json +40 -5
  35. package/examples/expo.factory.json +68 -5
  36. package/examples/flutter.factory.json +40 -4
  37. package/examples/luggage.json +1 -0
  38. package/examples/multi-role-agents.md +129 -0
  39. package/examples/mygo.factory.json +54 -4
  40. package/examples/queue-loop-demo.md +146 -0
  41. package/examples/react-native.factory.json +58 -5
  42. package/examples/roles.example.json +31 -0
  43. package/examples/swift.factory.json +60 -5
  44. package/examples/uni-app.factory.json +58 -5
  45. package/package.json +1 -1
  46. package/skills/apphx/SKILL.md +39 -4
  47. package/skills/apphx/resources/requirement.json +1 -0
  48. package/skills/apphx-obfuscator/LICENSE +21 -0
  49. package/skills/apphx-obfuscator/SKILL.md +72 -0
@@ -0,0 +1,1501 @@
1
+ import { basenameWithoutExtension, deriveUuid, extension, seededInt, writeIfChanged } from "./common.js";
2
+ import { existsSync, mkdirSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ // src/junk.ts
5
+ /**
6
+ * Deterministic "rubbish code injection + resource cleanup" transforms:
7
+ *
8
+ * - insertJunkCode -> garbage methods into .h/.m/.mm/.swift
9
+ * - createJunkFiles -> garbage .h/.m/.swift + pbxproj registration
10
+ * - ObjC garbage-method template pool
11
+ * - Swift garbage-method template pool
12
+ * - unused-resource detection + cleanup
13
+ * - ignorable-path predicate
14
+ *
15
+ * All randomness is seeded; `Math.random`, `Date.now` and `Math.random`-backed UUIDs are
16
+ * never used. Identical arguments always produce byte-identical output.
17
+ */
18
+ const DEFAULT_RUB_PREFIX = "OBFObj";
19
+ const LEXICON = [
20
+ "amber",
21
+ "brisk",
22
+ "cobalt",
23
+ "dapper",
24
+ "eager",
25
+ "fable",
26
+ "glade",
27
+ "haven",
28
+ "ivory",
29
+ "jolly",
30
+ "kindle",
31
+ "lumen",
32
+ "maple",
33
+ "noble",
34
+ "opal",
35
+ "pearl",
36
+ "quill",
37
+ "raven",
38
+ "sable",
39
+ "tiger",
40
+ "umber",
41
+ "velvet",
42
+ "woven",
43
+ "xenon",
44
+ "yonder",
45
+ "zephyr",
46
+ "archer",
47
+ "bramble",
48
+ "cedar",
49
+ "drift",
50
+ "ember",
51
+ "falcon",
52
+ "grove",
53
+ "harbor",
54
+ "indigo",
55
+ "jasper",
56
+ "kestrel",
57
+ "linden",
58
+ "meadow",
59
+ "nimbus",
60
+ "onyx",
61
+ "petal",
62
+ "quartz",
63
+ "rune",
64
+ "saffron",
65
+ "talon",
66
+ "vale",
67
+ "willow",
68
+ "yarrow",
69
+ "azure",
70
+ "beacon",
71
+ "cinder",
72
+ "dusk",
73
+ "eclipse",
74
+ "frost",
75
+ "gale",
76
+ "hollow",
77
+ "iris",
78
+ "juniper",
79
+ "knoll",
80
+ "lagoon",
81
+ "mirage",
82
+ "nestle",
83
+ "oasis",
84
+ "pinnacle",
85
+ "ripple",
86
+ "solace",
87
+ "thicket",
88
+ "vista",
89
+ "wander",
90
+ "wisp",
91
+ "acre",
92
+ "birch",
93
+ "canyon",
94
+ "delta",
95
+ "elevation",
96
+ "fjord",
97
+ "glacier",
98
+ "highland",
99
+ "inlet",
100
+ "jetty",
101
+ "knob",
102
+ "ledge",
103
+ "marrow",
104
+ "notch",
105
+ "orchard",
106
+ "prairie",
107
+ "quarry",
108
+ "ridge",
109
+ "summit",
110
+ "terrace",
111
+ "uplands",
112
+ "verge",
113
+ "watershed",
114
+ "woodland",
115
+ "alder",
116
+ "basin",
117
+ "clearing"
118
+ ];
119
+ function capitalize(value) {
120
+ return value.length === 0 ? value : value[0].toUpperCase() + value.slice(1);
121
+ }
122
+ /** Deterministic lowercase lexicon word (seed + salt). */
123
+ function randomWord(seed, salt) {
124
+ return LEXICON[seededInt(seed, `lexicon:${salt}`, 0, LEXICON.length - 1)];
125
+ }
126
+ /** Deterministic title-cased lexicon word. */
127
+ function randomWordTitle(seed, salt) {
128
+ return capitalize(randomWord(seed, salt));
129
+ }
130
+ /** Sequential deterministic RNG. Consumes salts in call order, mirroring Python's `random.*`. */
131
+ var Rng = class {
132
+ seed;
133
+ scope;
134
+ counter = 0;
135
+ constructor(seed, scope) {
136
+ this.seed = seed;
137
+ this.scope = scope;
138
+ }
139
+ salt() {
140
+ const value = `${this.scope}:${this.counter}`;
141
+ this.counter += 1;
142
+ return value;
143
+ }
144
+ int(min, max) {
145
+ return seededInt(this.seed, this.salt(), min, max);
146
+ }
147
+ pick(list) {
148
+ return list[this.int(0, list.length - 1)];
149
+ }
150
+ word() {
151
+ return randomWord(this.seed, this.salt());
152
+ }
153
+ wordTitle() {
154
+ return capitalize(this.word());
155
+ }
156
+ wordUpper() {
157
+ return this.word().toUpperCase();
158
+ }
159
+ /** Deterministic `random.sample(list, k)` (Fisher-Yates partial shuffle). */
160
+ sample(list, k) {
161
+ const items = [...list];
162
+ const count = Math.min(Math.max(0, k), items.length);
163
+ for (let i = 0; i < count; i += 1) {
164
+ const j = i + this.int(0, items.length - 1 - i);
165
+ const swap = items[i];
166
+ items[i] = items[j];
167
+ items[j] = swap;
168
+ }
169
+ return items.slice(0, count);
170
+ }
171
+ };
172
+ function dateString(rng) {
173
+ const year = rng.int(2018, 2026);
174
+ const month = rng.int(1, 12);
175
+ const day = rng.int(1, 28);
176
+ return `${year}/${String(month).padStart(2, "0")}/${String(day).padStart(2, "0")}`;
177
+ }
178
+ const OBJC_FUN_HEAD_LIST = [
179
+ "void",
180
+ "CGFloat",
181
+ "CGRect",
182
+ "NSInteger",
183
+ "NSString",
184
+ "NSArray",
185
+ "NSDictionary",
186
+ "NSNumber",
187
+ "NSURL",
188
+ "NSIndexPath",
189
+ "UIView",
190
+ "UIButton",
191
+ "UIDatePicker",
192
+ "UITextField",
193
+ "UISwitch",
194
+ "UISlider",
195
+ "UILabel",
196
+ "UIImageView",
197
+ "UIFont",
198
+ "UIColor"
199
+ ];
200
+ const SWIFT_FUN_HEAD_LIST = [
201
+ "Void",
202
+ "Bool",
203
+ "CGFloat",
204
+ "CGRect",
205
+ "NSInteger",
206
+ "NSString",
207
+ "NSArray",
208
+ "NSDictionary",
209
+ "UIImage",
210
+ "NSURL",
211
+ "UIView",
212
+ "UIButton",
213
+ "UIDatePicker",
214
+ "UITextField",
215
+ "UISwitch",
216
+ "UISlider",
217
+ "UILabel",
218
+ "UIImageView",
219
+ "UIFont",
220
+ "UIColor"
221
+ ];
222
+ const SPORT_OBJ_LIST = [
223
+ "NSObject",
224
+ "UIView",
225
+ "UIViewController"
226
+ ];
227
+ const OBJC_NO_STARS = [
228
+ "void",
229
+ "CGFloat",
230
+ "CGRect",
231
+ "NSInteger"
232
+ ];
233
+ const OBJC_ASSIGN = [
234
+ "BOOL",
235
+ "CGFloat",
236
+ "CGRect",
237
+ "NSInteger"
238
+ ];
239
+ const OBJC_COPY = [
240
+ "NSString",
241
+ "NSArray",
242
+ "NSDictionary",
243
+ "UIImage",
244
+ "NSNumber",
245
+ "NSURL",
246
+ "NSIndexPath"
247
+ ];
248
+ const SWIFT_VAR_LIST = [
249
+ "BOOL",
250
+ "CGFloat",
251
+ "CGRect",
252
+ "NSInteger",
253
+ "NSString",
254
+ "UIColor",
255
+ "UIFont",
256
+ "NSURL"
257
+ ];
258
+ const PRO_COUNT = 3;
259
+ function newRegistry() {
260
+ return {
261
+ unused: /* @__PURE__ */ new Map(),
262
+ used: /* @__PURE__ */ new Map()
263
+ };
264
+ }
265
+ /** Generate a garbage ObjC class name from an existing name. */
266
+ function objcGetMissObjName(oldObjName, seed, salt = "objc-name") {
267
+ let kept = (oldObjName.includes("+") ? oldObjName.split("+").at(-1) : oldObjName).replace(/[A-Z]/g, (match) => `_${match}`).split("_").filter((item) => item.length > 2);
268
+ if (kept.length > 2) kept = kept.slice(-2);
269
+ if (kept.length <= 2) kept.unshift(randomWordTitle(seed, `${salt}:pre`));
270
+ kept.unshift(randomWordTitle(seed, `${salt}:head`));
271
+ return kept.join("");
272
+ }
273
+ /** Generate a garbage Swift class name from an existing name. */
274
+ function swiftGetMissObjName(oldObjName, seed, salt = "swift-name") {
275
+ const title = randomWordTitle(seed, `${salt}:a`) + randomWordTitle(seed, `${salt}:b`);
276
+ if (title.includes(DEFAULT_RUB_PREFIX)) return title;
277
+ const lower = oldObjName.toLowerCase();
278
+ if (oldObjName.endsWith("View") || oldObjName.endsWith("view")) return `${title}View`;
279
+ if (lower.endsWith("controller") || lower.endsWith("control") || lower.endsWith("controll")) return `${title}Controller`;
280
+ if (oldObjName.endsWith("Cell") || oldObjName.endsWith("cell")) return `${title}Cell`;
281
+ if (oldObjName.endsWith("Model") || oldObjName.endsWith("model")) return `${title}Model`;
282
+ if (lower.includes("tool")) return `${title}Tools`;
283
+ if (oldObjName.endsWith("Label") || oldObjName.endsWith("label")) return `${title}Label`;
284
+ if (lower.endsWith("button") || lower.endsWith("btn")) return `${title}Button`;
285
+ if (oldObjName.endsWith("Manager") || oldObjName.endsWith("manager")) return `${title}Manager`;
286
+ if (oldObjName.endsWith("Handler") || oldObjName.endsWith("handler")) return `${title}Handler`;
287
+ if (oldObjName.endsWith("Operation") || oldObjName.endsWith("operation")) return `${title}Operation`;
288
+ if (oldObjName.startsWith("UI") || oldObjName.startsWith("CG") || oldObjName.startsWith("NS")) return `${randomWordTitle(seed, `${salt}:c`)}${oldObjName.slice(2)}`;
289
+ return `${title}Obj`;
290
+ }
291
+ function objcColor(rng) {
292
+ return `[UIColor colorWithRed:${rng.int(0, 255)}/255.0 green:${rng.int(0, 255)}/255.0 blue:${rng.int(0, 255)}/255.0 alpha:1.0]`;
293
+ }
294
+ function objcMethodName(rng, returnValue, rubPrefix) {
295
+ let suffix;
296
+ if (returnValue === "void") suffix = "Fun";
297
+ else if (returnValue.startsWith("CG")) suffix = returnValue.slice(2);
298
+ else suffix = "";
299
+ const name = rng.int(0, 1) === 0 ? rng.word() + capitalize(rng.word()) + suffix : rng.word() + capitalize(rng.word()) + capitalize(rng.word()) + suffix;
300
+ const prefixed = rubPrefix.length > 0 ? rubPrefix + name : name;
301
+ return `- (${returnValue}${OBJC_NO_STARS.includes(returnValue) ? "" : " *"})${prefixed}`;
302
+ }
303
+ function objcParameterTuple(rng, state) {
304
+ const parameterList = [];
305
+ const parameterMap = /* @__PURE__ */ new Map();
306
+ const count = rng.int(1, 3);
307
+ for (let index = 0; index < count; index += 1) {
308
+ let type = OBJC_FUN_HEAD_LIST[rng.int(1, OBJC_FUN_HEAD_LIST.length - 1)];
309
+ if (parameterMap.has(type)) type = OBJC_FUN_HEAD_LIST[rng.int(1, OBJC_FUN_HEAD_LIST.length - 1)];
310
+ let name;
311
+ if (parameterMap.has(type) || state.rubProMap.has(type)) name = state.rubProMap.get(type) ?? parameterMap.get(type);
312
+ else if (type === "void") name = rng.word() + capitalize(rng.word());
313
+ else if (type.startsWith("CG")) name = rng.word() + type.slice(2);
314
+ else name = rng.word() + capitalize(rng.word());
315
+ const stars = OBJC_NO_STARS.includes(type) ? "" : " *";
316
+ const parameter = index === 0 ? `:(${type}${stars})${name}` : `${name}:(${type}${stars})${name}`;
317
+ parameterList.push(parameter);
318
+ if (!state.rubProMap.has(type)) state.rubProMap.set(type, name);
319
+ parameterMap.set(type, name);
320
+ }
321
+ return {
322
+ paramString: parameterList.join(" "),
323
+ paramMap: parameterMap
324
+ };
325
+ }
326
+ const OBJC_BORDER_STYLES = [
327
+ "UITextBorderStyleNone",
328
+ "UITextBorderStyleLine",
329
+ "UITextBorderStyleBezel",
330
+ "UITextBorderStyleRoundedRect"
331
+ ];
332
+ const OBJC_CONTENT_MODES = [
333
+ "UIViewContentModeScaleToFill",
334
+ "UIViewContentModeScaleAspectFit",
335
+ "UIViewContentModeScaleAspectFill",
336
+ "UIViewContentModeRedraw",
337
+ "UIViewContentModeCenter",
338
+ "UIViewContentModeTop",
339
+ "UIViewContentModeBottom",
340
+ "UIViewContentModeLeft",
341
+ "UIViewContentModeRight",
342
+ "UIViewContentModeTopLeft",
343
+ "UIViewContentModeTopRight",
344
+ "UIViewContentModeBottomLeft",
345
+ "UIViewContentModeBottomRight"
346
+ ];
347
+ const OBJC_H_ALIGNMENTS = [
348
+ "UIControlContentHorizontalAlignmentCenter",
349
+ "UIControlContentHorizontalAlignmentLeft",
350
+ "UIControlContentHorizontalAlignmentRight",
351
+ "UIControlContentHorizontalAlignmentFill",
352
+ "UIControlContentHorizontalAlignmentLeading",
353
+ "UIControlContentHorizontalAlignmentTrailing"
354
+ ];
355
+ const OBJC_V_ALIGNMENTS = [
356
+ "UIControlContentVerticalAlignmentCenter",
357
+ "UIControlContentVerticalAlignmentTop",
358
+ "UIControlContentVerticalAlignmentBottom",
359
+ "UIControlContentVerticalAlignmentFill"
360
+ ];
361
+ function objcUISegmentedControlCode(rng, praName) {
362
+ const b = " ";
363
+ const code = [
364
+ `${b}${praName}.backgroundColor = ${objcColor(rng)};\n`,
365
+ `${b}${praName}.alpha = 0.1;\n`,
366
+ `${b}${praName}.contentMode = ${rng.pick(OBJC_CONTENT_MODES)};\n`,
367
+ `${b}${praName}.contentHorizontalAlignment = ${rng.pick(OBJC_H_ALIGNMENTS)};\n`,
368
+ `${b}${praName}.contentVerticalAlignment = ${rng.pick(OBJC_V_ALIGNMENTS)};\n`,
369
+ `${b}${praName}.tag = ${rng.int(0, 1e3)};\n`,
370
+ `${b}//设置sc的位置大小\n${b}${praName}.frame = CGRectMake(${rng.int(0, 1e3)}, ${rng.int(0, 1e3)}, ${rng.int(0, 1e3)}, ${rng.int(0, 1e3)});\n`,
371
+ `${b}//设置颜色\n${b}${praName}.tintColor = ${objcColor(rng)};\n`,
372
+ `${b}//设置sc当前停留的段\n${b}${praName}.selectedSegmentIndex = 1;\n`
373
+ ];
374
+ return rng.sample(code, PRO_COUNT).join("");
375
+ }
376
+ function objcUIButtonCode(rng, praName) {
377
+ const b = " ";
378
+ const code = [
379
+ `${b}${praName}.backgroundColor = ${objcColor(rng)};\n`,
380
+ `${b}${praName}.tintColor = ${objcColor(rng)};\n`,
381
+ `${b}${praName}.alpha = 0.1;\n`,
382
+ `${b}${praName}.contentMode = ${rng.pick(OBJC_CONTENT_MODES)};\n`,
383
+ `${b}${praName}.contentHorizontalAlignment = ${rng.pick(OBJC_H_ALIGNMENTS)};\n`,
384
+ `${b}${praName}.contentVerticalAlignment = ${rng.pick(OBJC_V_ALIGNMENTS)};\n`,
385
+ `${b}${praName}.tag = ${rng.int(0, 1e3)};\n`,
386
+ `${b}[${praName} setTitle:@"${rng.word()}${capitalize(rng.word())}" forState:UIControlStateNormal];\n`,
387
+ `${b}[${praName} setTitleColor:${objcColor(rng)} forState:UIControlStateNormal];\n`,
388
+ `${b}${praName}.titleLabel.font = [UIFont systemFontOfSize:${rng.int(10, 20)}];\n`
389
+ ];
390
+ return rng.sample(code, PRO_COUNT).join("");
391
+ }
392
+ function objcUISwitchCode(rng, praName) {
393
+ const b = " ";
394
+ const code = [
395
+ `${b}${praName}.backgroundColor = ${objcColor(rng)};\n`,
396
+ `${b}${praName}.alpha = 0.1;\n`,
397
+ `${b}${praName}.contentMode = ${rng.pick(OBJC_CONTENT_MODES)};\n`,
398
+ `${b}${praName}.contentHorizontalAlignment = ${rng.pick(OBJC_H_ALIGNMENTS)};\n`,
399
+ `${b}${praName}.contentVerticalAlignment = ${rng.pick(OBJC_V_ALIGNMENTS)};\n`,
400
+ `${b}${praName}.tag = ${rng.int(0, 1e3)};\n`,
401
+ `${b}//设置初始状态(默认状态为NO)\n${b}${praName}.on = YES;\n`,
402
+ `${b}//设置按钮处于关闭状态时边框的颜色\n${b}${praName}.tintColor = ${objcColor(rng)};\n`,
403
+ `${b}//设置开关处于开启时的状态\n${b}${praName}.onTintColor = ${objcColor(rng)};\n`,
404
+ `${b}//设置开关的状态钮颜色\n${b}${praName}.thumbTintColor = ${objcColor(rng)};\n`
405
+ ];
406
+ return rng.sample(code, PRO_COUNT).join("");
407
+ }
408
+ function objcUIControlCode(rng, praName) {
409
+ const b = " ";
410
+ const code = [
411
+ `${b}${praName}.backgroundColor = ${objcColor(rng)};\n`,
412
+ `${b}${praName}.alpha = 0.1;\n`,
413
+ `${b}${praName}.contentMode = ${rng.pick(OBJC_CONTENT_MODES)};\n`,
414
+ `${b}${praName}.contentHorizontalAlignment = ${rng.pick(OBJC_H_ALIGNMENTS)};\n`,
415
+ `${b}${praName}.contentVerticalAlignment = ${rng.pick(OBJC_V_ALIGNMENTS)};\n`,
416
+ `${b}${praName}.tag = ${rng.int(0, 1e3)};\n`,
417
+ `${b}//设置字体颜色\n${b}${praName}.tintColor = ${objcColor(rng)};\n`
418
+ ];
419
+ return rng.sample(code, PRO_COUNT).join("");
420
+ }
421
+ function objcUIImageViewCode(rng, praName) {
422
+ const b = " ";
423
+ const code = [
424
+ `${b}${praName}.backgroundColor = ${objcColor(rng)};\n`,
425
+ `${b}${praName}.alpha = 0.1;\n`,
426
+ `${b}${praName}.contentMode = ${rng.pick(OBJC_CONTENT_MODES)};\n`,
427
+ `${b}${praName}.tag = ${rng.int(0, 1e3)};\n`,
428
+ `${b}//边框\n${b}${praName}.layer.borderWidth = 1;\n`,
429
+ `${b}${praName}.layer.borderColor = ${objcColor(rng)}.CGColor;\n`,
430
+ `${b}//裁剪\n${b}${praName}.clipsToBounds = YES;\n`,
431
+ `${b}//缩放图片填充满UIImageView\n${b}${praName}.contentMode = UIViewContentModeScaleToFill;\n`
432
+ ];
433
+ return rng.sample(code, PRO_COUNT).join("");
434
+ }
435
+ function objcUITextFieldCode(rng, praName) {
436
+ const b = " ";
437
+ const code = [
438
+ `${b}${praName}.backgroundColor = ${objcColor(rng)};\n`,
439
+ `${b}${praName}.alpha = 0.1;\n`,
440
+ `${b}${praName}.contentMode = ${rng.pick(OBJC_CONTENT_MODES)};\n`,
441
+ `${b}${praName}.contentHorizontalAlignment = ${rng.pick(OBJC_H_ALIGNMENTS)};\n`,
442
+ `${b}${praName}.contentVerticalAlignment = ${rng.pick(OBJC_V_ALIGNMENTS)};\n`,
443
+ `${b}${praName}.tag = ${rng.int(0, 1e3)};\n`,
444
+ `${b}//设置占位文本\n${b}${praName}.placeholder = @"请输入文字";\n`,
445
+ `${b}//设置文本\n${b}${praName}.text = @"${rng.word()}${capitalize(rng.word())}";\n`,
446
+ `${b}//设置文本的颜色\n${b}${praName}.textColor = ${objcColor(rng)};\n`,
447
+ `${b}//设置文本的字体\n${b}${praName}.font = [UIFont systemFontOfSize: ${rng.int(10, 25)} ];\n`,
448
+ `${b}//设置文本的对齐方式\n${b}${praName}.textAlignment = NSTextAlignmentRight;\n`,
449
+ `${b}//设置边框样式(更多边框样式到补充说明中查看)默认的样式为UITextBorderStyleNone\n${b}${praName}.borderStyle = ${rng.pick(OBJC_BORDER_STYLES)};\n`
450
+ ];
451
+ return rng.sample(code, PRO_COUNT).join("");
452
+ }
453
+ function objcUIDatePickerCode(rng, praName) {
454
+ const b = " ";
455
+ const code = [
456
+ `${b}${praName}.backgroundColor = ${objcColor(rng)};\n`,
457
+ `${b}${praName}.tintColor = ${objcColor(rng)};\n`,
458
+ `${b}${praName}.alpha = 0.1;\n`,
459
+ `${b}${praName}.contentMode = ${rng.pick(OBJC_CONTENT_MODES)};\n`,
460
+ `${b}${praName}.contentHorizontalAlignment = ${rng.pick(OBJC_H_ALIGNMENTS)};\n`,
461
+ `${b}${praName}.contentVerticalAlignment = ${rng.pick(OBJC_V_ALIGNMENTS)};\n`,
462
+ `${b}${praName}.tag = ${rng.int(0, 1e3)};\n`,
463
+ `${b}//设置地区: zh-中国\n${b}${praName}.locale = [NSLocale localeWithLocaleIdentifier:@"zh"];\n`,
464
+ `${b}//设置日期模式(Displays month, day, and year depending on the locale setting)\n${b}${praName}.datePickerMode = UIDatePickerModeCountDownTimer;\n`,
465
+ `${b}// 设置当前显示时间\n${b}[${praName} setDate:[NSDate date] animated:YES];\n`,
466
+ `${b}// 设置显示最大时间(此处为当前时间)\n${b}[${praName} setMaximumDate:[NSDate date]];\n`
467
+ ];
468
+ return rng.sample(code, PRO_COUNT).join("");
469
+ }
470
+ function objcUIPageControlCode(rng, praName) {
471
+ const b = " ";
472
+ const code = [
473
+ `${b}${praName}.backgroundColor = ${objcColor(rng)};\n`,
474
+ `${b}${praName}.tintColor = ${objcColor(rng)};\n`,
475
+ `${b}${praName}.alpha = 0.1;\n`,
476
+ `${b}${praName}.contentMode = ${rng.pick(OBJC_CONTENT_MODES)};\n`,
477
+ `${b}${praName}.contentHorizontalAlignment = ${rng.pick(OBJC_H_ALIGNMENTS)};\n`,
478
+ `${b}${praName}.contentVerticalAlignment = ${rng.pick(OBJC_V_ALIGNMENTS)};\n`,
479
+ `${b}${praName}.tag = ${rng.int(0, 1e3)};\n`,
480
+ `${b}//设置小白点的个数\n${b}${praName}.numberOfPages = ${rng.int(0, 10)};\n`,
481
+ `${b}//设置当前选中的点\n${b}${praName}.currentPage = 0;\n`,
482
+ `${b}//设置当前选中的小白点的颜色\n${b}${praName}.currentPageIndicatorTintColor = ${objcColor(rng)};\n`,
483
+ `${b}//设置未选中小白点的颜色\n${b}${praName}.pageIndicatorTintColor = ${objcColor(rng)};\n`,
484
+ `${b}//用于控制是否只有一个页面时隐藏页面控件(默认值为NO)\n${b}${praName}.hidesForSinglePage = YES;\n`
485
+ ];
486
+ return rng.sample(code, PRO_COUNT).join("");
487
+ }
488
+ function objcUICollectionViewFlowLayoutCode(rng, layout) {
489
+ const b = " ";
490
+ const code = [
491
+ `${b}//设置item的行间距和列间距\n${b}${layout}.minimumInteritemSpacing = ${rng.int(5, 20)};\n`,
492
+ `${b}${layout}.minimumLineSpacing = ${rng.int(5, 20)};\n`,
493
+ `${b}//设置每个分区的 上左下右 的内边距\n${b}${layout}.sectionInset = UIEdgeInsetsMake(${rng.int(0, 10)}, ${rng.int(0, 10)} ,${rng.int(0, 10)}, ${rng.int(0, 10)});\n`,
494
+ `${b}//设置区头和区尾的大小\n${b}${layout}.headerReferenceSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, ${rng.int(50, 100)});\n`,
495
+ `${b}${layout}.footerReferenceSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, ${rng.int(50, 100)});\n`,
496
+ `${b}//设置分区的头视图和尾视图 是否始终固定在屏幕上边和下边\n${b}${layout}.sectionFootersPinToVisibleBounds = YES;\n`,
497
+ `${b}//设置滚动条方向\n${b}${layout}.scrollDirection = UICollectionViewScrollDirectionVertical;\n`
498
+ ];
499
+ return rng.sample(code, PRO_COUNT).join("");
500
+ }
501
+ function objcUICollectionViewCode(rng, praName) {
502
+ const b = " ";
503
+ const code = [
504
+ `${b}${praName}.backgroundColor = ${objcColor(rng)};\n`,
505
+ `${b}${praName}.alpha = 0.1;\n`,
506
+ `${b}${praName}.contentMode = ${rng.pick(OBJC_CONTENT_MODES)};\n`,
507
+ `${b}${praName}.tag = ${rng.int(0, 1e3)};\n`,
508
+ `${b}${praName}.showsVerticalScrollIndicator = NO; //是否显示滚动条\n`,
509
+ `${b}${praName}.scrollEnabled = YES; //滚动使能\n`
510
+ ];
511
+ return rng.sample(code, PRO_COUNT).join("");
512
+ }
513
+ function objcUILabelCode(rng, praName) {
514
+ const b = " ";
515
+ const code = [
516
+ `${b}${praName}.backgroundColor = ${objcColor(rng)};\n`,
517
+ `${b}${praName}.alpha = 0.1;\n`,
518
+ `${b}${praName}.contentMode = ${rng.pick(OBJC_CONTENT_MODES)};\n`,
519
+ `${b}${praName}.tag = ${rng.int(0, 1e3)};\n`,
520
+ `${b}//设置label的文字\n${b}${praName}.text = @"${rng.word()}${capitalize(rng.word())}";\n`,
521
+ `${b}//设置label的字体\n${b}${praName}.font = [UIFont systemFontOfSize:${rng.int(10, 25)}];\n`,
522
+ `${b}//设置label的颜色\n${b}${praName}.textColor = ${objcColor(rng)};\n`,
523
+ `${b}//设置label的阴影颜色和偏移\n${b}${praName}.shadowColor = ${objcColor(rng)};\n`,
524
+ `${b}${praName}.shadowOffset = CGSizeMake(${rng.int(10, 25)}, ${rng.int(10, 25)});\n`,
525
+ `${b}//设置文字对齐方式\n${b}${praName}.textAlignment = NSTextAlignmentLeft;//文字居中\n`,
526
+ `${b}//设置文案的换行模式\n${b}${praName}.lineBreakMode = NSLineBreakByTruncatingTail;//截取末尾\n`,
527
+ `${b}//设置高亮状态相关\n${b}${praName}.highlightedTextColor = ${objcColor(rng)};\n`,
528
+ `${b}${praName}.highlighted = YES;\n`,
529
+ `${b}//表示显示任意行\n${b}${praName}.numberOfLines = 0;\n`,
530
+ `${b}//设置label是否自适应字体大小\n${b}${praName}.adjustsFontSizeToFitWidth = YES;\n`,
531
+ `${b}//设置最小缩放字体(当adjustsFontSizeToFitWidth= YES,指定了最小缩放字体)\n${b}${praName}.minimumScaleFactor = 20;\n`,
532
+ `${b}//label截断是否紧缩文字\n${b}${praName}.allowsDefaultTighteningForTruncation = YES;\n`
533
+ ];
534
+ return rng.sample(code, PRO_COUNT).join("");
535
+ }
536
+ function objcUISliderCode(rng, praName) {
537
+ const b = " ";
538
+ const code = [
539
+ `${b}${praName}.backgroundColor = ${objcColor(rng)};\n`,
540
+ `${b}${praName}.alpha = 0.1;\n`,
541
+ `${b}${praName}.contentMode = ${rng.pick(OBJC_CONTENT_MODES)};\n`,
542
+ `${b}${praName}.contentHorizontalAlignment = ${rng.pick(OBJC_H_ALIGNMENTS)};\n`,
543
+ `${b}${praName}.contentVerticalAlignment = ${rng.pick(OBJC_V_ALIGNMENTS)};\n`,
544
+ `${b}${praName}.tag = ${rng.int(0, 1e3)};\n`,
545
+ `${b}// minimumValue : 当值可以改变时,滑块可以滑动到最小位置的值,默认为0.0\n${b}${praName}.minimumValue = 0.0;\n`,
546
+ `${b}//当值可以改变时,滑块可以滑动到最大位置的值,默认为1.0\n${b}${praName}.maximumValue = 100.0;\n`,
547
+ `${b}//当前值,这个值是介于滑块的最大值和最小值之间的,如果没有设置边界值,默认为0-1;\n${b}${praName}.value = 50;\n`,
548
+ `${b}//小于滑块当前值滑块条的颜色\n${b}${praName}.minimumTrackTintColor = ${objcColor(rng)};\n`,
549
+ `${b}//大于滑块当前值滑块条的颜色\n${b}${praName}.maximumTrackTintColor = ${objcColor(rng)};\n`,
550
+ `${b}//当前滑块的颜色,默认为白色\n${b}${praName}.thumbTintColor = ${objcColor(rng)};\n`,
551
+ `${b}// 小于滑块当前值滑块条的颜色\n${b}${praName}.minimumTrackTintColor = ${objcColor(rng)};\n`,
552
+ `${b}//大于滑块当前值滑块条的颜色\n${b}${praName}.maximumTrackTintColor = ${objcColor(rng)};\n`
553
+ ];
554
+ return rng.sample(code, PRO_COUNT).join("");
555
+ }
556
+ function objcCodeByObject(rng, praObjName, praName) {
557
+ const blank = " ";
558
+ const b = " ";
559
+ let code = "";
560
+ if (praObjName === "UIView") code += `${blank}if(${praName} != nil){\n${b}${praName}.backgroundColor = ${objcColor(rng)};\n${b}${praName}.alpha = 0.1;\n${b}${praName}.contentMode = ${rng.pick(OBJC_CONTENT_MODES)};\n${b}${praName}.tag = ${rng.int(0, 1e3)};\n${blank}}else{\n${b}${praName} = [[${praObjName} alloc] init];\n${blank}}\n`;
561
+ else if (praObjName === "UIButton") code += `${blank}if(${praName} != nil){\n${objcUIButtonCode(rng, praName)}${blank}}else{\n${b}${praName} = [[${praObjName} alloc] init];\n${blank}}\n`;
562
+ else if (praObjName === "UIDatePicker") code += `${blank}if(${praName} != nil){\n${objcUIDatePickerCode(rng, praName)}${blank}}else{\n${b}${praName} = [[${praObjName} alloc] init];\n${blank}}\n`;
563
+ else if (praObjName === "UIPageControl") code += `${blank}if(${praName} != nil){\n${objcUIPageControlCode(rng, praName)}${blank}}else{\n${b}${praName} = [[${praObjName} alloc] init];\n${blank}}\n`;
564
+ else if (praObjName === "UISegmentedControl") code += `${blank}if(${praName} != nil){\n${objcUISegmentedControlCode(rng, praName)}${blank}}else{\n${b}//创建一个数组\n${b}NSArray *${rng.word()}Array = @[@"${rng.word()}",@"${rng.word()}",@"${rng.word()}",@"${rng.word()}"];\n${b}${praName} = [[${praObjName} alloc] initWithItems:${rng.word()}Array];\n${blank}}\n`;
565
+ else if (praObjName === "UITextField") code += `${blank}if(${praName} != nil){\n${objcUITextFieldCode(rng, praName)}${blank}}else{\n${b}${praName} = [[${praObjName} alloc] init];\n${blank}}\n`;
566
+ else if (praObjName === "UISwitch") code += `${blank}if(${praName} != nil){\n${objcUISwitchCode(rng, praName)}${blank}}else{\n${b}${praName} = [[${praObjName} alloc] init];\n${blank}}\n`;
567
+ else if (praObjName === "UISlider") code += `${blank}if(${praName} != nil){\n${objcUISliderCode(rng, praName)}${blank}}else{\n${b}${praName} = [[${praObjName} alloc] init];\n${blank}}\n`;
568
+ else if (praObjName === "UIControl") code += `${blank}if(${praName} != nil){\n${objcUIControlCode(rng, praName)}${blank}}else{\n${b}${praName} = [[${praObjName} alloc] init];\n${blank}}\n`;
569
+ else if (praObjName === "UIImageView") code += `${blank}if(${praName} != nil){\n${objcUIImageViewCode(rng, praName)}${blank}}else{\n${b}${praName} = [[${praObjName} alloc] init];\n${blank}}\n`;
570
+ else if (praObjName === "UIViewController") code += `${blank}if(${praName} != nil){\n${b}${praName}.view.backgroundColor = ${objcColor(rng)};\n${blank}}else{\n${b}${praName} = [[${praObjName} alloc] init];\n${blank}}\n`;
571
+ else if (praObjName === "UICollectionView") {
572
+ const layout = `${rng.word()}Layout`;
573
+ code += `${blank}if(${praName} != nil){\n${objcUICollectionViewCode(rng, praName)}${blank}}else{\n${b}UICollectionViewFlowLayout *${layout} = [[UICollectionViewFlowLayout alloc] init];\n${objcUICollectionViewFlowLayoutCode(rng, layout)}${b}//${praName} 初始化\n${b}${praName} = [[${praObjName} alloc] initWithFrame:CGRectZero collectionViewLayout:${layout}];\n${blank}}\n`;
574
+ } else if (praObjName === "UILabel") code += `${blank}if(${praName} == nil){\n${b}${praName} = [[${praObjName} alloc] init];\n${blank}}\n${objcUILabelCode(rng, praName)}`;
575
+ else if (praObjName === "UIColor") code += `${blank}${praName} = [UIColor colorWithRed:${rng.int(0, 255)}/255 green:${rng.int(0, 255)}/255 blue:${rng.int(0, 255)}/255 alpha:1];\n`;
576
+ else if (praObjName === "UIFont") code += `${blank}if(${praName} != nil){\n${b}${praName} = [UIFont systemFontOfSize:${rng.int(10, 25)}];\n${blank}}else{\n${b}//pass\n${blank}}\n`;
577
+ else if (praObjName === "Void") {} else if (praObjName === "CGFloat") code += `${blank}${praName} = ${rng.int(0, 2e3)}.00;\n`;
578
+ else if (praObjName === "CGRect") code += `${blank}${praName} = CGRectMake(${rng.int(0, 200)}, ${rng.int(0, 200)}, ${rng.int(0, 200)}, ${rng.int(0, 200)});\n`;
579
+ else if (praObjName === "NSInteger") code += `${blank}${praName} = ${rng.int(0, 200)};\n`;
580
+ else if (praObjName === "NSString") code += `${blank}${praName} = @"${rng.word()}${capitalize(rng.word())}";\n`;
581
+ else if (praObjName === "NSArray") code += `${blank}${praName} = @[@"${rng.word()}", @"${rng.word()}", @"${rng.word()}", @"${rng.word()}"];\n`;
582
+ else if (praObjName === "NSDictionary") code += `${blank}${praName} = @{@"${rng.word()}":@"${rng.word()}", @"${rng.word()}":@"${rng.word()}", @"${rng.word()}":@"${rng.word()}"};\n`;
583
+ else if (praObjName === "NSNumber") code += `${blank}${praName} = [NSNumber numberWithInt:${rng.int(0, 200)}];\n`;
584
+ else if (praObjName === "NSURL") code += `${blank}${praName} = [NSURL URLWithString:@"https://www.${rng.word()}.com/${rng.word()}/${rng.word()}"];\n`;
585
+ else if (praObjName === "NSIndexPath") code += `${blank}${praName} = [NSIndexPath indexPathWithIndex:${rng.int(0, 200)}];\n`;
586
+ code += "\n";
587
+ return code;
588
+ }
589
+ function objcDetailImport(rng, state, className, classFunList, thisParamMap) {
590
+ const blank = " ";
591
+ const classFun = classFunList[rng.int(0, classFunList.length - 1)];
592
+ const classPraName = rng.word() + capitalize(rng.word());
593
+ let code = `${blank}${className} *${classPraName} = [[${className} alloc] init];\n`;
594
+ let importCode = "";
595
+ const parts = classFun.split(":");
596
+ for (let index = 0; index < parts.length; index += 1) {
597
+ let item = parts[index];
598
+ if (item.includes(";")) item = item.replace(/;/g, "");
599
+ if (item.includes("*")) item = item.replace(/\*/g, "");
600
+ if (index === 0) {
601
+ importCode += item.slice(item.indexOf(")") + 1).trim();
602
+ continue;
603
+ }
604
+ const open = item.indexOf("(");
605
+ const close = item.indexOf(")");
606
+ const praObjName = item.slice(open + 1, close).trim();
607
+ let praName = item.slice(close + 1).trim();
608
+ if (praName.includes(" ")) praName = praName.split(" ")[0];
609
+ if (thisParamMap.has(praObjName)) importCode += index === 1 ? `:${thisParamMap.get(praObjName)}` : `${praName}:${thisParamMap.get(praObjName)}`;
610
+ else if (!OBJC_NO_STARS.includes(praObjName)) code += `${blank}${praObjName} *${praName};\n`;
611
+ else code += `${blank}${praObjName} ${praName};\n`;
612
+ code += objcCodeByObject(rng, praObjName, praName);
613
+ importCode += index === 1 ? `:${praName}` : `${praName}:${praName}`;
614
+ if (index !== parts.length - 1) importCode += " ";
615
+ }
616
+ code += `${blank}[${classPraName} ${importCode}];\n`;
617
+ if (!state.headerFiles.includes(className)) state.headerFiles.push(className);
618
+ return code;
619
+ }
620
+ function objcImportCode(rng, state, thisParamMap) {
621
+ let code = "";
622
+ if (state.registry.unused.size > 0) {
623
+ const keys = [...state.registry.unused.keys()];
624
+ const className = keys[rng.int(0, keys.length - 1)];
625
+ const funList = state.registry.unused.get(className);
626
+ code += objcDetailImport(rng, state, className, funList, thisParamMap);
627
+ state.registry.unused.delete(className);
628
+ state.registry.used.set(className, funList);
629
+ } else if (state.registry.used.size > 0) {
630
+ const keys = [...state.registry.used.keys()];
631
+ const className = keys[rng.int(0, keys.length - 1)];
632
+ code += objcDetailImport(rng, state, className, state.registry.used.get(className), thisParamMap);
633
+ }
634
+ code += "\n";
635
+ return code;
636
+ }
637
+ function createObjCMethod(rng, rubPrefix, state) {
638
+ const blank = " ";
639
+ const returnValue = rng.pick(OBJC_FUN_HEAD_LIST);
640
+ let returnCode;
641
+ const funName = objcMethodName(rng, returnValue, rubPrefix);
642
+ const { paramString, paramMap } = objcParameterTuple(rng, state);
643
+ const hDeclaration = `${funName}${paramString};`;
644
+ let methodCode = `${funName}${paramString}{\n`;
645
+ const thisParamMap = /* @__PURE__ */ new Map();
646
+ for (const [praObjName, praName] of paramMap) {
647
+ if (praObjName === returnValue) returnCode = praName;
648
+ methodCode += objcCodeByObject(rng, praObjName, praName);
649
+ thisParamMap.set(praObjName, praName);
650
+ }
651
+ methodCode += objcImportCode(rng, state, thisParamMap);
652
+ if (returnValue !== "void") {
653
+ if (returnCode !== void 0) methodCode += `${blank}return ${returnCode};\n`;
654
+ else {
655
+ const praName = rng.word() + capitalize(rng.word());
656
+ if (!OBJC_NO_STARS.includes(returnValue)) methodCode += `${blank}${returnValue} *${praName};\n`;
657
+ else methodCode += `${blank}${returnValue} ${praName};\n`;
658
+ methodCode += objcCodeByObject(rng, returnValue, praName);
659
+ methodCode += `${blank}return ${praName};\n`;
660
+ }
661
+ }
662
+ methodCode += "}\n\n";
663
+ return {
664
+ methodCode,
665
+ hDeclaration
666
+ };
667
+ }
668
+ function generateObjCJunkInternal(amount, rubPrefix, seed, salt, state) {
669
+ const rng = new Rng(seed, salt);
670
+ let hCode = "";
671
+ let mCode = "";
672
+ const hFunList = [];
673
+ for (let i = 0; i < amount; i += 1) {
674
+ const { methodCode, hDeclaration } = createObjCMethod(rng, rubPrefix, state);
675
+ mCode += methodCode;
676
+ hCode += `${hDeclaration}\n\n`;
677
+ hFunList.push(hDeclaration);
678
+ }
679
+ for (const [praObjName, praName] of state.rubProMap) {
680
+ let keyword = "strong";
681
+ let stars = "*";
682
+ if (OBJC_ASSIGN.includes(praObjName)) {
683
+ keyword = "assign";
684
+ stars = "";
685
+ } else if (OBJC_COPY.includes(praObjName)) keyword = " copy";
686
+ hCode += `@property (nonatomic,${keyword}) ${praObjName} ${stars}${praName};\n\n`;
687
+ }
688
+ let headerImportCode = "";
689
+ for (const className of state.headerFiles) headerImportCode += `#import "${className}.h"\n`;
690
+ return {
691
+ hCode,
692
+ mCode,
693
+ headerImportCode,
694
+ hFunList
695
+ };
696
+ }
697
+ /** Generate a garbage ObjC method body. */
698
+ function generateObjCJunk(amount, rubPrefix, seed, salt) {
699
+ return generateObjCJunkInternal(amount, rubPrefix, seed, salt, {
700
+ rubProMap: /* @__PURE__ */ new Map(),
701
+ headerFiles: [],
702
+ registry: newRegistry()
703
+ });
704
+ }
705
+ /** Generate one deterministic ObjC garbage method (declaration + body). */
706
+ function generateObjCMethod(rubPrefix, seed, salt) {
707
+ const state = {
708
+ rubProMap: /* @__PURE__ */ new Map(),
709
+ headerFiles: [],
710
+ registry: newRegistry()
711
+ };
712
+ return createObjCMethod(new Rng(seed, salt), rubPrefix, state);
713
+ }
714
+ function swiftColor(rng) {
715
+ return `UIColor.init(red: CGFloat(${rng.int(0, 255)}/255), green: CGFloat(${rng.int(0, 255)}/255), blue: CGFloat(${rng.int(0, 255)}/255), alpha: 1)`;
716
+ }
717
+ const SWIFT_CONTENT_MODES = [
718
+ "scaleToFill",
719
+ "scaleAspectFit",
720
+ "scaleAspectFill",
721
+ "redraw",
722
+ "center",
723
+ "top",
724
+ "bottom",
725
+ "left",
726
+ "right",
727
+ "topLeft",
728
+ "topRight",
729
+ "bottomLeft",
730
+ "bottomRight"
731
+ ];
732
+ function swiftUIViewList(rng, praName, selfCode) {
733
+ const b = " ";
734
+ return [
735
+ `${b}//设置坐标\n${b}${selfCode}${praName}.frame = CGRect(x:${rng.int(0, 99)}, y:${rng.int(0, 99)}, width:${rng.int(0, 99)}, height:${rng.int(0, 99)})\n`,
736
+ `${b}//设置背景颜色\n${b}${selfCode}${praName}.backgroundColor = ${swiftColor(rng)}\n`,
737
+ `${b}//将图片作为背景颜色\n${b}${selfCode}${praName}.backgroundColor = UIColor.init(patternImage: UIImage(named: "${rng.word()}Image.png")!)\n`,
738
+ `${b}//不透明度alpha\n${b}${selfCode}${praName}.alpha = 0.${rng.int(0, 99)}\n`,
739
+ `${b}//隐藏属性hidden\n${b}${selfCode}${praName}.isHidden = true\n`,
740
+ `${b}//切边属性clipsToBounds\n${b}${selfCode}${praName}.clipsToBounds = true\n`,
741
+ `${b}//是否响应用户的交互\n${b}${selfCode}${praName}.isUserInteractionEnabled = true\n`,
742
+ `${b}//contentMode\n${b}${selfCode}${praName}.contentMode = UIView.ContentMode.${rng.pick(SWIFT_CONTENT_MODES)}\n`,
743
+ `${b}//设置圆角\n${b}${selfCode}${praName}.layer.masksToBounds = true\n${b}${selfCode}${praName}.layer.cornerRadius = ${rng.int(5, 20)}\n`,
744
+ `${b}//设置边框\n${b}${selfCode}${praName}.layer.borderColor = UIColor.purple.cgColor\n${b}${selfCode}${praName}.layer.borderWidth = 1.0\n`,
745
+ `${b}//设置标志值\n${b}${selfCode}${praName}.tag = ${rng.int(0, 255)}\n`,
746
+ `${b}//设置frame的center\n${b}${selfCode}${praName}.center = CGPoint(x: ${rng.int(0, 255)}, y: ${rng.int(0, 255)})\n`
747
+ ];
748
+ }
749
+ function swiftUILabelCode(rng, praName, selfCode) {
750
+ const b = " ";
751
+ const code = swiftUIViewList(rng, praName, selfCode);
752
+ code.push(`${b}//字体\n${b}${selfCode}${praName}.font = UIFont.systemFont(ofSize: ${rng.int(10, 30)})\n`, `${b}//字体颜色\n${b}${selfCode}${praName}.textColor = ${swiftColor(rng)}\n`, `${b}//对齐方式\n${b}${selfCode}${praName}.textAlignment = .left\n`, `${b}//多行显示\n${b}${selfCode}${praName}.numberOfLines = ${rng.int(0, 255)}\n`, `${b}//阴影\n${b}${selfCode}${praName}.shadowColor = ${swiftColor(rng)}\n${b}${selfCode}${praName}.shadowOffset = CGSize.init(width:${rng.int(0, 10)}, height:${rng.int(0, 10)})\n${b}${selfCode}${praName}.lineBreakMode = NSLineBreakMode.byTruncatingTail\n`, `${b}//高亮\n${b}${selfCode}${praName}.isHighlighted = true\n${b}${selfCode}${praName}.highlightedTextColor = ${swiftColor(rng)}\n`, `${b}//文字过长时省略方式\n${b}${selfCode}${praName}.lineBreakMode = .byTruncatingTail\n`, `${b}//当文字超出标签宽度时,自动调整文字大小,使其不被截断\n${b}${selfCode}${praName}.adjustsFontSizeToFitWidth = true\n`);
753
+ return rng.sample(code, PRO_COUNT).join("");
754
+ }
755
+ function swiftUICollectionViewCode(rng, praName, selfCode) {
756
+ const b = " ";
757
+ const code = swiftUIViewList(rng, praName, selfCode);
758
+ code.push(`${b}${selfCode}${praName}.showsVerticalScrollIndicator = false\n`);
759
+ return rng.sample(code, PRO_COUNT).join("");
760
+ }
761
+ function swiftUIViewControllerCode(rng, praName, selfCode) {
762
+ const b = " ";
763
+ return rng.sample([`${b}//设置背景颜色\n${b}${selfCode}${praName}.view.backgroundColor = ${swiftColor(rng)}\n`], 1).join("");
764
+ }
765
+ function swiftUIImageViewCode(rng, praName, selfCode) {
766
+ const b = " ";
767
+ const code = swiftUIViewList(rng, praName, selfCode);
768
+ code.push(`${b}//设置显示的图片\n${b}${selfCode}${praName}.image = UIImage(named: "${rng.word()}Image.png")\n`);
769
+ return rng.sample(code, PRO_COUNT).join("");
770
+ }
771
+ function swiftUIControlCode(rng, praName, selfCode) {
772
+ const b = " ";
773
+ const code = swiftUIViewList(rng, praName, selfCode);
774
+ code.push(`${b}//设置关闭状态的颜色\n${b}${selfCode}${praName}.tintColor = ${swiftColor(rng)}\n`);
775
+ return rng.sample(code, PRO_COUNT).join("");
776
+ }
777
+ function swiftUISliderCode(rng, praName, selfCode) {
778
+ const b = " ";
779
+ const code = swiftUIViewList(rng, praName, selfCode);
780
+ code.push(`${b}//最小值\n${b}${selfCode}${praName}.minimumValue = 0\n`, `${b}//最大值\n${b}${selfCode}${praName}.maximumValue = 1\n`, `${b}//当前值\n${b}${selfCode}${praName}.value = 0.5\n`, `${b}//左边槽的颜色\n${b}${selfCode}${praName}.minimumTrackTintColor = ${swiftColor(rng)}\n`, `${b}//右边槽的颜色\n${b}${selfCode}${praName}.maximumTrackTintColor = ${swiftColor(rng)}\n`, `${b}//左边图标\n${b}${selfCode}${praName}.minimumValueImage = UIImage(named:"${rng.word()}Image.png")\n`, `${b}//右边图标\n${b}${selfCode}${praName}.maximumValueImage = UIImage(named:"${rng.word()}Image.png")\n`);
781
+ return rng.sample(code, PRO_COUNT).join("");
782
+ }
783
+ function swiftUISwitchCode(rng, praName, selfCode) {
784
+ const b = " ";
785
+ const code = swiftUIViewList(rng, praName, selfCode);
786
+ code.push(`${b}//设置开启状态显示的颜色\n${b}${selfCode}${praName}.onTintColor = ${swiftColor(rng)}\n`, `${b}//设置关闭状态的颜色\n${b}${selfCode}${praName}.tintColor = ${swiftColor(rng)}\n`, `${b}//滑块上小圆点的颜色\n${b}${selfCode}${praName}.thumbTintColor = ${swiftColor(rng)}\n`);
787
+ return rng.sample(code, PRO_COUNT).join("");
788
+ }
789
+ function swiftUITextFieldCode(rng, praName, selfCode) {
790
+ const b = " ";
791
+ const code = swiftUIViewList(rng, praName, selfCode);
792
+ code.push(`${b}//设置边框样式为圆角矩形\n${b}${selfCode}${praName}.borderStyle = UITextField.BorderStyle.roundedRect\n`, `${b}//字体颜色\n${b}${selfCode}${praName}.textColor = ${swiftColor(rng)}\n`, `${b}//字体\n${b}${selfCode}${praName}.font = UIFont.systemFont(ofSize: ${rng.int(10, 30)})\n`, `${b}${selfCode}${praName}.textAlignment = NSTextAlignment.left\n`, `${b}//文本框提示文字\n${b}${selfCode}${praName}.placeholder = "请输入文字"\n`, `${b}//明文显示\n${b}${selfCode}${praName}.isSecureTextEntry = false\n`, `${b}//光标颜色\n${b}${selfCode}${praName}.tintColor = ${swiftColor(rng)}\n`, `${b}//当文字超出文本框宽度时,自动调整文字大小\n${b}${selfCode}${praName}.adjustsFontSizeToFitWidth = true\n`, `${b}//最小可缩小的字号\n${b}${selfCode}${praName}.minimumFontSize = ${rng.int(10, 20)}\n`, `${b}//清除按钮(输入框内右侧小叉)\n${b}${selfCode}${praName}.clearButtonMode = .whileEditing\n`, `${b}//设置文本框关联的键盘类型\n${b}${selfCode}${praName}.keyboardType = .default\n`, `${b}//设置键盘return键的样式\n${b}${selfCode}${praName}.returnKeyType = .send\n`);
793
+ return rng.sample(code, PRO_COUNT).join("");
794
+ }
795
+ function swiftUISegmentedControlCode(rng, praName, selfCode) {
796
+ const b = " ";
797
+ const code = swiftUIViewList(rng, praName, selfCode);
798
+ code.push(`${b}//默认第0个选中\n${b}${selfCode}${praName}.selectedSegmentIndex = 0\n`, `${b}//点击之后是否属于选中状态(true:否)\n${b}${selfCode}${praName}.isMomentary = true\n`);
799
+ const sizeName = rng.word();
800
+ code.push(`${b}//修改item内容的偏移量\n${b}let ${sizeName} = CGSize(width: -${rng.int(0, 20)}, height: -${rng.int(0, 20)})\n${b}${selfCode}${praName}.setContentOffset(${sizeName}, forSegmentAt: 0)\n`);
801
+ return rng.sample(code, PRO_COUNT).join("");
802
+ }
803
+ function swiftUIPageControlCode(rng, praName, selfCode) {
804
+ const b = " ";
805
+ const code = swiftUIViewList(rng, praName, selfCode);
806
+ code.push(`${b}//设置总页数\n${b}${selfCode}${praName}.numberOfPages = ${rng.int(0, 30)}\n`, `${b}//设置未选中颜色\n${b}${selfCode}${praName}.pageIndicatorTintColor = ${swiftColor(rng)}\n`, `${b}//当前多少页\n${b}${selfCode}${praName}.currentPage = 0\n`, `${b}//选中滑块的颜色\n${b}${selfCode}${praName}.currentPageIndicatorTintColor = ${swiftColor(rng)}\n`);
807
+ return rng.sample(code, PRO_COUNT).join("");
808
+ }
809
+ function swiftUIDatePickerCode(rng, praName, selfCode) {
810
+ const b = " ";
811
+ const code = swiftUIViewList(rng, praName, selfCode);
812
+ code.push(`${b}//设置datePickerMode\n${b}${selfCode}${praName}.datePickerMode = UIDatePicker.Mode.date\n`, `${b}//获取当前本地化\n${b}${selfCode}${praName}.locale = Locale.init(identifier: "zh_CN")\n`, `${b}//设置日历属性\n${b}${selfCode}${praName}.calendar = Calendar.current\n`, `${b}//时区的设置\n${b}${selfCode}${praName}.timeZone = TimeZone.current\n`, `${b}//日期属性\n${b}${selfCode}${praName}.date = Date.init(timeIntervalSinceNow: ${rng.int(0, 255)})\n`, `${b}//设置一个时间区段\n${b}${selfCode}${praName}.date = Date.init(timeIntervalSinceNow: ${rng.int(0, 255)})\n`, `${b}//时间间隔属性\n${b}${selfCode}${praName}.minuteInterval = ${rng.int(0, 255)}\n`);
813
+ return rng.sample(code, PRO_COUNT).join("");
814
+ }
815
+ function swiftUIButtonCode(rng, praName, selfCode) {
816
+ const b = " ";
817
+ const code = swiftUIViewList(rng, praName, selfCode);
818
+ code.push(`${b}//设置title\n${b}${selfCode}${praName}.setTitle("${rng.wordTitle()}", for: .normal)\n`, `${b}//设置title颜色\n${b}${selfCode}${praName}.setTitleColor(${swiftColor(rng)}, for: .normal)\n`, `${b}//字体\n${b}${selfCode}${praName}.titleLabel?.font = UIFont.systemFont(ofSize: ${rng.int(10, 30)})\n`);
819
+ return rng.sample(code, PRO_COUNT).join("");
820
+ }
821
+ function swiftUIViewCode(rng, praName, selfCode) {
822
+ return rng.sample(swiftUIViewList(rng, praName, selfCode), PRO_COUNT).join("");
823
+ }
824
+ function swiftUIFontCode(rng, praName, selfCode) {
825
+ return rng.sample([` ${selfCode}${praName} = UIFont.systemFont(ofSize: ${rng.int(10, 30)})\n`], 1).join("");
826
+ }
827
+ function swiftUIColorCode(rng, praName, selfCode) {
828
+ return rng.sample([` ${selfCode}${praName} = UIColor.init(red: CGFloat(${rng.int(0, 255)}/255), green: CGFloat(${rng.int(0, 255)}/255), blue: CGFloat(${rng.int(0, 255)}/255), alpha: 1)\n`], 1).join("");
829
+ }
830
+ function swiftNSArrayCode(rng, praName, selfCode) {
831
+ return ` ${selfCode}${praName} = ["${rng.word()}", "${rng.word()}", "${rng.word()}"]\n`;
832
+ }
833
+ function swiftNSDictionaryCode(rng, praName, selfCode) {
834
+ return ` ${selfCode}${praName} = ["${rng.word()}": "${rng.word()}", "${rng.word()}": "${rng.word()}"]\n`;
835
+ }
836
+ function swiftCodeByObject(rng, state, praObjName, praName, spaceCount, isNeedInit = false) {
837
+ const selfCode = state.rubProMap.has(praObjName) && state.rubProMap.get(praObjName) === praName ? "self." : "";
838
+ const blank = " ".repeat(spaceCount);
839
+ const b = blank + blank;
840
+ let code = "";
841
+ const letStr = SWIFT_VAR_LIST.includes(praObjName) ? "var" : "let";
842
+ if (isNeedInit) code += `${b}${letStr} ${praName} = ${praObjName}()\n`;
843
+ if (praObjName === "UIView") code += swiftUIViewCode(rng, praName, selfCode);
844
+ else if (praObjName === "UIButton") code += swiftUIButtonCode(rng, praName, selfCode);
845
+ else if (praObjName === "UIDatePicker") code += swiftUIDatePickerCode(rng, praName, selfCode);
846
+ else if (praObjName === "UIPageControl") code += swiftUIPageControlCode(rng, praName, selfCode);
847
+ else if (praObjName === "UISegmentedControl") code += swiftUISegmentedControlCode(rng, praName, selfCode);
848
+ else if (praObjName === "UITextField") code += swiftUITextFieldCode(rng, praName, selfCode);
849
+ else if (praObjName === "UISwitch") code += swiftUISwitchCode(rng, praName, selfCode);
850
+ else if (praObjName === "UISlider") code += swiftUISliderCode(rng, praName, selfCode);
851
+ else if (praObjName === "UIControl") code += swiftUIControlCode(rng, praName, selfCode);
852
+ else if (praObjName === "UIImageView") code += swiftUIImageViewCode(rng, praName, selfCode);
853
+ else if (praObjName === "UIViewController") code += swiftUIViewControllerCode(rng, praName, selfCode);
854
+ else if (praObjName === "UICollectionView") code += swiftUICollectionViewCode(rng, praName, selfCode);
855
+ else if (praObjName === "UILabel") code += swiftUILabelCode(rng, praName, selfCode);
856
+ else if (praObjName === "UIColor") code += swiftUIColorCode(rng, praName, selfCode);
857
+ else if (praObjName === "UIFont") code += swiftUIFontCode(rng, praName, selfCode);
858
+ else if (praObjName === "Void") {} else if (praObjName === "CGFloat") code += `${b}${selfCode}${praName} = ${rng.int(0, 2e3)}.00\n`;
859
+ else if (praObjName === "CGRect") code += `${b}${selfCode}${praName} = CGRect(x: ${rng.int(10, 200)}, y: ${rng.int(10, 200)}, width: ${rng.int(10, 200)}, height: ${rng.int(10, 200)})\n`;
860
+ else if (praObjName === "NSInteger") code += `${b}${selfCode}${praName} = ${rng.int(0, 2e3)}\n`;
861
+ else if (praObjName === "NSString" || praObjName === "String") code += `${b}${selfCode}${praName} = "${rng.word()}${capitalize(rng.word())}"\n`;
862
+ else if (praObjName === "NSArray" || praObjName === "Array") code += swiftNSArrayCode(rng, praName, selfCode);
863
+ else if (praObjName === "NSDictionary") code += swiftNSDictionaryCode(rng, praName, selfCode);
864
+ else if (praObjName === "NSURL") code += `${b}${selfCode}${praName} = NSURL(string: "https://www.${rng.word()}.com/${rng.word()}")!\n`;
865
+ return code;
866
+ }
867
+ function swiftMethodName(rng, returnValue, parameterStr, rubPrefix) {
868
+ let suffix;
869
+ if (returnValue === "Void" || returnValue === "void") suffix = "Fun";
870
+ else if (returnValue.startsWith("CG")) suffix = returnValue.slice(2);
871
+ else suffix = "";
872
+ const name = rng.int(0, 1) === 0 ? rng.word() + capitalize(rng.word()) + suffix : rng.word() + capitalize(rng.word()) + capitalize(rng.word()) + suffix;
873
+ return `func ${rubPrefix.length > 0 ? rubPrefix + name : name}${parameterStr} -> ${returnValue}`;
874
+ }
875
+ function swiftParameterTuple(rng, state) {
876
+ const parameterList = [];
877
+ const parameterMap = /* @__PURE__ */ new Map();
878
+ const count = rng.int(1, 3);
879
+ for (let index = 0; index < count; index += 1) {
880
+ let type = SWIFT_FUN_HEAD_LIST[rng.int(1, SWIFT_FUN_HEAD_LIST.length - 1)];
881
+ if (parameterMap.has(type)) type = SWIFT_FUN_HEAD_LIST[rng.int(1, SWIFT_FUN_HEAD_LIST.length - 1)];
882
+ let name;
883
+ if (parameterMap.has(type) || state.rubProMap.has(type)) name = state.rubProMap.get(type) ?? parameterMap.get(type);
884
+ else if (type === "void" || type === "Void") name = rng.word() + capitalize(rng.word());
885
+ else if (type.startsWith("CG")) name = rng.word() + type.slice(2);
886
+ else name = rng.word() + capitalize(rng.word());
887
+ parameterList.push(index === 0 ? `_ ${name}: ${type}` : ` ${name}: ${type}`);
888
+ if (!state.rubProMap.has(type)) state.rubProMap.set(type, name);
889
+ parameterMap.set(type, name);
890
+ }
891
+ return {
892
+ paramString: `(${parameterList.join(",")})`,
893
+ paramMap: parameterMap
894
+ };
895
+ }
896
+ function swiftDetailImport(rng, state, className, classFunList, thisParamMap) {
897
+ const blank = " ";
898
+ const classFun = classFunList[rng.int(0, classFunList.length - 1)];
899
+ if (!classFun.startsWith("func ")) return `${blank}// 无效的引用\n`;
900
+ const classPraName = rng.wordTitle();
901
+ let code = `${blank}let ${classPraName} = ${className}()\n`;
902
+ const openParen = classFun.indexOf("(");
903
+ const closeParen = classFun.indexOf(")");
904
+ let importCode = `.${classFun.slice(classFun.indexOf("func ") + 5, openParen)}(`;
905
+ let paramStr = classFun.slice(openParen + 1, closeParen);
906
+ if (paramStr.startsWith("_ ")) paramStr = paramStr.slice(2);
907
+ const parts = paramStr.split(",");
908
+ for (let index = 0; index < parts.length; index += 1) {
909
+ const [praName, praObjName] = parts[index].replace(/\s/g, "").split(":");
910
+ if (thisParamMap.has(praObjName)) {
911
+ importCode += index === 0 ? `${thisParamMap.get(praObjName)},` : `${praName}: ${thisParamMap.get(praObjName)},`;
912
+ continue;
913
+ }
914
+ code += swiftCodeByObject(rng, state, praObjName, praName, 4, true);
915
+ importCode += index === 0 ? `${praName},` : `${praName}: ${praName},`;
916
+ }
917
+ if (importCode.endsWith(",")) importCode = importCode.slice(0, -1);
918
+ importCode += ")";
919
+ code += `${blank}${classPraName}${importCode}\n`;
920
+ return code;
921
+ }
922
+ function swiftImportCode(rng, state, thisParamMap) {
923
+ let code = "";
924
+ if (state.registry.unused.size > 0) {
925
+ const keys = [...state.registry.unused.keys()];
926
+ const className = keys[rng.int(0, keys.length - 1)];
927
+ const funList = state.registry.unused.get(className);
928
+ code += swiftDetailImport(rng, state, className, funList, thisParamMap);
929
+ state.registry.unused.delete(className);
930
+ state.registry.used.set(className, funList);
931
+ } else if (state.registry.used.size > 0) {
932
+ const keys = [...state.registry.used.keys()];
933
+ const className = keys[rng.int(0, keys.length - 1)];
934
+ code += swiftDetailImport(rng, state, className, state.registry.used.get(className), thisParamMap);
935
+ }
936
+ code += "\n";
937
+ return code;
938
+ }
939
+ function createSwiftMethod(rng, rubPrefix, state) {
940
+ const blank = " ";
941
+ const returnValue = rng.pick(SWIFT_FUN_HEAD_LIST);
942
+ let returnCode;
943
+ const { paramString, paramMap } = swiftParameterTuple(rng, state);
944
+ const declaration = swiftMethodName(rng, returnValue, paramString, rubPrefix);
945
+ let methodCode = `${blank}${declaration}{\n`;
946
+ const thisParamMap = /* @__PURE__ */ new Map();
947
+ for (const [praObjName, praName] of paramMap) {
948
+ if (praObjName === returnValue) returnCode = praName;
949
+ methodCode += `${swiftCodeByObject(rng, state, praObjName, praName, 4)}\n`;
950
+ thisParamMap.set(praObjName, praName);
951
+ }
952
+ methodCode += swiftImportCode(rng, state, thisParamMap);
953
+ if (returnValue === "Void" || returnValue === "void") methodCode += `${blank}${blank}//\n`;
954
+ else if (returnCode !== void 0) methodCode += `${blank}${blank}return ${returnCode}\n`;
955
+ else {
956
+ const letStr = SWIFT_VAR_LIST.includes(returnValue) ? "var" : "let";
957
+ const praName = rng.word() + capitalize(rng.word());
958
+ methodCode += `${blank}${blank}${letStr} ${praName} = ${returnValue}()\n`;
959
+ methodCode += `${swiftCodeByObject(rng, state, returnValue, praName, 4)}\n`;
960
+ methodCode += `${blank}${blank}return ${praName}\n`;
961
+ }
962
+ methodCode += `${blank}}\n\n`;
963
+ return {
964
+ methodCode,
965
+ declaration
966
+ };
967
+ }
968
+ function swiftLazyProperty(rng, praName, praObjName) {
969
+ const blank = " ";
970
+ if (praObjName === "Bool") {
971
+ const nowDateStr = `${rng.word()}Date`;
972
+ const timeIntervalStr = `${rng.word()}Interval`;
973
+ const timeStampStr = `timeStamp${rng.wordTitle()}`;
974
+ return `${blank}var ${praName}: Bool {\n${blank}${blank}let ${nowDateStr} = NSDate()\n${blank}${blank}let ${timeIntervalStr}: TimeInterval = ${nowDateStr}.timeIntervalSince1970\n${blank}${blank}let ${timeStampStr} = Int(${timeIntervalStr})\n${blank}${blank}if (${timeStampStr}/2 == 0){\n${blank}${blank}${blank}return true\n${blank}${blank}}else{\n${blank}${blank}${blank}return false\n${blank}${blank}}\n${blank}}\n`;
975
+ }
976
+ if (praObjName === "CGFloat") return `${blank}var ${praName}: CGFloat! = 0.0\n`;
977
+ if (praObjName === "CGRect") return `${blank}var ${praName}: CGRect = CGRect(x: ${rng.int(30, 300)}, y: ${rng.int(30, 300)}, width: ${rng.int(30, 300)}, height: ${rng.int(30, 300)})\n`;
978
+ if (praObjName === "NSInteger") return `${blank}var ${praName}: NSInteger! = 0\n`;
979
+ if (praObjName === "NSString") return `${blank}var ${praName}: NSString! = ""\n`;
980
+ if (praObjName === "NSArray") return `${blank}var ${praName}: NSArray! = []\n`;
981
+ if (praObjName === "NSDictionary") return `${blank}var ${praName}: NSDictionary = [String:String]() as NSDictionary\n`;
982
+ if (praObjName === "NSNumber") return `${blank}var ${praName}: NSNumber = 0\n`;
983
+ if (praObjName === "NSURL") return `${blank}var ${praName}: NSURL = NSURL(string: ${`"https://www.${rng.word()}${rng.word()}.com"`} as String)!\n`;
984
+ return `${blank}var ${praName}: ${praObjName} = ${praObjName}()\n`;
985
+ }
986
+ function generateSwiftJunkInternal(amount, rubPrefix, seed, salt, state) {
987
+ const rng = new Rng(seed, salt);
988
+ let methodCode = "";
989
+ const funList = [];
990
+ for (let i = 0; i < amount; i += 1) {
991
+ const { methodCode: body, declaration } = createSwiftMethod(rng, rubPrefix, state);
992
+ methodCode += body;
993
+ funList.push(declaration);
994
+ }
995
+ let propertyCode = "";
996
+ for (const [praObjName, praName] of state.rubProMap) propertyCode += swiftLazyProperty(rng, praName, praObjName);
997
+ return {
998
+ propertyCode,
999
+ methodCode,
1000
+ funList
1001
+ };
1002
+ }
1003
+ /** Generate a garbage Swift method body. */
1004
+ function generateSwiftJunk(amount, rubPrefix, seed, salt) {
1005
+ return generateSwiftJunkInternal(amount, rubPrefix, seed, salt, {
1006
+ rubProMap: /* @__PURE__ */ new Map(),
1007
+ registry: newRegistry()
1008
+ });
1009
+ }
1010
+ /** Generate one deterministic Swift garbage method. */
1011
+ function generateSwiftMethod(rubPrefix, seed, salt) {
1012
+ const state = {
1013
+ rubProMap: /* @__PURE__ */ new Map(),
1014
+ registry: newRegistry()
1015
+ };
1016
+ return createSwiftMethod(new Rng(seed, salt), rubPrefix, state);
1017
+ }
1018
+ /** Deterministic port of getHeadCode (Xcode source-file header comment). */
1019
+ function generateFileHead(fileName, seed, salt) {
1020
+ const rng = new Rng(seed, `${salt}:head`);
1021
+ const line1 = rng.wordUpper();
1022
+ const line2 = rng.wordUpper();
1023
+ const line3 = rng.wordUpper();
1024
+ return `//\n// ${fileName}\n// ${line1}\n//\n// Created by ${line2} on ${dateString(rng)}.\n// Copyright © 2019 ${line3}. All rights reserved.\n//\n\n\n`;
1025
+ }
1026
+ const OBJC_IMPORT_LIST = [
1027
+ "#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>",
1028
+ "#import <UIKit/UIKit.h>",
1029
+ "#import <UIKit/UIKit.h>"
1030
+ ];
1031
+ /** Build one OC `.h`/`.m` file pair from an ObjCJunk tuple. */
1032
+ function generateObjCFile(objectName, objClass, junk, seed, salt) {
1033
+ const h = generateFileHead(`${objectName}.h`, seed, salt) + `${OBJC_IMPORT_LIST[SPORT_OBJ_LIST.indexOf(objClass)]}\n\n@interface ${objectName} : ${objClass}\n\n` + junk.hCode + "\n@end\n";
1034
+ let m = generateFileHead(`${objectName}.m`, seed, salt) + `#import "${objectName}.h"\n` + junk.headerImportCode + `
1035
+ @interface ${objectName} ()\n\n@end\n\n@implementation ${objectName}\n\n`;
1036
+ if (objClass === "UIViewController") m += "- (void)viewDidLoad {\n [super viewDidLoad];\n // Do any additional setup after loading the view from its nib.\n}\n\n";
1037
+ m += junk.mCode + "@end\n";
1038
+ return {
1039
+ h,
1040
+ m
1041
+ };
1042
+ }
1043
+ /** Build one Swift file from a SwiftJunk tuple. */
1044
+ function generateSwiftFile(objectName, objClass, junk, seed, salt) {
1045
+ let code = generateFileHead(`${objectName}.swift`, seed, salt) + `import Foundation
1046
+ import UIKit
1047
+
1048
+ class ${objectName}: ${objClass} {\n\n` + junk.propertyCode + "\n\n";
1049
+ if (objClass === "UIViewController") code += " override func viewDidLoad() {\n super.viewDidLoad()\n }\n";
1050
+ code += "\n" + junk.methodCode + "}\n";
1051
+ return code;
1052
+ }
1053
+ const IGNORED_SUBSTRINGS = [
1054
+ "/Pods/",
1055
+ "/.git/",
1056
+ "/Podfile",
1057
+ "/Podfile.lock",
1058
+ "/README.md",
1059
+ "/AppDelegate.",
1060
+ "/SceneDelegate.",
1061
+ "/.DS_Store",
1062
+ "/UserInterfaceState.xcuserstate",
1063
+ "/.svn/"
1064
+ ];
1065
+ /** True for paths that must be skipped (never obfuscated). */
1066
+ function isIgnoredPath(relativePath) {
1067
+ if (relativePath.includes(".framework")) return true;
1068
+ if (relativePath.includes("+")) return true;
1069
+ const normalized = relativePath.startsWith("/") ? relativePath : `/${relativePath}`;
1070
+ return IGNORED_SUBSTRINGS.some((part) => normalized.includes(part));
1071
+ }
1072
+ function classInterfacePattern(objectName) {
1073
+ return new RegExp(`@interface\\s+${objectName}(?:\\s|:|\\()`);
1074
+ }
1075
+ /** Insert ObjC junk declarations before the matching `@interface`'s `@end`. */
1076
+ function insertObjCHeaderJunk(content, objectName, hCode) {
1077
+ const lines = content.split("\n");
1078
+ const out = [];
1079
+ let importedUIKit = lines.some((line) => line.includes("<UIKit/UIKit.h>"));
1080
+ let didImport = false;
1081
+ let isPassInterface = false;
1082
+ let added = false;
1083
+ for (const line of lines) {
1084
+ const stripped = line.trim();
1085
+ if (!didImport && (line.includes("#import") || line.includes("#include"))) {
1086
+ out.push(line);
1087
+ if (!importedUIKit) {
1088
+ out.push("#import <UIKit/UIKit.h>");
1089
+ out.push("");
1090
+ importedUIKit = true;
1091
+ }
1092
+ didImport = true;
1093
+ continue;
1094
+ }
1095
+ if (line.includes("@interface") && !line.includes("//@interface") && classInterfacePattern(objectName).test(line)) isPassInterface = true;
1096
+ if (stripped === "@end" && !line.includes("//@end") && !added && isPassInterface) {
1097
+ added = true;
1098
+ out.push("");
1099
+ out.push(hCode);
1100
+ out.push(line);
1101
+ continue;
1102
+ }
1103
+ out.push(line);
1104
+ }
1105
+ return out.join("\n");
1106
+ }
1107
+ /** Insert ObjC junk method bodies before the matching `@implementation`'s `@end`. */
1108
+ function insertObjCImplJunk(content, objectName, mCode, headerImportCode) {
1109
+ const lines = content.split("\n");
1110
+ const out = [];
1111
+ let isLastEnd = false;
1112
+ let addedImport = false;
1113
+ for (const line of lines) {
1114
+ const stripped = line.replace(/\s/g, "");
1115
+ if (stripped.includes("@interface") && !line.includes("//@interface")) isLastEnd = false;
1116
+ if (stripped.includes("@implementation") && !line.includes("//@implementation") && line.includes(`@implementation ${objectName}`)) isLastEnd = true;
1117
+ if ((stripped.includes("#import") || stripped.includes("#include")) && !addedImport) {
1118
+ out.push(line);
1119
+ if (headerImportCode.length > 0) out.push(headerImportCode.replace(/\n$/, ""));
1120
+ addedImport = true;
1121
+ continue;
1122
+ }
1123
+ if (stripped === "@end" && isLastEnd) {
1124
+ out.push("");
1125
+ out.push(mCode);
1126
+ out.push("");
1127
+ out.push(line);
1128
+ continue;
1129
+ }
1130
+ out.push(line);
1131
+ }
1132
+ return out.join("\n");
1133
+ }
1134
+ /** Insert Swift junk properties + methods right after the class/struct/extension opening brace. */
1135
+ function insertSwiftJunk(content, objectName, propertyCode, methodCode) {
1136
+ const lines = content.split("\n");
1137
+ const out = [];
1138
+ let count = 0;
1139
+ let addedPro = false;
1140
+ let addedRun = false;
1141
+ for (let line of lines) {
1142
+ const stripped = line.replace(/\s/g, "");
1143
+ if ((stripped.includes(`class${objectName}:`) || stripped.includes(`extension${objectName}`) || stripped.includes(`struct${objectName}{`) || stripped.includes(`class${objectName}{`)) && !addedPro) count += 1;
1144
+ if (line.includes("{") && !addedPro && count === 1) count += 1;
1145
+ if (count === 2 && !addedPro) {
1146
+ line += propertyCode;
1147
+ line += "\n";
1148
+ addedPro = true;
1149
+ }
1150
+ if (addedPro && !addedRun) {
1151
+ line += methodCode;
1152
+ addedRun = true;
1153
+ }
1154
+ out.push(line);
1155
+ }
1156
+ return out.join("\n");
1157
+ }
1158
+ function registerInPbxproj(content, snippets) {
1159
+ const lines = content.split("\n");
1160
+ const out = [];
1161
+ let inGroup = false;
1162
+ let inSources = false;
1163
+ let addedFolderRef = false;
1164
+ let addedSources = false;
1165
+ for (const line of lines) {
1166
+ if (line.includes("/* Begin PBXGroup section */")) inGroup = true;
1167
+ if (line.includes("/* End PBXGroup section */")) inGroup = false;
1168
+ if (line.includes("/* Begin PBXSourcesBuildPhase section */")) inSources = true;
1169
+ if (line.includes("/* End PBXSourcesBuildPhase section */")) inSources = false;
1170
+ if (inGroup && !addedFolderRef && line.includes("children = (")) {
1171
+ out.push(line);
1172
+ out.push(` ${snippets.folderRef}`);
1173
+ addedFolderRef = true;
1174
+ continue;
1175
+ }
1176
+ if (inSources && !addedSources && line.includes("files = (")) {
1177
+ out.push(line);
1178
+ for (const item of snippets.sources) out.push(` ${item.trimEnd()}`);
1179
+ addedSources = true;
1180
+ continue;
1181
+ }
1182
+ if (line.includes("/* End PBXGroup section */")) {
1183
+ out.push(snippets.folderBlock.trimEnd());
1184
+ out.push(line);
1185
+ continue;
1186
+ }
1187
+ if (line.includes("/* End PBXFileReference section */")) {
1188
+ for (const item of snippets.fileRefs) out.push(`\t\t${item.trimEnd()}`);
1189
+ out.push(line);
1190
+ continue;
1191
+ }
1192
+ if (line.includes("/* End PBXBuildFile section */")) {
1193
+ for (const item of snippets.buildFiles) out.push(`\t\t${item.trimEnd()}`);
1194
+ out.push(line);
1195
+ continue;
1196
+ }
1197
+ out.push(line);
1198
+ }
1199
+ return out.join("\n");
1200
+ }
1201
+ const RESOURCE_CLEAN_EXTENSIONS = [
1202
+ ".jpg",
1203
+ ".bmp",
1204
+ ".png",
1205
+ ".jpeg",
1206
+ ".rgb",
1207
+ ".tif",
1208
+ ".gif",
1209
+ ".mp3",
1210
+ ".mp4",
1211
+ ".caf"
1212
+ ];
1213
+ const CODE_SEARCH_EXTENSIONS = /* @__PURE__ */ new Set([
1214
+ "h",
1215
+ "m",
1216
+ "mm",
1217
+ "swift",
1218
+ "c",
1219
+ "cpp",
1220
+ "cc",
1221
+ "hpp",
1222
+ "java",
1223
+ "kt",
1224
+ "dart",
1225
+ "js",
1226
+ "ts",
1227
+ "jsx",
1228
+ "tsx"
1229
+ ]);
1230
+ const TEXT_SEARCH_EXTENSIONS = /* @__PURE__ */ new Set([
1231
+ "json",
1232
+ "plist",
1233
+ "strings",
1234
+ "xml",
1235
+ "storyboard",
1236
+ "xib",
1237
+ "html",
1238
+ "htm",
1239
+ "txt",
1240
+ "md",
1241
+ "csv",
1242
+ "tsv",
1243
+ "yml",
1244
+ "yaml",
1245
+ "css",
1246
+ "scss",
1247
+ "less"
1248
+ ]);
1249
+ function basenameOf(path) {
1250
+ const parts = path.split("/");
1251
+ return parts[parts.length - 1];
1252
+ }
1253
+ /** True for loose resource files (not imagesets), mirroring `isResource`. */
1254
+ function isResourcePath(relativePath) {
1255
+ const base = basenameOf(relativePath);
1256
+ return RESOURCE_CLEAN_EXTENSIONS.some((ext) => base.endsWith(ext));
1257
+ }
1258
+ /** Resource name (basename up to the first dot), mirroring `searchAllResName`. */
1259
+ function resourceNameFromPath(relativePath) {
1260
+ return basenameOf(relativePath).split(".")[0];
1261
+ }
1262
+ function imagesetDirOf(absolutePath) {
1263
+ let dir = dirname(absolutePath);
1264
+ for (;;) {
1265
+ if (basenameOf(dir).endsWith(".imageset")) return dir;
1266
+ const parent = dirname(dir);
1267
+ if (parent === dir) return void 0;
1268
+ dir = parent;
1269
+ }
1270
+ }
1271
+ function imagesetRelative(relativePath) {
1272
+ const parts = relativePath.split("/");
1273
+ const index = parts.findIndex((part) => part.endsWith(".imageset"));
1274
+ return parts.slice(0, index + 1).join("/");
1275
+ }
1276
+ /** Names referenced by a single code line, mirroring `findResNameAtFileLine`. */
1277
+ function lineReferencesResource(line, resourceNames) {
1278
+ const refs = [];
1279
+ for (const raw of line.split("\"")) {
1280
+ let item = raw;
1281
+ if (item.includes(".")) item = item.split(".")[0];
1282
+ if (resourceNames.has(item)) refs.push(item);
1283
+ else if (resourceNames.has(`${item}@1x`)) refs.push(`${item}@1x`);
1284
+ else if (resourceNames.has(`${item}@2x`)) refs.push(`${item}@2x`);
1285
+ else if (resourceNames.has(`${item}@3x`)) refs.push(`${item}@3x`);
1286
+ }
1287
+ return refs;
1288
+ }
1289
+ function isSearchCarrier(relativePath) {
1290
+ const ext = extension(relativePath);
1291
+ return CODE_SEARCH_EXTENSIONS.has(ext) || TEXT_SEARCH_EXTENSIONS.has(ext);
1292
+ }
1293
+ function cleanPbxproj(content, unusedNames) {
1294
+ const lines = content.split("\n");
1295
+ const kept = [];
1296
+ for (const line of lines) {
1297
+ let drop = false;
1298
+ for (const name of unusedNames) if (line.includes(name)) {
1299
+ drop = true;
1300
+ break;
1301
+ }
1302
+ if (!drop) kept.push(line);
1303
+ }
1304
+ return kept.join("\n");
1305
+ }
1306
+ /**
1307
+ * Inject deterministic ObjC/Swift garbage methods into eligible source files.
1308
+ * Matched `.h`/`.m`/`.mm` pairs share one generated junk tuple (so declarations
1309
+ * and implementations stay in sync); `.swift` files get lazy properties + methods.
1310
+ */
1311
+ function insertJunkCode(files, options, seed) {
1312
+ const amount = Math.max(1, options.amount ?? 1);
1313
+ const rubPrefix = options.rubPrefix ?? DEFAULT_RUB_PREFIX;
1314
+ const eligible = files.filter((file) => {
1315
+ const ext = extension(file.relative);
1316
+ return (ext === "h" || ext === "m" || ext === "mm" || ext === "swift") && !isIgnoredPath(file.relative);
1317
+ });
1318
+ const byStem = /* @__PURE__ */ new Map();
1319
+ for (const file of eligible) {
1320
+ const stem = basenameWithoutExtension(file.relative);
1321
+ const list = byStem.get(stem) ?? [];
1322
+ list.push(file);
1323
+ byStem.set(stem, list);
1324
+ }
1325
+ const registry = newRegistry();
1326
+ const changedPaths = [];
1327
+ let changed = 0;
1328
+ for (const stem of [...byStem.keys()].sort()) {
1329
+ const entries = byStem.get(stem);
1330
+ if (entries.some((entry) => extension(entry.relative) === "swift")) {
1331
+ const junk = generateSwiftJunkInternal(amount, rubPrefix, seed, stem, {
1332
+ rubProMap: /* @__PURE__ */ new Map(),
1333
+ registry
1334
+ });
1335
+ registry.unused.set(stem, junk.funList);
1336
+ for (const entry of entries) {
1337
+ if (extension(entry.relative) !== "swift") continue;
1338
+ const next = insertSwiftJunk(readFileSync(entry.absolute, "utf8"), stem, junk.propertyCode, junk.methodCode);
1339
+ if (writeIfChanged(entry, next)) {
1340
+ changed += 1;
1341
+ changedPaths.push(entry.relative);
1342
+ }
1343
+ }
1344
+ } else {
1345
+ const junk = generateObjCJunkInternal(amount, rubPrefix, seed, stem, {
1346
+ rubProMap: /* @__PURE__ */ new Map(),
1347
+ headerFiles: [],
1348
+ registry
1349
+ });
1350
+ registry.unused.set(stem, junk.hFunList);
1351
+ for (const entry of entries) {
1352
+ const ext = extension(entry.relative);
1353
+ const content = readFileSync(entry.absolute, "utf8");
1354
+ const next = ext === "h" ? insertObjCHeaderJunk(content, stem, junk.hCode) : insertObjCImplJunk(content, stem, junk.mCode, junk.headerImportCode);
1355
+ if (writeIfChanged(entry, next)) {
1356
+ changed += 1;
1357
+ changedPaths.push(entry.relative);
1358
+ }
1359
+ }
1360
+ }
1361
+ }
1362
+ return {
1363
+ changed,
1364
+ changedPaths
1365
+ };
1366
+ }
1367
+ /**
1368
+ * Create deterministic garbage `.h`/`.m`/`.swift` files under a generated folder
1369
+ * and register them into the project's `project.pbxproj`.
1370
+ */
1371
+ function createJunkFiles(root, files, options, seed) {
1372
+ const count = Math.max(1, options.count ?? 1);
1373
+ const amount = Math.max(1, options.amount ?? 1);
1374
+ const rubPrefix = options.rubPrefix ?? DEFAULT_RUB_PREFIX;
1375
+ const language = options.language ?? "OC";
1376
+ const pbx = files.find((file) => file.relative.endsWith("project.pbxproj"));
1377
+ const rng = new Rng(seed, "junk-files");
1378
+ const folderName = rng.wordTitle() + rng.wordTitle();
1379
+ const folderUdid = deriveUuid(seed, `folder:${folderName}`);
1380
+ const folderAbsolute = join(root, folderName);
1381
+ mkdirSync(folderAbsolute, { recursive: true });
1382
+ const changedPaths = [];
1383
+ let changed = 0;
1384
+ const children = [];
1385
+ const fileRefs = [];
1386
+ const sources = [];
1387
+ const buildFiles = [];
1388
+ for (let index = 0; index < count; index += 1) {
1389
+ const salt = `file:${index}`;
1390
+ const objClass = SPORT_OBJ_LIST[rng.int(0, 2)];
1391
+ if (language === "Swift") {
1392
+ const objectName = objcGetMissObjName(objClass, seed, `${salt}:name`);
1393
+ const fileContent = generateSwiftFile(objectName, objClass, generateSwiftJunk(amount, rubPrefix, seed, `${salt}:code`), seed, salt);
1394
+ writeFileSync(join(folderAbsolute, `${objectName}.swift`), fileContent);
1395
+ changed += 1;
1396
+ changedPaths.push(`${folderName}/${objectName}.swift`);
1397
+ const udid = deriveUuid(seed, `${objectName}.swift:ref`);
1398
+ const buildUdid = deriveUuid(seed, `${objectName}.swift:build`);
1399
+ children.push(`${udid} /* ${objectName}.swift */,`);
1400
+ fileRefs.push(`${udid} /* ${objectName}.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ${objectName}.swift; sourceTree = "<group>"; };\n`);
1401
+ sources.push(`${buildUdid} /* ${objectName}.swift in Sources */,\n`);
1402
+ buildFiles.push(`${buildUdid} /* ${objectName}.swift in Sources */ = {isa = PBXBuildFile; fileRef = ${udid} /* ${objectName}.swift */; };\n`);
1403
+ } else {
1404
+ const objectName = objcGetMissObjName(objClass, seed, `${salt}:name`);
1405
+ const { h, m } = generateObjCFile(objectName, objClass, generateObjCJunk(amount, rubPrefix, seed, `${salt}:code`), seed, salt);
1406
+ writeFileSync(join(folderAbsolute, `${objectName}.h`), h);
1407
+ writeFileSync(join(folderAbsolute, `${objectName}.m`), m);
1408
+ changed += 2;
1409
+ changedPaths.push(`${folderName}/${objectName}.h`, `${folderName}/${objectName}.m`);
1410
+ const hUdid = deriveUuid(seed, `${objectName}.h:ref`);
1411
+ const mUdid = deriveUuid(seed, `${objectName}.m:ref`);
1412
+ const mBuild = deriveUuid(seed, `${objectName}.m:build`);
1413
+ children.push(`${hUdid} /* ${objectName}.h */,`, `${mUdid} /* ${objectName}.m */,`);
1414
+ fileRefs.push(`${hUdid} /* ${objectName}.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ${objectName}.h; sourceTree = "<group>"; };\n`);
1415
+ fileRefs.push(`${mUdid} /* ${objectName}.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ${objectName}.m; sourceTree = "<group>"; };\n`);
1416
+ sources.push(`${mBuild} /* ${objectName}.m in Sources */,\n`);
1417
+ buildFiles.push(`${mBuild} /* ${objectName}.m in Sources */ = {isa = PBXBuildFile; fileRef = ${mUdid} /* ${objectName}.m */; };\n`);
1418
+ }
1419
+ }
1420
+ const folderBlock = `\t\t${folderUdid} /* ${folderName} */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n` + children.map((child) => `\t\t\t\t${child}`).join("\n") + `\n\t\t\t);\n\t\t\tpath = ${folderName};\n\t\t\tsourceTree = "<group>";\n\t\t};`;
1421
+ if (pbx) {
1422
+ const next = registerInPbxproj(readFileSync(pbx.absolute, "utf8"), {
1423
+ folderRef: `${folderUdid} /* ${folderName} */,`,
1424
+ folderBlock,
1425
+ fileRefs,
1426
+ sources,
1427
+ buildFiles
1428
+ });
1429
+ if (writeIfChanged(pbx, next)) {
1430
+ changed += 1;
1431
+ changedPaths.push(pbx.relative);
1432
+ }
1433
+ }
1434
+ return {
1435
+ changed,
1436
+ changedPaths
1437
+ };
1438
+ }
1439
+ /**
1440
+ * Detect resources never referenced by project code, remove their pbxproj lines,
1441
+ * and delete the files / `.imageset` directories.
1442
+ */
1443
+ function cleanUnusedResources(files, options = {}) {
1444
+ const ignore = new Set(options.ignore ?? []);
1445
+ const resNameMap = /* @__PURE__ */ new Map();
1446
+ for (const entry of files) {
1447
+ const rel = entry.relative;
1448
+ if (`/${rel}`.includes("/Pods/") || rel.includes(".appiconset") || rel.includes(".launchimage")) continue;
1449
+ const imageset = imagesetDirOf(entry.absolute);
1450
+ if (imageset) {
1451
+ const name = basenameOf(imageset).split(".")[0];
1452
+ resNameMap.set(name, {
1453
+ path: imageset,
1454
+ isDir: true,
1455
+ relative: imagesetRelative(rel)
1456
+ });
1457
+ } else if (isResourcePath(rel)) resNameMap.set(resourceNameFromPath(rel), {
1458
+ path: entry.absolute,
1459
+ isDir: false,
1460
+ relative: rel
1461
+ });
1462
+ }
1463
+ for (const name of ignore) resNameMap.delete(name);
1464
+ const remaining = new Set(resNameMap.keys());
1465
+ for (const entry of files) {
1466
+ if (!isSearchCarrier(entry.relative)) continue;
1467
+ const content = readFileSync(entry.absolute, "utf8");
1468
+ for (const line of content.split("\n")) for (const ref of lineReferencesResource(line, remaining)) resNameMap.delete(ref);
1469
+ }
1470
+ const changedPaths = [];
1471
+ let changed = 0;
1472
+ const pbx = files.find((file) => file.relative.endsWith("project.pbxproj"));
1473
+ if (pbx) {
1474
+ const next = cleanPbxproj(readFileSync(pbx.absolute, "utf8"), new Set(resNameMap.keys()));
1475
+ if (writeIfChanged(pbx, next)) {
1476
+ changed += 1;
1477
+ changedPaths.push(pbx.relative);
1478
+ }
1479
+ }
1480
+ for (const item of resNameMap.values()) if (item.isDir) {
1481
+ if (existsSync(item.path)) {
1482
+ rmSync(item.path, {
1483
+ recursive: true,
1484
+ force: true
1485
+ });
1486
+ changed += 1;
1487
+ changedPaths.push(item.relative);
1488
+ }
1489
+ } else if (existsSync(item.path)) {
1490
+ unlinkSync(item.path);
1491
+ changed += 1;
1492
+ changedPaths.push(item.relative);
1493
+ }
1494
+ return {
1495
+ changed,
1496
+ changedPaths
1497
+ };
1498
+ }
1499
+ export { cleanUnusedResources, createJunkFiles, generateFileHead, generateObjCFile, generateObjCJunk, generateObjCMethod, generateSwiftFile, generateSwiftJunk, generateSwiftMethod, insertJunkCode, insertObjCHeaderJunk, insertObjCImplJunk, insertSwiftJunk, isIgnoredPath, isResourcePath, lineReferencesResource, objcGetMissObjName, randomWord, randomWordTitle, resourceNameFromPath, swiftGetMissObjName };
1500
+
1501
+ //# sourceMappingURL=junk.js.map