@temboplus/frontend-core 0.2.1 → 0.2.3

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 (200) hide show
  1. package/README.md +126 -25
  2. package/esm/deps/jsr.io/@std/internal/1.0.5/assertion_state.d.ts.map +1 -0
  3. package/esm/deps/jsr.io/@std/testing/1.0.9/_test_suite.d.ts.map +1 -0
  4. package/esm/deps/jsr.io/@std/testing/1.0.9/bdd.d.ts.map +1 -0
  5. package/esm/mod.d.ts +2 -0
  6. package/esm/mod.d.ts.map +1 -1
  7. package/esm/mod.js +2 -0
  8. package/esm/src/config/config_service.d.ts +11 -0
  9. package/esm/src/config/config_service.d.ts.map +1 -0
  10. package/esm/src/config/config_service.js +19 -0
  11. package/esm/src/config/index.d.ts +2 -0
  12. package/esm/src/config/index.d.ts.map +1 -0
  13. package/esm/src/config/index.js +1 -0
  14. package/esm/src/{models/bank/banks.d.ts → data/banks_tz.d.ts} +1 -1
  15. package/esm/src/data/banks_tz.d.ts.map +1 -0
  16. package/esm/src/data/countries.d.ts +6 -0
  17. package/esm/src/data/countries.d.ts.map +1 -0
  18. package/esm/src/data/countries.js +974 -0
  19. package/esm/src/data/currencies.d.ts +1901 -0
  20. package/esm/src/data/currencies.d.ts.map +1 -0
  21. package/esm/src/data/currencies.js +1073 -0
  22. package/esm/src/data/phone_patterns.d.ts +3809 -0
  23. package/esm/src/data/phone_patterns.d.ts.map +1 -0
  24. package/esm/src/data/phone_patterns.js +2325 -0
  25. package/esm/src/models/amount/amount.d.ts +10 -12
  26. package/esm/src/models/amount/amount.d.ts.map +1 -1
  27. package/esm/src/models/amount/amount.js +58 -96
  28. package/esm/src/models/bank/bank.d.ts +58 -53
  29. package/esm/src/models/bank/bank.d.ts.map +1 -1
  30. package/esm/src/models/bank/bank.js +49 -84
  31. package/esm/src/models/bank/index.d.ts +1 -1
  32. package/esm/src/models/bank/index.d.ts.map +1 -1
  33. package/esm/src/models/bank/index.js +1 -1
  34. package/esm/src/models/bank/service.d.ts +106 -0
  35. package/esm/src/models/bank/service.d.ts.map +1 -0
  36. package/esm/src/models/bank/service.js +240 -0
  37. package/esm/src/models/country/country.d.ts +568 -0
  38. package/esm/src/models/country/country.d.ts.map +1 -0
  39. package/esm/src/models/country/country.js +165 -0
  40. package/esm/src/models/country/country.test.d.ts.map +1 -0
  41. package/esm/src/models/country/index.d.ts +3 -0
  42. package/esm/src/models/country/index.d.ts.map +1 -0
  43. package/esm/src/models/country/index.js +2 -0
  44. package/esm/src/models/country/service.d.ts +75 -0
  45. package/esm/src/models/country/service.d.ts.map +1 -0
  46. package/esm/src/models/country/service.js +267 -0
  47. package/esm/src/models/currency/currency.d.ts +341 -0
  48. package/esm/src/models/currency/currency.d.ts.map +1 -0
  49. package/esm/src/models/currency/currency.js +225 -0
  50. package/esm/src/models/currency/currency.test.d.ts.map +1 -0
  51. package/esm/src/models/currency/index.d.ts +3 -0
  52. package/esm/src/models/currency/index.d.ts.map +1 -0
  53. package/esm/src/models/currency/index.js +2 -0
  54. package/esm/src/models/currency/service.d.ts +96 -0
  55. package/esm/src/models/currency/service.d.ts.map +1 -0
  56. package/esm/src/models/currency/service.js +194 -0
  57. package/esm/src/models/index.d.ts +2 -0
  58. package/esm/src/models/index.d.ts.map +1 -1
  59. package/esm/src/models/index.js +2 -0
  60. package/esm/src/models/phone_number/format.d.ts +14 -0
  61. package/esm/src/models/phone_number/format.d.ts.map +1 -0
  62. package/esm/src/models/phone_number/format.js +14 -0
  63. package/esm/src/models/phone_number/global/phone_number.d.ts +160 -0
  64. package/esm/src/models/phone_number/global/phone_number.d.ts.map +1 -0
  65. package/esm/src/models/phone_number/global/phone_number.js +453 -0
  66. package/esm/src/models/phone_number/global/phone_number.test.d.ts.map +1 -0
  67. package/esm/src/models/phone_number/global/service.d.ts +260 -0
  68. package/esm/src/models/phone_number/global/service.d.ts.map +1 -0
  69. package/esm/src/models/phone_number/global/service.js +477 -0
  70. package/esm/src/models/phone_number/global/service.test.d.ts.map +1 -0
  71. package/esm/src/models/phone_number/index.d.ts +5 -3
  72. package/esm/src/models/phone_number/index.d.ts.map +1 -1
  73. package/esm/src/models/phone_number/index.js +5 -3
  74. package/esm/src/models/phone_number/{antd_validator.d.ts → tz/antd_validator.d.ts} +2 -2
  75. package/esm/src/models/phone_number/tz/antd_validator.d.ts.map +1 -0
  76. package/esm/src/models/phone_number/{antd_validator.js → tz/antd_validator.js} +2 -2
  77. package/esm/src/models/phone_number/tz/antdvalidator.test.d.ts.map +1 -0
  78. package/esm/src/models/phone_number/tz/network_operator.d.ts.map +1 -0
  79. package/{script/src/models/phone_number → esm/src/models/phone_number/tz}/phone_number.d.ts +46 -29
  80. package/esm/src/models/phone_number/tz/phone_number.d.ts.map +1 -0
  81. package/esm/src/models/phone_number/{phone_number.js → tz/phone_number.js} +87 -41
  82. package/esm/src/models/phone_number/tz/phone_number.test.d.ts.map +1 -0
  83. package/esm/src/reports/index.d.ts +2 -0
  84. package/esm/src/reports/index.d.ts.map +1 -0
  85. package/esm/src/reports/index.js +1 -0
  86. package/esm/src/reports/report_manager.d.ts +144 -0
  87. package/esm/src/reports/report_manager.d.ts.map +1 -0
  88. package/esm/src/reports/report_manager.js +315 -0
  89. package/package.json +4 -3
  90. package/script/deps/jsr.io/@std/internal/1.0.5/assertion_state.d.ts.map +1 -0
  91. package/script/deps/jsr.io/@std/testing/1.0.9/_test_suite.d.ts.map +1 -0
  92. package/script/deps/jsr.io/@std/testing/1.0.9/bdd.d.ts.map +1 -0
  93. package/script/mod.d.ts +2 -0
  94. package/script/mod.d.ts.map +1 -1
  95. package/script/mod.js +2 -0
  96. package/script/src/config/config_service.d.ts +11 -0
  97. package/script/src/config/config_service.d.ts.map +1 -0
  98. package/script/src/config/config_service.js +23 -0
  99. package/script/src/config/index.d.ts +2 -0
  100. package/script/src/config/index.d.ts.map +1 -0
  101. package/script/src/config/index.js +17 -0
  102. package/script/src/{models/bank/banks.d.ts → data/banks_tz.d.ts} +1 -1
  103. package/script/src/data/banks_tz.d.ts.map +1 -0
  104. package/script/src/data/countries.d.ts +6 -0
  105. package/script/src/data/countries.d.ts.map +1 -0
  106. package/script/src/data/countries.js +976 -0
  107. package/script/src/data/currencies.d.ts +1901 -0
  108. package/script/src/data/currencies.d.ts.map +1 -0
  109. package/script/src/data/currencies.js +1075 -0
  110. package/script/src/data/phone_patterns.d.ts +3809 -0
  111. package/script/src/data/phone_patterns.d.ts.map +1 -0
  112. package/script/src/data/phone_patterns.js +2327 -0
  113. package/script/src/models/amount/amount.d.ts +10 -12
  114. package/script/src/models/amount/amount.d.ts.map +1 -1
  115. package/script/src/models/amount/amount.js +60 -98
  116. package/script/src/models/bank/bank.d.ts +58 -53
  117. package/script/src/models/bank/bank.d.ts.map +1 -1
  118. package/script/src/models/bank/bank.js +49 -87
  119. package/script/src/models/bank/index.d.ts +1 -1
  120. package/script/src/models/bank/index.d.ts.map +1 -1
  121. package/script/src/models/bank/index.js +1 -1
  122. package/script/src/models/bank/service.d.ts +106 -0
  123. package/script/src/models/bank/service.d.ts.map +1 -0
  124. package/script/src/models/bank/service.js +247 -0
  125. package/script/src/models/country/country.d.ts +568 -0
  126. package/script/src/models/country/country.d.ts.map +1 -0
  127. package/script/src/models/country/country.js +169 -0
  128. package/script/src/models/country/country.test.d.ts.map +1 -0
  129. package/script/src/models/country/index.d.ts +3 -0
  130. package/script/src/models/country/index.d.ts.map +1 -0
  131. package/script/src/models/country/index.js +18 -0
  132. package/script/src/models/country/service.d.ts +75 -0
  133. package/script/src/models/country/service.d.ts.map +1 -0
  134. package/script/src/models/country/service.js +274 -0
  135. package/script/src/models/currency/currency.d.ts +341 -0
  136. package/script/src/models/currency/currency.d.ts.map +1 -0
  137. package/script/src/models/currency/currency.js +229 -0
  138. package/script/src/models/currency/currency.test.d.ts.map +1 -0
  139. package/script/src/models/currency/index.d.ts +3 -0
  140. package/script/src/models/currency/index.d.ts.map +1 -0
  141. package/script/src/models/currency/index.js +18 -0
  142. package/script/src/models/currency/service.d.ts +96 -0
  143. package/script/src/models/currency/service.d.ts.map +1 -0
  144. package/script/src/models/currency/service.js +201 -0
  145. package/script/src/models/index.d.ts +2 -0
  146. package/script/src/models/index.d.ts.map +1 -1
  147. package/script/src/models/index.js +2 -0
  148. package/script/src/models/phone_number/format.d.ts +14 -0
  149. package/script/src/models/phone_number/format.d.ts.map +1 -0
  150. package/script/src/models/phone_number/format.js +17 -0
  151. package/script/src/models/phone_number/global/phone_number.d.ts +160 -0
  152. package/script/src/models/phone_number/global/phone_number.d.ts.map +1 -0
  153. package/script/src/models/phone_number/global/phone_number.js +457 -0
  154. package/script/src/models/phone_number/global/phone_number.test.d.ts.map +1 -0
  155. package/script/src/models/phone_number/global/service.d.ts +260 -0
  156. package/script/src/models/phone_number/global/service.d.ts.map +1 -0
  157. package/script/src/models/phone_number/global/service.js +485 -0
  158. package/script/src/models/phone_number/global/service.test.d.ts.map +1 -0
  159. package/script/src/models/phone_number/index.d.ts +5 -3
  160. package/script/src/models/phone_number/index.d.ts.map +1 -1
  161. package/script/src/models/phone_number/index.js +5 -3
  162. package/script/src/models/phone_number/{antd_validator.d.ts → tz/antd_validator.d.ts} +2 -2
  163. package/script/src/models/phone_number/tz/antd_validator.d.ts.map +1 -0
  164. package/script/src/models/phone_number/{antd_validator.js → tz/antd_validator.js} +1 -1
  165. package/script/src/models/phone_number/tz/antdvalidator.test.d.ts.map +1 -0
  166. package/script/src/models/phone_number/tz/network_operator.d.ts.map +1 -0
  167. package/{esm/src/models/phone_number → script/src/models/phone_number/tz}/phone_number.d.ts +46 -29
  168. package/script/src/models/phone_number/tz/phone_number.d.ts.map +1 -0
  169. package/script/src/models/phone_number/{phone_number.js → tz/phone_number.js} +89 -43
  170. package/script/src/models/phone_number/tz/phone_number.test.d.ts.map +1 -0
  171. package/script/src/reports/index.d.ts +2 -0
  172. package/script/src/reports/index.d.ts.map +1 -0
  173. package/script/src/reports/index.js +17 -0
  174. package/script/src/reports/report_manager.d.ts +144 -0
  175. package/script/src/reports/report_manager.d.ts.map +1 -0
  176. package/script/src/reports/report_manager.js +325 -0
  177. package/esm/src/models/bank/banks.d.ts.map +0 -1
  178. package/esm/src/models/bank/utils.d.ts +0 -25
  179. package/esm/src/models/bank/utils.d.ts.map +0 -1
  180. package/esm/src/models/bank/utils.js +0 -35
  181. package/esm/src/models/phone_number/antd_validator.d.ts.map +0 -1
  182. package/esm/src/models/phone_number/antdvalidator.test.d.ts.map +0 -1
  183. package/esm/src/models/phone_number/network_operator.d.ts.map +0 -1
  184. package/esm/src/models/phone_number/phone_number.d.ts.map +0 -1
  185. package/esm/src/models/phone_number/phone_number.test.d.ts.map +0 -1
  186. package/script/src/models/bank/banks.d.ts.map +0 -1
  187. package/script/src/models/bank/utils.d.ts +0 -25
  188. package/script/src/models/bank/utils.d.ts.map +0 -1
  189. package/script/src/models/bank/utils.js +0 -41
  190. package/script/src/models/phone_number/antd_validator.d.ts.map +0 -1
  191. package/script/src/models/phone_number/antdvalidator.test.d.ts.map +0 -1
  192. package/script/src/models/phone_number/network_operator.d.ts.map +0 -1
  193. package/script/src/models/phone_number/phone_number.d.ts.map +0 -1
  194. package/script/src/models/phone_number/phone_number.test.d.ts.map +0 -1
  195. /package/esm/src/{models/bank/banks.js → data/banks_tz.js} +0 -0
  196. /package/esm/src/models/phone_number/{network_operator.d.ts → tz/network_operator.d.ts} +0 -0
  197. /package/esm/src/models/phone_number/{network_operator.js → tz/network_operator.js} +0 -0
  198. /package/script/src/{models/bank/banks.js → data/banks_tz.js} +0 -0
  199. /package/script/src/models/phone_number/{network_operator.d.ts → tz/network_operator.d.ts} +0 -0
  200. /package/script/src/models/phone_number/{network_operator.js → tz/network_operator.js} +0 -0
