@zelloptt/react-native-zello-sdk 2.0.1 → 4.0.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 (201) hide show
  1. package/README.md +100 -15
  2. package/android/build.gradle +29 -10
  3. package/android/gradle.properties +4 -4
  4. package/android/src/main/java/com/zellosdk/ZelloAndroidSdkModule.kt +93 -68
  5. package/android/src/main/java/com/zellosdk/ZelloAndroidSdkModuleHelper.kt +25 -0
  6. package/app.plugin.js +97 -0
  7. package/ios/Extensions/ZelloContact+Extension.swift +26 -3
  8. package/ios/Extensions/ZelloHistoryVoiceMessage+Extension.swift +3 -0
  9. package/ios/Extensions/ZelloIOSSdkModule+Extension.swift +8 -2
  10. package/ios/Extensions/ZelloIncomingEmergency+Extension.swift +1 -0
  11. package/ios/Extensions/ZelloTranscription+Extension.swift +18 -0
  12. package/ios/ZelloIOSSdkModule.swift +24 -7
  13. package/ios/ZelloIOSSdkModuleBridge.m +1 -0
  14. package/ios/ZelloSdkModule.h +8 -0
  15. package/ios/ZelloSdkModule.mm +189 -0
  16. package/ios/ZelloSdkModuleImpl.swift +280 -0
  17. package/lib/commonjs/docs/assets/highlight.css +17 -10
  18. package/lib/commonjs/docs/assets/icons.js +1 -1
  19. package/lib/commonjs/docs/assets/icons.js.map +1 -1
  20. package/lib/commonjs/docs/assets/icons.svg +1 -1
  21. package/lib/commonjs/docs/assets/main.js +220 -288
  22. package/lib/commonjs/docs/assets/main.js.map +1 -1
  23. package/lib/commonjs/docs/assets/navigation.js +1 -1
  24. package/lib/commonjs/docs/assets/navigation.js.map +1 -1
  25. package/lib/commonjs/docs/assets/search.js +1 -1
  26. package/lib/commonjs/docs/assets/search.js.map +1 -1
  27. package/lib/commonjs/docs/assets/style.css +21 -6
  28. package/lib/commonjs/docs/classes/sdk.Zello.html +793 -97
  29. package/lib/commonjs/docs/classes/types.ZelloAlertMessage.html +122 -9
  30. package/lib/commonjs/docs/classes/types.ZelloChannel.html +155 -10
  31. package/lib/commonjs/docs/classes/types.ZelloChannelUser.html +86 -4
  32. package/lib/commonjs/docs/classes/types.ZelloDispatchCall.html +90 -6
  33. package/lib/commonjs/docs/classes/types.ZelloDispatchChannel.html +163 -11
  34. package/lib/commonjs/docs/classes/types.ZelloGroupConversation.html +178 -13
  35. package/lib/commonjs/docs/classes/types.ZelloHistoryAlertMessage.html +131 -10
  36. package/lib/commonjs/docs/classes/types.ZelloHistoryImageMessage.html +123 -9
  37. package/lib/commonjs/docs/classes/types.ZelloHistoryLocationMessage.html +155 -13
  38. package/lib/commonjs/docs/classes/types.ZelloHistoryTextMessage.html +131 -10
  39. package/lib/commonjs/docs/classes/types.ZelloHistoryVoiceMessage.html +145 -10
  40. package/lib/commonjs/docs/classes/types.ZelloImageMessage.html +130 -10
  41. package/lib/commonjs/docs/classes/types.ZelloIncomingEmergency.html +114 -9
  42. package/lib/commonjs/docs/classes/types.ZelloIncomingVoiceMessage.html +124 -8
  43. package/lib/commonjs/docs/classes/types.ZelloLocationMessage.html +146 -12
  44. package/lib/commonjs/docs/classes/types.ZelloOutgoingEmergency.html +98 -7
  45. package/lib/commonjs/docs/classes/types.ZelloOutgoingVoiceMessage.html +120 -9
  46. package/lib/commonjs/docs/classes/types.ZelloRecentEntry.html +114 -9
  47. package/lib/commonjs/docs/classes/types.ZelloTextMessage.html +122 -9
  48. package/lib/commonjs/docs/classes/types.ZelloTranscription.html +122 -0
  49. package/lib/commonjs/docs/classes/types.ZelloTranslation.html +91 -0
  50. package/lib/commonjs/docs/classes/types.ZelloUser.html +142 -11
  51. package/lib/commonjs/docs/classes/types.ZelloUserSupportedFeatures.html +82 -5
  52. package/lib/commonjs/docs/enums/events.ZelloEvent.html +563 -95
  53. package/lib/commonjs/docs/enums/types.ZelloAccountStatus.html +67 -5
  54. package/lib/commonjs/docs/enums/types.ZelloChannelAlertLevel.html +67 -5
  55. package/lib/commonjs/docs/enums/types.ZelloChannelConnectionStatus.html +68 -3
  56. package/lib/commonjs/docs/enums/types.ZelloChannelType.html +84 -0
  57. package/lib/commonjs/docs/enums/types.ZelloConnectionError.html +68 -3
  58. package/lib/commonjs/docs/enums/types.ZelloConnectionState.html +73 -3
  59. package/lib/commonjs/docs/enums/types.ZelloContactType.html +73 -3
  60. package/lib/commonjs/docs/enums/types.ZelloDispatchCallStatus.html +73 -3
  61. package/lib/commonjs/docs/enums/types.ZelloOutgoingVoiceMessageError.html +63 -3
  62. package/lib/commonjs/docs/enums/types.ZelloOutgoingVoiceMessageState.html +78 -3
  63. package/lib/commonjs/docs/enums/types.ZelloRecentEntryType.html +78 -3
  64. package/lib/commonjs/docs/enums/types.ZelloUserStatus.html +81 -7
  65. package/lib/commonjs/docs/hierarchy.html +29 -1
  66. package/lib/commonjs/docs/index.html +155 -26
  67. package/lib/commonjs/docs/interfaces/specs_NativeZelloSdk.Spec.html +504 -0
  68. package/lib/commonjs/docs/modules/events.html +37 -1
  69. package/lib/commonjs/docs/modules/index.html +37 -1
  70. package/lib/commonjs/docs/modules/sdk.html +37 -1
  71. package/lib/commonjs/docs/modules/specs_NativeZelloSdk.html +41 -0
  72. package/lib/commonjs/docs/modules/types.html +45 -1
  73. package/lib/commonjs/docs/modules.html +36 -1
  74. package/lib/commonjs/docs/types/types.ZelloChannelOptions.html +114 -9
  75. package/lib/commonjs/docs/types/types.ZelloConfig.html +86 -7
  76. package/lib/commonjs/docs/types/types.ZelloConsoleSettings.html +96 -9
  77. package/lib/commonjs/docs/types/types.ZelloContact.html +80 -6
  78. package/lib/commonjs/docs/types/types.ZelloCredentials.html +75 -6
  79. package/lib/commonjs/docs/types/types.ZelloHistoryMessage.html +97 -8
  80. package/lib/commonjs/docs/types/types.ZelloMessage.html +91 -7
  81. package/lib/commonjs/docs/variables/specs_NativeZelloSdk.default.html +34 -0
  82. package/lib/commonjs/events/index.js +217 -0
  83. package/lib/commonjs/events/index.js.map +1 -1
  84. package/lib/commonjs/sdk/index.js +731 -911
  85. package/lib/commonjs/sdk/index.js.map +1 -1
  86. package/lib/commonjs/specs/NativeZelloSdk.js +27 -0
  87. package/lib/commonjs/specs/NativeZelloSdk.js.map +1 -0
  88. package/lib/commonjs/types/index.js +423 -302
  89. package/lib/commonjs/types/index.js.map +1 -1
  90. package/lib/commonjs/utils/index.js +27 -4
  91. package/lib/commonjs/utils/index.js.map +1 -1
  92. package/lib/module/docs/assets/highlight.css +17 -10
  93. package/lib/module/docs/assets/icons.js +1 -1
  94. package/lib/module/docs/assets/icons.js.map +1 -1
  95. package/lib/module/docs/assets/icons.svg +1 -1
  96. package/lib/module/docs/assets/main.js +220 -288
  97. package/lib/module/docs/assets/main.js.map +1 -1
  98. package/lib/module/docs/assets/navigation.js +1 -1
  99. package/lib/module/docs/assets/navigation.js.map +1 -1
  100. package/lib/module/docs/assets/search.js +1 -1
  101. package/lib/module/docs/assets/search.js.map +1 -1
  102. package/lib/module/docs/assets/style.css +21 -6
  103. package/lib/module/docs/classes/sdk.Zello.html +793 -97
  104. package/lib/module/docs/classes/types.ZelloAlertMessage.html +122 -9
  105. package/lib/module/docs/classes/types.ZelloChannel.html +155 -10
  106. package/lib/module/docs/classes/types.ZelloChannelUser.html +86 -4
  107. package/lib/module/docs/classes/types.ZelloDispatchCall.html +90 -6
  108. package/lib/module/docs/classes/types.ZelloDispatchChannel.html +163 -11
  109. package/lib/module/docs/classes/types.ZelloGroupConversation.html +178 -13
  110. package/lib/module/docs/classes/types.ZelloHistoryAlertMessage.html +131 -10
  111. package/lib/module/docs/classes/types.ZelloHistoryImageMessage.html +123 -9
  112. package/lib/module/docs/classes/types.ZelloHistoryLocationMessage.html +155 -13
  113. package/lib/module/docs/classes/types.ZelloHistoryTextMessage.html +131 -10
  114. package/lib/module/docs/classes/types.ZelloHistoryVoiceMessage.html +145 -10
  115. package/lib/module/docs/classes/types.ZelloImageMessage.html +130 -10
  116. package/lib/module/docs/classes/types.ZelloIncomingEmergency.html +114 -9
  117. package/lib/module/docs/classes/types.ZelloIncomingVoiceMessage.html +124 -8
  118. package/lib/module/docs/classes/types.ZelloLocationMessage.html +146 -12
  119. package/lib/module/docs/classes/types.ZelloOutgoingEmergency.html +98 -7
  120. package/lib/module/docs/classes/types.ZelloOutgoingVoiceMessage.html +120 -9
  121. package/lib/module/docs/classes/types.ZelloRecentEntry.html +114 -9
  122. package/lib/module/docs/classes/types.ZelloTextMessage.html +122 -9
  123. package/lib/module/docs/classes/types.ZelloTranscription.html +122 -0
  124. package/lib/module/docs/classes/types.ZelloTranslation.html +91 -0
  125. package/lib/module/docs/classes/types.ZelloUser.html +142 -11
  126. package/lib/module/docs/classes/types.ZelloUserSupportedFeatures.html +82 -5
  127. package/lib/module/docs/enums/events.ZelloEvent.html +563 -95
  128. package/lib/module/docs/enums/types.ZelloAccountStatus.html +67 -5
  129. package/lib/module/docs/enums/types.ZelloChannelAlertLevel.html +67 -5
  130. package/lib/module/docs/enums/types.ZelloChannelConnectionStatus.html +68 -3
  131. package/lib/module/docs/enums/types.ZelloChannelType.html +84 -0
  132. package/lib/module/docs/enums/types.ZelloConnectionError.html +68 -3
  133. package/lib/module/docs/enums/types.ZelloConnectionState.html +73 -3
  134. package/lib/module/docs/enums/types.ZelloContactType.html +73 -3
  135. package/lib/module/docs/enums/types.ZelloDispatchCallStatus.html +73 -3
  136. package/lib/module/docs/enums/types.ZelloOutgoingVoiceMessageError.html +63 -3
  137. package/lib/module/docs/enums/types.ZelloOutgoingVoiceMessageState.html +78 -3
  138. package/lib/module/docs/enums/types.ZelloRecentEntryType.html +78 -3
  139. package/lib/module/docs/enums/types.ZelloUserStatus.html +81 -7
  140. package/lib/module/docs/hierarchy.html +29 -1
  141. package/lib/module/docs/index.html +155 -26
  142. package/lib/module/docs/interfaces/specs_NativeZelloSdk.Spec.html +504 -0
  143. package/lib/module/docs/modules/events.html +37 -1
  144. package/lib/module/docs/modules/index.html +37 -1
  145. package/lib/module/docs/modules/sdk.html +37 -1
  146. package/lib/module/docs/modules/specs_NativeZelloSdk.html +41 -0
  147. package/lib/module/docs/modules/types.html +45 -1
  148. package/lib/module/docs/modules.html +36 -1
  149. package/lib/module/docs/types/types.ZelloChannelOptions.html +114 -9
  150. package/lib/module/docs/types/types.ZelloConfig.html +86 -7
  151. package/lib/module/docs/types/types.ZelloConsoleSettings.html +96 -9
  152. package/lib/module/docs/types/types.ZelloContact.html +80 -6
  153. package/lib/module/docs/types/types.ZelloCredentials.html +75 -6
  154. package/lib/module/docs/types/types.ZelloHistoryMessage.html +97 -8
  155. package/lib/module/docs/types/types.ZelloMessage.html +91 -7
  156. package/lib/module/docs/variables/specs_NativeZelloSdk.default.html +34 -0
  157. package/lib/module/events/index.js +217 -0
  158. package/lib/module/events/index.js.map +1 -1
  159. package/lib/module/sdk/index.js +730 -912
  160. package/lib/module/sdk/index.js.map +1 -1
  161. package/lib/module/specs/NativeZelloSdk.js +25 -0
  162. package/lib/module/specs/NativeZelloSdk.js.map +1 -0
  163. package/lib/module/types/index.js +378 -301
  164. package/lib/module/types/index.js.map +1 -1
  165. package/lib/module/utils/index.js +27 -5
  166. package/lib/module/utils/index.js.map +1 -1
  167. package/lib/typescript/commonjs/src/events/index.d.ts +9 -0
  168. package/lib/typescript/commonjs/src/events/index.d.ts.map +1 -1
  169. package/lib/typescript/commonjs/src/sdk/index.d.ts +10 -0
  170. package/lib/typescript/commonjs/src/sdk/index.d.ts.map +1 -1
  171. package/lib/typescript/commonjs/src/specs/NativeZelloSdk.d.ts +55 -0
  172. package/lib/typescript/commonjs/src/specs/NativeZelloSdk.d.ts.map +1 -0
  173. package/lib/typescript/commonjs/src/types/index.d.ts +106 -4
  174. package/lib/typescript/commonjs/src/types/index.d.ts.map +1 -1
  175. package/lib/typescript/commonjs/src/utils/index.d.ts +2 -1
  176. package/lib/typescript/commonjs/src/utils/index.d.ts.map +1 -1
  177. package/lib/typescript/module/src/events/index.d.ts +9 -0
  178. package/lib/typescript/module/src/events/index.d.ts.map +1 -1
  179. package/lib/typescript/module/src/index.d.ts +4 -4
  180. package/lib/typescript/module/src/index.d.ts.map +1 -1
  181. package/lib/typescript/module/src/sdk/index.d.ts +11 -1
  182. package/lib/typescript/module/src/sdk/index.d.ts.map +1 -1
  183. package/lib/typescript/module/src/specs/NativeZelloSdk.d.ts +55 -0
  184. package/lib/typescript/module/src/specs/NativeZelloSdk.d.ts.map +1 -0
  185. package/lib/typescript/module/src/types/index.d.ts +106 -4
  186. package/lib/typescript/module/src/types/index.d.ts.map +1 -1
  187. package/lib/typescript/module/src/utils/algorithms/index.d.ts +1 -1
  188. package/lib/typescript/module/src/utils/algorithms/index.d.ts.map +1 -1
  189. package/lib/typescript/module/src/utils/index.d.ts +2 -1
  190. package/lib/typescript/module/src/utils/index.d.ts.map +1 -1
  191. package/package.json +53 -16
  192. package/react-native-zello-sdk.podspec +23 -24
  193. package/scripts/podfile-transform.js +416 -0
  194. package/scripts/setup-ios.js +248 -0
  195. package/scripts/zello_pods.rb +128 -0
  196. package/scripts/zello_sdk_requirement.rb +12 -0
  197. package/src/events/index.ts +9 -0
  198. package/src/sdk/index.ts +105 -225
  199. package/src/specs/NativeZelloSdk.ts +89 -0
  200. package/src/types/index.ts +153 -6
  201. package/src/utils/index.ts +50 -3
@@ -0,0 +1,416 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Text transformations that migrate a customer Podfile to the SPM-only ZelloSDK setup.
5
+ * Shared by the `setup-ios` CLI and the Expo config plugin. Pure: string in, result out.
6
+ * Every step is idempotent and aborts (reports `manual`) instead of guessing.
7
+ */
8
+
9
+ const MIN_IOS = '17.0';
10
+
11
+ const REQUIRE_LINES = [
12
+ "require Pod::Executable.execute_command('node', ['-p',",
13
+ ' "require.resolve(\'@zelloptt/react-native-zello-sdk/scripts/zello_pods.rb\', {paths: [process.argv[1]]})",',
14
+ ' __dir__]).strip',
15
+ ];
16
+
17
+ const RESILIENT_POD_NAMES = [
18
+ 'PhoneNumberKit',
19
+ 'SnowplowTracker',
20
+ 'CocoaLumberjack',
21
+ 'PromisesSwift',
22
+ ];
23
+
24
+ // Only top-level Podfile targets with such names are auto-detected as app extensions.
25
+ const EXTENSION_NAME_RE = /Extension|NSE|Widget/i;
26
+ const COMMENT_RE = /^\s*#/;
27
+ const BLANK_RE = /^\s*$/;
28
+
29
+ function stripComment(line) {
30
+ // Good enough for Podfile structure scanning: drop trailing `# ...` outside of simple quotes.
31
+ let quote = null;
32
+ for (let i = 0; i < line.length; i++) {
33
+ const ch = line[i];
34
+ if (quote) {
35
+ if (ch === quote && line[i - 1] !== '\\') {
36
+ quote = null;
37
+ }
38
+ } else if (ch === '"' || ch === "'") {
39
+ quote = ch;
40
+ } else if (ch === '#') {
41
+ return line.slice(0, i);
42
+ }
43
+ }
44
+ return line;
45
+ }
46
+
47
+ /** Removes lines [start, end] and one adjacent blank line if that would leave two in a row. */
48
+ function removeRange(lines, start, end) {
49
+ lines.splice(start, end - start + 1);
50
+ if (
51
+ start > 0 &&
52
+ start < lines.length &&
53
+ BLANK_RE.test(lines[start - 1]) &&
54
+ BLANK_RE.test(lines[start])
55
+ ) {
56
+ lines.splice(start, 1);
57
+ }
58
+ }
59
+
60
+ function compareVersions(a, b) {
61
+ const pa = String(a).split('.').map(Number);
62
+ const pb = String(b).split('.').map(Number);
63
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
64
+ const d = (pa[i] || 0) - (pb[i] || 0);
65
+ if (d !== 0) {
66
+ return d;
67
+ }
68
+ }
69
+ return 0;
70
+ }
71
+
72
+ // 3a -------------------------------------------------------------------------
73
+
74
+ function removeZelloPods(lines, result) {
75
+ const podRe = /^\s*pod\s*\(?\s*['"]ZelloSDK['"]/;
76
+ let removed = false;
77
+ for (let i = 0; i < lines.length; i++) {
78
+ if (!podRe.test(lines[i])) {
79
+ continue;
80
+ }
81
+ const code = stripComment(lines[i]).trimEnd();
82
+ if (/[,\\]$/.test(code) || /\(/.test(code.split(/['"]ZelloSDK/)[0])) {
83
+ result.manual.push(
84
+ `Line ${i + 1}: multi-line or parenthesised \`pod 'ZelloSDK'\` declaration. Delete it by hand.`
85
+ );
86
+ continue;
87
+ }
88
+ let start = i;
89
+ while (
90
+ start > 0 &&
91
+ COMMENT_RE.test(lines[start - 1]) &&
92
+ /zellosdk|podspec/i.test(lines[start - 1])
93
+ ) {
94
+ start--;
95
+ }
96
+ removeRange(lines, start, i);
97
+ i = start - 1;
98
+ removed = true;
99
+ }
100
+ if (removed) {
101
+ result.notes.push("Removed `pod 'ZelloSDK'` (now resolved via SwiftPM).");
102
+ }
103
+ }
104
+
105
+ // 3b -------------------------------------------------------------------------
106
+
107
+ function removeResilientReadmeForm(lines) {
108
+ const steps = [
109
+ /^installer\.pods_project\.targets\.each do \|\w+\|$/,
110
+ /^if %w\[[^\]]*\]\.include\?\(\w+\.name\)$/,
111
+ /^\w+\.build_configurations\.each do \|\w+\|$/,
112
+ /^\w+\.build_settings\[['"]BUILD_LIBRARY_FOR_DISTRIBUTION['"]\] = ['"]YES['"]$/,
113
+ /^end$/,
114
+ /^end$/,
115
+ /^end$/,
116
+ ];
117
+ let removed = false;
118
+ for (let i = 0; i + steps.length <= lines.length; i++) {
119
+ if (
120
+ steps.every((re, k) => re.test(stripComment(lines[i + k]).trim())) &&
121
+ RESILIENT_POD_NAMES.some((n) => lines[i + 1].includes(n))
122
+ ) {
123
+ removeRange(lines, i, i + steps.length - 1);
124
+ removed = true;
125
+ i--;
126
+ }
127
+ }
128
+ return removed;
129
+ }
130
+
131
+ function removeResilientExampleForm(lines) {
132
+ let removed = false;
133
+ for (let i = 0; i < lines.length; i++) {
134
+ const m = /^\s*(\w+)\s*=\s*\[([^\]]*)\]\s*$/.exec(stripComment(lines[i]));
135
+ if (!m || !RESILIENT_POD_NAMES.some((n) => m[2].includes(n))) {
136
+ continue;
137
+ }
138
+ const variable = m[1];
139
+ let start = i;
140
+ while (start > 0 && COMMENT_RE.test(lines[start - 1])) {
141
+ start--;
142
+ }
143
+ const comment = lines.slice(start, i).join('\n');
144
+ if (
145
+ !/resilient|BUILD_LIBRARY_FOR_DISTRIBUTION|library evolution/i.test(
146
+ comment
147
+ )
148
+ ) {
149
+ start = i;
150
+ }
151
+ removeRange(lines, start, i);
152
+ removed = true;
153
+
154
+ const branch = [
155
+ new RegExp(`^if ${variable}\\.include\\?\\(\\w+\\.name\\)$`),
156
+ /^\w+\.build_settings\[['"]BUILD_LIBRARY_FOR_DISTRIBUTION['"]\] = ['"]YES['"]$/,
157
+ /^end$/,
158
+ ];
159
+ for (let j = 0; j + branch.length <= lines.length; j++) {
160
+ if (branch.every((re, k) => re.test(stripComment(lines[j + k]).trim()))) {
161
+ removeRange(lines, j, j + branch.length - 1);
162
+ break;
163
+ }
164
+ }
165
+ i = start - 1;
166
+ }
167
+ return removed;
168
+ }
169
+
170
+ function removeResilientWorkaround(lines, result) {
171
+ const a = removeResilientReadmeForm(lines);
172
+ const b = removeResilientExampleForm(lines);
173
+ if (a || b) {
174
+ result.notes.push(
175
+ 'Removed the resilient-pods (BUILD_LIBRARY_FOR_DISTRIBUTION) workaround.'
176
+ );
177
+ }
178
+ const text = lines.join('\n');
179
+ const leftover =
180
+ /zello_resilient_pods/.test(text) ||
181
+ (/BUILD_LIBRARY_FOR_DISTRIBUTION/.test(text) &&
182
+ RESILIENT_POD_NAMES.some((n) => text.includes(n)));
183
+ if (leftover) {
184
+ result.manual.push(
185
+ 'Found an unrecognised resilient-pods (BUILD_LIBRARY_FOR_DISTRIBUTION for PhoneNumberKit/SnowplowTracker/' +
186
+ 'CocoaLumberjack/PromisesSwift) workaround. It is not needed with SwiftPM; delete it by hand.'
187
+ );
188
+ }
189
+ }
190
+
191
+ // 3c -------------------------------------------------------------------------
192
+
193
+ function noteUseSpm(lines, result) {
194
+ if (lines.some((l) => /ZELLO_USE_SPM/.test(stripComment(l)))) {
195
+ result.manual.push(
196
+ 'Found `ZELLO_USE_SPM` in the Podfile. It is no longer read (SwiftPM is the only path); delete it by hand, and from any scripts/CI that set it.'
197
+ );
198
+ }
199
+ }
200
+
201
+ // 3d -------------------------------------------------------------------------
202
+
203
+ function ensurePlatform(lines, result) {
204
+ const re = /^(\s*platform\s+:ios\s*,\s*)(.*?)(\s*#.*)?$/;
205
+ const idx = lines.findIndex((l) => !COMMENT_RE.test(l) && re.test(l));
206
+ if (idx === -1) {
207
+ result.notes.push(
208
+ `No \`platform :ios\` line found; make sure your deployment target is ${MIN_IOS} or later.`
209
+ );
210
+ return;
211
+ }
212
+ const m = re.exec(lines[idx]);
213
+ const value = m[2].trim();
214
+ const literal = /^(['"])(\d+(?:\.\d+)*)\1$/.exec(value);
215
+ let replace = false;
216
+ if (literal) {
217
+ replace = compareVersions(literal[2], MIN_IOS) < 0;
218
+ } else if (value === 'min_ios_version_supported') {
219
+ replace = true;
220
+ } else {
221
+ result.notes.push(
222
+ `\`${lines[idx].trim()}\` is not a literal version; make sure it resolves to ${MIN_IOS} or later.`
223
+ );
224
+ return;
225
+ }
226
+ if (replace) {
227
+ lines[idx] = `${m[1]}'${MIN_IOS}'${m[3] || ''}`;
228
+ result.notes.push(`Set \`platform :ios\` to '${MIN_IOS}'.`);
229
+ }
230
+ }
231
+
232
+ // Target detection -----------------------------------------------------------
233
+
234
+ function scanTargets(lines) {
235
+ const stack = [];
236
+ const targets = [];
237
+ lines.forEach((raw, index) => {
238
+ const line = stripComment(raw);
239
+ const code = line.trim();
240
+ if (!code) {
241
+ return;
242
+ }
243
+ const target =
244
+ /^(abstract_)?target\s*\(?\s*['"]([^'"]+)['"]\s*\)?\s+do\b/.exec(code);
245
+ if (target) {
246
+ const node = {
247
+ name: target[2],
248
+ abstract: Boolean(target[1]),
249
+ isTarget: true,
250
+ start: index,
251
+ body: [],
252
+ };
253
+ stack.push(node);
254
+ targets.push({
255
+ ...node,
256
+ node,
257
+ parents: stack.slice(0, -1).filter((n) => n.isTarget),
258
+ });
259
+ return;
260
+ }
261
+ if (/^end\b/.test(code)) {
262
+ stack.pop();
263
+ return;
264
+ }
265
+ if (
266
+ /\bdo(\s*\|[^|]*\|)?$/.test(code) ||
267
+ /^(if|unless|case|while|until|begin|def|class|module)\b/.test(code)
268
+ ) {
269
+ stack.push({ isTarget: false });
270
+ return;
271
+ }
272
+ stack.forEach((n) => n.isTarget && n.body.push(code));
273
+ });
274
+ return targets;
275
+ }
276
+
277
+ function detectTargets(lines, result, options) {
278
+ const all = scanTargets(lines);
279
+ const topLevel = all.filter(
280
+ (t) => !t.abstract && t.parents.every((p) => p.abstract)
281
+ );
282
+ let appTarget = options.appTarget;
283
+ if (!appTarget) {
284
+ const rn = topLevel.filter((t) =>
285
+ t.node.body.some((c) => /^use_react_native!/.test(c))
286
+ );
287
+ const candidates = rn.length ? rn : topLevel.length === 1 ? topLevel : [];
288
+ if (candidates.length !== 1) {
289
+ result.manual.push(
290
+ candidates.length === 0
291
+ ? 'Could not determine the app target (no top-level `target` with `use_react_native!`). Pass --app-target.'
292
+ : `More than one app target candidate (${candidates
293
+ .map((t) => t.name)
294
+ .join(', ')}). Pass --app-target.`
295
+ );
296
+ } else {
297
+ appTarget = candidates[0].name;
298
+ }
299
+ }
300
+ let extensionTargets = options.extensionTargets;
301
+ if (!extensionTargets) {
302
+ const others = topLevel
303
+ .filter((t) => t.name !== appTarget)
304
+ .map((t) => t.name);
305
+ extensionTargets = others.filter((n) => EXTENSION_NAME_RE.test(n));
306
+ const skipped = others.filter((n) => !extensionTargets.includes(n));
307
+ if (skipped.length) {
308
+ result.notes.push(
309
+ `Not treated as extension targets: ${skipped.join(', ')}. ` +
310
+ 'Pass --extension-target <name> for every app extension that uses ZelloSDK.'
311
+ );
312
+ }
313
+ }
314
+ return { appTarget, extensionTargets };
315
+ }
316
+
317
+ // 3e / 3f --------------------------------------------------------------------
318
+
319
+ function insertRequire(lines, result) {
320
+ if (
321
+ lines.some(
322
+ (l) => !COMMENT_RE.test(l) && l.includes('scripts/zello_pods.rb')
323
+ )
324
+ ) {
325
+ return;
326
+ }
327
+ const idx = lines.findIndex((l) =>
328
+ /^\s*prepare_react_native_project!/.test(l)
329
+ );
330
+ if (idx === -1) {
331
+ result.manual.push(
332
+ 'Could not find `prepare_react_native_project!` to anchor the `zello_pods.rb` require. Add the require line manually.'
333
+ );
334
+ return;
335
+ }
336
+ const pad = idx > 0 && !BLANK_RE.test(lines[idx - 1]) ? [''] : [];
337
+ lines.splice(idx, 0, ...pad, ...REQUIRE_LINES, '');
338
+ result.notes.push('Added the `zello_pods.rb` require.');
339
+ }
340
+
341
+ function formatCall(variable, appTarget, extensionTargets) {
342
+ const ext = extensionTargets.map((n) => `'${n}'`).join(', ');
343
+ return `zello_post_install(${variable}, app_target: '${appTarget}', extension_targets: [${ext}])`;
344
+ }
345
+
346
+ function insertPostInstall(lines, result, options) {
347
+ if (
348
+ lines.some((l) => !COMMENT_RE.test(l) && /\bzello_post_install\(/.test(l))
349
+ ) {
350
+ return;
351
+ }
352
+ const re = /^(\s*)post_install\s+do\s*\|(\w+)\|\s*$/;
353
+ const hits = lines
354
+ .map((l, i) => (re.test(stripComment(l)) ? i : -1))
355
+ .filter((i) => i >= 0);
356
+ const { appTarget, extensionTargets } = detectTargets(lines, result, options);
357
+
358
+ if (hits.length !== 1 || !appTarget) {
359
+ if (hits.length !== 1) {
360
+ result.manual.push(
361
+ hits.length === 0
362
+ ? 'No `post_install do |installer|` block found.'
363
+ : 'More than one `post_install` block found.'
364
+ );
365
+ }
366
+ const call = formatCall(
367
+ 'installer',
368
+ appTarget || 'YourApp',
369
+ extensionTargets || []
370
+ );
371
+ result.snippet = `post_install do |installer|\n ${call}\n # ...your existing post_install code...\nend`;
372
+ return;
373
+ }
374
+ const m = re.exec(stripComment(lines[hits[0]]));
375
+ lines.splice(
376
+ hits[0] + 1,
377
+ 0,
378
+ `${m[1]} ${formatCall(m[2], appTarget, extensionTargets)}`
379
+ );
380
+ result.notes.push(
381
+ `Added \`zello_post_install\` (app target: ${appTarget}; extension targets: ${
382
+ extensionTargets.length ? extensionTargets.join(', ') : 'none'
383
+ }).`
384
+ );
385
+ }
386
+
387
+ // ----------------------------------------------------------------------------
388
+
389
+ /**
390
+ * @param {string} source Podfile contents
391
+ * @param {{appTarget?: string, extensionTargets?: string[]}} [options]
392
+ * @returns {{content: string, changed: boolean, notes: string[], manual: string[], snippet?: string}}
393
+ */
394
+ function transformPodfile(source, options = {}) {
395
+ const result = { content: source, changed: false, notes: [], manual: [] };
396
+ const eol = source.includes('\r\n') ? '\r\n' : '\n';
397
+ const lines = source.split(/\r?\n/);
398
+
399
+ removeZelloPods(lines, result);
400
+ removeResilientWorkaround(lines, result);
401
+ noteUseSpm(lines, result);
402
+ ensurePlatform(lines, result);
403
+ insertRequire(lines, result);
404
+ insertPostInstall(lines, result, options);
405
+
406
+ result.content = lines.join(eol);
407
+ result.changed = result.content !== source;
408
+ return result;
409
+ }
410
+
411
+ module.exports = {
412
+ MIN_IOS,
413
+ REQUIRE_LINES,
414
+ transformPodfile,
415
+ compareVersions,
416
+ };
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * One-time iOS setup for @zelloptt/react-native-zello-sdk:
6
+ * npx @zelloptt/react-native-zello-sdk setup-ios [options]
7
+ *
8
+ * Migrates the app's Podfile to the SwiftPM-based native ZelloSDK. Never touches .xcodeproj
9
+ * (the `zello_post_install` Podfile helper owns that). Exit codes: 0 applied/no-op,
10
+ * 1 error, 2 manual step required.
11
+ */
12
+
13
+ const fs = require('node:fs');
14
+ const path = require('node:path');
15
+ const readline = require('node:readline');
16
+ const { transformPodfile, REQUIRE_LINES } = require('./podfile-transform');
17
+
18
+ const USAGE = `Usage: react-native-zello-sdk setup-ios [options]
19
+
20
+ Options:
21
+ --podfile <path> Podfile to migrate (default: <project-root>/ios/Podfile)
22
+ --project-root <dir> React Native project root (default: current directory)
23
+ --app-target <name> App target (default: detected)
24
+ --extension-target <name> Extension target, repeatable (default: detected)
25
+ --dry-run Print the diff, write nothing
26
+ --yes Apply without asking for confirmation
27
+ -h, --help Show this help
28
+ `;
29
+
30
+ function parseArgs(argv) {
31
+ const opts = { extensionTargets: [] };
32
+ const args = argv.slice();
33
+ const value = (flag) => {
34
+ const v = args.shift();
35
+ if (v === undefined || v.startsWith('--')) {
36
+ throw new Error(`${flag} requires a value`);
37
+ }
38
+ return v;
39
+ };
40
+ while (args.length) {
41
+ const arg = args.shift();
42
+ switch (arg) {
43
+ case 'setup-ios':
44
+ opts.command = 'setup-ios';
45
+ break;
46
+ case '--podfile':
47
+ opts.podfile = value(arg);
48
+ break;
49
+ case '--project-root':
50
+ opts.projectRoot = value(arg);
51
+ break;
52
+ case '--app-target':
53
+ opts.appTarget = value(arg);
54
+ break;
55
+ case '--extension-target':
56
+ opts.extensionTargets.push(value(arg));
57
+ break;
58
+ case '--dry-run':
59
+ opts.dryRun = true;
60
+ break;
61
+ case '--yes':
62
+ case '-y':
63
+ opts.yes = true;
64
+ break;
65
+ case '-h':
66
+ case '--help':
67
+ opts.help = true;
68
+ break;
69
+ default:
70
+ throw new Error(`Unknown argument: ${arg}`);
71
+ }
72
+ }
73
+ return opts;
74
+ }
75
+
76
+ /** Minimal unified diff (LCS based; Podfiles are small). */
77
+ function unifiedDiff(before, after, label) {
78
+ const a = before.split('\n');
79
+ const b = after.split('\n');
80
+ const dp = Array.from({ length: a.length + 1 }, () =>
81
+ new Array(b.length + 1).fill(0)
82
+ );
83
+ for (let i = a.length - 1; i >= 0; i--) {
84
+ for (let j = b.length - 1; j >= 0; j--) {
85
+ dp[i][j] =
86
+ a[i] === b[j]
87
+ ? dp[i + 1][j + 1] + 1
88
+ : Math.max(dp[i + 1][j], dp[i][j + 1]);
89
+ }
90
+ }
91
+ const ops = [];
92
+ let i = 0;
93
+ let j = 0;
94
+ while (i < a.length || j < b.length) {
95
+ if (i < a.length && j < b.length && a[i] === b[j]) {
96
+ ops.push([' ', a[i]]);
97
+ i++;
98
+ j++;
99
+ } else if (
100
+ j < b.length &&
101
+ (i === a.length || dp[i][j + 1] >= dp[i + 1][j])
102
+ ) {
103
+ ops.push(['+', b[j++]]);
104
+ } else {
105
+ ops.push(['-', a[i++]]);
106
+ }
107
+ }
108
+ const context = 3;
109
+ const keep = ops.map((_, k) =>
110
+ ops
111
+ .slice(Math.max(0, k - context), k + context + 1)
112
+ .some(([u]) => u !== ' ')
113
+ );
114
+ const out = [`--- a/${label}`, `+++ b/${label}`];
115
+ let inHunk = false;
116
+ ops.forEach(([t, line], k) => {
117
+ if (keep[k]) {
118
+ if (!inHunk) {
119
+ out.push('@@');
120
+ inHunk = true;
121
+ }
122
+ out.push(t + line);
123
+ } else {
124
+ inHunk = false;
125
+ }
126
+ });
127
+ return out.join('\n');
128
+ }
129
+
130
+ function ask(question, io) {
131
+ return new Promise((resolve) => {
132
+ const rl = readline.createInterface({ input: io.stdin, output: io.stdout });
133
+ rl.question(question, (answer) => {
134
+ rl.close();
135
+ resolve(/^y(es)?$/i.test(answer.trim()));
136
+ });
137
+ });
138
+ }
139
+
140
+ /**
141
+ * @returns {Promise<number>} exit code
142
+ */
143
+ async function main(argv, io = {}) {
144
+ const out = io.stdout || process.stdout;
145
+ const err = io.stderr || process.stderr;
146
+ const cwd = io.cwd || process.cwd();
147
+ const log = (s) => out.write(`${s}\n`);
148
+ const fail = (s) => err.write(`${s}\n`);
149
+
150
+ let opts;
151
+ try {
152
+ opts = parseArgs(argv);
153
+ } catch (e) {
154
+ fail(`${e.message}\n\n${USAGE}`);
155
+ return 1;
156
+ }
157
+ if (opts.help || (!opts.command && argv.length === 0)) {
158
+ log(USAGE);
159
+ return 0;
160
+ }
161
+ if (!opts.command) {
162
+ fail(`Missing command \`setup-ios\`.\n\n${USAGE}`);
163
+ return 1;
164
+ }
165
+
166
+ const root = path.resolve(cwd, opts.projectRoot || '.');
167
+ const podfile = path.resolve(
168
+ cwd,
169
+ opts.podfile || path.join(root, 'ios', 'Podfile')
170
+ );
171
+ if (!fs.existsSync(podfile)) {
172
+ fail(
173
+ `Podfile not found at ${podfile}.\n` +
174
+ 'Run this from your React Native project root, or pass --project-root <dir> / --podfile <path> (monorepos).'
175
+ );
176
+ return 1;
177
+ }
178
+
179
+ const source = fs.readFileSync(podfile, 'utf8');
180
+ const result = transformPodfile(source, {
181
+ appTarget: opts.appTarget,
182
+ extensionTargets: opts.extensionTargets.length
183
+ ? opts.extensionTargets
184
+ : undefined,
185
+ });
186
+
187
+ if (result.manual.length) {
188
+ fail(`Manual step required; ${podfile} was not modified:`);
189
+ result.manual.forEach((m) => fail(` - ${m}`));
190
+ if (result.snippet) {
191
+ fail(`\nAdd this to your Podfile:\n\n${result.snippet}\n`);
192
+ }
193
+ fail(
194
+ 'Also add the require line before `prepare_react_native_project!`:\n\n' +
195
+ REQUIRE_LINES.join('\n') +
196
+ '\n'
197
+ );
198
+ return 2;
199
+ }
200
+
201
+ result.notes.forEach((n) => log(`- ${n}`));
202
+ if (!result.changed) {
203
+ log('Podfile is already set up. Nothing to do.');
204
+ return 0;
205
+ }
206
+
207
+ log(
208
+ `\n${unifiedDiff(source, result.content, path.relative(cwd, podfile) || podfile)}\n`
209
+ );
210
+ if (opts.dryRun) {
211
+ log('Dry run: no files written.');
212
+ return 0;
213
+ }
214
+ if (!opts.yes) {
215
+ if (!io.stdin && !process.stdin.isTTY) {
216
+ fail(
217
+ 'Refusing to modify the Podfile without confirmation. Re-run with --yes (or --dry-run to preview).'
218
+ );
219
+ return 1;
220
+ }
221
+ if (
222
+ !(await ask('Apply these changes? [y/N] ', {
223
+ stdin: io.stdin || process.stdin,
224
+ stdout: out,
225
+ }))
226
+ ) {
227
+ log('Aborted; no files written.');
228
+ return 1;
229
+ }
230
+ }
231
+ fs.writeFileSync(podfile, result.content);
232
+ log(`Updated ${podfile}. Next: run \`bundle exec pod install\` in ios/.`);
233
+ return 0;
234
+ }
235
+
236
+ module.exports = { main, parseArgs, unifiedDiff };
237
+
238
+ if (require.main === module) {
239
+ main(process.argv.slice(2)).then(
240
+ (code) => {
241
+ process.exitCode = code;
242
+ },
243
+ (e) => {
244
+ process.stderr.write(`${e.stack || e}\n`);
245
+ process.exitCode = 1;
246
+ }
247
+ );
248
+ }