@@ -0,0 +1,477 @@
1
+ /**
2
+ * @fileoverview
3
+ *
4
+ * # Global Phone Number Service
5
+ *
6
+ * ## Features
7
+ * 1. Loads and maintains phone number metadata from patterns database
8
+ * 2. Validates phone numbers against country-specific patterns
9
+ * 3. Provides utility functions for phone number operations
10
+ * 4. Follows singleton pattern for efficient resource usage
11
+ */
12
+ import { Country } from "../../country/country.js";
13
+ import { PhoneNumber } from "./phone_number.js";
14
+ import phonePatterns from "../../../data/phone_patterns.js";
15
+ import { PhoneNumberFormat } from "../format.js";
16
+ /**
17
+ * Phone number pattern type
18
+ */
19
+ export var PhoneNumberType;
20
+ (function (PhoneNumberType) {
21
+ PhoneNumberType["LANDLINE"] = "landline";
22
+ PhoneNumberType["MOBILE"] = "mobile";
23
+ PhoneNumberType["TOLL_FREE"] = "toll_free";
24
+ PhoneNumberType["PREMIUM_RATE"] = "premium_rate";
25
+ PhoneNumberType["SHARED_COST"] = "shared_cost";
26
+ PhoneNumberType["EMERGENCY"] = "emergency";
27
+ PhoneNumberType["SPECIAL_SERVICES"] = "special_services";
28
+ PhoneNumberType["VOIP"] = "voip";
29
+ PhoneNumberType["PERSONAL"] = "personal";
30
+ PhoneNumberType["UNKNOWN"] = "unknown";
31
+ })(PhoneNumberType || (PhoneNumberType = {}));
32
+ /**
33
+ * Error thrown when a phone number has an ambiguous country due to shared dial code
34
+ */
35
+ export class SharedDialCodeError extends Error {
36
+ /**
37
+ * Creates a new SharedDialCodeError
38
+ *
39
+ * @param dialCode - The shared dial code
40
+ * @param countries - Countries that share this dial code
41
+ */
42
+ constructor(dialCode, countries) {
43
+ const message = `Dial code +${dialCode} is shared by multiple countries: ${countries.join(", ")}. Please use 'fromWithCountry' with a specific country.`;
44
+ super(message);
45
+ /** The dial code that's shared */
46
+ Object.defineProperty(this, "dialCode", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: void 0
51
+ });
52
+ /** List of country codes that share this dial code */
53
+ Object.defineProperty(this, "countries", {
54
+ enumerable: true,
55
+ configurable: true,
56
+ writable: true,
57
+ value: void 0
58
+ });
59
+ this.name = "SharedDialCodeError";
60
+ this.dialCode = dialCode;
61
+ this.countries = countries;
62
+ }
63
+ }
64
+ /**
65
+ * Service for managing global phone number operations
66
+ */
67
+ export class GlobalPhoneNumberService {
68
+ /**
69
+ * Private constructor to enforce singleton pattern
70
+ */
71
+ constructor() {
72
+ Object.defineProperty(this, "countryMetadata", {
73
+ enumerable: true,
74
+ configurable: true,
75
+ writable: true,
76
+ value: {}
77
+ });
78
+ Object.defineProperty(this, "sharedCountryCodes", {
79
+ enumerable: true,
80
+ configurable: true,
81
+ writable: true,
82
+ value: {}
83
+ });
84
+ Object.defineProperty(this, "initialized", {
85
+ enumerable: true,
86
+ configurable: true,
87
+ writable: true,
88
+ value: false
89
+ });
90
+ }
91
+ /**
92
+ * Gets the singleton instance of GlobalPhoneNumberService
93
+ * Creates the instance if it doesn't exist
94
+ *
95
+ * @returns {GlobalPhoneNumberService} The singleton instance
96
+ */
97
+ static getInstance() {
98
+ if (!GlobalPhoneNumberService.instance) {
99
+ GlobalPhoneNumberService.instance = new GlobalPhoneNumberService();
100
+ GlobalPhoneNumberService.instance.initialize();
101
+ }
102
+ return GlobalPhoneNumberService.instance;
103
+ }
104
+ /**
105
+ * Initializes the service with phone patterns data
106
+ * Should be called once when the service is first used
107
+ */
108
+ initialize() {
109
+ try {
110
+ if (this.initialized)
111
+ return;
112
+ // Parse the phone patterns data
113
+ const data = JSON.parse(JSON.stringify(phonePatterns));
114
+ // Extract shared country codes
115
+ this.sharedCountryCodes = data._shared_country_codes || {};
116
+ const countries = Object.entries(data)
117
+ .filter(([key]) => !key.startsWith("_"))
118
+ .reduce((result, [key, value]) => {
119
+ result[key] = value;
120
+ return result;
121
+ }, {});
122
+ this.countryMetadata = countries;
123
+ this.initialized = true;
124
+ }
125
+ catch (error) {
126
+ console.error("Failed to initialize GlobalPhoneNumberService:", error);
127
+ }
128
+ }
129
+ /**
130
+ * Gets the metadata for a specific country
131
+ *
132
+ * @param {string} countryCode - The ISO country code
133
+ * @returns {CountryMetadata | undefined} The country metadata or undefined if not found
134
+ */
135
+ getCountryMetadata(countryCode) {
136
+ return this.countryMetadata[countryCode];
137
+ }
138
+ /**
139
+ * Gets all country metadata
140
+ *
141
+ * @returns {CountryMetadataMap} All country metadata
142
+ */
143
+ getAllCountryMetadata() {
144
+ return this.countryMetadata;
145
+ }
146
+ /**
147
+ * Gets all the countries that share a specific dial code
148
+ *
149
+ * @param {string | number} dialCode - The dial code to check
150
+ * @returns {string[]} Array of ISO country codes that share this dial code
151
+ */
152
+ getCountriesWithDialCode(dialCode) {
153
+ const dialCodeStr = dialCode.toString();
154
+ return this.sharedCountryCodes[dialCodeStr] || [];
155
+ }
156
+ /**
157
+ * Checks if a dial code is shared between multiple countries
158
+ *
159
+ * @param {string | number} dialCode - The dial code to check
160
+ * @returns {boolean} True if the dial code is shared, false otherwise
161
+ */
162
+ isSharedDialCode(dialCode) {
163
+ const dialCodeStr = dialCode.toString();
164
+ const countries = this.sharedCountryCodes[dialCodeStr];
165
+ return countries !== undefined && countries.length > 1;
166
+ }
167
+ /**
168
+ * Finds the country code associated with a given dial code
169
+ *
170
+ * @param dialCode - The dial code to look up
171
+ * @returns The country code or undefined if not found
172
+ */
173
+ getCountryForDialCode(dialCode) {
174
+ for (const [countryCode, metadata] of Object.entries(this.countryMetadata)) {
175
+ if (metadata.code.toString() === dialCode) {
176
+ return countryCode;
177
+ }
178
+ }
179
+ return undefined;
180
+ }
181
+ /**
182
+ * Extracts dial code information from a phone number
183
+ *
184
+ * @param phoneNumber - The phone number in international format (with +)
185
+ * @returns Dial code information or undefined if not found
186
+ */
187
+ extractDialCode(phoneNumber) {
188
+ const cleaned = this.cleanPhoneNumber(phoneNumber);
189
+ if (!cleaned.startsWith("+"))
190
+ return undefined;
191
+ const numberWithoutPlus = cleaned.substring(1);
192
+ // Try to find the dial code by checking prefixes of increasing length
193
+ for (let i = 3; i >= 1; i--) {
194
+ if (numberWithoutPlus.length <= i)
195
+ continue;
196
+ const dialCode = numberWithoutPlus.substring(0, i);
197
+ // Check if any country has this dial code
198
+ let countryFound = false;
199
+ for (const [_, metadata] of Object.entries(this.countryMetadata)) {
200
+ if (metadata.code.toString() === dialCode) {
201
+ countryFound = true;
202
+ break;
203
+ }
204
+ }
205
+ if (countryFound) {
206
+ const nationalNumber = numberWithoutPlus.substring(dialCode.length);
207
+ const isShared = this.isSharedDialCode(dialCode);
208
+ const possibleCountries = isShared
209
+ ? this.sharedCountryCodes[dialCode]
210
+ : [this.getCountryForDialCode(dialCode) ?? ""];
211
+ return {
212
+ dialCode,
213
+ isShared,
214
+ nationalNumber,
215
+ possibleCountries,
216
+ };
217
+ }
218
+ }
219
+ return undefined;
220
+ }
221
+ /**
222
+ * Gets the countries that might be associated with a phone number
223
+ *
224
+ * @param {string} phoneNumber - The phone number in international format
225
+ * @returns {Country[]} Array of possible countries for this phone number
226
+ */
227
+ getPossibleCountries(phoneNumber) {
228
+ const cleanedNumber = this.cleanPhoneNumber(phoneNumber);
229
+ if (!cleanedNumber.startsWith("+"))
230
+ return [];
231
+ const dialCodeInfo = this.extractDialCode(cleanedNumber);
232
+ if (!dialCodeInfo)
233
+ return [];
234
+ const possibleCountries = [];
235
+ for (const countryCode of dialCodeInfo.possibleCountries) {
236
+ const country = Country.fromCode(countryCode);
237
+ if (country)
238
+ possibleCountries.push(country);
239
+ }
240
+ return possibleCountries;
241
+ }
242
+ /**
243
+ * Determines the most likely type of a phone number
244
+ *
245
+ * @param {string} countryCode - ISO country code
246
+ * @param {string} nationalNumber - The national number to check
247
+ * @returns {PhoneNumberType} The type of the phone number
248
+ */
249
+ getNumberType(countryCode, nationalNumber) {
250
+ if (!countryCode || !nationalNumber) {
251
+ return PhoneNumberType.UNKNOWN;
252
+ }
253
+ const metadata = this.countryMetadata[countryCode];
254
+ if (!metadata || !metadata.patterns) {
255
+ return PhoneNumberType.UNKNOWN;
256
+ }
257
+ // Verify that required patterns exist
258
+ if (!metadata.patterns.landline || !metadata.patterns.mobile) {
259
+ console.error(`Country ${countryCode} is missing required patterns for landline or mobile`);
260
+ return PhoneNumberType.UNKNOWN;
261
+ }
262
+ // Check each type of pattern
263
+ for (const [type, pattern] of Object.entries(metadata.patterns)) {
264
+ if (!pattern)
265
+ continue;
266
+ try {
267
+ const regex = new RegExp(pattern);
268
+ if (regex.test(nationalNumber)) {
269
+ return type;
270
+ }
271
+ }
272
+ catch (e) {
273
+ console.error(`Invalid regex pattern for ${countryCode}.${type}:`, e);
274
+ }
275
+ }
276
+ return PhoneNumberType.UNKNOWN;
277
+ }
278
+ /**
279
+ * Validates a phone number against country-specific patterns
280
+ *
281
+ * @param {string} countryCode - ISO country code
282
+ * @param {string} nationalNumber - The national number to validate
283
+ * @returns {boolean} True if the phone number is valid, false otherwise
284
+ */
285
+ validatePattern(countryCode, nationalNumber) {
286
+ if (!countryCode || !nationalNumber) {
287
+ return false;
288
+ }
289
+ const metadata = this.countryMetadata[countryCode];
290
+ if (!metadata || !metadata.patterns) {
291
+ return false;
292
+ }
293
+ // Verify that required patterns exist
294
+ if (!metadata.patterns.landline || !metadata.patterns.mobile) {
295
+ console.error(`Country ${countryCode} is missing required patterns for landline or mobile`);
296
+ return false;
297
+ }
298
+ // Check if the number matches any of the patterns for this country
299
+ for (const [type, pattern] of Object.entries(metadata.patterns)) {
300
+ if (!pattern)
301
+ continue;
302
+ try {
303
+ const regex = new RegExp(pattern);
304
+ if (regex.test(nationalNumber)) {
305
+ return true;
306
+ }
307
+ }
308
+ catch (e) {
309
+ console.error(`Invalid regex pattern for ${countryCode}.${type}:`, e);
310
+ }
311
+ }
312
+ return false;
313
+ }
314
+ /**
315
+ * Formats a phone number according to the country's formatting rules
316
+ *
317
+ * @param {string} phoneNumber - The phone number to format
318
+ * @param {PhoneNumberFormat} format - The desired format
319
+ * @returns {string} The formatted phone number
320
+ */
321
+ formatNumber(phoneNumber, format = PhoneNumberFormat.INTERNATIONAL) {
322
+ const phone = PhoneNumber.from(phoneNumber);
323
+ if (!phone)
324
+ return phoneNumber;
325
+ return phone.getWithFormat(format);
326
+ }
327
+ /**
328
+ * Creates a PhoneNumber from an international format string
329
+ *
330
+ * @param {string} phoneNumber - The phone number in international format
331
+ * @returns {PhoneNumber | undefined} The parsed phone number or undefined if invalid
332
+ */
333
+ parsePhoneNumber(phoneNumber) {
334
+ return PhoneNumber.from(phoneNumber);
335
+ }
336
+ /**
337
+ * Creates a PhoneNumber from a phone number with explicit country
338
+ *
339
+ * @param {string} phoneNumber - The phone number in any format
340
+ * @param {Country | string} country - The country or country code
341
+ * @returns {PhoneNumber | undefined} The parsed phone number or undefined if invalid
342
+ */
343
+ parsePhoneNumberWithCountry(phoneNumber, country) {
344
+ const countryObj = typeof country === "string"
345
+ ? Country.fromCode(country)
346
+ : country;
347
+ if (!countryObj)
348
+ return undefined;
349
+ return PhoneNumber.fromWithCountry(phoneNumber, countryObj);
350
+ }
351
+ /**
352
+ * Extracts the information needed for dialing from one country to another
353
+ *
354
+ * @param {string} fromCountry - ISO code of the country dialing from
355
+ * @param {PhoneNumber} phoneNumber - The phone number to dial
356
+ * @returns {string} The appropriately formatted dialing string
357
+ */
358
+ getDialingString(fromCountry, phoneNumber) {
359
+ if (!fromCountry || !phoneNumber || !PhoneNumber.is(phoneNumber)) {
360
+ return "";
361
+ }
362
+ // Simple implementation that always uses international format
363
+ // A production version would handle local dialing formats
364
+ return phoneNumber.getWithFormat(PhoneNumberFormat.INTERNATIONAL);
365
+ }
366
+ /**
367
+ * Cleans a phone number by removing all non-digit characters except the leading plus
368
+ *
369
+ * @param {string} phoneNumber - The phone number to clean
370
+ * @returns {string} The cleaned phone number
371
+ */
372
+ cleanPhoneNumber(phoneNumber) {
373
+ if (!phoneNumber)
374
+ return "";
375
+ // Preserve the leading +
376
+ const hasPlus = phoneNumber.trim().startsWith("+");
377
+ // Remove all non-digit characters
378
+ const digitsOnly = phoneNumber.replace(/\D/g, "");
379
+ // Add the plus back if it was present
380
+ return hasPlus ? `+${digitsOnly}` : digitsOnly;
381
+ }
382
+ /**
383
+ * Extracts the country and national number from an international phone number
384
+ *
385
+ * @param {string} phoneNumber - The phone number in international format
386
+ * @returns {[Country | undefined, string]} The country and national number
387
+ */
388
+ extractParts(phoneNumber) {
389
+ const cleaned = this.cleanPhoneNumber(phoneNumber);
390
+ if (!cleaned.startsWith("+"))
391
+ return [undefined, cleaned];
392
+ const dialCodeInfo = this.extractDialCode(cleaned);
393
+ if (!dialCodeInfo)
394
+ return [undefined, cleaned.substring(1)];
395
+ if (dialCodeInfo.isShared) {
396
+ // For shared dial codes, we return undefined for the country
397
+ return [undefined, dialCodeInfo.nationalNumber];
398
+ }
399
+ else {
400
+ // For non-shared dial codes, we return the country
401
+ const countryCode = dialCodeInfo.possibleCountries[0];
402
+ const country = countryCode ? Country.fromCode(countryCode) : undefined;
403
+ return [country, dialCodeInfo.nationalNumber];
404
+ }
405
+ }
406
+ /**
407
+ * Gets a list of commonly used examples of valid phone numbers for a country
408
+ *
409
+ * @param {string} countryCode - The ISO country code
410
+ * @returns {string[]} Array of example phone numbers
411
+ */
412
+ getExampleNumbers(countryCode) {
413
+ const metadata = this.countryMetadata[countryCode];
414
+ if (!metadata)
415
+ return [];
416
+ const dialCode = metadata.code;
417
+ const examples = [];
418
+ // Since landline and mobile patterns are required, we can always generate examples
419
+ // Landline example
420
+ examples.push(`+${dialCode}${this.generateExampleFromPattern(metadata.patterns.landline)}`);
421
+ // Mobile example
422
+ examples.push(`+${dialCode}${this.generateExampleFromPattern(metadata.patterns.mobile)}`);
423
+ return examples;
424
+ }
425
+ /**
426
+ * Generates an example phone number that would match a given pattern
427
+ * This is a simple implementation that handles basic patterns
428
+ *
429
+ * @param pattern - The regex pattern
430
+ * @returns A string that would match the pattern
431
+ */
432
+ generateExampleFromPattern(pattern) {
433
+ // Very basic implementation - a real one would be more sophisticated
434
+ // but this handles simple patterns like "^[2-8]\\d{7}$"
435
+ // Find basic digit patterns like \d{7}
436
+ const digitMatch = pattern.match(/\\d\{(\d+)\}/);
437
+ const digitCount = digitMatch ? parseInt(digitMatch[1]) : 8;
438
+ // Find range patterns like [2-8]
439
+ const rangeMatch = pattern.match(/\[(\d)-(\d)\]/);
440
+ const firstDigit = rangeMatch ? rangeMatch[1] : "5";
441
+ // Combine them
442
+ return `${firstDigit}${"0".repeat(digitCount - 1)}`;
443
+ }
444
+ /**
445
+ * Checks if a phone number is valid for a specific country
446
+ *
447
+ * @param {string} phoneNumber - The phone number to validate
448
+ * @param {string} countryCode - The ISO country code
449
+ * @returns {boolean} True if the phone number is valid for the country, false otherwise
450
+ */
451
+ isValidForCountry(phoneNumber, countryCode) {
452
+ const country = Country.fromCode(countryCode);
453
+ if (!country)
454
+ return false;
455
+ const phone = PhoneNumber.fromWithCountry(phoneNumber, country);
456
+ return phone !== undefined;
457
+ }
458
+ /**
459
+ * Checks if a given dial code exists in our database
460
+ *
461
+ * @param dialCode - The dial code to check
462
+ * @returns True if the dial code exists, false otherwise
463
+ */
464
+ hasDialCode(dialCode) {
465
+ // Check if it's a shared dial code
466
+ if (this.sharedCountryCodes[dialCode]?.length > 0) {
467
+ return true;
468
+ }
469
+ // Check if any country has this dial code
470
+ for (const metadata of Object.values(this.countryMetadata)) {
471
+ if (metadata.code.toString() === dialCode) {
472
+ return true;
473
+ }
474
+ }
475
+ return false;
476
+ }
477
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.test.d.ts","sourceRoot":"","sources":["../../../../../src/src/models/phone_number/global/service.test.ts"],"names":[],"mappings":""}
@@ -1,4 +1,6 @@
1
- export * from "./antd_validator.js";
2
- export * from "./phone_number.js";
3
- export * from "./network_operator.js";
1
+ export * from "./tz/antd_validator.js";
2
+ export * from "./tz/phone_number.js";
3
+ export * from "./tz/network_operator.js";
4
+ export * from "./global/phone_number.js";
5
+ export * from "./format.js";
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/models/phone_number/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/models/phone_number/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,aAAa,CAAA"}
@@ -1,3 +1,5 @@
1
- export * from "./antd_validator.js";
2
- export * from "./phone_number.js";
3
- export * from "./network_operator.js";
1
+ export * from "./tz/antd_validator.js";
2
+ export * from "./tz/phone_number.js";
3
+ export * from "./tz/network_operator.js";
4
+ export * from "./global/phone_number.js";
5
+ export * from "./format.js";
@@ -1,5 +1,5 @@
1
1
  import type { RuleObject } from "antd/es/form";
2
- import { PhoneNumber } from "./phone_number.js";
2
+ import { TZPhoneNumber } from "./phone_number.js";
3
3
  /**
4
4
  * Validates a Tanzanian phone number according to specified format rules.
5
5
  * This validator is designed for Ant Design Form components and performs the following validations:
@@ -73,5 +73,5 @@ import { PhoneNumber } from "./phone_number.js";
73
73
  * $ -> End of string
74
74
  */
75
75
  export declare const TZ_PHONE_NUMBER_REGEX: RegExp;
76
- export declare const PHONENUMBER_VALIDATOR: (rule: RuleObject, value: string | null | undefined) => Promise<PhoneNumber | undefined>;
76
+ export declare const PHONENUMBER_VALIDATOR: (rule: RuleObject, value: string | null | undefined) => Promise<TZPhoneNumber | undefined>;
77
77
  //# sourceMappingURL=antd_validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"antd_validator.d.ts","sourceRoot":"","sources":["../../../../../src/src/models/phone_number/tz/antd_validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,eAAO,MAAM,qBAAqB,QACkF,CAAC;AAErH,eAAO,MAAM,qBAAqB,SAC1B,UAAU,SACT,MAAM,GAAG,IAAI,GAAG,SAAS,KAC/B,OAAO,CAAC,aAAa,GAAG,SAAS,CAiBnC,CAAC"}
@@ -1,4 +1,4 @@
1
- import { PhoneNumber } from "./phone_number.js";
1
+ import { TZPhoneNumber } from "./phone_number.js";
2
2
  /**
3
3
  * Validates a Tanzanian phone number according to specified format rules.
4
4
  * This validator is designed for Ant Design Form components and performs the following validations:
@@ -83,7 +83,7 @@ export const PHONENUMBER_VALIDATOR = (rule, value) => {
83
83
  // If field is not required and empty, validation passes
84
84
  return Promise.resolve(undefined);
85
85
  }
86
- const phone = PhoneNumber.from(phoneString);
86
+ const phone = TZPhoneNumber.from(phoneString);
87
87
  if (phone)
88
88
  return Promise.resolve(phone);
89
89
  return Promise.reject(new Error("Invalid phone number format."));
@@ -0,0 +1 @@
1
+ {"version":3,"file":"antdvalidator.test.d.ts","sourceRoot":"","sources":["../../../../../src/src/models/phone_number/tz/antdvalidator.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network_operator.d.ts","sourceRoot":"","sources":["../../../../../src/src/models/phone_number/tz/network_operator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,oBAAY,eAAe;IACzB,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,OAAO,YAAY;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,EAAE,EAAE,eAAe,CAAC;IAEpB,+DAA+D;IAC/D,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAE/B,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IAEpB,wDAAwD;IACxD,kBAAkB,EAAE,MAAM,CAAC;IAE3B,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAC1C,eAAe,EACf,mBAAmB,CA8BpB,CAAC"}
@@ -23,49 +23,66 @@
23
23
  * - Tigo: 65, 67, etc.
24
24
  * - Halotel: 62, etc.
25
25
  *
26
+ * 4. Phone numbers can be formatted in the following ways:
27
+ * - International format: "+255 XXX XXX XXX"
28
+ * - National format: "0XXX XXX XXX"
29
+ * - Compact format: "XXXXXXXXX"
30
+ * - RFC3966 format: "tel:+255XXXXXXXXX"
31
+ *
26
32
  * ## Solution
27
- * The PhoneNumber class provides:
33
+ * The TZPhoneNumber class provides:
28
34
  * 1. Parsing and validation of different input formats
29
35
  * 2. Standardized storage in compact format
30
36
  * 3. Formatting options for display and API use
31
37
  * 4. Network operator identification
32
38
  */
33
39
  import { type NetworkOperatorInfo } from "./network_operator.js";
34
- /**
35
- * Enumeration for various mobile number formats.
36
- * @enum {string}
37
- */
38
- export declare enum MobileNumberFormat {
39
- s255 = "255",// Mobile numbers prefixed with 255
40
- sp255 = "+255",// Mobile numbers prefixed with +255
41
- s0 = "0",// Mobile numbers prefixed with 0
42
- none = ""
43
- }
40
+ import { PhoneNumberFormat } from "../format.js";
44
41
  /**
45
42
  * Represents a TZ phone number
46
43
  */
47
- export declare class PhoneNumber {
44
+ export declare class TZPhoneNumber {
48
45
  /**
49
46
  * Stores the phone number in a compact format excluding country code and the initial '0'.
50
47
  */
51
- compactNumber: string;
48
+ private _compactNumber;
52
49
  /**
53
- * Constructs a new `PhoneNumber` instance.
50
+ * Private constructor to prevent direct instantiation.
51
+ * Use TZPhoneNumber.from() instead.
54
52
  *
55
53
  * @param compactNumber - The phone number in a compact format (e.g., "712345678").
56
54
  */
57
- constructor(compactNumber: string);
55
+ private constructor();
56
+ /**
57
+ * Gets the compact number (national number without formatting)
58
+ */
59
+ get compactNumber(): string;
58
60
  /**
59
- * Formats the compact phone number with the specified `MobileNumberFormat`.
61
+ * Formats the phone number according to the specified format
60
62
  *
61
- * @param format - The desired phone number format (e.g., `+255` or `255`).
62
- * @returns The phone number formatted as a string.
63
+ * @param format - The desired format from GlobalPhoneNumberFormat
64
+ * @returns The formatted phone number string
65
+ */
66
+ getWithFormat(format: PhoneNumberFormat): string;
67
+ /**
68
+ * Formats the phone number in international format with spaces
69
+ * Format: +255 XXX XXX XXX
70
+ */
71
+ private formatInternational;
72
+ /**
73
+ * Formats the phone number in national format with spaces
74
+ * Format: 0XXX XXX XXX
75
+ */
76
+ private formatNational;
77
+ /**
78
+ * Formats the phone number according to RFC3966
79
+ * Format: tel:+255XXXXXXXXX
63
80
  */
64
- getNumberWithFormat(format: MobileNumberFormat): string;
81
+ private formatRFC3966;
65
82
  /**
66
- * Returns the formatted label of the phone number using the `s255` format.
83
+ * Returns the formatted label of the phone number using the international format.
67
84
  *
68
- * @returns The phone number label in `255` format.
85
+ * @returns The phone number label in international format.
69
86
  */
70
87
  get label(): string;
71
88
  /**
@@ -75,12 +92,12 @@ export declare class PhoneNumber {
75
92
  */
76
93
  get networkOperator(): NetworkOperatorInfo;
77
94
  /**
78
- * Creates a `PhoneNumber` instance from a given string.
95
+ * Creates a `TZPhoneNumber` instance from a given string.
79
96
  *
80
97
  * @param s - The input phone number string in various formats (e.g., "+255712345678", "0712345678").
81
- * @returns A `PhoneNumber` instance if valid, otherwise `undefined`.
98
+ * @returns A `TZPhoneNumber` instance if valid, otherwise `undefined`.
82
99
  */
83
- static from(s: string): PhoneNumber | undefined;
100
+ static from(input: string): TZPhoneNumber | undefined;
84
101
  /**
85
102
  * Checks if a string can be constructed into a valid phone number object.
86
103
  * @param {string | undefined} input - The string to validate as a phone number.
@@ -89,16 +106,16 @@ export declare class PhoneNumber {
89
106
  */
90
107
  static canConstruct(input?: string | null): boolean;
91
108
  /**
92
- * Checks if an unknown value contains valid data to construct a PhoneNumber instance.
109
+ * Checks if an unknown value contains valid data to construct a TZPhoneNumber instance.
93
110
  * Validates the structural integrity of the phone number object.
94
111
  *
95
112
  * @param {unknown} obj - The value to validate.
96
- * @returns {obj is PhoneNumber} Type predicate indicating if the value has a valid phone number structure.
113
+ * @returns {obj is TZPhoneNumber} Type predicate indicating if the value has a valid phone number structure.
97
114
  *
98
115
  * @example
99
116
  * const maybePhone = JSON.parse(someData);
100
- * if (PhoneNumber.is(maybePhone)) {
101
- * // maybePhone is typed as PhoneNumber
117
+ * if (TZPhoneNumber.is(maybePhone)) {
118
+ * // maybePhone is typed as TZPhoneNumber
102
119
  * console.log(maybePhone.label);
103
120
  * }
104
121
  *
@@ -108,7 +125,7 @@ export declare class PhoneNumber {
108
125
  * - compactNumber is a 9-digit string
109
126
  * - Prefix matches a valid network operator
110
127
  */
111
- static is(obj: unknown): obj is PhoneNumber;
128
+ static is(obj: unknown): obj is TZPhoneNumber;
112
129
  /**
113
130
  * Checks the validity of the phone number data
114
131
  * @returns true if the phone number information is available and valid