namefully 1.0.9 → 1.2.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 (189) hide show
  1. package/LICENSE +21 -674
  2. package/dist/example/index.js +2734 -0
  3. package/dist/lib/config.d.ts +121 -0
  4. package/dist/lib/config.js +189 -0
  5. package/dist/lib/config.js.map +1 -0
  6. package/dist/lib/constants.d.ts +4 -0
  7. package/dist/lib/constants.js +31 -0
  8. package/dist/lib/constants.js.map +1 -0
  9. package/dist/lib/error.d.ts +172 -0
  10. package/dist/lib/error.js +210 -0
  11. package/dist/lib/error.js.map +1 -0
  12. package/dist/lib/{usecases/index.d.ts → example/example.d.ts} +0 -0
  13. package/dist/lib/full-name.d.ts +71 -0
  14. package/dist/lib/full-name.js +147 -0
  15. package/dist/lib/full-name.js.map +1 -0
  16. package/dist/lib/index.d.ts +16 -6
  17. package/dist/lib/index.js +29 -8
  18. package/dist/lib/index.js.map +1 -1
  19. package/dist/lib/name.d.ts +177 -0
  20. package/dist/lib/name.js +322 -0
  21. package/dist/lib/name.js.map +1 -0
  22. package/dist/lib/namefully.d.ts +303 -208
  23. package/dist/lib/namefully.js +603 -442
  24. package/dist/lib/namefully.js.map +1 -1
  25. package/dist/lib/parser.d.ts +46 -0
  26. package/dist/lib/parser.js +173 -0
  27. package/dist/lib/parser.js.map +1 -0
  28. package/dist/lib/src/config.d.ts +121 -0
  29. package/dist/lib/src/constants.d.ts +4 -0
  30. package/dist/lib/src/error.d.ts +172 -0
  31. package/dist/lib/src/full-name.d.ts +71 -0
  32. package/dist/lib/src/index.d.ts +16 -6
  33. package/dist/lib/src/name.d.ts +177 -0
  34. package/dist/lib/src/namefully.d.ts +303 -208
  35. package/dist/lib/src/parser.d.ts +46 -0
  36. package/dist/lib/src/types.d.ts +127 -0
  37. package/dist/lib/src/utils.d.ts +63 -0
  38. package/dist/lib/src/validator.d.ts +66 -0
  39. package/dist/lib/types.d.ts +127 -0
  40. package/dist/lib/types.js +181 -0
  41. package/dist/lib/types.js.map +1 -0
  42. package/dist/lib/utils.d.ts +63 -0
  43. package/dist/lib/utils.js +138 -0
  44. package/dist/lib/utils.js.map +1 -0
  45. package/dist/lib/validator.d.ts +66 -0
  46. package/dist/lib/validator.js +332 -0
  47. package/dist/lib/validator.js.map +1 -0
  48. package/dist/umd/namefully.js +2191 -2111
  49. package/dist/umd/namefully.js.map +1 -1
  50. package/dist/umd/namefully.min.js +1 -1
  51. package/dist/umd/namefully.min.js.LICENSE.txt +8 -20
  52. package/dist/umd/namefully.min.js.map +1 -1
  53. package/package.json +50 -53
  54. package/readme.md +151 -175
  55. package/changelog.md +0 -114
  56. package/dist/lib/core/constants.d.ts +0 -26
  57. package/dist/lib/core/constants.js +0 -42
  58. package/dist/lib/core/constants.js.map +0 -1
  59. package/dist/lib/core/index.d.ts +0 -9
  60. package/dist/lib/core/index.js +0 -13
  61. package/dist/lib/core/index.js.map +0 -1
  62. package/dist/lib/core/parsers/array-name.parser.d.ts +0 -42
  63. package/dist/lib/core/parsers/array-name.parser.js +0 -84
  64. package/dist/lib/core/parsers/array-name.parser.js.map +0 -1
  65. package/dist/lib/core/parsers/array-string.parser.d.ts +0 -48
  66. package/dist/lib/core/parsers/array-string.parser.js +0 -96
  67. package/dist/lib/core/parsers/array-string.parser.js.map +0 -1
  68. package/dist/lib/core/parsers/index.d.ts +0 -11
  69. package/dist/lib/core/parsers/index.js +0 -11
  70. package/dist/lib/core/parsers/index.js.map +0 -1
  71. package/dist/lib/core/parsers/nama.parser.d.ts +0 -34
  72. package/dist/lib/core/parsers/nama.parser.js +0 -75
  73. package/dist/lib/core/parsers/nama.parser.js.map +0 -1
  74. package/dist/lib/core/parsers/parser.d.ts +0 -29
  75. package/dist/lib/core/parsers/parser.js +0 -3
  76. package/dist/lib/core/parsers/parser.js.map +0 -1
  77. package/dist/lib/core/parsers/string.parser.d.ts +0 -61
  78. package/dist/lib/core/parsers/string.parser.js +0 -63
  79. package/dist/lib/core/parsers/string.parser.js.map +0 -1
  80. package/dist/lib/core/utils/utils.d.ts +0 -14
  81. package/dist/lib/core/utils/utils.js +0 -67
  82. package/dist/lib/core/utils/utils.js.map +0 -1
  83. package/dist/lib/models/enums.d.ts +0 -91
  84. package/dist/lib/models/enums.js +0 -98
  85. package/dist/lib/models/enums.js.map +0 -1
  86. package/dist/lib/models/firstname.d.ts +0 -41
  87. package/dist/lib/models/firstname.js +0 -59
  88. package/dist/lib/models/firstname.js.map +0 -1
  89. package/dist/lib/models/index.d.ts +0 -12
  90. package/dist/lib/models/index.js +0 -15
  91. package/dist/lib/models/index.js.map +0 -1
  92. package/dist/lib/models/lastname.d.ts +0 -44
  93. package/dist/lib/models/lastname.js +0 -86
  94. package/dist/lib/models/lastname.js.map +0 -1
  95. package/dist/lib/models/misc.d.ts +0 -80
  96. package/dist/lib/models/misc.js +0 -3
  97. package/dist/lib/models/misc.js.map +0 -1
  98. package/dist/lib/models/name.d.ts +0 -48
  99. package/dist/lib/models/name.js +0 -72
  100. package/dist/lib/models/name.js.map +0 -1
  101. package/dist/lib/models/summary.d.ts +0 -23
  102. package/dist/lib/models/summary.js +0 -60
  103. package/dist/lib/models/summary.js.map +0 -1
  104. package/dist/lib/src/core/constants.d.ts +0 -26
  105. package/dist/lib/src/core/index.d.ts +0 -9
  106. package/dist/lib/src/core/parsers/array-name.parser.d.ts +0 -42
  107. package/dist/lib/src/core/parsers/array-string.parser.d.ts +0 -48
  108. package/dist/lib/src/core/parsers/index.d.ts +0 -11
  109. package/dist/lib/src/core/parsers/nama.parser.d.ts +0 -34
  110. package/dist/lib/src/core/parsers/parser.d.ts +0 -29
  111. package/dist/lib/src/core/parsers/string.parser.d.ts +0 -61
  112. package/dist/lib/src/core/utils/utils.d.ts +0 -14
  113. package/dist/lib/src/models/enums.d.ts +0 -91
  114. package/dist/lib/src/models/firstname.d.ts +0 -41
  115. package/dist/lib/src/models/index.d.ts +0 -12
  116. package/dist/lib/src/models/lastname.d.ts +0 -44
  117. package/dist/lib/src/models/misc.d.ts +0 -80
  118. package/dist/lib/src/models/name.d.ts +0 -48
  119. package/dist/lib/src/models/summary.d.ts +0 -23
  120. package/dist/lib/src/validators/array-name.validator.d.ts +0 -25
  121. package/dist/lib/src/validators/array-string.validator.d.ts +0 -43
  122. package/dist/lib/src/validators/common/validation-error.d.ts +0 -19
  123. package/dist/lib/src/validators/common/validation-rule.d.ts +0 -69
  124. package/dist/lib/src/validators/common/validation-type.d.ts +0 -24
  125. package/dist/lib/src/validators/firstname.validator.d.ts +0 -20
  126. package/dist/lib/src/validators/fullname.validator.d.ts +0 -21
  127. package/dist/lib/src/validators/index.d.ts +0 -21
  128. package/dist/lib/src/validators/lastname.validator.d.ts +0 -20
  129. package/dist/lib/src/validators/middlename.validator.d.ts +0 -20
  130. package/dist/lib/src/validators/nama.validator.d.ts +0 -21
  131. package/dist/lib/src/validators/namon.validator.d.ts +0 -20
  132. package/dist/lib/src/validators/prefix.validator.d.ts +0 -14
  133. package/dist/lib/src/validators/string-name.validator.d.ts +0 -20
  134. package/dist/lib/src/validators/suffix.validator.d.ts +0 -14
  135. package/dist/lib/src/validators/validator.d.ts +0 -13
  136. package/dist/lib/usecases/compress.usecase.d.ts +0 -8
  137. package/dist/lib/usecases/constants.d.ts +0 -7
  138. package/dist/lib/usecases/describe.usecase.d.ts +0 -12
  139. package/dist/lib/usecases/format.usecase.d.ts +0 -6
  140. package/dist/lib/usecases/namefully.usecase.d.ts +0 -14
  141. package/dist/lib/usecases/shorten.usecase.d.ts +0 -6
  142. package/dist/lib/validators/array-name.validator.d.ts +0 -25
  143. package/dist/lib/validators/array-name.validator.js +0 -82
  144. package/dist/lib/validators/array-name.validator.js.map +0 -1
  145. package/dist/lib/validators/array-string.validator.d.ts +0 -43
  146. package/dist/lib/validators/array-string.validator.js +0 -80
  147. package/dist/lib/validators/array-string.validator.js.map +0 -1
  148. package/dist/lib/validators/common/validation-error.d.ts +0 -19
  149. package/dist/lib/validators/common/validation-error.js +0 -26
  150. package/dist/lib/validators/common/validation-error.js.map +0 -1
  151. package/dist/lib/validators/common/validation-rule.d.ts +0 -69
  152. package/dist/lib/validators/common/validation-rule.js +0 -73
  153. package/dist/lib/validators/common/validation-rule.js.map +0 -1
  154. package/dist/lib/validators/common/validation-type.d.ts +0 -24
  155. package/dist/lib/validators/common/validation-type.js +0 -28
  156. package/dist/lib/validators/common/validation-type.js.map +0 -1
  157. package/dist/lib/validators/firstname.validator.d.ts +0 -20
  158. package/dist/lib/validators/firstname.validator.js +0 -29
  159. package/dist/lib/validators/firstname.validator.js.map +0 -1
  160. package/dist/lib/validators/fullname.validator.d.ts +0 -21
  161. package/dist/lib/validators/fullname.validator.js +0 -38
  162. package/dist/lib/validators/fullname.validator.js.map +0 -1
  163. package/dist/lib/validators/index.d.ts +0 -21
  164. package/dist/lib/validators/index.js +0 -35
  165. package/dist/lib/validators/index.js.map +0 -1
  166. package/dist/lib/validators/lastname.validator.d.ts +0 -20
  167. package/dist/lib/validators/lastname.validator.js +0 -29
  168. package/dist/lib/validators/lastname.validator.js.map +0 -1
  169. package/dist/lib/validators/middlename.validator.d.ts +0 -20
  170. package/dist/lib/validators/middlename.validator.js +0 -38
  171. package/dist/lib/validators/middlename.validator.js.map +0 -1
  172. package/dist/lib/validators/nama.validator.d.ts +0 -21
  173. package/dist/lib/validators/nama.validator.js +0 -43
  174. package/dist/lib/validators/nama.validator.js.map +0 -1
  175. package/dist/lib/validators/namon.validator.d.ts +0 -20
  176. package/dist/lib/validators/namon.validator.js +0 -29
  177. package/dist/lib/validators/namon.validator.js.map +0 -1
  178. package/dist/lib/validators/prefix.validator.d.ts +0 -14
  179. package/dist/lib/validators/prefix.validator.js +0 -31
  180. package/dist/lib/validators/prefix.validator.js.map +0 -1
  181. package/dist/lib/validators/string-name.validator.d.ts +0 -20
  182. package/dist/lib/validators/string-name.validator.js +0 -29
  183. package/dist/lib/validators/string-name.validator.js.map +0 -1
  184. package/dist/lib/validators/suffix.validator.d.ts +0 -14
  185. package/dist/lib/validators/suffix.validator.js +0 -31
  186. package/dist/lib/validators/suffix.validator.js.map +0 -1
  187. package/dist/lib/validators/validator.d.ts +0 -13
  188. package/dist/lib/validators/validator.js +0 -9
  189. package/dist/lib/validators/validator.js.map +0 -1
@@ -91,7 +91,7 @@ return /******/ (function(modules) { // webpackBootstrap
91
91
  /******/
92
92
  /******/
93
93
  /******/ // Load entry module and return exports
94
- /******/ return __webpack_require__(__webpack_require__.s = 5);
94
+ /******/ return __webpack_require__(__webpack_require__.s = 9);
95
95
  /******/ })
96
96
  /************************************************************************/
97
97
  /******/ ([
@@ -101,1440 +101,1274 @@ return /******/ (function(modules) { // webpackBootstrap
101
101
  "use strict";
102
102
 
103
103
  Object.defineProperty(exports, "__esModule", { value: true });
104
- const tslib_1 = __webpack_require__(2);
104
+ exports.Separator = exports.Namon = exports.CapsRange = exports.Flat = exports.NameType = exports.NameOrder = exports.Surname = exports.Title = void 0;
105
105
  /**
106
- * Make all the locals available
107
- *
108
- * Created on March 06, 2020
109
- * @author Ralph Florent <ralflornt@gmail.com>
106
+ * The abbreviation type to indicate whether or not to add period to a prefix
107
+ * using the American or British way.
110
108
  */
111
- tslib_1.__exportStar(__webpack_require__(13), exports);
112
- tslib_1.__exportStar(__webpack_require__(14), exports);
113
- tslib_1.__exportStar(__webpack_require__(15), exports);
114
- var namon_validator_1 = __webpack_require__(16);
115
- exports.NamonValidator = namon_validator_1.default;
116
- var prefix_validator_1 = __webpack_require__(17);
117
- exports.PrefixValidator = prefix_validator_1.default;
118
- var suffix_validator_1 = __webpack_require__(18);
119
- exports.SuffixValidator = suffix_validator_1.default;
120
- var firstname_validator_1 = __webpack_require__(19);
121
- exports.FirstnameValidator = firstname_validator_1.default;
122
- var lastname_validator_1 = __webpack_require__(20);
123
- exports.LastnameValidator = lastname_validator_1.default;
124
- var middlename_validator_1 = __webpack_require__(21);
125
- exports.MiddlenameValidator = middlename_validator_1.default;
126
- var fullname_validator_1 = __webpack_require__(22);
127
- exports.FullnameValidator = fullname_validator_1.default;
128
- var nama_validator_1 = __webpack_require__(23);
129
- exports.NamaValidator = nama_validator_1.default;
130
- var array_name_validator_1 = __webpack_require__(24);
131
- exports.ArrayNameValidator = array_name_validator_1.default;
132
- var array_string_validator_1 = __webpack_require__(25);
133
- exports.ArrayStringValidator = array_string_validator_1.default;
134
- var string_name_validator_1 = __webpack_require__(26);
135
- exports.StringNameValidator = string_name_validator_1.default;
136
-
137
-
138
- /***/ }),
139
- /* 1 */
140
- /***/ (function(module, exports, __webpack_require__) {
141
-
142
- "use strict";
143
-
144
- Object.defineProperty(exports, "__esModule", { value: true });
145
- const tslib_1 = __webpack_require__(2);
109
+ var Title;
110
+ (function (Title) {
111
+ // A period after the prefix.
112
+ Title["US"] = "US";
113
+ // No period after the prefix.
114
+ Title["UK"] = "UK";
115
+ })(Title = exports.Title || (exports.Title = {}));
146
116
  /**
147
- * Make all the locals available
117
+ * An option indicating how to format a surname.
148
118
  *
149
- * Created on March 06, 2020
150
- * @author Ralph Florent <ralflornt@gmail.com>
119
+ * This enum can be set via `Config` or when creating a `LastName`. As this can
120
+ * become ambiguous at the time of handling it, the value set in `Config` is
121
+ * prioritized and viewed as the source of truth for future considerations.
122
+ */
123
+ var Surname;
124
+ (function (Surname) {
125
+ // The fatherly surname only.
126
+ Surname["FATHER"] = "father";
127
+ // The motherly surname only.
128
+ Surname["MOTHER"] = "mother";
129
+ // The junction of both the fatherly and motherly surnames with a hyphen.
130
+ Surname["HYPHENATED"] = "hyphenated";
131
+ // The junction of both the fatherly and motherly surnames with a space.
132
+ Surname["ALL"] = "all";
133
+ })(Surname = exports.Surname || (exports.Surname = {}));
134
+ /**
135
+ * The order of appearance of a `FullName`.
136
+ */
137
+ var NameOrder;
138
+ (function (NameOrder) {
139
+ // The first part of a full name, usually the first piece of a person name.
140
+ NameOrder["FIRST_NAME"] = "firstName";
141
+ // The last part of a full name, usually the last piece of a person name.
142
+ NameOrder["LAST_NAME"] = "lastName";
143
+ })(NameOrder = exports.NameOrder || (exports.NameOrder = {}));
144
+ /**
145
+ * The types of name handled in this according the name standards.
146
+ */
147
+ var NameType;
148
+ (function (NameType) {
149
+ NameType["FIRST_NAME"] = "firstName";
150
+ NameType["MIDDLE_NAME"] = "middleName";
151
+ NameType["LAST_NAME"] = "lastName";
152
+ NameType["BIRTH_NAME"] = "birthName";
153
+ })(NameType = exports.NameType || (exports.NameType = {}));
154
+ /**
155
+ * The possible variants to indicate how to flatten a `FullName`.
156
+ */
157
+ var Flat;
158
+ (function (Flat) {
159
+ // Use the first name's initial combined with the remaining parts.
160
+ Flat["FIRST_NAME"] = "firstName";
161
+ // Use the middle name's initial combined with the remaining parts.
162
+ Flat["MIDDLE_NAME"] = "middleName";
163
+ // Use the last name's initial combined with the remaining parts.
164
+ Flat["LAST_NAME"] = "lastName";
165
+ // Use both the first and middle names' initials combined with the remaining parts.
166
+ Flat["FIRST_MID"] = "firstMid";
167
+ // Use both the last and middle names' initials combined with the remaining parts.
168
+ Flat["MID_LAST"] = "midLast";
169
+ // Use the first, middle and last names' initials combined with the remaining parts.
170
+ Flat["ALL"] = "all";
171
+ })(Flat = exports.Flat || (exports.Flat = {}));
172
+ /**
173
+ * The range to use when capitalizing a string content.
174
+ */
175
+ var CapsRange;
176
+ (function (CapsRange) {
177
+ // No capitalization.
178
+ CapsRange[CapsRange["NONE"] = 0] = "NONE";
179
+ // Apply capitalization to the first letter.
180
+ CapsRange[CapsRange["INITIAL"] = 1] = "INITIAL";
181
+ // Apply capitalization to all the letters.
182
+ CapsRange[CapsRange["ALL"] = 2] = "ALL";
183
+ })(CapsRange = exports.CapsRange || (exports.CapsRange = {}));
184
+ /**
185
+ * The types of name handled in this utility according the name standards.
186
+ */
187
+ class Namon {
188
+ constructor(index, key) {
189
+ this.index = index;
190
+ this.key = key;
191
+ }
192
+ /**
193
+ * Whether this string key is part of the predefined keys.
194
+ */
195
+ static has(key) {
196
+ return Namon.all.has(key);
197
+ }
198
+ /**
199
+ * Makes a string key a namon type.
200
+ */
201
+ static cast(key) {
202
+ return Namon.has(key) ? Namon.all.get(key) : undefined;
203
+ }
204
+ /**
205
+ * String representation of this object.
206
+ */
207
+ toString() {
208
+ return `Namon.${this.key}`;
209
+ }
210
+ /**
211
+ * Whether this and the other value are equal.
212
+ */
213
+ equal(other) {
214
+ return other instanceof Namon && other.index === this.index && other.key === this.key;
215
+ }
216
+ }
217
+ exports.Namon = Namon;
218
+ Namon.PREFIX = new Namon(0, 'prefix');
219
+ Namon.FIRST_NAME = new Namon(1, 'firstName');
220
+ Namon.MIDDLE_NAME = new Namon(2, 'middleName');
221
+ Namon.LAST_NAME = new Namon(3, 'lastName');
222
+ Namon.SUFFIX = new Namon(4, 'suffix');
223
+ /**
224
+ * The list of supported name types.
151
225
  */
152
- tslib_1.__exportStar(__webpack_require__(8), exports);
153
- tslib_1.__exportStar(__webpack_require__(9), exports);
154
- tslib_1.__exportStar(__webpack_require__(10), exports);
155
- tslib_1.__exportStar(__webpack_require__(11), exports);
156
- tslib_1.__exportStar(__webpack_require__(12), exports);
157
-
158
-
159
- /***/ }),
160
- /* 2 */
161
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
162
-
163
- "use strict";
164
- __webpack_require__.r(__webpack_exports__);
165
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__extends", function() { return __extends; });
166
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__assign", function() { return __assign; });
167
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__rest", function() { return __rest; });
168
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__decorate", function() { return __decorate; });
169
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__param", function() { return __param; });
170
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__metadata", function() { return __metadata; });
171
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__awaiter", function() { return __awaiter; });
172
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__generator", function() { return __generator; });
173
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__exportStar", function() { return __exportStar; });
174
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__values", function() { return __values; });
175
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__read", function() { return __read; });
176
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__spread", function() { return __spread; });
177
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__spreadArrays", function() { return __spreadArrays; });
178
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__await", function() { return __await; });
179
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__asyncGenerator", function() { return __asyncGenerator; });
180
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__asyncDelegator", function() { return __asyncDelegator; });
181
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__asyncValues", function() { return __asyncValues; });
182
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__makeTemplateObject", function() { return __makeTemplateObject; });
183
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__importStar", function() { return __importStar; });
184
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__importDefault", function() { return __importDefault; });
185
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__classPrivateFieldGet", function() { return __classPrivateFieldGet; });
186
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__classPrivateFieldSet", function() { return __classPrivateFieldSet; });
187
- /*! *****************************************************************************
188
- Copyright (c) Microsoft Corporation. All rights reserved.
189
- Licensed under the Apache License, Version 2.0 (the "License"); you may not use
190
- this file except in compliance with the License. You may obtain a copy of the
191
- License at http://www.apache.org/licenses/LICENSE-2.0
192
-
193
- THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
194
- KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
195
- WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
196
- MERCHANTABLITY OR NON-INFRINGEMENT.
197
-
198
- See the Apache Version 2.0 License for specific language governing permissions
199
- and limitations under the License.
200
- ***************************************************************************** */
201
- /* global Reflect, Promise */
202
-
203
- var extendStatics = function(d, b) {
204
- extendStatics = Object.setPrototypeOf ||
205
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
206
- function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
207
- return extendStatics(d, b);
208
- };
209
-
210
- function __extends(d, b) {
211
- extendStatics(d, b);
212
- function __() { this.constructor = d; }
213
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
214
- }
215
-
216
- var __assign = function() {
217
- __assign = Object.assign || function __assign(t) {
218
- for (var s, i = 1, n = arguments.length; i < n; i++) {
219
- s = arguments[i];
220
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
221
- }
222
- return t;
223
- }
224
- return __assign.apply(this, arguments);
225
- }
226
-
227
- function __rest(s, e) {
228
- var t = {};
229
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
230
- t[p] = s[p];
231
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
232
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
233
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
234
- t[p[i]] = s[p[i]];
235
- }
236
- return t;
237
- }
238
-
239
- function __decorate(decorators, target, key, desc) {
240
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
241
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
242
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
243
- return c > 3 && r && Object.defineProperty(target, key, r), r;
244
- }
245
-
246
- function __param(paramIndex, decorator) {
247
- return function (target, key) { decorator(target, key, paramIndex); }
248
- }
249
-
250
- function __metadata(metadataKey, metadataValue) {
251
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
252
- }
253
-
254
- function __awaiter(thisArg, _arguments, P, generator) {
255
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
256
- return new (P || (P = Promise))(function (resolve, reject) {
257
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
258
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
259
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
260
- step((generator = generator.apply(thisArg, _arguments || [])).next());
261
- });
262
- }
263
-
264
- function __generator(thisArg, body) {
265
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
266
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
267
- function verb(n) { return function (v) { return step([n, v]); }; }
268
- function step(op) {
269
- if (f) throw new TypeError("Generator is already executing.");
270
- while (_) try {
271
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
272
- if (y = 0, t) op = [op[0] & 2, t.value];
273
- switch (op[0]) {
274
- case 0: case 1: t = op; break;
275
- case 4: _.label++; return { value: op[1], done: false };
276
- case 5: _.label++; y = op[1]; op = [0]; continue;
277
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
278
- default:
279
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
280
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
281
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
282
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
283
- if (t[2]) _.ops.pop();
284
- _.trys.pop(); continue;
285
- }
286
- op = body.call(thisArg, _);
287
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
288
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
289
- }
290
- }
291
-
292
- function __exportStar(m, exports) {
293
- for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
294
- }
295
-
296
- function __values(o) {
297
- var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
298
- if (m) return m.call(o);
299
- if (o && typeof o.length === "number") return {
300
- next: function () {
301
- if (o && i >= o.length) o = void 0;
302
- return { value: o && o[i++], done: !o };
303
- }
304
- };
305
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
306
- }
307
-
308
- function __read(o, n) {
309
- var m = typeof Symbol === "function" && o[Symbol.iterator];
310
- if (!m) return o;
311
- var i = m.call(o), r, ar = [], e;
312
- try {
313
- while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
314
- }
315
- catch (error) { e = { error: error }; }
316
- finally {
317
- try {
318
- if (r && !r.done && (m = i["return"])) m.call(i);
319
- }
320
- finally { if (e) throw e.error; }
321
- }
322
- return ar;
323
- }
324
-
325
- function __spread() {
326
- for (var ar = [], i = 0; i < arguments.length; i++)
327
- ar = ar.concat(__read(arguments[i]));
328
- return ar;
329
- }
330
-
331
- function __spreadArrays() {
332
- for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
333
- for (var r = Array(s), k = 0, i = 0; i < il; i++)
334
- for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
335
- r[k] = a[j];
336
- return r;
337
- };
338
-
339
- function __await(v) {
340
- return this instanceof __await ? (this.v = v, this) : new __await(v);
341
- }
342
-
343
- function __asyncGenerator(thisArg, _arguments, generator) {
344
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
345
- var g = generator.apply(thisArg, _arguments || []), i, q = [];
346
- return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
347
- function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
348
- function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
349
- function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
350
- function fulfill(value) { resume("next", value); }
351
- function reject(value) { resume("throw", value); }
352
- function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
353
- }
354
-
355
- function __asyncDelegator(o) {
356
- var i, p;
357
- return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
358
- function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; }
359
- }
360
-
361
- function __asyncValues(o) {
362
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
363
- var m = o[Symbol.asyncIterator], i;
364
- return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
365
- function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
366
- function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
367
- }
368
-
369
- function __makeTemplateObject(cooked, raw) {
370
- if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
371
- return cooked;
372
- };
373
-
374
- function __importStar(mod) {
375
- if (mod && mod.__esModule) return mod;
376
- var result = {};
377
- if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
378
- result.default = mod;
379
- return result;
380
- }
381
-
382
- function __importDefault(mod) {
383
- return (mod && mod.__esModule) ? mod : { default: mod };
384
- }
385
-
386
- function __classPrivateFieldGet(receiver, privateMap) {
387
- if (!privateMap.has(receiver)) {
388
- throw new TypeError("attempted to get private field on non-instance");
389
- }
390
- return privateMap.get(receiver);
391
- }
392
-
393
- function __classPrivateFieldSet(receiver, privateMap, value) {
394
- if (!privateMap.has(receiver)) {
395
- throw new TypeError("attempted to set private field on non-instance");
396
- }
397
- privateMap.set(receiver, value);
398
- return value;
399
- }
400
-
401
-
402
- /***/ }),
403
- /* 3 */
404
- /***/ (function(module, exports, __webpack_require__) {
405
-
406
- "use strict";
407
-
408
- Object.defineProperty(exports, "__esModule", { value: true });
409
- const tslib_1 = __webpack_require__(2);
226
+ Namon.values = [Namon.PREFIX, Namon.FIRST_NAME, Namon.MIDDLE_NAME, Namon.LAST_NAME, Namon.SUFFIX];
410
227
  /**
411
- * Make all the locals available
412
- *
413
- * Created on March 06, 2020
414
- * @author Ralph Florent <ralflornt@gmail.com>
228
+ * All the predefined name types.
415
229
  */
416
- tslib_1.__exportStar(__webpack_require__(4), exports);
417
- tslib_1.__exportStar(__webpack_require__(30), exports);
418
- tslib_1.__exportStar(__webpack_require__(31), exports);
419
-
420
-
421
- /***/ }),
422
- /* 4 */
423
- /***/ (function(module, exports, __webpack_require__) {
424
-
425
- "use strict";
426
-
427
- Object.defineProperty(exports, "__esModule", { value: true });
428
- var array_name_parser_1 = __webpack_require__(7);
429
- exports.ArrayNameParser = array_name_parser_1.default;
430
- var array_string_parser_1 = __webpack_require__(27);
431
- exports.ArrayStringParser = array_string_parser_1.default;
432
- var nama_parser_1 = __webpack_require__(28);
433
- exports.NamaParser = nama_parser_1.default;
434
- var string_parser_1 = __webpack_require__(29);
435
- exports.StringParser = string_parser_1.default;
436
-
437
-
438
- /***/ }),
439
- /* 5 */
440
- /***/ (function(module, exports, __webpack_require__) {
441
-
442
- "use strict";
443
-
444
- Object.defineProperty(exports, "__esModule", { value: true });
445
- const tslib_1 = __webpack_require__(2);
230
+ Namon.all = new Map([
231
+ [Namon.PREFIX.key, Namon.PREFIX],
232
+ [Namon.FIRST_NAME.key, Namon.FIRST_NAME],
233
+ [Namon.MIDDLE_NAME.key, Namon.MIDDLE_NAME],
234
+ [Namon.LAST_NAME.key, Namon.LAST_NAME],
235
+ [Namon.SUFFIX.key, Namon.SUFFIX],
236
+ ]);
446
237
  /**
447
- * Main entry to `Namefully`
448
- *
449
- * Created on March 03, 2020
450
- * @author Ralph Florent <ralflornt@gmail.com>
238
+ * The token used to indicate how to split string values.
451
239
  */
452
- tslib_1.__exportStar(__webpack_require__(6), exports);
453
- tslib_1.__exportStar(__webpack_require__(3), exports);
454
- tslib_1.__exportStar(__webpack_require__(1), exports);
455
- tslib_1.__exportStar(__webpack_require__(0), exports);
240
+ class Separator {
241
+ constructor(name, token) {
242
+ this.name = name;
243
+ this.token = token;
244
+ }
245
+ /**
246
+ * String representation of this object.
247
+ */
248
+ toString() {
249
+ return `Separator.${this.name}`;
250
+ }
251
+ }
252
+ exports.Separator = Separator;
253
+ Separator.COMMA = new Separator('comma', ',');
254
+ Separator.COLON = new Separator('colon', ':');
255
+ Separator.DOUBLE_QUOTE = new Separator('doubleQuote', '"');
256
+ Separator.EMPTY = new Separator('empty', '');
257
+ Separator.HYPHEN = new Separator('hyphen', '-');
258
+ Separator.PERIOD = new Separator('period', '.');
259
+ Separator.SEMI_COLON = new Separator('semiColon', ';');
260
+ Separator.SINGLE_QUOTE = new Separator('singleQuote', `'`);
261
+ Separator.SPACE = new Separator('space', ' ');
262
+ Separator.UNDERSCORE = new Separator('underscore', '_');
263
+ /**
264
+ * All the available separators.
265
+ */
266
+ Separator.all = new Map([
267
+ [Separator.COMMA.name, Separator.COMMA],
268
+ [Separator.COLON.name, Separator.COLON],
269
+ [Separator.DOUBLE_QUOTE.name, Separator.DOUBLE_QUOTE],
270
+ [Separator.EMPTY.name, Separator.EMPTY],
271
+ [Separator.HYPHEN.name, Separator.HYPHEN],
272
+ [Separator.PERIOD.name, Separator.PERIOD],
273
+ [Separator.SEMI_COLON.name, Separator.SEMI_COLON],
274
+ [Separator.SINGLE_QUOTE.name, Separator.SINGLE_QUOTE],
275
+ [Separator.SPACE.name, Separator.SPACE],
276
+ [Separator.UNDERSCORE.name, Separator.UNDERSCORE],
277
+ ]);
278
+ /**
279
+ * All the available tokens.
280
+ */
281
+ Separator.tokens = [...Separator.all.values()].map((s) => s.token);
456
282
 
457
283
 
458
284
  /***/ }),
459
- /* 6 */
285
+ /* 1 */
460
286
  /***/ (function(module, exports, __webpack_require__) {
461
287
 
462
288
  "use strict";
463
289
 
464
290
  Object.defineProperty(exports, "__esModule", { value: true });
291
+ exports.UnknownError = exports.NotAllowedError = exports.ValidationError = exports.InputError = exports.NameError = exports.NameErrorType = void 0;
292
+ const utils_1 = __webpack_require__(2);
465
293
  /**
466
- * `Namefully` person name handler
467
- *
468
- * Created on March 03, 2020
469
- * @author Ralph Florent <ralflornt@gmail.com>
470
- *
471
- * @license GPL-3.0
472
- * @see {@link https://github.com/ralflorent/namefully|namefully} for more info.
473
- */
474
- const index_1 = __webpack_require__(3);
475
- const index_2 = __webpack_require__(1);
476
- const index_3 = __webpack_require__(0);
477
- /**
478
- * Person name handler
479
- * @class
480
- * @classdesc
481
- * `Namefully` does not magically guess which part of the name is what. It relies
482
- * actually on how the developer indicates the roles of the name parts so that
483
- * it, internally, can perform certain operations and saves the developer some
484
- * calculations/processings. Nevertheless, Namefully can be constructed using
485
- * distinct raw data shape. This is intended to give some flexibility to the
486
- * developer so that he or she is not bound to a particular data format. Please,
487
- * do follow closely the APIs to know how to properly use it in order to avoid
488
- * some errors (mainly validation's).
489
- *
490
- * `Namefully` also works like a trap door. Once a raw data is provided and
491
- * validated, a developer can only ACCESS in a vast amount of, yet effective ways
492
- * the name info. NO EDITING is possible. If the name is mistaken, a new instance
493
- * of `Namefully` must be created. Remember, this utility's primary objective is
494
- * to help to **handle** a person name.
495
- *
496
- * Note that the name standards used for the current version of this library are
497
- * as follows:
498
- * [Prefix] Firstname [Middlename] Lastname [Suffix]
499
- * The opening `[` and closing `]` brackets mean that these parts are optional.
500
- * In other words, the most basic and typical case is a name that looks like this:
501
- * `John Smith`, where `John` is the first name and `Smith`, the last name.
502
- * @see https://departments.weber.edu/qsupport&training/Data_Standards/Name.htm
503
- * for more info on name standards.
504
- *
505
- * **IMPORTANT**: Keep in mind that the order of appearance matters and can be
506
- * altered through configured parameters, which we will be seeing later on. By
507
- * default, the order of appearance is as shown above and will be used as a basis
508
- * for future examples and use cases.
509
- *
510
- * Once imported, all that is required to do is to create an instance of
511
- * `Namefully` and the rest will follow.
512
- *
513
- * Some terminologies used across the library are:
514
- * - namon: piece of a name (e.g., firstname)
515
- * - nama: pieces of a name (e.g., firstname + lastname)
516
- *
517
- * Happy naming!
294
+ * The error types supported by `Namefully`.
518
295
  */
519
- class Namefully {
296
+ var NameErrorType;
297
+ (function (NameErrorType) {
520
298
  /**
521
- * Constructs an instance of the utility and helps to benefit from many helpers
522
- * @param {string | string[] | Array<Name> | Nama} raw element to parse or
523
- * construct the pieces of the name
524
- * @param {Config} options to configure how to run the utility
299
+ * Thrown when a name entry/argument is incorrect.
300
+ *
301
+ * For example, a name should have a minimum of 2 characters, so an empty
302
+ * string or a string of one character would cause this kind of error.
525
303
  */
526
- constructor(raw, options) {
527
- // well, first thing first
528
- this.configure(options);
529
- // let's try to parse this, baby!
530
- this.build(raw);
531
- }
304
+ NameErrorType[NameErrorType["INPUT"] = 0] = "INPUT";
532
305
  /**
533
- * Gets the full name ordered as configured
534
- * @param {'firstname'|'lastname'} orderedBy force to order by first or last
535
- * name by overriding the preset configuration
536
- * @returns {string} the suffix
306
+ * Thrown when the name components do not match the validation rules if the
307
+ * `Config.bypass` is not flagged up. This bypass option skips the validation
308
+ * rules.
537
309
  *
538
- * @see {format} to alter manually the order of appearance of the full name.
539
- * For example, ::format('l f m') outputs `lastname firstname middlename`.
540
- */
541
- getFullname(orderedBy) {
542
- orderedBy = orderedBy || this.config.orderedBy; // override config
543
- const { titling, ending } = this.config;
544
- const pxSep = titling === 'us' ? index_2.Separator.PERIOD : index_2.Separator.EMPTY; // Mr[.]
545
- const sxSep = ending !== index_2.Separator.SPACE ? ending : index_2.Separator.EMPTY; // [,] PhD
546
- const nama = [];
547
- if (this.fullname.prefix)
548
- nama.push(index_2.Separator.EMPTY.concat(this.fullname.prefix, pxSep));
549
- switch (orderedBy) {
550
- case 'firstname':
551
- nama.push(this.getFirstname());
552
- nama.push(...this.getMiddlenames());
553
- nama.push(index_2.Separator.EMPTY.concat(this.getLastname(), sxSep));
554
- break;
555
- case 'lastname':
556
- nama.push(this.getLastname());
557
- nama.push(this.getFirstname());
558
- nama.push(this.getMiddlenames().join(index_2.Separator.SPACE).concat(sxSep));
559
- break;
560
- }
561
- if (this.fullname.suffix)
562
- nama.push(this.fullname.suffix);
563
- return nama.join(index_2.Separator.SPACE);
564
- }
310
+ * See also: `ValidationError`
311
+ */
312
+ NameErrorType[NameErrorType["VALIDATION"] = 1] = "VALIDATION";
565
313
  /**
566
- * Gets the first name part of the full name
567
- * @returns {string} the first name
314
+ * Thrown by not allowed operations such as in NameBuilder or name formatting.
315
+ *
316
+ * See also: `NotAllowedError`, `Namefully.format`.
568
317
  */
569
- getFirstname() {
570
- return this.fullname.firstname.tostring();
571
- }
318
+ NameErrorType[NameErrorType["NOT_ALLOWED"] = 2] = "NOT_ALLOWED";
572
319
  /**
573
- * Gets the last name part of the full name
574
- * @param {LastnameFormat} [format] overrides the how-to format of a surname
575
- * output, considering its subparts.
576
- * @returns {string} the last name
320
+ * Thrown by any other unknown sources or unexpected situation.
577
321
  */
578
- getLastname(format) {
579
- return this.fullname.lastname.tostring(format);
580
- }
322
+ NameErrorType[NameErrorType["UNKNOWN"] = 3] = "UNKNOWN";
323
+ })(NameErrorType = exports.NameErrorType || (exports.NameErrorType = {}));
324
+ /**
325
+ * Base class for all name-related errors.
326
+ *
327
+ * A custom error is intended to convey information to the user about a failure,
328
+ * so that it can be addressed programmatically.
329
+ *
330
+ * A name handling failure is not considered a native error that should cause a
331
+ * program failure. Au contraire, it is expected that a programmer using this utility
332
+ * would consider validating a name using its own business rules. That is not
333
+ * this utility's job to guess those rules. So, the predefined `ValidationRules`
334
+ * obey some common validation techniques when it comes to sanitizing a person
335
+ * name. For this reason, the [Config.bypass] is set to `true` by default,
336
+ * indicating that those predefined rules should be skipped for the sake of the
337
+ * program.
338
+ *
339
+ * A programmer may leverage `Parser` to indicate business-tailored rules if he
340
+ * or she wants this utility to perform those safety checks behind the scenes.
341
+ *
342
+ * A name error intends to provide useful information about what causes the error
343
+ * and let the user take initiative on what happens next to the given name:
344
+ * reconstructing it or skipping it.
345
+ */
346
+ class NameError extends Error {
581
347
  /**
582
- * Gets the middle names part of the full name
583
- * @returns {Array<string>} the middle names
348
+ * Creates an error with a message describing the issue for a name source.
349
+ * @param source name input that caused the error
350
+ * @param message a message describing the failure.
351
+ * @param type of `NameErrorType`
584
352
  */
585
- getMiddlenames() {
586
- return this.fullname.middlename ? this.fullname.middlename.map(n => n.namon) : [];
353
+ constructor(source, message, type = NameErrorType.UNKNOWN) {
354
+ super(message);
355
+ this.source = source;
356
+ this.type = type;
357
+ this.name = 'NameError';
587
358
  }
588
359
  /**
589
- * Gets the prefix part of the full name
590
- * @returns {string} the prefix
360
+ * The actual source input which caused the error.
591
361
  */
592
- getPrefix() {
593
- const pxSep = this.config.titling === 'us' ? index_2.Separator.PERIOD : index_2.Separator.EMPTY;
594
- return this.fullname.prefix ?
595
- index_2.Separator.EMPTY.concat(this.fullname.prefix, pxSep) :
596
- index_2.Separator.EMPTY;
362
+ get sourceAsString() {
363
+ let input = '';
364
+ if (!this.source)
365
+ input = '<undefined>';
366
+ if (typeof this.source === 'string')
367
+ input = this.source;
368
+ if (utils_1.isNameArray(this.source))
369
+ input = this.source.map((n) => n.toString()).join(' ');
370
+ if (utils_1.isStringArray(this.source))
371
+ input = this.source.join(' ');
372
+ return input;
597
373
  }
598
374
  /**
599
- * Gets the suffix part of the full name
600
- * @returns {string} the suffix
375
+ * Whether a message describing the failure exists.
601
376
  */
602
- getSuffix() {
603
- return this.fullname.suffix || index_2.Separator.EMPTY;
377
+ get hasMessage() {
378
+ return this.message && this.message.trim().length > 0;
604
379
  }
605
380
  /**
606
- * Gets the initials of the full name
607
- * @param {'firstname'|'lastname'} orderedBy force to order by first or last
608
- * name by overriding the preset configuration
609
- * @param {boolean} [withMid] whether to include middle names's
610
- * @returns {Array<string>} the initials
611
- *
612
- * @example
613
- * Given the names:
614
- * - `John Smith` => ['J', 'S']
615
- * - `John Ben Smith` => ['J', 'S']
616
- * when `withMid` is set to true:
617
- * - `John Ben Smith` => ['J', 'B', 'S']
618
- *
619
- * **NOTE**:
620
- * Ordered by last name obeys the following format:
621
- * `lastname firstname [middlename]`
622
- * which means that if no middle name was set, setting `withMid` to true
623
- * will output nothing and warn the end user about it.
624
- */
625
- getInitials(orderedBy, withMid = false) {
626
- orderedBy = orderedBy || this.config.orderedBy; // override config
627
- const midInits = this.fullname.middlename ?
628
- this.fullname.middlename.map(n => n.getInitials()) : [];
629
- if (withMid && !this.fullname.middlename) {
630
- console.warn('No initials for middle names since none was set.');
631
- }
632
- const initials = [];
633
- switch (orderedBy) {
634
- case 'firstname':
635
- initials.push(...this.fullname.firstname.getInitials());
636
- if (withMid)
637
- midInits.forEach(m => initials.push(...m));
638
- initials.push(...this.fullname.lastname.getInitials());
639
- break;
640
- case 'lastname':
641
- initials.push(...this.fullname.lastname.getInitials());
642
- initials.push(...this.fullname.firstname.getInitials());
643
- if (withMid)
644
- midInits.forEach(m => initials.push(...m));
645
- break;
646
- }
647
- return initials;
381
+ * Returns a string representation of the error.
382
+ */
383
+ toString() {
384
+ let report = `${this.name} (${this.sourceAsString})`;
385
+ if (this.hasMessage)
386
+ report = `${report}: ${this.message}`;
387
+ return report;
648
388
  }
389
+ }
390
+ exports.NameError = NameError;
391
+ /**
392
+ * An error thrown when a name source input is incorrect.
393
+ *
394
+ * A `Name` is a name for this utility under certain criteria (i.e., 2+ chars),
395
+ * hence, a wrong input will cause this kind of error. Another common reason
396
+ * may be a wrong key in a Json name parsing mechanism.
397
+ *
398
+ * Keep in mind that this error is different from a `ValidationError`.
399
+ */
400
+ class InputError extends NameError {
649
401
  /**
650
- * Gives some descriptive statistics that summarize the central tendency,
651
- * dispersion and shape of the characters' distribution.
652
- * @param what which variant to use when describe a name part
653
- * @returns {string} the stats behind the full name.
654
- *
655
- * Treated as a categorical dataset, the summary contains the following info:
656
- * `count` : the number of *unrestricted* characters of the name;
657
- * `frequency` : the highest frequency within the characters;
658
- * `top` : the character with the highest frequency;
659
- * `unique` : the count of unique characters of the name.
660
- *
661
- * @example
662
- * Given the name "Thomas Alva Edison", the summary will output as follows:
402
+ * Creates a new `InputError` with an optional error `message`.
663
403
  *
664
- * Descriptive statistics for "Thomas Alva Edison"
665
- * count : 16
666
- * frequency: 3
667
- * top : A
668
- * unique : 12
669
- *
670
- * **NOTE:**
671
- * During the setup, a set of restricted characters can be defined to be removed
672
- * from the stats. By default, the only restricted character is the `space`.
673
- * That is why the `count` for the example below result in `16` instead of
674
- * `16`.
675
- * Another thing to consider is that the summary is case *insensitive*. Note
676
- * that the letter `a` has the top frequency, be it `3`.
677
- */
678
- describe(what = 'fullname') {
679
- switch (what) {
680
- case 'fullname':
681
- return this.summary;
682
- case 'firstname':
683
- return this.fullname.firstname.describe();
684
- case 'lastname':
685
- return this.fullname.lastname.describe();
686
- case 'middlename':
687
- return !this.fullname.middlename ? null :
688
- new index_2.Summary(this.fullname.middlename.map(n => n.namon).join(index_2.Separator.SPACE));
689
- }
404
+ * The name source is by nature a string content, maybe wrapped up in a different
405
+ * type. This string value may be extracted to form the following output:
406
+ * "InputError (stringName)",
407
+ * "InputError (stringName): message".
408
+ */
409
+ constructor(error) {
410
+ super(error.source, error.message, NameErrorType.INPUT);
411
+ this.name = 'InputError';
690
412
  }
413
+ }
414
+ exports.InputError = InputError;
415
+ /**
416
+ * An error thrown to indicate that a name fails the validation rules.
417
+ */
418
+ class ValidationError extends NameError {
691
419
  /**
692
- * Shortens a complex full name to a simple typical name, a combination of
693
- * first name and last name.
694
- * @param {'firstname'|'lastname'} orderedBy force to order by first or last
695
- * name by overriding the preset configuration
696
- * @returns {string} a typical name
420
+ * Creates error containing the invalid `nameType` and a `message` that
421
+ * briefly describes the problem if provided.
697
422
  *
698
- * @example
699
- * For a given name such as `Mr Keanu Charles Reeves`, shortening this name
700
- * is equivalent to making it `Keanu Reeves`.
423
+ * For example, a validation error can be interpreted as:
424
+ * "ValidationError (nameType='stringName')",
425
+ * "ValidationError (nameType='stringName'): message"
701
426
  */
702
- shorten(orderedBy) {
703
- orderedBy = orderedBy || this.config.orderedBy; // override config
704
- return orderedBy === 'firstname' ?
705
- [
706
- this.fullname.firstname.namon,
707
- this.fullname.lastname.namon,
708
- ].join(index_2.Separator.SPACE) :
709
- [
710
- this.fullname.lastname.namon,
711
- this.fullname.firstname.namon,
712
- ].join(index_2.Separator.SPACE);
713
- }
714
- /**
715
- * Compresses a name by using different forms of variants
716
- * @param {number} [limit] a threshold to limit the number of characters
717
- * @param {'firstname'|'lastname'|'middlename'|'firstmid'|'midlast'} [by]
718
- * a variant to use when compressing the long name. The last two variants
719
- * represent respectively the combination of `firstname + middlename` and
720
- * `middlename + lastname`.
721
- * @param {boolean} [warning] should warn when the set limit is violated
722
- *
723
- * @example
724
- * The compressing operation is only executed iff there is valid entry and it
725
- * surpasses the limit set. In the examples below, let us assume that the
726
- * name goes beyond the limit value.
727
- *
728
- * Compressing a long name refers to reducing the name to the following forms:
729
- * 1. by firstname: 'John Moe Beau Lennon' => 'J. Moe Beau Lennon'
730
- * 2. by middlename: 'John Moe Beau Lennon' => 'John M. B. Lennon'
731
- * 3. by lastname: 'John Moe Beau Lennon' => 'John Moe Beau L.'
732
- * 4. by firstmid: 'John Moe Beau Lennon' => 'J. M. B. Lennon'
733
- * 5. by midlast: 'John Moe Beau Lennon' => 'John M. B. L.'
734
- *
735
- * By default, it compresses by 'firstmid' variant: 'J. M. B. Lennon'.
736
- */
737
- compress(limit = 20, by = 'middlename', warning = true) {
738
- if (this.getFullname().length <= limit) // no need to compress
739
- return this.getFullname();
740
- const { firstname: fn, lastname: ln, middlename } = this.fullname;
741
- const mn = this.getMiddlenames().join(index_2.Separator.SPACE);
742
- const hasmid = Array.isArray(middlename) && middlename.length > 0;
743
- const sep = this.config.titling === 'us' ? index_2.Separator.PERIOD : index_2.Separator.EMPTY;
744
- const firsts = fn.getInitials().join(sep).concat(sep);
745
- const lasts = ln.getInitials().join(sep).concat(sep);
746
- const mids = hasmid ? middlename.map(n => n.getInitials()).join(sep).concat(sep) : index_2.Separator.EMPTY;
747
- let cname = '';
748
- if (this.config.orderedBy === 'firstname') {
749
- switch (by) {
750
- case 'firstname':
751
- cname = hasmid ?
752
- [firsts, mn, ln.tostring()].join(index_2.Separator.SPACE) :
753
- [firsts, ln.tostring()].join(index_2.Separator.SPACE);
754
- break;
755
- case 'lastname':
756
- cname = hasmid ?
757
- [fn.tostring(), mn, lasts].join(index_2.Separator.SPACE) :
758
- [fn.tostring(), lasts].join(index_2.Separator.SPACE);
759
- break;
760
- case 'middlename':
761
- cname = hasmid ?
762
- [fn.tostring(), mids, ln.tostring()].join(index_2.Separator.SPACE) :
763
- [fn.tostring(), ln.tostring()].join(index_2.Separator.SPACE);
764
- break;
765
- case 'firstmid':
766
- cname = hasmid ?
767
- [firsts, mids, ln.tostring()].join(index_2.Separator.SPACE) :
768
- [firsts, ln.tostring()].join(index_2.Separator.SPACE);
769
- break;
770
- case 'midlast':
771
- cname = hasmid ?
772
- [fn.tostring(), mids, lasts].join(index_2.Separator.SPACE) :
773
- [fn.tostring(), lasts].join(index_2.Separator.SPACE);
774
- break;
775
- }
776
- }
777
- else {
778
- switch (by) {
779
- case 'firstname':
780
- cname = hasmid ?
781
- [ln.tostring(), firsts, mn].join(index_2.Separator.SPACE) :
782
- [ln.tostring(), firsts].join(index_2.Separator.SPACE);
783
- break;
784
- case 'lastname':
785
- cname = hasmid ?
786
- [lasts, fn.tostring(), mn].join(index_2.Separator.SPACE) :
787
- [lasts, fn.tostring()].join(index_2.Separator.SPACE);
788
- break;
789
- case 'middlename':
790
- cname = hasmid ?
791
- [ln.tostring(), fn.tostring(), mids].join(index_2.Separator.SPACE) :
792
- [ln.tostring(), fn.tostring()].join(index_2.Separator.SPACE);
793
- break;
794
- case 'firstmid':
795
- cname = hasmid ?
796
- [ln.tostring(), firsts, mids].join(index_2.Separator.SPACE) :
797
- [ln.tostring(), firsts].join(index_2.Separator.SPACE);
798
- break;
799
- case 'midlast':
800
- cname = hasmid ?
801
- [lasts, fn.tostring(), mids].join(index_2.Separator.SPACE) :
802
- [lasts, fn.tostring()].join(index_2.Separator.SPACE);
803
- break;
804
- }
805
- }
806
- if (warning && cname.length > limit)
807
- console.warn(`The compressed name <${cname}> still surpasses the set limit ${limit}`);
808
- return cname;
809
- }
810
- /**
811
- * Zips or compresses a name by using different forms of variants
812
- * @param by a variant to use when compressing the long name. The last two
813
- * variants represent respectively the combination of `firstname + middlename`
814
- * and `middlename + lastname`.
815
- */
816
- zip(by = 'mn') {
817
- let v;
818
- if (by === 'fn' || by === 'firstname')
819
- v = 'firstname';
820
- if (by === 'mn' || by === 'middlename')
821
- v = 'middlename';
822
- if (by === 'ln' || by === 'lastname')
823
- v = 'lastname';
824
- if (by === 'fm' || by === 'firstmid')
825
- v = 'firstmid';
826
- if (by === 'ml' || by === 'midlast')
827
- v = 'midlast';
828
- return this.compress(0, v, false);
829
- }
830
- /**
831
- * Suggests possible (randomly) usernames closest to the name
832
- * @returns {Array<string>} a set of usernames
833
- *
834
- * **NOTE**
835
- * The validity of these usernames are not checked against any social media
836
- * or web app online.
837
- */
838
- username() {
839
- const unames = [];
840
- const { firstname: f, lastname: l } = this.fullname;
841
- const p = index_2.Separator.PERIOD;
842
- // Given `John Smith`
843
- unames.push(f.lower() + l.lower()); // johnsmith
844
- unames.push(l.lower() + f.lower()); // smithjohn
845
- unames.push(f.lower()[0] + l.lower()); // jsmith
846
- unames.push(l.lower()[0] + f.lower()); // sjohn
847
- unames.push(f.lower()[0] + p + l.lower()); // j.smith
848
- unames.push(l.lower()[0] + p + f.lower()); // s.john
849
- unames.push(f.lower().slice(0, 2) + l.lower()); // josmith
850
- unames.push(l.lower().slice(0, 2) + f.lower()); // smjohn
851
- unames.push(f.lower().slice(0, 2) + p + l.lower()); // jo.smith
852
- unames.push(l.lower().slice(0, 2) + p + f.lower()); // sm.john
853
- return unames;
854
- }
855
- /**
856
- * Formats the name as desired
857
- * @param {string} how to format the full name
858
- * @returns {string} the formatted name as specified
859
- *
860
- * How to format it?
861
- * 'f': first name
862
- * 'F': capitalized first name
863
- * 'l': last name (official)
864
- * 'L': capitalized last name
865
- * 'm': middle names
866
- * 'M': Capitalized middle names
867
- * 'O': official document format
868
- *
869
- * @example
870
- * Given the name `Joe Jim Smith`, call the `format` with the how string.
871
- * - format('l f') => 'Smith Joe'
872
- * - format('L, f') => 'SMITH, Joe'
873
- * - format('fml') => 'JoeJimSmith'
874
- * - format('FML') => 'JOEJIMSMITH'
875
- * - format('L, f m') => 'SMITH, Joe Jim'
876
- * - format('O') => 'SMITH, Joe Jim'
877
- */
878
- format(how) {
879
- if (!how)
880
- return this.getFullname();
881
- const formatted = [];
882
- const tokens = [
883
- '.', ',', ' ', '-', '_', 'f', 'F', 'l', 'L', 'm', 'M',
884
- 'n', 'N', 'o', 'O', 'p', 'P', 's', 'S'
885
- ];
886
- for (const c of how) {
887
- if (tokens.indexOf(c) === -1)
888
- throw new Error(`<${c}> is an invalid character for the formatting.`);
889
- formatted.push(this.map(c));
890
- }
891
- return formatted.join(index_2.Separator.EMPTY).trim();
427
+ constructor(error) {
428
+ super(error.source, error.message, NameErrorType.VALIDATION);
429
+ this.nameType = error.nameType;
430
+ this.name = 'ValidationError';
892
431
  }
893
- /**
894
- * Configures how the setup will be working
895
- * @param {Config} options for a customized setup
896
- */
897
- configure(options) {
898
- // consider using deepmerge if objects no longer stay shallow
899
- this.config = Object.assign(Object.assign({}, index_1.CONFIG), options); // if options, it overrides CONFIG
432
+ toString() {
433
+ let report = `${this.name} (${this.nameType}='${this.sourceAsString}')`;
434
+ if (this.hasMessage)
435
+ report = `${report}: ${this.message}`;
436
+ return report;
900
437
  }
438
+ }
439
+ exports.ValidationError = ValidationError;
440
+ /**
441
+ * Thrown by not allowed operations such as in name formatting.
442
+ *
443
+ * For example, this will occur when trying to format a name accordingly using
444
+ * a non-supported key.
445
+ */
446
+ class NotAllowedError extends NameError {
901
447
  /**
902
- * Defines the full name by having the pieces (namon) of the names ready
903
- * @param parser customized or user-defined parser to get the full name
448
+ * Creates a new `NotAllowedError` with an optional error `message` and the
449
+ * `operation` name.
450
+ *
451
+ * For example, an error of this kind can be interpreted as:
452
+ * "NotAllowedError (stringName)",
453
+ * "NotAllowedError (stringName) - operationName",
454
+ * "NotAllowedError (stringName) - operationName: message"
904
455
  */
905
- initialize(parser) {
906
- const { orderedBy, separator, bypass, lastnameFormat } = this.config;
907
- this.fullname = parser.parse({ orderedBy, separator, bypass, lastnameFormat });
456
+ constructor(error) {
457
+ super(error.source, error.message, NameErrorType.NOT_ALLOWED);
458
+ this.operation = error.operation;
459
+ this.name = 'NotAllowedError';
460
+ }
461
+ toString() {
462
+ let report = `${this.name} (${this.sourceAsString})`;
463
+ if (this.operation && this.operation.trim().length > 0)
464
+ report = `${report} - ${this.operation}`;
465
+ if (this.hasMessage)
466
+ report = `${report}: ${this.message}`;
467
+ return report;
908
468
  }
469
+ }
470
+ exports.NotAllowedError = NotAllowedError;
471
+ /**
472
+ * A fallback error thrown by any unknown sources or unexpected failure that are
473
+ * not of `NameError`.
474
+ *
475
+ * In this particular case, an `origin` remains useful as it provides details
476
+ * on the sources and the true nature of the unexpected error.
477
+ * At this point, deciding whether to exit the program or not depends on the
478
+ * programmer.
479
+ */
480
+ class UnknownError extends NameError {
909
481
  /**
910
- * Maps a character to a specific piece of the name
911
- * @param c character to be mapped
912
- * @return {string} piece of name
482
+ * Creates a new `UnknownError` with an optional error `message`.
483
+ * Optionally, the original error revealing the true nature of the failure.
913
484
  */
914
- map(c) {
915
- switch (c) {
916
- case '.':
917
- return index_2.Separator.PERIOD;
918
- case ',':
919
- return index_2.Separator.COMMA;
920
- case ' ':
921
- return index_2.Separator.SPACE;
922
- case '-':
923
- return index_2.Separator.HYPHEN;
924
- case '_':
925
- return index_2.Separator.UNDERSCORE;
926
- case 'f':
927
- return this.fullname.firstname.namon;
928
- case 'F':
929
- return this.fullname.firstname.upper();
930
- case 'l':
931
- return this.fullname.lastname.namon;
932
- case 'L':
933
- return this.fullname.lastname.upper();
934
- case 'm':
935
- return this.fullname.middlename
936
- .map(n => n.namon).join(index_2.Separator.SPACE);
937
- case 'M':
938
- return this.fullname.middlename
939
- .map(n => n.upper()).join(index_2.Separator.SPACE);
940
- case 'o':
941
- case 'O':
942
- const { titling, ending } = this.config;
943
- const pxSep = titling === 'us' ? index_2.Separator.PERIOD : index_2.Separator.EMPTY;
944
- const sxSep = ending !== index_2.Separator.SPACE ? ending : index_2.Separator.EMPTY;
945
- const official = [
946
- this.fullname.prefix ? index_2.Separator.EMPTY.concat(this.fullname.prefix, pxSep) : index_2.Separator.EMPTY,
947
- this.fullname.lastname.upper().concat(index_2.Separator.COMMA),
948
- this.fullname.firstname.tostring(),
949
- this.fullname.middlename.map(n => n.namon).join(index_2.Separator.SPACE).concat(sxSep),
950
- this.fullname.suffix || index_2.Separator.EMPTY,
951
- ].join(index_2.Separator.SPACE).trim();
952
- return c === 'o' ? official : official.toUpperCase();
953
- case 'p':
954
- return this.fullname.prefix || index_2.Separator.EMPTY;
955
- case 'P':
956
- return this.fullname.prefix ? this.fullname.prefix.toUpperCase() : index_2.Separator.EMPTY;
957
- case 's':
958
- return this.fullname.suffix || index_2.Separator.EMPTY;
959
- case 'S':
960
- return this.fullname.suffix ? this.fullname.suffix.toUpperCase() : index_2.Separator.EMPTY;
961
- default:
962
- return index_2.Separator.EMPTY;
963
- }
485
+ constructor(error) {
486
+ super(error.source, error.message, NameErrorType.UNKNOWN);
487
+ this.origin = error.error;
488
+ this.name = 'UnknownError';
964
489
  }
965
- /**
966
- * Builds a high qualitty of data using parsers and validators
967
- * @param {string | string[] | Array<Name> | Nama} raw data to parse or
968
- * construct the pieces of the name
969
- */
970
- build(raw) {
971
- if (this.config.parser) {
972
- this.initialize(this.config.parser);
973
- }
974
- else if (typeof raw === 'string') { // check for string type
975
- this.initialize(new index_1.StringParser(raw));
976
- }
977
- else if (Array.isArray(raw) && raw.length) { // check for Array<T>
978
- if (typeof raw[0] === 'string') { // check for Array<string>
979
- for (const key of raw)
980
- if (typeof key !== 'string')
981
- throw new Error(`Cannot parse raw data as array of 'string'`);
982
- this.initialize(new index_1.ArrayStringParser(raw));
983
- }
984
- else if (raw[0] instanceof index_2.Name) { // check for Array<Name>
985
- for (const obj of raw)
986
- if (!(obj instanceof index_2.Name))
987
- throw new Error(`Cannot parse raw data as array of '${index_2.Name.name}'`);
988
- this.initialize(new index_1.ArrayNameParser(raw));
989
- }
990
- else {
991
- // typescript should stop them, but let's be paranoid (for JS developers)
992
- throw new Error(`Cannot parse raw data as arrays that are not of '${index_2.Name.name}' or string`);
993
- }
994
- }
995
- else if (raw instanceof Object) { // check for json object
996
- for (const entry of Object.entries(raw)) { // make sure keys are correct
997
- const key = entry[0], value = entry[1];
998
- if (['firstname', 'lastname', 'middlename', 'prefix', 'suffix'].indexOf(key) === -1)
999
- throw new Error(`Cannot parse raw data as json object that does not contains keys of '${index_2.Namon}'`);
1000
- if (typeof value !== 'string') // make sure the values are proper string
1001
- throw new Error(`Cannot parse raw data. The key <${key}> should be a 'string' type`);
1002
- }
1003
- this.initialize(new index_1.NamaParser(raw));
1004
- }
1005
- else {
1006
- // typescript should stop them, but let's be paranoid again (for JS developers)
1007
- throw new Error(`Cannot parse raw data. Review the data type expected.`);
1008
- }
1009
- // paranoid coder mode: on :P
1010
- if (!this.config.bypass)
1011
- new index_3.FullnameValidator().validate(this.fullname);
1012
- this.summary = new index_2.Summary(this.getFullname());
490
+ toString() {
491
+ let report = super.toString();
492
+ if (this.origin)
493
+ report += `\n${this.origin.toString()}`;
494
+ return report;
1013
495
  }
1014
496
  }
1015
- exports.Namefully = Namefully;
1016
- Namefully.prototype.full = Namefully.prototype.getFullname;
1017
- Namefully.prototype.fn = Namefully.prototype.getFirstname;
1018
- Namefully.prototype.ln = Namefully.prototype.getLastname;
1019
- Namefully.prototype.mn = Namefully.prototype.getMiddlenames;
1020
- Namefully.prototype.px = Namefully.prototype.getPrefix;
1021
- Namefully.prototype.sx = Namefully.prototype.getSuffix;
1022
- Namefully.prototype.inits = Namefully.prototype.getInitials;
1023
- Namefully.prototype.stats = Namefully.prototype.describe;
497
+ exports.UnknownError = UnknownError;
1024
498
 
1025
499
 
1026
500
  /***/ }),
1027
- /* 7 */
501
+ /* 2 */
1028
502
  /***/ (function(module, exports, __webpack_require__) {
1029
503
 
1030
504
  "use strict";
1031
505
 
1032
506
  Object.defineProperty(exports, "__esModule", { value: true });
507
+ exports.isNameArray = exports.isStringArray = exports.toggleCase = exports.decapitalize = exports.capitalize = exports.NameIndex = void 0;
508
+ const constants_1 = __webpack_require__(5);
509
+ const name_1 = __webpack_require__(3);
510
+ const types_1 = __webpack_require__(0);
1033
511
  /**
1034
- * An array `Name` parser
512
+ * A fixed set of values to handle specific positions for list of names.
1035
513
  *
1036
- * Created on March 15, 2020
1037
- * @author Ralph Florent <ralflornt@gmail.com>
1038
- */
1039
- const index_1 = __webpack_require__(1);
1040
- const index_2 = __webpack_require__(0);
1041
- /**
1042
- * Represents a `Name[]` parser
1043
- * @class
1044
- * @implements {Parser<Name[]>}
1045
- * @classdesc
1046
- * This parser parses an array of the class `Name` while checking that every part
1047
- * plays the role they are supposed to play. The class `Name` is a ready-made
1048
- * recipe that saves the how-to parsing for a raw data input.
514
+ * As for list of names, this helps to follow a specific order based on the
515
+ * count of elements. It is expected that the list has to be between two and
516
+ * five elements. Also, the order of appearance set in the configuration
517
+ * influences how the parsing is carried out.
518
+ *
519
+ * Ordered by first name, the parser works as follows:
520
+ * - 2 elements: firstName lastName
521
+ * - 3 elements: firstName middleName lastName
522
+ * - 4 elements: prefix firstName middleName lastName
523
+ * - 5 elements: prefix firstName middleName lastName suffix
524
+ *
525
+ * Ordered by last name, the parser works as follows:
526
+ * - 2 elements: lastName firstName
527
+ * - 3 elements: lastName firstName middleName
528
+ * - 4 elements: prefix lastName firstName middleName
529
+ * - 5 elements: prefix lastName firstName middleName suffix
1049
530
  *
1050
- * **NOTE**:
1051
- * In this specific case, the user is expected to carefully set each name part
1052
- * and submit a high-quality data. Why is this parser if the data is already
1053
- * shaped as wanted? Well, it is better to be safe than sorry, so we implement a
1054
- * double-check of these values and reconfirm a cleaner data. Remember, namefully
1055
- * works like a trapdoor, once the data is set and confirmed safe, no editing is
1056
- * possible.
531
+ * For example, `Jane Smith` (ordered by first name) is expected to be indexed:
532
+ * `['Jane', 'Smith']`.
1057
533
  */
1058
- class ArrayNameParser {
534
+ class NameIndex {
535
+ constructor(prefix, firstName, middleName, lastName, suffix) {
536
+ this.prefix = prefix;
537
+ this.firstName = firstName;
538
+ this.middleName = middleName;
539
+ this.lastName = lastName;
540
+ this.suffix = suffix;
541
+ }
1059
542
  /**
1060
- * Create a parser ready to parse the raw data
1061
- * @param {Name[]} raw data
543
+ * The minimum number of parts in a list of names.
1062
544
  */
1063
- constructor(raw) {
1064
- this.raw = raw;
545
+ static get min() {
546
+ return constants_1.MIN_NUMBER_OF_NAME_PARTS;
1065
547
  }
1066
548
  /**
1067
- * Parses the raw data into a full name
1068
- * @returns {Fullname}
549
+ * The maximum number of parts in a list of names.
1069
550
  */
1070
- parse(options) {
1071
- const { bypass, lastnameFormat } = options;
1072
- // validate first
1073
- if (!bypass)
1074
- new index_2.ArrayNameValidator().validate(this.raw);
1075
- // then distribute all the elements accordingly
1076
- const fullname = this.distribute(lastnameFormat);
1077
- // finally return high quality of data
1078
- return fullname;
1079
- }
1080
- distribute(lastnameFormat) {
1081
- const fullname = {
1082
- firstname: null,
1083
- lastname: null,
1084
- middlename: [],
1085
- prefix: null,
1086
- suffix: null,
1087
- };
1088
- this.raw.forEach(name => {
1089
- switch (name.type) {
1090
- case index_1.Namon.PREFIX:
1091
- fullname.prefix = name.namon;
1092
- break;
1093
- case index_1.Namon.FIRST_NAME:
1094
- fullname.firstname = new index_1.Firstname(name.namon);
1095
- break;
1096
- case index_1.Namon.LAST_NAME:
1097
- if (name instanceof index_1.Lastname)
1098
- fullname.lastname = new index_1.Lastname(name.father, name.mother, lastnameFormat);
1099
- else
1100
- fullname.lastname = new index_1.Lastname(name.namon, null, lastnameFormat);
1101
- break;
1102
- case index_1.Namon.MIDDLE_NAME:
1103
- fullname.middlename.push(name);
1104
- break;
1105
- case index_1.Namon.SUFFIX:
1106
- fullname.suffix = name.namon;
1107
- break;
551
+ static get max() {
552
+ return constants_1.MAX_NUMBER_OF_NAME_PARTS;
553
+ }
554
+ /**
555
+ * The default or base indexing: firstName lastName.
556
+ */
557
+ static base() {
558
+ return new this(-1, 0, -1, 1, -1);
559
+ }
560
+ /**
561
+ * Gets the name index for a list of names based on the `count` of elements
562
+ * and their `order` of appearance.
563
+ */
564
+ static when(order, count = 2) {
565
+ if (order === types_1.NameOrder.FIRST_NAME) {
566
+ switch (count) {
567
+ case 2: // first name + last name
568
+ return new this(-1, 0, -1, 1, -1);
569
+ case 3: // first name + middle name + last name
570
+ return new this(-1, 0, 1, 2, -1);
571
+ case 4: // prefix + first name + middle name + last name
572
+ return new this(0, 1, 2, 3, -1);
573
+ case 5: // prefix + first name + middle name + last name + suffix
574
+ return new this(0, 1, 2, 3, 4);
575
+ default:
576
+ return NameIndex.base();
1108
577
  }
1109
- });
1110
- return fullname;
578
+ }
579
+ else {
580
+ switch (count) {
581
+ case 2: // last name + first name
582
+ return new this(-1, 1, -1, 0, -1);
583
+ case 3: // last name + first name + middle name
584
+ return new this(-1, 1, 2, 0, -1);
585
+ case 4: // prefix + last name + first name + middle name
586
+ return new this(0, 2, 3, 1, -1);
587
+ case 5: // prefix + last name + first name + middle name + suffix
588
+ return new this(0, 2, 3, 1, 4);
589
+ default:
590
+ return NameIndex.base();
591
+ }
592
+ }
593
+ }
594
+ }
595
+ exports.NameIndex = NameIndex;
596
+ /**
597
+ * Capitalizes a string via a `CapsRange` option.
598
+ */
599
+ function capitalize(str, range = types_1.CapsRange.INITIAL) {
600
+ if (!str || range === types_1.CapsRange.NONE)
601
+ return str;
602
+ const initial = str[0].toUpperCase();
603
+ const rest = str.slice(1).toLowerCase();
604
+ return range === types_1.CapsRange.INITIAL ? initial.concat(rest) : str.toUpperCase();
605
+ }
606
+ exports.capitalize = capitalize;
607
+ /**
608
+ * Decapitalizes a string via a `CapsRange` option.
609
+ */
610
+ function decapitalize(str, range = types_1.CapsRange.INITIAL) {
611
+ if (!str || range === types_1.CapsRange.NONE)
612
+ return str;
613
+ const initial = str[0].toLowerCase();
614
+ const rest = str.slice(1);
615
+ return range === types_1.CapsRange.INITIAL ? initial.concat(rest) : str.toLowerCase();
616
+ }
617
+ exports.decapitalize = decapitalize;
618
+ /**
619
+ * Toggles a string representation.
620
+ */
621
+ function toggleCase(str) {
622
+ const chars = [];
623
+ for (const c of str) {
624
+ if (c === c.toUpperCase()) {
625
+ chars.push(c.toLowerCase());
626
+ }
627
+ else {
628
+ chars.push(c.toUpperCase());
629
+ }
1111
630
  }
631
+ return chars.join('');
632
+ }
633
+ exports.toggleCase = toggleCase;
634
+ function isStringArray(value) {
635
+ return Array.isArray(value) && value.length > 0 && value.every((e) => typeof e === 'string');
636
+ }
637
+ exports.isStringArray = isStringArray;
638
+ function isNameArray(value) {
639
+ return Array.isArray(value) && value.length > 0 && value.every((e) => e instanceof name_1.Name);
1112
640
  }
1113
- exports.default = ArrayNameParser;
641
+ exports.isNameArray = isNameArray;
1114
642
 
1115
643
 
1116
644
  /***/ }),
1117
- /* 8 */
645
+ /* 3 */
1118
646
  /***/ (function(module, exports, __webpack_require__) {
1119
647
 
1120
648
  "use strict";
1121
649
 
1122
650
  Object.defineProperty(exports, "__esModule", { value: true });
651
+ exports.LastName = exports.FirstName = exports.Name = void 0;
652
+ const error_1 = __webpack_require__(1);
653
+ const types_1 = __webpack_require__(0);
654
+ const utils_1 = __webpack_require__(2);
1123
655
  /**
1124
- * Name class definition
1125
- *
1126
- * Created on March 06, 2020
1127
- * @author Ralph Florent <ralflornt@gmail.com>
1128
- */
1129
- const index_1 = __webpack_require__(1);
1130
- /**
1131
- * Represents a namon with some extra functionalities
1132
- * @class
1133
- * @see {@link Namon} interface to understand the concept of namon/nama.
656
+ * Representation of a string type name with some extra capabilities.
1134
657
  */
1135
658
  class Name {
1136
659
  /**
1137
- * Constructs a `Name`
1138
- * @param namon a piece of string that will be defined as a namon
1139
- * @param type which namon that is
660
+ * Creates augmented names by adding extra functionality to a string name.
661
+ * @param type must be indicated to categorize the name so it can be
662
+ * treated accordingly.
663
+ * @param capsRange determines how the name should be capitalized initially.
1140
664
  */
1141
- constructor(namon, type, capitalized) {
1142
- this.namon = namon;
665
+ constructor(value, type, capsRange) {
1143
666
  this.type = type;
1144
- this.initial = namon[0];
1145
- this.body = namon.slice(1, namon.length);
1146
- if (!!capitalized)
1147
- this.capitalize(capitalized);
667
+ this.capsRange = capsRange !== null && capsRange !== void 0 ? capsRange : types_1.CapsRange.INITIAL;
668
+ this.value = value;
669
+ if (capsRange)
670
+ this.caps(capsRange);
671
+ }
672
+ set value(newValue) {
673
+ if (newValue.trim().length < 2) {
674
+ throw new error_1.InputError({ source: newValue, message: 'must be 2+ characters' });
675
+ }
676
+ this.namon = newValue;
677
+ this.initial = newValue[0];
1148
678
  }
1149
679
  /**
1150
- * Gives some descriptive statistics that summarize the central tendency,
1151
- * dispersion and shape of the characters' distribution.
1152
- * @see {@link describe} in `Namefully` class for further information
680
+ * The piece of string treated as a name.
1153
681
  */
1154
- describe() {
1155
- return new index_1.Summary(this.namon);
682
+ get value() {
683
+ return this.namon;
1156
684
  }
1157
685
  /**
1158
- * Gets the initials of the name
1159
- * @returns {Array<string>} the initials
686
+ * The length of the name.
1160
687
  */
1161
- getInitials() {
1162
- return [this.initial];
688
+ get length() {
689
+ return this.namon.length;
1163
690
  }
1164
691
  /**
1165
- * Capitalizes a name
1166
- * @param {'initial' | 'all'} option how to capitalize it
692
+ * Whether the name is a prefix.
1167
693
  */
1168
- capitalize(option = 'initial') {
1169
- if (option === 'initial') {
1170
- this.initial = this.initial.toUpperCase();
1171
- this.namon = this.initial.concat(this.body);
1172
- }
1173
- else {
1174
- this.initial = this.initial.toUpperCase();
1175
- this.namon = this.namon.toUpperCase();
1176
- }
694
+ get isPrefix() {
695
+ return this.type === types_1.Namon.PREFIX;
1177
696
  }
1178
697
  /**
1179
- * Converts all the alphabetic characters in a string to lowercase
698
+ * Whether the name is a first name.
1180
699
  */
1181
- lower() {
1182
- return this.namon.toLowerCase();
700
+ get isFirstName() {
701
+ return this.type === types_1.Namon.FIRST_NAME;
1183
702
  }
1184
703
  /**
1185
- * Converts all the alphabetic characters in a string to uppercase
704
+ * Whether the name is a middle name.
1186
705
  */
1187
- upper() {
1188
- return this.namon.toUpperCase();
706
+ get isMiddleName() {
707
+ return this.type === types_1.Namon.MIDDLE_NAME;
1189
708
  }
1190
- }
1191
- exports.Name = Name;
1192
-
1193
-
1194
- /***/ }),
1195
- /* 9 */
1196
- /***/ (function(module, exports, __webpack_require__) {
1197
-
1198
- "use strict";
1199
-
1200
- Object.defineProperty(exports, "__esModule", { value: true });
709
+ /**
710
+ * Whether the name is a last name.
711
+ */
712
+ get isLastName() {
713
+ return this.type === types_1.Namon.LAST_NAME;
714
+ }
715
+ /**
716
+ * Whether the name is a suffix.
717
+ */
718
+ get isSuffix() {
719
+ return this.type === types_1.Namon.SUFFIX;
720
+ }
721
+ /**
722
+ * Creates a prefix.
723
+ */
724
+ static prefix(value) {
725
+ return new this(value, types_1.Namon.PREFIX);
726
+ }
727
+ /**
728
+ * Creates a first name.
729
+ */
730
+ static first(value) {
731
+ return new this(value, types_1.Namon.FIRST_NAME);
732
+ }
733
+ /**
734
+ * Creates a middle name.
735
+ */
736
+ static middle(value) {
737
+ return new this(value, types_1.Namon.MIDDLE_NAME);
738
+ }
739
+ /**
740
+ * Creates a last name.
741
+ */
742
+ static last(value) {
743
+ return new this(value, types_1.Namon.LAST_NAME);
744
+ }
745
+ /**
746
+ * Creates a suffix.
747
+ */
748
+ static suffix(value) {
749
+ return new this(value, types_1.Namon.SUFFIX);
750
+ }
751
+ /**
752
+ * Gets the initials (first character) of this name.
753
+ */
754
+ initials() {
755
+ return [this.initial];
756
+ }
757
+ /**
758
+ * String representation of this object.
759
+ */
760
+ toString() {
761
+ return this.namon;
762
+ }
763
+ /**
764
+ * Returns true if the other is equal to this name.
765
+ */
766
+ equal(other) {
767
+ return other instanceof Name && other.value === this.value && other.type === this.type;
768
+ }
769
+ /**
770
+ * Capitalizes the name.
771
+ */
772
+ caps(range) {
773
+ this.value = utils_1.capitalize(this.namon, range !== null && range !== void 0 ? range : this.capsRange);
774
+ return this;
775
+ }
776
+ /**
777
+ * De-capitalizes the name.
778
+ */
779
+ decaps(range) {
780
+ this.value = utils_1.decapitalize(this.namon, range !== null && range !== void 0 ? range : this.capsRange);
781
+ return this;
782
+ }
783
+ }
784
+ exports.Name = Name;
1201
785
  /**
1202
- * First name class definition
1203
- *
1204
- * Created on March 06, 2020
1205
- * @author Ralph Florent <ralflornt@gmail.com>
786
+ * Representation of a first name with some extra functionality.
1206
787
  */
1207
- const index_1 = __webpack_require__(1);
788
+ class FirstName extends Name {
789
+ /**
790
+ * Creates an extended version of `Name` and flags it as a first name `type`.
791
+ *
792
+ * Some may consider `more` additional name parts of a given name as their
793
+ * first names, but not as their middle names. Though, it may mean the same,
794
+ * `more` provides the freedom to do it as it pleases.
795
+ */
796
+ constructor(value, ...more) {
797
+ super(value, types_1.Namon.FIRST_NAME);
798
+ for (const name of more) {
799
+ if (name.trim().length < 2) {
800
+ throw new error_1.InputError({ source: name, message: 'must be 2+ characters' });
801
+ }
802
+ }
803
+ this._more = more;
804
+ }
805
+ /**
806
+ * Determines whether a first name has `more` name parts.
807
+ */
808
+ get hasMore() {
809
+ return this._more.length > 0;
810
+ }
811
+ get length() {
812
+ return super.length + (this.hasMore ? this._more.reduce((acc, n) => acc + n).length : 0);
813
+ }
814
+ /**
815
+ * Returns a combined version of the `value` and `more` if any.
816
+ */
817
+ get asNames() {
818
+ const names = [Name.first(this.value)];
819
+ if (this.hasMore) {
820
+ names.push(...this._more.map((n) => Name.first(n)));
821
+ }
822
+ return names;
823
+ }
824
+ /**
825
+ * The additional name parts of the first name.
826
+ */
827
+ get more() {
828
+ return this._more;
829
+ }
830
+ toString(withMore = false) {
831
+ return withMore && this.hasMore ? `${this.value} ${this._more.join(' ')}`.trim() : this.value;
832
+ }
833
+ initials(withMore = false) {
834
+ const inits = [this.initial];
835
+ if (withMore && this.hasMore) {
836
+ inits.push(...this._more.map((n) => n[0]));
837
+ }
838
+ return inits;
839
+ }
840
+ caps(range) {
841
+ range = range || this.capsRange;
842
+ this.value = utils_1.capitalize(this.value, range);
843
+ if (this.hasMore)
844
+ this._more = this._more.map((n) => utils_1.capitalize(n, range));
845
+ return this;
846
+ }
847
+ decaps(range) {
848
+ range = range || this.capsRange;
849
+ this.value = utils_1.decapitalize(this.value, range);
850
+ if (this.hasMore)
851
+ this._more = this._more.map((n) => utils_1.decapitalize(n, range));
852
+ return this;
853
+ }
854
+ /**
855
+ * Makes a copy of the current name.
856
+ */
857
+ copyWith(values) {
858
+ var _a, _b;
859
+ return new FirstName((_a = values.first) !== null && _a !== void 0 ? _a : this.value, ...((_b = values.more) !== null && _b !== void 0 ? _b : this._more));
860
+ }
861
+ }
862
+ exports.FirstName = FirstName;
1208
863
  /**
1209
- * Represents a first name with some extra functionalities
1210
- * @class
1211
- * @extends Name
864
+ * Representation of a last name with some extra functionality.
1212
865
  */
1213
- class Firstname extends index_1.Name {
866
+ class LastName extends Name {
867
+ /**
868
+ * Creates an extended version of `Name` and flags it as a last name `type`.
869
+ *
870
+ * Some people may keep their `mother`'s surname and want to keep a clear cut
871
+ * from their `father`'s surname. However, there are no clear rules about it.
872
+ */
873
+ constructor(father, mother, format = types_1.Surname.FATHER) {
874
+ super(father, types_1.Namon.LAST_NAME);
875
+ this.format = format;
876
+ if (mother && mother.trim().length < 2) {
877
+ throw new error_1.InputError({ source: mother, message: 'must be 2+ characters' });
878
+ }
879
+ this._mother = mother;
880
+ }
1214
881
  /**
1215
- * Constructs a `Firstname`
1216
- * @param {string} namon a piece of string that will be defined as a namon
1217
- * @param {string[]} [more] additional pieces considered as a given name
882
+ * The surname inherited from a father side.
1218
883
  */
1219
- constructor(namon, more) {
1220
- super(namon, index_1.Namon.FIRST_NAME);
1221
- this.namon = namon;
1222
- this.more = more;
884
+ get father() {
885
+ return this.value;
1223
886
  }
1224
887
  /**
1225
- * Gives some descriptive statistics that summarize the central tendency,
1226
- * dispersion and shape of the characters' distribution.
1227
- * @param {boolean} includeAll whether to include other pieces of the first
1228
- * name in the summary
1229
- * @see {@link describe} in `Namefully` class for further information
888
+ * The surname inherited from a mother side.
1230
889
  */
1231
- describe(includeAll = false) {
1232
- return new index_1.Summary(this.tostring(includeAll));
890
+ get mother() {
891
+ return this._mother;
1233
892
  }
1234
893
  /**
1235
- * Returns a string representation of the first name
1236
- * @param {boolean} includeAll whether to include other pieces of the first
1237
- * name
894
+ * Returns `true` if the mother's surname is defined.
1238
895
  */
1239
- tostring(includeAll = false) {
1240
- return !includeAll ?
1241
- this.namon :
1242
- this.namon.concat(index_1.Separator.SPACE, this.more.join(index_1.Separator.SPACE));
896
+ get hasMother() {
897
+ return !!this._mother;
898
+ }
899
+ get length() {
900
+ var _a, _b;
901
+ return super.length + ((_b = (_a = this._mother) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
1243
902
  }
1244
903
  /**
1245
- * Gets the initials of the first name
1246
- * @returns {Array<string>} the initials
904
+ * Returns a combined version of the `father` and `mother` if any.
1247
905
  */
1248
- getInitials(includeAll = false) {
1249
- const initials = [this.namon[0]];
1250
- if (includeAll && Array.isArray(this.more) && this.more.length) {
1251
- initials.push(...this.more.map(n => n[0]));
906
+ get asNames() {
907
+ const names = [Name.last(this.value)];
908
+ if (this.hasMother) {
909
+ names.push(Name.last(this._mother));
1252
910
  }
1253
- return initials;
911
+ return names;
912
+ }
913
+ toString(format) {
914
+ var _a;
915
+ format = format !== null && format !== void 0 ? format : this.format;
916
+ switch (format) {
917
+ case types_1.Surname.FATHER:
918
+ return this.value;
919
+ case types_1.Surname.MOTHER:
920
+ return (_a = this.mother) !== null && _a !== void 0 ? _a : '';
921
+ case types_1.Surname.HYPHENATED:
922
+ return this.hasMother ? `${this.value}-${this._mother}` : this.value;
923
+ case types_1.Surname.ALL:
924
+ return this.hasMother ? `${this.value} ${this._mother}` : this.value;
925
+ }
926
+ }
927
+ initials(format) {
928
+ format = format || this.format;
929
+ const inits = [];
930
+ switch (format) {
931
+ case types_1.Surname.MOTHER:
932
+ if (this.hasMother)
933
+ inits.push(this._mother[0]);
934
+ break;
935
+ case types_1.Surname.HYPHENATED:
936
+ case types_1.Surname.ALL:
937
+ inits.push(this.initial);
938
+ if (this.hasMother)
939
+ inits.push(this._mother[0]);
940
+ break;
941
+ case types_1.Surname.FATHER:
942
+ default:
943
+ inits.push(this.initial);
944
+ }
945
+ return inits;
946
+ }
947
+ caps(range) {
948
+ range = range || this.capsRange;
949
+ this.value = utils_1.capitalize(this.value, range);
950
+ if (this.hasMother)
951
+ this._mother = utils_1.capitalize(this._mother, range);
952
+ return this;
953
+ }
954
+ decaps(range) {
955
+ range = range || this.capsRange;
956
+ this.value = utils_1.decapitalize(this.value, range);
957
+ if (this.hasMother)
958
+ this._mother = utils_1.decapitalize(this._mother, range);
959
+ return this;
960
+ }
961
+ /**
962
+ * Makes a copy of the current name.
963
+ */
964
+ copyWith(values) {
965
+ var _a, _b, _c;
966
+ return new LastName((_a = values.father) !== null && _a !== void 0 ? _a : this.value, (_b = values.mother) !== null && _b !== void 0 ? _b : this.mother, (_c = values.format) !== null && _c !== void 0 ? _c : this.format);
1254
967
  }
1255
968
  }
1256
- exports.Firstname = Firstname;
969
+ exports.LastName = LastName;
1257
970
 
1258
971
 
1259
972
  /***/ }),
1260
- /* 10 */
973
+ /* 4 */
1261
974
  /***/ (function(module, exports, __webpack_require__) {
1262
975
 
1263
976
  "use strict";
1264
977
 
1265
978
  Object.defineProperty(exports, "__esModule", { value: true });
979
+ exports.Config = void 0;
980
+ const types_1 = __webpack_require__(0);
981
+ const defaultName = 'default';
982
+ const copyAlias = '_copy';
1266
983
  /**
1267
- * Last name class definition
984
+ * The Configuration to use across the other components.
1268
985
  *
1269
- * Created on March 06, 2020
1270
- * @author Ralph Florent <ralflornt@gmail.com>
1271
- */
1272
- const index_1 = __webpack_require__(1);
1273
- /**
1274
- * Represents a last name with some extra functionalities
1275
- * @class
1276
- * @extends Name
1277
- */
1278
- class Lastname extends index_1.Name {
1279
- /**
1280
- * Constructs a `Lastname`
1281
- * @param {string} father a piece of string that will be defined as a namon
1282
- * @param {string} [mother] additional pieces considered as a last name
1283
- * @param {LastnameFormat} [format] how to output a surname considering its
1284
- * subparts
1285
- */
1286
- constructor(father, mother, format = 'father') {
1287
- super(father, index_1.Namon.LAST_NAME);
1288
- this.father = father;
1289
- this.mother = mother;
1290
- this.format = format;
986
+ * The multiton pattern is used to handle configurations across the `namefully`
987
+ * setup. This adds consistency when building other components such as `FirstName`,
988
+ * `LastName`, or `Name` of distinct types that may be of particular shapes.
989
+ *
990
+ * For example, a person's `FullName` may appear by:
991
+ * - NameOrder.FIRST_NAME: `Jon Snow` or
992
+ * - NameOrder.LAST_NAME: `Snow Jon`.
993
+ *
994
+ * `Config` makes it easy to set up a specific configuration for `Namefully`
995
+ * and reuse it through other instances or components along the way. If a new
996
+ * `Config` is needed, a named configuration may be created. It is actually
997
+ * advised to use named `Config.create(name)` instead as it may help mitigate issues
998
+ * and avoid confusion and ambiguity in the future. Plus, a named configuration
999
+ * explains its purpose.
1000
+ *
1001
+ * ```ts
1002
+ * const defaultConfig = Config.create();
1003
+ * const mergedConfig = Config.merge({ name: 'other', title: Title.US });
1004
+ * const copyConfig = mergedConfig.copyWith({ ending: true });
1005
+ * ```
1006
+ *
1007
+ * Additionally, a configuration may be merged with or copied from an existing
1008
+ * configuration, prioritizing the new one's values, as shown in the example
1009
+ * above.
1010
+ */
1011
+ class Config {
1012
+ constructor(name, orderedBy = types_1.NameOrder.FIRST_NAME, separator = types_1.Separator.SPACE, title = types_1.Title.UK, ending = false, bypass = true, surname = types_1.Surname.FATHER) {
1013
+ this._name = name;
1014
+ this._orderedBy = orderedBy;
1015
+ this._separator = separator;
1016
+ this._title = title;
1017
+ this._ending = ending;
1018
+ this._bypass = bypass;
1019
+ this._surname = surname;
1291
1020
  }
1292
1021
  /**
1293
- * Gives some descriptive statistics that summarize the central tendency,
1294
- * dispersion and shape of the characters' distribution.
1295
- * @param {LastnameFormat} [format] overrides the how-to format of a surname
1296
- * output, considering its subparts.
1297
- * @see {@link describe} in `Namefully` class for further information
1022
+ * The order of appearance of a full name.
1298
1023
  */
1299
- describe(format) {
1300
- format = format || this.format;
1301
- return new index_1.Summary(this.tostring(format));
1024
+ get orderedBy() {
1025
+ return this._orderedBy;
1302
1026
  }
1303
1027
  /**
1304
- * Returns a string representation of the last name
1305
- * @param {LastnameFormat} [format] overrides the how-to format of a surname
1306
- * output, considering its subparts.
1028
+ * The token used to indicate how to split string values.
1307
1029
  */
1308
- tostring(format) {
1309
- format = format || this.format;
1310
- switch (format) {
1311
- case 'father':
1312
- return this.father;
1313
- case 'mother':
1314
- return this.mother || index_1.Separator.EMPTY;
1315
- case 'hyphenated':
1316
- return this.mother ? this.father.concat(index_1.Separator.HYPHEN, this.mother) : this.father;
1317
- case 'all':
1318
- return this.mother ? this.father.concat(index_1.Separator.SPACE, this.mother) : this.father;
1319
- // default:
1320
- // return this.father;
1030
+ get separator() {
1031
+ return this._separator;
1032
+ }
1033
+ /**
1034
+ * The abbreviation type to indicate whether or not to add period to a prefix
1035
+ * using the American or British way.
1036
+ */
1037
+ get title() {
1038
+ return this._title;
1039
+ }
1040
+ /**
1041
+ * The option indicating if an ending suffix is used in a formal way.
1042
+ */
1043
+ get ending() {
1044
+ return this._ending;
1045
+ }
1046
+ /**
1047
+ * A bypass of the validation rules with this option. This option is ideal
1048
+ * to avoid checking their validity.
1049
+ */
1050
+ get bypass() {
1051
+ return this._bypass;
1052
+ }
1053
+ /**
1054
+ * An option indicating how to format a surname.
1055
+ *
1056
+ * The supported formats are:
1057
+ * - `FATHER` name only
1058
+ * - `MOTHER` name only
1059
+ * - `HYPHENATED`, joining both father and mother names with a hyphen
1060
+ * - `ALL`, joining both father and mother names with a space.
1061
+ *
1062
+ * Note that this option can be set when creating a `LastName`. As this can
1063
+ * become ambiguous at the time of handling it, the value set in this is
1064
+ * prioritized and viewed as the source of truth for future considerations.
1065
+ */
1066
+ get surname() {
1067
+ return this._surname;
1068
+ }
1069
+ /**
1070
+ * The name of the cached configuration.
1071
+ */
1072
+ get name() {
1073
+ return this._name;
1074
+ }
1075
+ /**
1076
+ * Returns a named configuration with default values.
1077
+ * @param name describing its purpose.
1078
+ */
1079
+ static create(name = defaultName) {
1080
+ if (!Config.cache.has(name)) {
1081
+ Config.cache.set(name, new this(name));
1321
1082
  }
1083
+ return Config.cache.get(name);
1322
1084
  }
1323
1085
  /**
1324
- * Gets the initials of the last name
1325
- * @returns {Array<string>} the initials
1086
+ * Returns a combined version of the existing values of the default configuration
1087
+ * and the provided optional values of another configuration.
1088
+ * @param other partial config to be combined with.
1326
1089
  */
1327
- getInitials(format) {
1328
- format = format || this.format;
1329
- const initials = [];
1330
- switch (format) {
1331
- case 'father':
1332
- initials.push(this.father[0]);
1333
- break;
1334
- case 'mother':
1335
- if (!!this.mother && this.mother.length)
1336
- initials.push(this.mother[0]);
1337
- break;
1338
- case 'hyphenated':
1339
- case 'all':
1340
- initials.push(this.father[0]);
1341
- if (!!this.mother && this.mother.length)
1342
- initials.push(this.mother[0]);
1343
- break;
1090
+ static merge(other) {
1091
+ var _a, _b, _c, _d, _e, _f;
1092
+ if (!other) {
1093
+ return Config.create();
1344
1094
  }
1345
- return initials;
1095
+ else {
1096
+ const config = Config.create(other.name);
1097
+ config._orderedBy = (_a = other.orderedBy) !== null && _a !== void 0 ? _a : config.orderedBy;
1098
+ config._separator = (_b = other.separator) !== null && _b !== void 0 ? _b : config.separator;
1099
+ config._title = (_c = other.title) !== null && _c !== void 0 ? _c : config.title;
1100
+ config._ending = (_d = other.ending) !== null && _d !== void 0 ? _d : config.ending;
1101
+ config._bypass = (_e = other.bypass) !== null && _e !== void 0 ? _e : config.bypass;
1102
+ config._surname = (_f = other.surname) !== null && _f !== void 0 ? _f : config.surname;
1103
+ return config;
1104
+ }
1105
+ }
1106
+ /**
1107
+ * Returns a copy of this configuration merged with the provided values.
1108
+ *
1109
+ * The word `_copy` is added to the existing config's name to create the new
1110
+ * config's name if the name already exists for previous configurations. This
1111
+ * is useful to maintain the uniqueness of each configuration. For example,
1112
+ * if the new copy is made from the default configuration, this new copy will
1113
+ * be named `default_copy`.
1114
+ */
1115
+ copyWith(options = {}) {
1116
+ const { name, orderedBy, separator, title, ending, bypass, surname } = options;
1117
+ const config = Config.create(this.genNewName(name !== null && name !== void 0 ? name : this.name + copyAlias));
1118
+ config._orderedBy = orderedBy !== null && orderedBy !== void 0 ? orderedBy : this.orderedBy;
1119
+ config._separator = separator !== null && separator !== void 0 ? separator : this.separator;
1120
+ config._title = title !== null && title !== void 0 ? title : this.title;
1121
+ config._ending = ending !== null && ending !== void 0 ? ending : this.ending;
1122
+ config._bypass = bypass !== null && bypass !== void 0 ? bypass : this.bypass;
1123
+ config._surname = surname !== null && surname !== void 0 ? surname : this.surname;
1124
+ return config;
1125
+ }
1126
+ /**
1127
+ * Makes an exact copy of the current configuration.
1128
+ */
1129
+ clone() {
1130
+ return this.copyWith();
1131
+ }
1132
+ /**
1133
+ * Resets the configuration by setting it back to its default values.
1134
+ */
1135
+ reset() {
1136
+ this._orderedBy = types_1.NameOrder.FIRST_NAME;
1137
+ this._separator = types_1.Separator.SPACE;
1138
+ this._title = types_1.Title.UK;
1139
+ this._ending = false;
1140
+ this._bypass = true;
1141
+ this._surname = types_1.Surname.FATHER;
1142
+ Config.cache.set(this.name, this);
1143
+ }
1144
+ /**
1145
+ * Alters the name order between the first and last name, and rearrange the
1146
+ * order of appearance of a name set.
1147
+ */
1148
+ updateOrder(order) {
1149
+ if (order && order !== this._orderedBy) {
1150
+ Config.cache.get(this.name)._orderedBy = order;
1151
+ }
1152
+ }
1153
+ /**
1154
+ * Generates a unique new name.
1155
+ */
1156
+ genNewName(name) {
1157
+ return name === this.name || Config.cache.has(name) ? this.genNewName(name + copyAlias) : name;
1346
1158
  }
1347
1159
  }
1348
- exports.Lastname = Lastname;
1160
+ exports.Config = Config;
1161
+ /**
1162
+ * Cache for multiple instances.
1163
+ */
1164
+ Config.cache = new Map();
1349
1165
 
1350
1166
 
1351
1167
  /***/ }),
1352
- /* 11 */
1168
+ /* 5 */
1353
1169
  /***/ (function(module, exports, __webpack_require__) {
1354
1170
 
1355
1171
  "use strict";
1356
1172
 
1357
- /**
1358
- * All the enums are listed here
1359
- *
1360
- * Created on March 06, 2020
1361
- * @author Ralph Florent <ralflornt@gmail.com>
1362
- */
1363
1173
  Object.defineProperty(exports, "__esModule", { value: true });
1364
- /**
1365
- * Enum `Namon` contains the finite set of a representative piece of a name
1366
- * @readonly
1367
- * @enum {string}
1368
- * The word `Namon` is the singular form used to refer to a chunk|part|piece of
1369
- * a name. And the plural form is `Nama`. (Same idea as in criterion/criteria)
1370
- */
1371
- var Namon;
1372
- (function (Namon) {
1373
- Namon["PREFIX"] = "prefix";
1374
- Namon["LAST_NAME"] = "lastname";
1375
- Namon["MIDDLE_NAME"] = "middlename";
1376
- Namon["FIRST_NAME"] = "firstname";
1377
- Namon["SUFFIX"] = "suffix";
1378
- })(Namon = exports.Namon || (exports.Namon = {}));
1379
- /**
1380
- * Enum for the prefix values
1381
- * @readonly
1382
- * @enum {string}
1383
- * American and Canadian English follow slightly different rules for abbreviated
1384
- * titles than British and Australian English. In North American English, titles
1385
- * before a name require a period: `Mr., Mrs., Ms., Dr.` In British and Australian
1386
- * English, no full stops are used in these abbreviations.
1387
- */
1388
- var Prefix;
1389
- (function (Prefix) {
1390
- Prefix["FIRT_LIEUTENANT"] = "1st Lt";
1391
- Prefix["ADMIRAL"] = "Adm";
1392
- Prefix["ATTORNEY"] = "Atty";
1393
- Prefix["BROTHER"] = "Brother";
1394
- Prefix["CAPTAIN"] = "Capt";
1395
- Prefix["CHIEF"] = "Chief";
1396
- Prefix["COMMANDER"] = "Cmdr";
1397
- Prefix["COLONEL"] = "Col";
1398
- Prefix["UNI_DEAN"] = "Dean";
1399
- Prefix["DOCTOR"] = "Dr";
1400
- Prefix["ELDER"] = "Elder";
1401
- Prefix["FATHER"] = "Father";
1402
- Prefix["GENERAL"] = "Gen";
1403
- Prefix["HONORABLE"] = "Hon";
1404
- Prefix["LIEUTENANT_COLONEL"] = "Lt Col";
1405
- Prefix["MAJOR"] = "Maj";
1406
- Prefix["MASTER_SERGEANT"] = "MSgt";
1407
- Prefix["MISTER"] = "Mr";
1408
- Prefix["MARRIED_WOMAN"] = "Mrs";
1409
- Prefix["SINGLE_WOMAN"] = "Ms";
1410
- Prefix["PRINCE"] = "Prince";
1411
- Prefix["PROFESSOR"] = "Prof";
1412
- Prefix["RABBI"] = "Rabbi";
1413
- Prefix["REVEREND"] = "Rev";
1414
- Prefix["SISTER"] = "Sister";
1415
- })(Prefix = exports.Prefix || (exports.Prefix = {}));
1416
- /**
1417
- * Enum for the suffix values
1418
- * @readonly
1419
- * @enum {string}
1420
- */
1421
- var Suffix;
1422
- (function (Suffix) {
1423
- Suffix["THE_SECOND"] = "II";
1424
- Suffix["THE_THIRD"] = "III";
1425
- Suffix["THE_FOURTH"] = "IV";
1426
- Suffix["CERT_PUB_ACCOUNTANT"] = "CPA";
1427
- Suffix["DOCTOR_DENTAL_MED"] = "DDS";
1428
- Suffix["ESQUIRE"] = "Esq";
1429
- Suffix["JURIST_DOCTOR"] = "JD";
1430
- Suffix["JUNIOR"] = "Jr";
1431
- Suffix["DOCTOR_OF_LAWS"] = "LLD";
1432
- Suffix["DOCTORATE"] = "PhD";
1433
- Suffix["RETIRED_ARMED_FORCES"] = "Ret";
1434
- Suffix["REGISTERED_NURSE"] = "RN";
1435
- Suffix["SENIOR"] = "Sr";
1436
- Suffix["DOCTOR_OF_OSTEO"] = "DO";
1437
- })(Suffix = exports.Suffix || (exports.Suffix = {}));
1438
- /**
1439
- * Enum for the separator values representing some of the ASCII characters
1440
- * @readonly
1441
- * @enum {string}
1442
- */
1443
- var Separator;
1444
- (function (Separator) {
1445
- Separator["COLON"] = ":";
1446
- Separator["COMMA"] = ",";
1447
- Separator["EMPTY"] = "";
1448
- Separator["HYPHEN"] = "-";
1449
- Separator["PERIOD"] = ".";
1450
- Separator["SPACE"] = " ";
1451
- Separator["UNDERSCORE"] = "_";
1452
- })(Separator = exports.Separator || (exports.Separator = {}));
1174
+ exports.ALLOWED_TOKENS = exports.MAX_NUMBER_OF_NAME_PARTS = exports.MIN_NUMBER_OF_NAME_PARTS = exports.version = void 0;
1175
+ exports.version = '1.2.0';
1176
+ exports.MIN_NUMBER_OF_NAME_PARTS = 2;
1177
+ exports.MAX_NUMBER_OF_NAME_PARTS = 5;
1178
+ exports.ALLOWED_TOKENS = [
1179
+ '.',
1180
+ ',',
1181
+ ' ',
1182
+ '-',
1183
+ '_',
1184
+ 'b',
1185
+ 'B',
1186
+ 'f',
1187
+ 'F',
1188
+ 'l',
1189
+ 'L',
1190
+ 'm',
1191
+ 'M',
1192
+ 'n',
1193
+ 'N',
1194
+ 'o',
1195
+ 'O',
1196
+ 'p',
1197
+ 'P',
1198
+ 's',
1199
+ 'S',
1200
+ '$',
1201
+ ];
1453
1202
 
1454
1203
 
1455
1204
  /***/ }),
1456
- /* 12 */
1205
+ /* 6 */
1457
1206
  /***/ (function(module, exports, __webpack_require__) {
1458
1207
 
1459
1208
  "use strict";
1460
1209
 
1461
1210
  Object.defineProperty(exports, "__esModule", { value: true });
1462
- /**
1463
- * Summary of descriptive stats of the name
1211
+ exports.FullName = void 0;
1212
+ const config_1 = __webpack_require__(4);
1213
+ const error_1 = __webpack_require__(1);
1214
+ const name_1 = __webpack_require__(3);
1215
+ const types_1 = __webpack_require__(0);
1216
+ const validator_1 = __webpack_require__(7);
1217
+ /**
1218
+ * The core component of this utility.
1464
1219
  *
1465
- * Created on March 06, 2020
1466
- * @author Ralph Florent <ralflornt@gmail.com>
1467
- */
1468
- const index_1 = __webpack_require__(1);
1469
- /**
1470
- * Represents the statistical summary of a string representation
1471
- * @class
1220
+ * This component is comprised of five entities that make it easy to handle a
1221
+ * full name set: prefix, first name, middle name, last name, and suffix.
1222
+ * This class is intended for internal processes. However, it is understandable
1223
+ * that it might be needed at some point for additional purposes. For this reason,
1224
+ * it's made available.
1225
+ *
1226
+ * It is recommended to avoid using this class unless it is highly necessary or
1227
+ * a custom parser is used for uncommon use cases. This utility tries to cover
1228
+ * as many use cases as possible.
1229
+ *
1230
+ * Additionally, an optional configuration can be used to indicate some specific
1231
+ * behaviors related to that name handling.
1472
1232
  */
1473
- class Summary {
1233
+ class FullName {
1474
1234
  /**
1475
- * Creates a `Summary` of a given string of alphabetical characters
1476
- * @param namon piece of name
1477
- * @param restrictions a set of undesired characters
1235
+ * Creates a full name as it goes
1236
+ * @param options optional configuration for additional features.
1478
1237
  */
1479
- constructor(namon, restrictions = [index_1.Separator.SPACE]) {
1480
- this.namon = namon;
1481
- this.compute(restrictions);
1238
+ constructor(options) {
1239
+ this._middleName = [];
1240
+ this._config = config_1.Config.merge(options);
1482
1241
  }
1483
1242
  /**
1484
- * Returns a string representation of the summary
1243
+ * A snapshot of the configuration used to set up this full name.
1485
1244
  */
1486
- tostring() {
1487
- return index_1.Separator.EMPTY.concat(`Descriptive statistics for "${this.namon}" \n`, `count : ${this.count} \n`, `frequency: ${this.frequency} \n`, `top : ${this.top} \n`, `unique : ${this.unique} \n`);
1245
+ get config() {
1246
+ return this._config;
1488
1247
  }
1489
- compute(restrictions = []) {
1490
- // compute stats for the string
1491
- let count = 0, maxfreq = 0, uniq = 0, top = '';
1492
- const freqs = this.groupByChar();
1493
- for (const char in freqs) {
1494
- if (restrictions.indexOf(char) === -1) {
1495
- count += freqs[char];
1496
- if (freqs[char] >= maxfreq) {
1497
- maxfreq = freqs[char];
1498
- top = char;
1499
- }
1500
- uniq++;
1248
+ /**
1249
+ * The prefix part of the full name.
1250
+ */
1251
+ get prefix() {
1252
+ return this._prefix;
1253
+ }
1254
+ /**
1255
+ * The first name part of the full name.
1256
+ */
1257
+ get firstName() {
1258
+ return this._firstName;
1259
+ }
1260
+ /**
1261
+ * The last name part of the full name.
1262
+ */
1263
+ get lastName() {
1264
+ return this._lastName;
1265
+ }
1266
+ /**
1267
+ * The middle name part of the full name.
1268
+ */
1269
+ get middleName() {
1270
+ return this._middleName;
1271
+ }
1272
+ /**
1273
+ * The suffix part of the full name.
1274
+ */
1275
+ get suffix() {
1276
+ return this._suffix;
1277
+ }
1278
+ /**
1279
+ * Parses a json name into a full name.
1280
+ * @param json parsable name element
1281
+ * @param config optional configuration for additional features.
1282
+ */
1283
+ static parse(json, config) {
1284
+ try {
1285
+ const fullName = new FullName(config);
1286
+ fullName.setPrefix(json.prefix);
1287
+ fullName.setFirstName(json.firstName);
1288
+ fullName.setMiddleName(json.middleName);
1289
+ fullName.setLastName(json.lastName);
1290
+ fullName.setSuffix(json.suffix);
1291
+ return fullName;
1292
+ }
1293
+ catch (error) {
1294
+ if (error instanceof error_1.NameError) {
1295
+ throw error;
1296
+ }
1297
+ else {
1298
+ throw new error_1.UnknownError({
1299
+ source: Object.values(json).join(' '),
1300
+ message: 'could not parse JSON content',
1301
+ error,
1302
+ });
1501
1303
  }
1502
1304
  }
1503
- this.count = count;
1504
- this.frequency = maxfreq;
1505
- this.top = top;
1506
- this.unique = uniq;
1507
1305
  }
1508
- groupByChar() {
1509
- const frequencies = {};
1510
- for (const char of this.namon.toUpperCase())
1511
- if (Object.keys(frequencies).includes(char))
1512
- frequencies[char] += 1;
1513
- else
1514
- frequencies[char] = 1;
1515
- return frequencies;
1306
+ setPrefix(name) {
1307
+ if (!name)
1308
+ return this;
1309
+ if (!this._config.bypass)
1310
+ validator_1.Validators.prefix.validate(name);
1311
+ const prefix = name instanceof name_1.Name ? name.value : name;
1312
+ this._prefix = name_1.Name.prefix(this._config.title === types_1.Title.US ? `${prefix}.` : prefix);
1313
+ return this;
1314
+ }
1315
+ setFirstName(name) {
1316
+ if (!this._config.bypass)
1317
+ validator_1.Validators.firstName.validate(name);
1318
+ this._firstName = name instanceof name_1.FirstName ? name : new name_1.FirstName(name);
1319
+ return this;
1320
+ }
1321
+ setLastName(name) {
1322
+ if (!this._config.bypass)
1323
+ validator_1.Validators.lastName.validate(name);
1324
+ this._lastName = name instanceof name_1.LastName ? name : new name_1.LastName(name);
1325
+ return this;
1326
+ }
1327
+ setMiddleName(names) {
1328
+ if (!Array.isArray(names))
1329
+ return;
1330
+ if (!this._config.bypass)
1331
+ validator_1.Validators.middleName.validate(names);
1332
+ this._middleName = names.map((name) => name instanceof name_1.Name ? name : name_1.Name.middle(name));
1333
+ return this;
1334
+ }
1335
+ setSuffix(name) {
1336
+ if (!name)
1337
+ return this;
1338
+ if (!this._config.bypass)
1339
+ validator_1.Validators.suffix.validate(name);
1340
+ this._suffix = name_1.Name.suffix(name instanceof name_1.Name ? name.value : name);
1341
+ return this;
1342
+ }
1343
+ /**
1344
+ * Returns true if a namon has been set.
1345
+ */
1346
+ has(namon) {
1347
+ if (namon.equal(types_1.Namon.PREFIX))
1348
+ return !!this._prefix;
1349
+ if (namon.equal(types_1.Namon.SUFFIX))
1350
+ return !!this._suffix;
1351
+ return namon.equal(types_1.Namon.MIDDLE_NAME) ? this._middleName.length > 0 : true;
1516
1352
  }
1517
1353
  }
1518
- exports.Summary = Summary;
1354
+ exports.FullName = FullName;
1519
1355
 
1520
1356
 
1521
1357
  /***/ }),
1522
- /* 13 */
1358
+ /* 7 */
1523
1359
  /***/ (function(module, exports, __webpack_require__) {
1524
1360
 
1525
1361
  "use strict";
1526
1362
 
1527
- /**
1528
- * Validation rules
1529
- *
1530
- * Created on March 06, 2020
1531
- * @author Ralph Florent <ralflornt@gmail.com>
1532
- */
1533
1363
  Object.defineProperty(exports, "__esModule", { value: true });
1364
+ exports.Validators = exports.ArrayNameValidator = exports.ArrayStringValidator = exports.NamaValidator = void 0;
1365
+ const constants_1 = __webpack_require__(5);
1366
+ const error_1 = __webpack_require__(1);
1367
+ const name_1 = __webpack_require__(3);
1368
+ const types_1 = __webpack_require__(0);
1369
+ const utils_1 = __webpack_require__(2);
1534
1370
  /**
1535
1371
  * Represents a set of validation rules (regex)
1536
- * @class
1537
- * @static
1538
1372
  *
1539
1373
  * This regex is intented to match specific alphabets only as a person name does
1540
1374
  * not contain special characters. `\w` does not cover non-Latin characters. So,
@@ -1546,30 +1380,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
1546
1380
  * [\u00D8-\u00f6]: German/Icelandic chars from Ø (index 216) to ö (index 246)
1547
1381
  * [\u00f8-\u00ff]: German/Icelandic chars from ø (index 248) to ÿ (index 255)
1548
1382
  * [\u0400-\u04FF]: Cyrillic alphabet from Ѐ (index 1024) to ӿ (index 1279)
1549
- * [\u04FFΆ-ωΑ-ώ]: Greek alphabet from Ά (index 902) to ω (index 969)
1383
+ * [Ά-ωΑ-ώ]: Greek alphabet from Ά (index 902) to ω (index 969)
1550
1384
  */
1551
1385
  class ValidationRule {
1552
1386
  }
1553
- exports.ValidationRule = ValidationRule;
1387
+ ValidationRule.base = /[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ]/;
1554
1388
  /**
1555
1389
  * Matches one name part (namon) that is of nature:
1556
1390
  * - Latin (English, Spanish, French, etc.)
1557
1391
  * - European (Greek, Cyrillic, Icelandic, German)
1558
1392
  * - hyphenated
1559
1393
  * - with apostrophe
1560
- */
1561
- ValidationRule.namon = /^[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ]+((['-][a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ])?[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ]*)*$/;
1562
- /**
1563
- * Matches 1+ name parts (namon) that are of nature:
1564
- * - Latin (English, Spanish, French, etc.)
1565
- * - European (Greek, Cyrillic, Icelandic, German)
1566
- * - hyphenated
1567
- * - with apostrophe
1568
- * - with comma
1569
- * - with period
1570
1394
  * - with space
1571
1395
  */
1572
- ValidationRule.fullname = /^[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ]+(([',. -][a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ ])?[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ]*)*$/;
1396
+ ValidationRule.namon = new RegExp(`^${ValidationRule.base.source}+(([' -]${ValidationRule.base.source})?${ValidationRule.base.source}*)*$`);
1573
1397
  /**
1574
1398
  * Matches one name part (namon) that is of nature:
1575
1399
  * - Latin (English, Spanish, French, etc.)
@@ -1577,7 +1401,7 @@ ValidationRule.fullname = /^[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400
1577
1401
  * - hyphenated
1578
1402
  * - with apostrophe
1579
1403
  */
1580
- ValidationRule.firstname = /^[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ]+((['-][a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ])?[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ]*)*$/;
1404
+ ValidationRule.firstName = ValidationRule.namon;
1581
1405
  /**
1582
1406
  * Matches 1+ names part (namon) that are of nature:
1583
1407
  * - Latin (English, Spanish, French, etc.)
@@ -1586,979 +1410,1235 @@ ValidationRule.firstname = /^[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u040
1586
1410
  * - with apostrophe
1587
1411
  * - with space
1588
1412
  */
1589
- ValidationRule.middlename = /^[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ]+(([' -][a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ])?[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ]*)*$/;
1413
+ ValidationRule.middleName = new RegExp(`^${ValidationRule.base.source}+(([' -]${ValidationRule.base.source})?${ValidationRule.base.source}*)*$`);
1590
1414
  /**
1591
1415
  * Matches one name part (namon) that is of nature:
1592
1416
  * - Latin (English, Spanish, French, etc.)
1593
1417
  * - European (Greek, Cyrillic, Icelandic, German)
1594
1418
  * - hyphenated
1595
1419
  * - with apostrophe
1420
+ * - with space
1596
1421
  */
1597
- ValidationRule.lastname = /^[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ]+((['-][a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ])?[a-zA-Z\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff\u0400-\u04FFΆ-ωΑ-ώ]*)*$/;
1598
-
1599
-
1600
- /***/ }),
1601
- /* 14 */
1602
- /***/ (function(module, exports, __webpack_require__) {
1603
-
1604
- "use strict";
1605
-
1606
- /**
1607
- * Validation types
1608
- *
1609
- * Created on March 06, 2020
1610
- * @author Ralph Florent <ralflornt@gmail.com>
1611
- */
1612
- Object.defineProperty(exports, "__esModule", { value: true });
1613
- /**
1614
- * Enum for the validation types
1615
- * @enum
1616
- */
1617
- var ValidatorType;
1618
- (function (ValidatorType) {
1619
- ValidatorType[ValidatorType["NONE"] = 0] = "NONE";
1620
- ValidatorType[ValidatorType["NAMON"] = 1] = "NAMON";
1621
- ValidatorType[ValidatorType["NAMA"] = 2] = "NAMA";
1622
- ValidatorType[ValidatorType["ARR_NAMES"] = 3] = "ARR_NAMES";
1623
- ValidatorType[ValidatorType["ARR_STRING"] = 4] = "ARR_STRING";
1624
- ValidatorType[ValidatorType["FULL_NAME"] = 5] = "FULL_NAME";
1625
- ValidatorType[ValidatorType["PREFIX"] = 6] = "PREFIX";
1626
- ValidatorType[ValidatorType["FIRST_NAME"] = 7] = "FIRST_NAME";
1627
- ValidatorType[ValidatorType["MIDDLE_NAME"] = 8] = "MIDDLE_NAME";
1628
- ValidatorType[ValidatorType["LAST_NAME"] = 9] = "LAST_NAME";
1629
- ValidatorType[ValidatorType["SUFFIX"] = 10] = "SUFFIX";
1630
- ValidatorType[ValidatorType["CUSTOM"] = 11] = "CUSTOM";
1631
- })(ValidatorType = exports.ValidatorType || (exports.ValidatorType = {}));
1632
-
1633
-
1634
- /***/ }),
1635
- /* 15 */
1636
- /***/ (function(module, exports, __webpack_require__) {
1637
-
1638
- "use strict";
1639
-
1640
- /**
1641
- * Validation error
1642
- *
1643
- * Created on March 06, 2020
1644
- * @author Ralph Florent <ralflornt@gmail.com>
1645
- */
1646
- Object.defineProperty(exports, "__esModule", { value: true });
1647
- /**
1648
- * Represents a validation error
1649
- * @class
1650
- * @extends Error
1651
- */
1652
- class ValidationError extends Error {
1653
- /**
1654
- * Create a validation `Error`
1655
- * @param message of error to display
1656
- * @param type categorizes the error
1657
- */
1658
- constructor(message, type) {
1659
- super(`${type ? type + ' :: ' + message : message}`);
1660
- this.name = 'ValidationError';
1422
+ ValidationRule.lastName = ValidationRule.namon;
1423
+ class ArrayValidator {
1424
+ validate(values) {
1425
+ if (values.length === 0 ||
1426
+ values.length < constants_1.MIN_NUMBER_OF_NAME_PARTS ||
1427
+ values.length > constants_1.MAX_NUMBER_OF_NAME_PARTS) {
1428
+ throw new error_1.InputError({
1429
+ source: values.map((n) => n.toString()),
1430
+ message: `expecting a list of ${constants_1.MIN_NUMBER_OF_NAME_PARTS}-${constants_1.MIN_NUMBER_OF_NAME_PARTS} elements`,
1431
+ });
1432
+ }
1661
1433
  }
1662
1434
  }
1663
- exports.ValidationError = ValidationError;
1664
-
1665
-
1666
- /***/ }),
1667
- /* 16 */
1668
- /***/ (function(module, exports, __webpack_require__) {
1669
-
1670
- "use strict";
1671
-
1672
- Object.defineProperty(exports, "__esModule", { value: true });
1673
- /**
1674
- * Namon validator
1675
- *
1676
- * Created on March 15, 2020
1677
- * @author Ralph Florent <ralflornt@gmail.com>
1678
- */
1679
- const index_1 = __webpack_require__(0);
1680
- /**
1681
- * Represents a namon validator to help to parse single pieces of string
1682
- * @class
1683
- * @implements {Validator}
1684
- */
1685
1435
  class NamonValidator {
1686
- constructor() {
1687
- this.type = index_1.ValidatorType.NAMON;
1436
+ constructor() { }
1437
+ static create() {
1438
+ return this.validator || (this.validator = new this());
1688
1439
  }
1689
- /**
1690
- * Validates the content of a name
1691
- * @param {string} value data to validate
1692
- */
1693
- validate(value) {
1694
- if (!index_1.ValidationRule.namon.test(value))
1695
- throw new index_1.ValidationError(`invalid string content '${value}'`, 'Name');
1696
- }
1697
- }
1698
- exports.default = NamonValidator;
1699
-
1700
-
1701
- /***/ }),
1702
- /* 17 */
1703
- /***/ (function(module, exports, __webpack_require__) {
1704
-
1705
- "use strict";
1706
-
1707
- Object.defineProperty(exports, "__esModule", { value: true });
1708
- /**
1709
- * Prefix validator
1710
- *
1711
- * Created on March 15, 2020
1712
- * @author Ralph Florent <ralflornt@gmail.com>
1713
- */
1714
- const index_1 = __webpack_require__(1);
1715
- const index_2 = __webpack_require__(0);
1716
- /**
1717
- * Represents a prefix validator
1718
- * @class
1719
- * @implements {Validator}
1720
- */
1721
- class PrefixValidator {
1722
- constructor() {
1723
- this.type = index_2.ValidatorType.PREFIX;
1724
- }
1725
- /**
1726
- * Validates the content of a prefix name
1727
- * @param {string} value data to validate
1728
- */
1729
- validate(value) {
1730
- const prefixes = Object.entries(index_1.Prefix).map(e => e[1].toLowerCase()); // values
1731
- if (prefixes.indexOf(value.toLowerCase()) === -1)
1732
- throw new index_2.ValidationError(`unknown value '${value}'`, 'Prefix');
1440
+ validate(value, type) {
1441
+ if (value instanceof name_1.Name) {
1442
+ NameValidator.create().validate(value, type);
1443
+ }
1444
+ else if (typeof value === 'string') {
1445
+ if (!ValidationRule.namon.test(value)) {
1446
+ throw new error_1.ValidationError({
1447
+ source: value,
1448
+ nameType: 'namon',
1449
+ message: 'invalid content',
1450
+ });
1451
+ }
1452
+ }
1453
+ else {
1454
+ throw new error_1.InputError({
1455
+ source: typeof value,
1456
+ message: 'expecting types of string | Name',
1457
+ });
1458
+ }
1733
1459
  }
1734
1460
  }
1735
- exports.default = PrefixValidator;
1736
-
1737
-
1738
- /***/ }),
1739
- /* 18 */
1740
- /***/ (function(module, exports, __webpack_require__) {
1741
-
1742
- "use strict";
1743
-
1744
- Object.defineProperty(exports, "__esModule", { value: true });
1745
- /**
1746
- * Suffix validator
1747
- *
1748
- * Created on March 15, 2020
1749
- * @author Ralph Florent <ralflornt@gmail.com>
1750
- */
1751
- const index_1 = __webpack_require__(1);
1752
- const index_2 = __webpack_require__(0);
1753
- /**
1754
- * Represents a suffix validator
1755
- * @class
1756
- * @implements {Validator}
1757
- */
1758
- class SuffixValidator {
1759
- constructor() {
1760
- this.type = index_2.ValidatorType.SUFFIX;
1461
+ class FirstNameValidator {
1462
+ constructor() { }
1463
+ static create() {
1464
+ return this.validator || (this.validator = new this());
1761
1465
  }
1762
- /**
1763
- * Validates the content of a suffix name
1764
- * @param {string} value data to validate
1765
- */
1766
1466
  validate(value) {
1767
- const suffixes = Object.entries(index_1.Suffix).map(e => e[1].toLowerCase()); // values
1768
- if (suffixes.indexOf(value.toLowerCase()) === -1)
1769
- throw new index_2.ValidationError(`unknown value '${value}'`, 'Suffix');
1467
+ if (value instanceof name_1.FirstName) {
1468
+ value.asNames.forEach((name) => this.validate(name.value));
1469
+ }
1470
+ else if (typeof value === 'string') {
1471
+ if (!ValidationRule.firstName.test(value)) {
1472
+ throw new error_1.ValidationError({
1473
+ source: value,
1474
+ nameType: 'firstName',
1475
+ message: 'invalid content',
1476
+ });
1477
+ }
1478
+ }
1479
+ else {
1480
+ throw new error_1.InputError({
1481
+ source: typeof value,
1482
+ message: 'expecting types string | FirstName',
1483
+ });
1484
+ }
1770
1485
  }
1771
1486
  }
1772
- exports.default = SuffixValidator;
1773
-
1774
-
1775
- /***/ }),
1776
- /* 19 */
1777
- /***/ (function(module, exports, __webpack_require__) {
1778
-
1779
- "use strict";
1780
-
1781
- Object.defineProperty(exports, "__esModule", { value: true });
1782
- /**
1783
- * First name validator
1784
- *
1785
- * Created on March 15, 2020
1786
- * @author Ralph Florent <ralflornt@gmail.com>
1787
- */
1788
- const index_1 = __webpack_require__(0);
1789
- /**
1790
- * Represents a first name validator
1791
- * @class
1792
- * @implements {Validator}
1793
- */
1794
- class FirstnameValidator {
1795
- constructor() {
1796
- this.type = index_1.ValidatorType.FIRST_NAME;
1487
+ class MiddleNameValidator {
1488
+ constructor() { }
1489
+ static create() {
1490
+ return this.validator || (this.validator = new this());
1797
1491
  }
1798
- /**
1799
- * Validates the content of a first name
1800
- * @param {string} value data to validate
1801
- */
1802
1492
  validate(value) {
1803
- if (!index_1.ValidationRule.firstname.test(value))
1804
- throw new index_1.ValidationError(`invalid string content '${value}'`, 'First name');
1493
+ if (typeof value === 'string') {
1494
+ if (!ValidationRule.middleName.test(value)) {
1495
+ throw new error_1.ValidationError({
1496
+ source: value,
1497
+ nameType: 'middleName',
1498
+ message: 'invalid content',
1499
+ });
1500
+ }
1501
+ }
1502
+ else if (Array.isArray(value)) {
1503
+ try {
1504
+ const validator = NamonValidator.create();
1505
+ for (const name of value)
1506
+ validator.validate(name, types_1.Namon.MIDDLE_NAME);
1507
+ }
1508
+ catch (error) {
1509
+ throw new error_1.ValidationError({
1510
+ source: value,
1511
+ nameType: 'middleName',
1512
+ message: error === null || error === void 0 ? void 0 : error.message,
1513
+ });
1514
+ }
1515
+ }
1516
+ else {
1517
+ throw new error_1.InputError({
1518
+ source: typeof value,
1519
+ message: 'expecting types of string | string[] | Name[]',
1520
+ });
1521
+ }
1805
1522
  }
1806
1523
  }
1807
- exports.default = FirstnameValidator;
1808
-
1809
-
1810
- /***/ }),
1811
- /* 20 */
1812
- /***/ (function(module, exports, __webpack_require__) {
1813
-
1814
- "use strict";
1815
-
1816
- Object.defineProperty(exports, "__esModule", { value: true });
1817
- /**
1818
- * Last name validator
1819
- *
1820
- * Created on March 15, 2020
1821
- * @author Ralph Florent <ralflornt@gmail.com>
1822
- */
1823
- const index_1 = __webpack_require__(0);
1824
- /**
1825
- * Represents a last name validator
1826
- * @class
1827
- * @implements {Validator}
1828
- */
1829
- class LastnameValidator {
1830
- constructor() {
1831
- this.type = index_1.ValidatorType.LAST_NAME;
1524
+ class LastNameValidator {
1525
+ constructor() { }
1526
+ static create() {
1527
+ return this.validator || (this.validator = new this());
1832
1528
  }
1833
- /**
1834
- * Validates the content of a last name
1835
- * @param {string} value data to validate
1836
- */
1837
1529
  validate(value) {
1838
- if (!index_1.ValidationRule.lastname.test(value))
1839
- throw new index_1.ValidationError(`invalid string content '${value}'`, 'Last name');
1840
- }
1841
- }
1842
- exports.default = LastnameValidator;
1843
-
1844
-
1845
- /***/ }),
1846
- /* 21 */
1847
- /***/ (function(module, exports, __webpack_require__) {
1848
-
1849
- "use strict";
1850
-
1851
- Object.defineProperty(exports, "__esModule", { value: true });
1852
- /**
1853
- * Middle name validator
1854
- *
1855
- * Created on March 15, 2020
1856
- * @author Ralph Florent <ralflornt@gmail.com>
1857
- */
1858
- const index_1 = __webpack_require__(0);
1859
- /**
1860
- * Represents a middle name validator
1861
- * @class
1862
- * @implements {Validator}
1863
- */
1864
- class MiddlenameValidator {
1865
- constructor() {
1866
- this.type = index_1.ValidatorType.MIDDLE_NAME;
1867
- }
1868
- /**
1869
- * Validates the content of a list of middle names
1870
- * @param {string | Array<string>} values to validate
1871
- */
1872
- validate(values) {
1873
- if (typeof values === 'string') {
1874
- if (!index_1.ValidationRule.middlename.test(values))
1875
- throw new index_1.ValidationError(`invalid string content '${values}'`, 'Middle name');
1530
+ if (value instanceof name_1.LastName) {
1531
+ value.asNames.forEach((name) => this.validate(name.value));
1876
1532
  }
1877
- else if (values instanceof Array) {
1878
- const namonValidator = new index_1.NamonValidator();
1879
- values.forEach(v => namonValidator.validate(v));
1533
+ else if (typeof value === 'string') {
1534
+ if (!ValidationRule.lastName.test(value)) {
1535
+ throw new error_1.ValidationError({
1536
+ source: value,
1537
+ nameType: 'lastName',
1538
+ message: 'invalid content',
1539
+ });
1540
+ }
1880
1541
  }
1881
1542
  else {
1882
- throw new Error('Expecting string or Array<string> type');
1543
+ throw new error_1.InputError({
1544
+ source: typeof value,
1545
+ message: 'expecting types string | LastName',
1546
+ });
1883
1547
  }
1884
1548
  }
1885
1549
  }
1886
- exports.default = MiddlenameValidator;
1887
-
1888
-
1889
- /***/ }),
1890
- /* 22 */
1891
- /***/ (function(module, exports, __webpack_require__) {
1892
-
1893
- "use strict";
1894
-
1895
- Object.defineProperty(exports, "__esModule", { value: true });
1896
- /**
1897
- * `Fullname` validator
1898
- *
1899
- * Created on March 15, 2020
1900
- * @author Ralph Florent <ralflornt@gmail.com>
1901
- */
1902
- const index_1 = __webpack_require__(1);
1903
- const index_2 = __webpack_require__(0);
1904
- /**
1905
- * Represents a `Fullname` (JSON signature) validator for provided custom parser
1906
- * @class
1907
- * @implements {Validator}
1908
- */
1909
- class FullnameValidator {
1910
- constructor() {
1911
- this.type = index_2.ValidatorType.FULL_NAME;
1912
- }
1913
- /**
1914
- * Validates that the `Fullname` contract is met
1915
- * @param {Fullname} value data to validate
1916
- */
1917
- validate(v) {
1918
- if (!v.firstname || !(v.firstname instanceof index_1.Firstname))
1919
- throw new index_2.ValidationError('first name is corrupted', 'Fullname');
1920
- if (!v.lastname || !(v.lastname instanceof index_1.Lastname))
1921
- throw new index_2.ValidationError('last name is corrupted', 'Fullname');
1922
- if (v.middlename && !(v.middlename instanceof Array))
1923
- throw new index_2.ValidationError('middle name is corrupted', 'Fullname');
1924
- if (v.prefix)
1925
- new index_2.PrefixValidator().validate(v.prefix);
1926
- if (v.suffix)
1927
- new index_2.SuffixValidator().validate(v.suffix);
1550
+ class NameValidator {
1551
+ constructor() { }
1552
+ static create() {
1553
+ return this.validator || (this.validator = new this());
1554
+ }
1555
+ validate(name, type) {
1556
+ if (type && name.type !== type) {
1557
+ throw new error_1.ValidationError({
1558
+ source: [name],
1559
+ nameType: name.type.toString(),
1560
+ message: 'wrong type',
1561
+ });
1562
+ }
1563
+ if (!ValidationRule.namon.test(name.value)) {
1564
+ throw new error_1.ValidationError({
1565
+ source: [name],
1566
+ nameType: name.type.toString(),
1567
+ message: 'invalid content',
1568
+ });
1569
+ }
1928
1570
  }
1929
1571
  }
1930
- exports.default = FullnameValidator;
1931
-
1932
-
1933
- /***/ }),
1934
- /* 23 */
1935
- /***/ (function(module, exports, __webpack_require__) {
1936
-
1937
- "use strict";
1938
-
1939
- Object.defineProperty(exports, "__esModule", { value: true });
1940
- /**
1941
- * Nama validator
1942
- *
1943
- * Created on March 15, 2020
1944
- * @author Ralph Florent <ralflornt@gmail.com>
1945
- */
1946
- const index_1 = __webpack_require__(1);
1947
- const index_2 = __webpack_require__(0);
1948
- /**
1949
- * Represents a `Nama` validator to help the nama parser
1950
- * @class
1951
- * @implements {Validator}
1952
- */
1953
1572
  class NamaValidator {
1954
- constructor() {
1955
- this.type = index_2.ValidatorType.NAMA;
1573
+ constructor() { }
1574
+ static create() {
1575
+ return this.validator || (this.validator = new this());
1956
1576
  }
1957
- /**
1958
- * Validates the content of a JSON-formatted names
1959
- * @param {string} value data to validate
1960
- */
1961
1577
  validate(value) {
1962
- const entries = Object.entries(value);
1963
- if (entries.length <= 1 && entries.length > 5)
1964
- throw new index_2.ValidationError('incomplete JSON object', 'Nama');
1965
- const validators = {
1966
- [index_1.Namon.PREFIX]: new index_2.PrefixValidator(),
1967
- [index_1.Namon.FIRST_NAME]: new index_2.FirstnameValidator(),
1968
- [index_1.Namon.MIDDLE_NAME]: new index_2.MiddlenameValidator(),
1969
- [index_1.Namon.LAST_NAME]: new index_2.LastnameValidator(),
1970
- [index_1.Namon.SUFFIX]: new index_2.SuffixValidator(),
1971
- };
1972
- for (const entry of entries) {
1973
- const k = entry[0];
1974
- const v = entry[1];
1975
- validators[k].validate(v);
1578
+ this.validateKeys(value);
1579
+ Validators.firstName.validate(value.get(types_1.Namon.FIRST_NAME));
1580
+ Validators.lastName.validate(value.get(types_1.Namon.LAST_NAME));
1581
+ if (value.has(types_1.Namon.PREFIX)) {
1582
+ Validators.namon.validate(value.get(types_1.Namon.PREFIX));
1583
+ }
1584
+ if (value.has(types_1.Namon.SUFFIX)) {
1585
+ Validators.namon.validate(value.get(types_1.Namon.SUFFIX));
1586
+ }
1587
+ }
1588
+ validateKeys(nama) {
1589
+ if (!nama.size) {
1590
+ throw new error_1.InputError({ source: undefined, message: 'Map<k,v> must not be empty' });
1591
+ }
1592
+ else if (nama.size < constants_1.MIN_NUMBER_OF_NAME_PARTS || nama.size > constants_1.MAX_NUMBER_OF_NAME_PARTS) {
1593
+ throw new error_1.InputError({
1594
+ source: [...nama.values()],
1595
+ message: `expecting ${constants_1.MIN_NUMBER_OF_NAME_PARTS}-${constants_1.MIN_NUMBER_OF_NAME_PARTS} fields`,
1596
+ });
1597
+ }
1598
+ if (!nama.has(types_1.Namon.FIRST_NAME)) {
1599
+ throw new error_1.InputError({
1600
+ source: [...nama.values()],
1601
+ message: '"firstName" is a required key',
1602
+ });
1603
+ }
1604
+ if (!nama.has(types_1.Namon.LAST_NAME)) {
1605
+ throw new error_1.InputError({
1606
+ source: [...nama.values()],
1607
+ message: '"lastName" is a required key',
1608
+ });
1976
1609
  }
1977
1610
  }
1978
1611
  }
1979
- exports.default = NamaValidator;
1980
-
1981
-
1982
- /***/ }),
1983
- /* 24 */
1984
- /***/ (function(module, exports, __webpack_require__) {
1985
-
1986
- "use strict";
1987
-
1988
- Object.defineProperty(exports, "__esModule", { value: true });
1989
- /**
1990
- * Array of `Name` validator
1991
- *
1992
- * Created on March 15, 2020
1993
- * @author Ralph Florent <ralflornt@gmail.com>
1994
- */
1995
- const index_1 = __webpack_require__(1);
1996
- const index_2 = __webpack_require__(0);
1997
- /**
1998
- * Represents a validator to help the array `Name` parser
1999
- * @class
2000
- * @classdesc
2001
- * This validator validates a array of `Name` objects following a specific order
2002
- * based on the count of elements. It is expected that the array has to be
2003
- * between two and five elements.
2004
- *
2005
- */
2006
- class ArrayNameValidator {
2007
- constructor() {
2008
- this.type = index_2.ValidatorType.ARR_NAMES;
1612
+ exports.NamaValidator = NamaValidator;
1613
+ class ArrayStringValidator extends ArrayValidator {
1614
+ constructor(index = utils_1.NameIndex.base()) {
1615
+ super();
1616
+ this.index = index;
2009
1617
  }
2010
- /**
2011
- * Validates the content of a set of custom `Name`s
2012
- * @param {Array<Name>} value data to validate
2013
- */
2014
1618
  validate(values) {
2015
- if (values.length <= 1 || values.length > 5) {
2016
- throw new index_2.ValidationError(`must be an array of 2 - 5 'Name's`, 'Array of Names');
2017
- }
2018
- const validators = {
2019
- [index_1.Namon.PREFIX]: new index_2.PrefixValidator(),
2020
- [index_1.Namon.FIRST_NAME]: new index_2.FirstnameValidator(),
2021
- [index_1.Namon.MIDDLE_NAME]: new index_2.MiddlenameValidator(),
2022
- [index_1.Namon.LAST_NAME]: new index_2.LastnameValidator(),
2023
- [index_1.Namon.SUFFIX]: new index_2.SuffixValidator(),
2024
- };
1619
+ this.validateIndex(values);
2025
1620
  switch (values.length) {
2026
- case 2: // first name + last name
2027
- values.forEach(n => {
2028
- if (![index_1.Namon.FIRST_NAME, index_1.Namon.LAST_NAME].includes(n.type))
2029
- throw new index_2.ValidationError('Both first and last names are required');
2030
- if (n.type === index_1.Namon.LAST_NAME && n instanceof index_1.Lastname)
2031
- validators[n.type].validate(n.mother);
2032
- validators[n.type].validate(n.namon);
2033
- });
1621
+ case 2:
1622
+ Validators.firstName.validate(values[this.index.firstName]);
1623
+ Validators.lastName.validate(values[this.index.lastName]);
2034
1624
  break;
2035
- case 3: // first name + middle name + last name
2036
- values.forEach(n => {
2037
- if (![index_1.Namon.FIRST_NAME, index_1.Namon.MIDDLE_NAME, index_1.Namon.LAST_NAME].includes(n.type))
2038
- throw new index_2.ValidationError('First, middle and last names are required');
2039
- if (n.type === index_1.Namon.LAST_NAME && n instanceof index_1.Lastname)
2040
- validators[n.type].validate(n.mother);
2041
- validators[n.type].validate(n.namon);
2042
- });
1625
+ case 3:
1626
+ Validators.firstName.validate(values[this.index.firstName]);
1627
+ Validators.middleName.validate(values[this.index.middleName]);
1628
+ Validators.lastName.validate(values[this.index.lastName]);
2043
1629
  break;
2044
- case 4: // first name + middle name + last name
2045
- values.forEach(n => {
2046
- if (![index_1.Namon.PREFIX, index_1.Namon.FIRST_NAME, index_1.Namon.MIDDLE_NAME,
2047
- index_1.Namon.LAST_NAME].includes(n.type))
2048
- throw new index_2.ValidationError('More fields are required');
2049
- if (n.type === index_1.Namon.LAST_NAME && n instanceof index_1.Lastname)
2050
- validators[n.type].validate(n.mother);
2051
- validators[n.type].validate(n.namon);
2052
- });
1630
+ case 4:
1631
+ Validators.namon.validate(values[this.index.prefix]);
1632
+ Validators.firstName.validate(values[this.index.firstName]);
1633
+ Validators.middleName.validate(values[this.index.middleName]);
1634
+ Validators.lastName.validate(values[this.index.lastName]);
2053
1635
  break;
2054
- case 5: // first name + middle name + last name
2055
- values.forEach(n => {
2056
- if (![index_1.Namon.PREFIX, index_1.Namon.FIRST_NAME, index_1.Namon.MIDDLE_NAME, index_1.Namon.LAST_NAME,
2057
- index_1.Namon.SUFFIX].includes(n.type))
2058
- throw new index_2.ValidationError('More fields are required');
2059
- if (n.type === index_1.Namon.LAST_NAME && n instanceof index_1.Lastname)
2060
- validators[n.type].validate(n.mother);
2061
- validators[n.type].validate(n.namon);
2062
- });
1636
+ case 5:
1637
+ Validators.namon.validate(values[this.index.prefix]);
1638
+ Validators.firstName.validate(values[this.index.firstName]);
1639
+ Validators.middleName.validate(values[this.index.middleName]);
1640
+ Validators.lastName.validate(values[this.index.lastName]);
1641
+ Validators.namon.validate(values[this.index.suffix]);
2063
1642
  break;
2064
1643
  }
2065
1644
  }
1645
+ validateIndex(values) {
1646
+ super.validate(values);
1647
+ }
1648
+ }
1649
+ exports.ArrayStringValidator = ArrayStringValidator;
1650
+ class ArrayNameValidator {
1651
+ constructor() { }
1652
+ static create() {
1653
+ return this.validator || (this.validator = new this());
1654
+ }
1655
+ validate(value) {
1656
+ if (value.length < constants_1.MIN_NUMBER_OF_NAME_PARTS) {
1657
+ throw new error_1.InputError({
1658
+ source: value,
1659
+ message: `expecting at least ${constants_1.MIN_NUMBER_OF_NAME_PARTS} elements`,
1660
+ });
1661
+ }
1662
+ if (!this.hasBasicNames(value)) {
1663
+ throw new error_1.InputError({
1664
+ source: value,
1665
+ message: 'both first and last names are required',
1666
+ });
1667
+ }
1668
+ }
1669
+ hasBasicNames(names) {
1670
+ const accumulator = {};
1671
+ for (const name of names) {
1672
+ if (name.isFirstName || name.isLastName) {
1673
+ accumulator[name.type.key] = name.toString();
1674
+ }
1675
+ }
1676
+ return Object.keys(accumulator).length === constants_1.MIN_NUMBER_OF_NAME_PARTS;
1677
+ }
1678
+ }
1679
+ exports.ArrayNameValidator = ArrayNameValidator;
1680
+ /**
1681
+ * A list of validators for a specific namon.
1682
+ */
1683
+ class Validators {
2066
1684
  }
2067
- exports.default = ArrayNameValidator;
1685
+ exports.Validators = Validators;
1686
+ Validators.namon = NamonValidator.create();
1687
+ Validators.nama = NamaValidator.create();
1688
+ Validators.prefix = NamonValidator.create();
1689
+ Validators.firstName = FirstNameValidator.create();
1690
+ Validators.middleName = MiddleNameValidator.create();
1691
+ Validators.lastName = LastNameValidator.create();
1692
+ Validators.suffix = NamonValidator.create();
2068
1693
 
2069
1694
 
2070
1695
  /***/ }),
2071
- /* 25 */
1696
+ /* 8 */
2072
1697
  /***/ (function(module, exports, __webpack_require__) {
2073
1698
 
2074
1699
  "use strict";
2075
1700
 
2076
1701
  Object.defineProperty(exports, "__esModule", { value: true });
2077
- /**
2078
- * Array of string validator
2079
- *
2080
- * Created on March 15, 2020
2081
- * @author Ralph Florent <ralflornt@gmail.com>
2082
- */
2083
- const index_1 = __webpack_require__(0);
2084
- /**
2085
- * Represents a validator to help the array string parser
2086
- * @class
2087
- * @classdesc
2088
- * This validator validates an array of string name following a specific order
2089
- * based on the count of elements. It is expected that the array has to be between
2090
- * two and five elements. Also, the order of appearance set in the configuration
2091
- * influences how this validation is carried out.
2092
- *
2093
- * Ordered by first name, the validator validates the following:
2094
- * - 2 elements: firstname lastname
2095
- * - 3 elements: firstname middlename lastname
2096
- * - 4 elements: prefix firstname middlename lastname
2097
- * - 5 elements: prefix firstname middlename lastname suffix
2098
- *
2099
- * Ordered by last name, the validator validates the following:
2100
- * - 2 elements: lastname firstname
2101
- * - 3 elements: lastname firstname middlename
2102
- * - 4 elements: prefix lastname firstname middlename
2103
- * - 5 elements: prefix lastname firstname middlename suffix
2104
- */
2105
- class ArrayStringValidator {
1702
+ exports.ArrayNameParser = exports.NamaParser = exports.ArrayStringParser = exports.StringParser = exports.Parser = void 0;
1703
+ const full_name_1 = __webpack_require__(6);
1704
+ const config_1 = __webpack_require__(4);
1705
+ const utils_1 = __webpack_require__(2);
1706
+ const validator_1 = __webpack_require__(7);
1707
+ const name_1 = __webpack_require__(3);
1708
+ const types_1 = __webpack_require__(0);
1709
+ const error_1 = __webpack_require__(1);
1710
+ /**
1711
+ * A parser signature that helps to organize the names accordingly.
1712
+ */
1713
+ class Parser {
2106
1714
  /**
2107
- * Creates an instance of the validator
2108
- * @param indexing how to index the name parts
1715
+ * Constructs a custom parser accordingly.
1716
+ * @param raw data to be parsed
2109
1717
  */
2110
- constructor(indexing) {
2111
- this.indexing = indexing;
2112
- this.type = index_1.ValidatorType.ARR_STRING;
1718
+ constructor(raw) {
1719
+ this.raw = raw;
2113
1720
  }
2114
1721
  /**
2115
- * Validates the content of a name
2116
- * @param {string} value data to validate
1722
+ * Builds a dynamic `Parser` on the fly and throws a `NameError` when unable
1723
+ * to do so. The built parser only knows how to operate birth names.
2117
1724
  */
2118
- validate(values) {
2119
- if (values.length <= 1 || values.length > 5)
2120
- throw new index_1.ValidationError('must be an array of 2 - 5 elements', 'Array of names');
2121
- const pf = new index_1.PrefixValidator();
2122
- const sf = new index_1.SuffixValidator();
2123
- const fn = new index_1.FirstnameValidator();
2124
- const ln = new index_1.LastnameValidator();
2125
- const mn = new index_1.MiddlenameValidator();
2126
- const index = this.indexing;
2127
- switch (values.length) {
1725
+ static build(text) {
1726
+ const parts = text.trim().split(types_1.Separator.SPACE.token);
1727
+ const length = parts.length;
1728
+ if (length === 0 || length === 1) {
1729
+ throw new error_1.InputError({
1730
+ source: text,
1731
+ message: 'cannot build from invalid input',
1732
+ });
1733
+ }
1734
+ else if (length === 2 || length === 3) {
1735
+ return new StringParser(text);
1736
+ }
1737
+ else {
1738
+ const last = parts.pop();
1739
+ const [first, ...middles] = parts;
1740
+ return new ArrayStringParser([first, middles.join(' '), last]);
1741
+ }
1742
+ }
1743
+ /**
1744
+ * Builds asynchronously a dynamic `Parser`.
1745
+ */
1746
+ static buildAsync(text) {
1747
+ try {
1748
+ return Promise.resolve(Parser.build(text));
1749
+ }
1750
+ catch (error) {
1751
+ return Promise.reject(error);
1752
+ }
1753
+ }
1754
+ }
1755
+ exports.Parser = Parser;
1756
+ class StringParser extends Parser {
1757
+ constructor(raw) {
1758
+ super(raw);
1759
+ }
1760
+ parse(options) {
1761
+ const config = config_1.Config.merge(options);
1762
+ const names = this.raw.split(config.separator.token);
1763
+ return new ArrayStringParser(names).parse(options);
1764
+ }
1765
+ }
1766
+ exports.StringParser = StringParser;
1767
+ class ArrayStringParser extends Parser {
1768
+ constructor(raw) {
1769
+ super(raw);
1770
+ }
1771
+ parse(options) {
1772
+ const config = config_1.Config.merge(options);
1773
+ const fullName = new full_name_1.FullName(config);
1774
+ const raw = this.raw.map((n) => n.trim());
1775
+ const index = utils_1.NameIndex.when(config.orderedBy, raw.length);
1776
+ const validator = new validator_1.ArrayStringValidator(index);
1777
+ if (config.bypass) {
1778
+ validator.validateIndex(raw);
1779
+ }
1780
+ else {
1781
+ validator.validate(raw);
1782
+ }
1783
+ switch (raw.length) {
2128
1784
  case 2:
2129
- fn.validate(values[index.firstname]);
2130
- ln.validate(values[index.lastname]);
1785
+ fullName.setFirstName(new name_1.FirstName(raw[index.firstName]));
1786
+ fullName.setLastName(new name_1.LastName(raw[index.lastName]));
2131
1787
  break;
2132
1788
  case 3:
2133
- fn.validate(values[index.firstname]);
2134
- mn.validate(values[index.middlename]);
2135
- ln.validate(values[index.lastname]);
1789
+ fullName.setFirstName(new name_1.FirstName(raw[index.firstName]));
1790
+ fullName.setMiddleName(this.split(raw[index.middleName], config));
1791
+ fullName.setLastName(new name_1.LastName(raw[index.lastName]));
2136
1792
  break;
2137
1793
  case 4:
2138
- pf.validate(values[index.prefix]);
2139
- fn.validate(values[index.firstname]);
2140
- mn.validate(values[index.middlename]);
2141
- ln.validate(values[index.lastname]);
1794
+ fullName.setPrefix(name_1.Name.prefix(raw[index.prefix]));
1795
+ fullName.setFirstName(new name_1.FirstName(raw[index.firstName]));
1796
+ fullName.setMiddleName(this.split(raw[index.middleName], config));
1797
+ fullName.setLastName(new name_1.LastName(raw[index.lastName]));
2142
1798
  break;
2143
1799
  case 5:
2144
- pf.validate(values[index.prefix]);
2145
- fn.validate(values[index.firstname]);
2146
- mn.validate(values[index.middlename]);
2147
- ln.validate(values[index.lastname]);
2148
- sf.validate(values[index.suffix]);
1800
+ fullName.setPrefix(name_1.Name.prefix(raw[index.prefix]));
1801
+ fullName.setFirstName(new name_1.FirstName(raw[index.firstName]));
1802
+ fullName.setMiddleName(this.split(raw[index.middleName], config));
1803
+ fullName.setLastName(new name_1.LastName(raw[index.lastName]));
1804
+ fullName.setSuffix(name_1.Name.suffix(raw[index.suffix]));
2149
1805
  break;
2150
1806
  }
1807
+ return fullName;
1808
+ }
1809
+ split(raw, config) {
1810
+ return raw.split(config.separator.token).map((name) => name_1.Name.middle(name));
1811
+ }
1812
+ }
1813
+ exports.ArrayStringParser = ArrayStringParser;
1814
+ class NamaParser extends Parser {
1815
+ constructor(raw) {
1816
+ super(raw);
1817
+ }
1818
+ parse(options) {
1819
+ const config = config_1.Config.merge(options);
1820
+ if (config.bypass) {
1821
+ validator_1.NamaValidator.create().validateKeys(this.asNama());
1822
+ }
1823
+ else {
1824
+ validator_1.NamaValidator.create().validate(this.asNama());
1825
+ }
1826
+ return full_name_1.FullName.parse(this.raw, config);
1827
+ }
1828
+ asNama() {
1829
+ return new Map(Object.entries(this.raw).map(([key, value]) => {
1830
+ const namon = types_1.Namon.cast(key);
1831
+ if (!namon) {
1832
+ throw new error_1.InputError({
1833
+ source: Object.values(this.raw).join(' '),
1834
+ message: `unsupported key "${key}"`,
1835
+ });
1836
+ }
1837
+ return [namon, value];
1838
+ }));
1839
+ }
1840
+ }
1841
+ exports.NamaParser = NamaParser;
1842
+ class ArrayNameParser extends Parser {
1843
+ constructor(raw) {
1844
+ super(raw);
1845
+ }
1846
+ parse(options) {
1847
+ const config = config_1.Config.merge(options);
1848
+ const fullName = new full_name_1.FullName(config);
1849
+ validator_1.ArrayNameValidator.create().validate(this.raw);
1850
+ for (const name of this.raw) {
1851
+ if (name.isPrefix) {
1852
+ fullName.setPrefix(name);
1853
+ }
1854
+ else if (name.isSuffix) {
1855
+ fullName.setSuffix(name);
1856
+ }
1857
+ else if (name.isFirstName) {
1858
+ fullName.setFirstName(name instanceof name_1.FirstName ? name : new name_1.FirstName(name.value));
1859
+ }
1860
+ else if (name.isMiddleName) {
1861
+ fullName.middleName.push(name);
1862
+ }
1863
+ else if (name.isLastName) {
1864
+ const lastName = new name_1.LastName(name.value, name instanceof name_1.LastName ? name.mother : undefined, config.surname);
1865
+ fullName.setLastName(lastName);
1866
+ }
1867
+ }
1868
+ return fullName;
2151
1869
  }
2152
1870
  }
2153
- exports.default = ArrayStringValidator;
1871
+ exports.ArrayNameParser = ArrayNameParser;
2154
1872
 
2155
1873
 
2156
1874
  /***/ }),
2157
- /* 26 */
1875
+ /* 9 */
2158
1876
  /***/ (function(module, exports, __webpack_require__) {
2159
1877
 
2160
1878
  "use strict";
2161
1879
 
1880
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
1881
+ if (k2 === undefined) k2 = k;
1882
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
1883
+ }) : (function(o, m, k, k2) {
1884
+ if (k2 === undefined) k2 = k;
1885
+ o[k2] = m[k];
1886
+ }));
1887
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
1888
+ for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);
1889
+ };
2162
1890
  Object.defineProperty(exports, "__esModule", { value: true });
2163
1891
  /**
2164
- * String of full name validator
1892
+ * Welcome to namefully!
2165
1893
  *
2166
- * Created on March 15, 2020
2167
- * @author Ralph Florent <ralflornt@gmail.com>
2168
- */
2169
- const index_1 = __webpack_require__(0);
2170
- /**
2171
- * Represents a string full name validator
2172
- * @class
2173
- * @implements {Validator}
1894
+ * `namefully` is a JavaScript utility for handing person names.
1895
+ *
1896
+ * Sources
1897
+ * - repo: https://github.com/ralflorent/namefully
1898
+ * - docs: https://namefully.netlify.app
1899
+ * - npm: https://npmjs.com/package/namefully
1900
+ *
1901
+ * @license MIT
2174
1902
  */
2175
- class StringNameValidator {
2176
- constructor() {
2177
- this.type = index_1.ValidatorType.FULL_NAME;
2178
- }
2179
- /**
2180
- * Validates the content of a name
2181
- * @param {string} value data to validate
2182
- */
2183
- validate(value) {
2184
- if (!index_1.ValidationRule.fullname.test(value))
2185
- throw new index_1.ValidationError(`invalid string content '${value}'`, 'Full name');
2186
- }
2187
- }
2188
- exports.default = StringNameValidator;
1903
+ __exportStar(__webpack_require__(4), exports);
1904
+ __exportStar(__webpack_require__(1), exports);
1905
+ __exportStar(__webpack_require__(6), exports);
1906
+ __exportStar(__webpack_require__(3), exports);
1907
+ __exportStar(__webpack_require__(10), exports);
1908
+ var parser_1 = __webpack_require__(8);
1909
+ Object.defineProperty(exports, "Parser", { enumerable: true, get: function () { return parser_1.Parser; } });
1910
+ __exportStar(__webpack_require__(0), exports);
1911
+ var utils_1 = __webpack_require__(2);
1912
+ Object.defineProperty(exports, "NameIndex", { enumerable: true, get: function () { return utils_1.NameIndex; } });
2189
1913
 
2190
1914
 
2191
1915
  /***/ }),
2192
- /* 27 */
1916
+ /* 10 */
2193
1917
  /***/ (function(module, exports, __webpack_require__) {
2194
1918
 
2195
1919
  "use strict";
2196
1920
 
1921
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
1922
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1923
+ return new (P || (P = Promise))(function (resolve, reject) {
1924
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1925
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1926
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1927
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
1928
+ });
1929
+ };
2197
1930
  Object.defineProperty(exports, "__esModule", { value: true });
2198
- /**
2199
- * An array of string parser
1931
+ exports.Namefully = void 0;
1932
+ const config_1 = __webpack_require__(4);
1933
+ const constants_1 = __webpack_require__(5);
1934
+ const error_1 = __webpack_require__(1);
1935
+ const parser_1 = __webpack_require__(8);
1936
+ const types_1 = __webpack_require__(0);
1937
+ const utils_1 = __webpack_require__(2);
1938
+ /**
1939
+ * A helper for organizing person names in a particular order, way, or shape.
2200
1940
  *
2201
- * Created on March 15, 2020
2202
- * @author Ralph Florent <ralflornt@gmail.com>
2203
- */
2204
- const index_1 = __webpack_require__(1);
2205
- const index_2 = __webpack_require__(0);
2206
- const index_3 = __webpack_require__(3);
2207
- /**
2208
- * Represents an array string parser
2209
- * @class
2210
- * @implements {Parser<string[]>}
2211
- * @classdesc
2212
- * This parser parses an array of string name following a specific order based
2213
- * on the count of elements. It is expected that the array has to be between two
2214
- * and five elements. Also, the order of appearance set in the configuration
2215
- * influences how this parsing is carried out.
1941
+ * Though `namefully` is easy to use, it does not magically guess which part of
1942
+ * the name is what (prefix, suffix, first, last, or middle names). It relies
1943
+ * actually on how the name parts are indicated (i.e., their roles) so that
1944
+ * it can perform internally certain operations and saves us some extra
1945
+ * calculations/processing. In addition, `Namefully` can be created using
1946
+ * distinct raw data shapes. This is intended to give some flexibility to the
1947
+ * developer so that he or she is not bound to a particular data format.
1948
+ * By following closely the API reference to know how to harness its usability,
1949
+ * this utility aims to save time in formatting names.
2216
1950
  *
2217
- * Ordered by first name, the parser works as follows:
2218
- * - 2 elements: firstname lastname
2219
- * - 3 elements: firstname middlename lastname
2220
- * - 4 elements: prefix firstname middlename lastname
2221
- * - 5 elements: prefix firstname middlename lastname suffix
1951
+ * `namefully` also works like a trapdoor. Once a raw data is provided and
1952
+ * validated, a developer can only *access* in a vast amount of, yet effective
1953
+ * ways the name info. *No editing* is possible. If the name is mistaken, a new
1954
+ * instance of `Namefully` must be created. In other words, it's immutable.
1955
+ * Remember, this utility's primary objective is to help manipulate a person name.
2222
1956
  *
2223
- * Ordered by last name, the parser works as follows:
2224
- * - 2 elements: lastname firstname
2225
- * - 3 elements: lastname firstname middlename
2226
- * - 4 elements: prefix lastname firstname middlename
2227
- * - 5 elements: prefix lastname firstname middlename suffix
1957
+ * Note that the name standards used for the current version of this library
1958
+ * are as follows:
1959
+ * `[prefix] firstName [middleName] lastName [suffix]`
1960
+ * The opening `[` and closing `]` symbols mean that these parts are optional.
1961
+ * In other words, the most basic and typical case is a name that looks like
1962
+ * this: `John Smith`, where `John` is the first name piece and `Smith`, the last
1963
+ * name piece.
2228
1964
  *
1965
+ * @see https://departments.weber.edu/qsupport&training/Data_Standards/Name.htm
1966
+ * for more info on name standards.
1967
+ *
1968
+ * **IMPORTANT**: Keep in mind that the order of appearance (or name order) matters
1969
+ * and may be altered through configured parameters, which will be seen later.
1970
+ * By default, the order of appearance is as shown above and will be used as a
1971
+ * basis for future examples and use cases.
1972
+ *
1973
+ * Once imported, all that is required to do is to create an instance of
1974
+ * `Namefully` and the rest will follow.
1975
+ *
1976
+ * Some terminologies used across the library are:
1977
+ * - namon: 1 piece of name (e.g., first name)
1978
+ * - nama: 2+ pieces of name (e.g., first name + last name)
1979
+ *
1980
+ * Happy name handling 😊!
2229
1981
  */
2230
- class ArrayStringParser {
1982
+ class Namefully {
2231
1983
  /**
2232
- * Create a parser ready to parse the raw data
2233
- * @param {Array<string>} raw data
1984
+ * Creates a name with distinguishable parts from a raw string content.
1985
+ * @param names element to parse.
1986
+ * @param options additional settings.
1987
+ *
1988
+ * An optional configuration may be provided with specifics on how to treat
1989
+ * a full name during its course. By default, all name parts are validated
1990
+ * against some basic validation rules to avoid common runtime exceptions.
2234
1991
  */
2235
- constructor(raw) {
2236
- this.raw = raw;
1992
+ constructor(names, options) {
1993
+ this.build(this.toParser(names), options);
2237
1994
  }
2238
1995
  /**
2239
- * Parses the raw data into a full name
2240
- * @returns {Fullname}
1996
+ * Constructs a `Namefully` instance from a text.
1997
+ *
1998
+ * It works like `parse` except that this function returns `null` where `parse`
1999
+ * would throw a `NameError`.
2241
2000
  */
2242
- parse(options) {
2243
- // given this setting
2244
- const { orderedBy, bypass } = options;
2245
- // validate first
2246
- const raw = this.raw.map(n => n.trim()); // cleanup
2247
- const index = index_3.organizeNameIndex(orderedBy, raw.length);
2248
- if (!bypass)
2249
- new index_2.ArrayStringValidator(index).validate(raw);
2250
- // then distribute all the elements accordingly
2251
- const fullname = this.distribute(raw, index);
2252
- // finally return high quality of data
2253
- return fullname;
2254
- }
2255
- distribute(raw, index) {
2256
- const fullname = {
2257
- firstname: null,
2258
- lastname: null,
2259
- middlename: [],
2260
- prefix: null,
2261
- suffix: null,
2262
- };
2263
- switch (raw.length) {
2264
- case 2: // first name + last name
2265
- fullname.firstname = new index_1.Firstname(raw[index.firstname]);
2266
- fullname.lastname = new index_1.Lastname(raw[index.lastname]);
2267
- break;
2268
- case 3: // first name + middle name + last name
2269
- fullname.firstname = new index_1.Firstname(raw[index.firstname]);
2270
- fullname.middlename.push(new index_1.Name(raw[index.middlename], index_1.Namon.MIDDLE_NAME));
2271
- fullname.lastname = new index_1.Lastname(raw[index.lastname]);
2272
- break;
2273
- case 4: // prefix + first name + middle name + last name
2274
- fullname.prefix = raw[index.prefix];
2275
- fullname.firstname = new index_1.Firstname(raw[index.firstname]);
2276
- fullname.middlename.push(new index_1.Name(raw[index.middlename], index_1.Namon.MIDDLE_NAME));
2277
- fullname.lastname = new index_1.Lastname(raw[index.lastname]);
2278
- break;
2279
- case 5: // prefix + first name + middle name + last name + suffix
2280
- fullname.prefix = raw[index.prefix];
2281
- fullname.firstname = new index_1.Firstname(raw[index.firstname]);
2282
- fullname.middlename.push(new index_1.Name(raw[index.middlename], index_1.Namon.MIDDLE_NAME));
2283
- fullname.lastname = new index_1.Lastname(raw[index.lastname]);
2284
- fullname.suffix = raw[index.suffix];
2285
- break;
2001
+ static tryParse(text) {
2002
+ try {
2003
+ return new this(parser_1.Parser.build(text));
2004
+ }
2005
+ catch (error) {
2006
+ return undefined;
2286
2007
  }
2287
- return fullname;
2288
2008
  }
2289
- }
2290
- exports.default = ArrayStringParser;
2291
-
2292
-
2293
- /***/ }),
2294
- /* 28 */
2295
- /***/ (function(module, exports, __webpack_require__) {
2296
-
2297
- "use strict";
2298
-
2299
- Object.defineProperty(exports, "__esModule", { value: true });
2300
- /**
2301
- * A `Nama` (JSON signature) parser
2302
- *
2303
- * Created on March 15, 2020
2304
- * @author Ralph Florent <ralflornt@gmail.com>
2305
- */
2306
- const index_1 = __webpack_require__(1);
2307
- const index_2 = __webpack_require__(0);
2308
- /**
2309
- * Represents a `Nama` parser
2310
- * @class
2311
- * @implements {Parser<Nama>}
2312
- * @classdesc
2313
- * This parser parses a JSON signature of the name parts provided as string
2314
- * values. This is to facilitate a developer's life that holds users' info in a
2315
- * JSON format. In other words, the developer only needs to provide similar info
2316
- * and the rest will follow.
2317
- */
2318
- class NamaParser {
2319
2009
  /**
2320
- * Create a parser ready to parse the raw data
2321
- * @param {Nama} raw data as JSON object
2010
+ * Constructs a `Namefully` instance from a text.
2011
+ *
2012
+ * It throws a `NameError` if the text cannot be parsed. Use `tryParse`
2013
+ * instead if a `null` return is preferred over a throwable error.
2014
+ *
2015
+ * This operation is computed asynchronously, which gives more flexibility at
2016
+ * the time of catching the error (and stack trace if any). The acceptable
2017
+ * text format is a string composed of two or more name pieces. For instance,
2018
+ * `John Lennon`, or `John Winston Ono Lennon` are parsable names and follow
2019
+ * the basic name standard rules (i.e., first-middle-last).
2020
+ *
2021
+ * Keep in mind that prefix and suffix are not considered during the parsing
2022
+ * process.
2322
2023
  */
2323
- constructor(raw) {
2324
- this.raw = raw;
2024
+ static parse(text) {
2025
+ return __awaiter(this, void 0, void 0, function* () {
2026
+ return parser_1.Parser.buildAsync(text).then((parser) => new Namefully(parser));
2027
+ });
2325
2028
  }
2326
2029
  /**
2327
- * Parses the raw data into a full name
2328
- * @returns {Fullname}
2030
+ * The current configuration.
2329
2031
  */
2330
- parse(options) {
2331
- // validate first
2332
- if (!options.bypass)
2333
- new index_2.NamaValidator().validate(this.raw);
2334
- // then distribute all the elements accordingly
2335
- const fullname = this.distribute();
2336
- // finally return high quality of data
2337
- return fullname;
2338
- }
2339
- distribute() {
2340
- const fullname = {
2341
- firstname: null,
2342
- lastname: null,
2343
- middlename: [],
2344
- prefix: null,
2345
- suffix: null,
2032
+ get config() {
2033
+ return this._config;
2034
+ }
2035
+ /**
2036
+ * The number of characters of the `birthName`, including spaces.
2037
+ */
2038
+ get length() {
2039
+ return this.birth.length;
2040
+ }
2041
+ /**
2042
+ * The prefix part.
2043
+ */
2044
+ get prefix() {
2045
+ var _a;
2046
+ return (_a = this._fullName.prefix) === null || _a === void 0 ? void 0 : _a.toString();
2047
+ }
2048
+ /**
2049
+ * The firt name.
2050
+ */
2051
+ get first() {
2052
+ return this.firstName();
2053
+ }
2054
+ /**
2055
+ * The first middle name if any.
2056
+ */
2057
+ get middle() {
2058
+ return this.hasMiddle ? this.middleName()[0] : undefined;
2059
+ }
2060
+ /**
2061
+ * Returns true if any middle name has been set.
2062
+ */
2063
+ get hasMiddle() {
2064
+ return this._fullName.has(types_1.Namon.MIDDLE_NAME);
2065
+ }
2066
+ /**
2067
+ * The last name.
2068
+ */
2069
+ get last() {
2070
+ return this.lastName();
2071
+ }
2072
+ /**
2073
+ * The suffix part.
2074
+ */
2075
+ get suffix() {
2076
+ var _a;
2077
+ return (_a = this._fullName.suffix) === null || _a === void 0 ? void 0 : _a.toString();
2078
+ }
2079
+ /**
2080
+ * The birth name.
2081
+ */
2082
+ get birth() {
2083
+ return this.birthName();
2084
+ }
2085
+ /**
2086
+ * The shortest version of a person name.
2087
+ */
2088
+ get short() {
2089
+ return this.shorten();
2090
+ }
2091
+ /**
2092
+ * The longest version of a person name.
2093
+ */
2094
+ get long() {
2095
+ return this.birth;
2096
+ }
2097
+ /**
2098
+ * The entire name set.
2099
+ */
2100
+ get full() {
2101
+ return this.fullName();
2102
+ }
2103
+ /**
2104
+ * The first name combined with the last name's initial.
2105
+ */
2106
+ get public() {
2107
+ return this.format('f $l');
2108
+ }
2109
+ /**
2110
+ * Returns the full name as set.
2111
+ */
2112
+ toString() {
2113
+ return this.full;
2114
+ }
2115
+ /**
2116
+ * Fetches the raw form of a name piece.
2117
+ */
2118
+ get(namon) {
2119
+ if (namon.equal(types_1.Namon.PREFIX))
2120
+ return this._fullName.prefix;
2121
+ if (namon.equal(types_1.Namon.FIRST_NAME))
2122
+ return this._fullName.firstName;
2123
+ if (namon.equal(types_1.Namon.MIDDLE_NAME))
2124
+ return this._fullName.middleName;
2125
+ if (namon.equal(types_1.Namon.LAST_NAME))
2126
+ return this._fullName.lastName;
2127
+ if (namon.equal(types_1.Namon.SUFFIX))
2128
+ return this._fullName.suffix;
2129
+ return undefined;
2130
+ }
2131
+ /**
2132
+ * Whether this name is equal to another one from a raw-string perspective.
2133
+ */
2134
+ equal(other) {
2135
+ return this.toString() === other.toString();
2136
+ }
2137
+ /**
2138
+ * Gets a JSON representation of the full name.
2139
+ */
2140
+ toJson() {
2141
+ return {
2142
+ prefix: this.prefix,
2143
+ firstName: this.first,
2144
+ middleName: this.middleName(),
2145
+ lastName: this.last,
2146
+ suffix: this.suffix,
2346
2147
  };
2347
- for (const entry of Object.entries(this.raw)) {
2348
- const key = entry[0];
2349
- const value = entry[1];
2350
- switch (key) {
2351
- case index_1.Namon.FIRST_NAME:
2352
- fullname.firstname = new index_1.Firstname(value);
2148
+ }
2149
+ /**
2150
+ * Confirms that a name part has been set.
2151
+ */
2152
+ has(namon) {
2153
+ return this._fullName.has(namon);
2154
+ }
2155
+ /**
2156
+ * Gets the full name ordered as configured.
2157
+ *
2158
+ * The name order `orderedBy` forces to order by first or last name by
2159
+ * overriding the preset configuration.
2160
+ *
2161
+ * `Namefully.format` may also be used to alter manually the order of appearance
2162
+ * of full name.
2163
+ *
2164
+ * For example:
2165
+ * ```ts
2166
+ * const name = new Namefully('Jon Stark Snow');
2167
+ * console.log(name.fullName(NameOrder.LAST_NAME)); // "Snow Jon Stark"
2168
+ * console.log(name.format('l f m')); // "Snow Jon Stark"
2169
+ * ```
2170
+ */
2171
+ fullName(orderedBy) {
2172
+ const sep = this._config.ending ? ',' : '';
2173
+ const names = [];
2174
+ orderedBy = orderedBy || this._config.orderedBy;
2175
+ if (this.prefix)
2176
+ names.push(this.prefix);
2177
+ if (orderedBy === types_1.NameOrder.FIRST_NAME) {
2178
+ names.push(this.first, ...this.middleName(), this.last + sep);
2179
+ }
2180
+ else {
2181
+ names.push(this.last, this.first, this.middleName().join(' ') + sep);
2182
+ }
2183
+ if (this.suffix)
2184
+ names.push(this.suffix);
2185
+ return names.join(' ').trim();
2186
+ }
2187
+ /**
2188
+ * Gets the birth name ordered as configured, no `prefix` or `suffix`.
2189
+ *
2190
+ * @param orderedBy forces to order by first or last name by overriding the
2191
+ * preset configuration.
2192
+ */
2193
+ birthName(orderedBy) {
2194
+ orderedBy = orderedBy || this._config.orderedBy;
2195
+ return orderedBy === types_1.NameOrder.FIRST_NAME
2196
+ ? [this.first, ...this.middleName(), this.last].join(' ')
2197
+ : [this.last, this.first, ...this.middleName()].join(' ');
2198
+ }
2199
+ /**
2200
+ * Gets the first name part of the `FullName`.
2201
+ *
2202
+ * @param withMore determines whether to include other pieces of the first
2203
+ * name.
2204
+ */
2205
+ firstName(withMore = true) {
2206
+ return this._fullName.firstName.toString(withMore);
2207
+ }
2208
+ /**
2209
+ * Gets the middle name part of the `FullName`.
2210
+ */
2211
+ middleName() {
2212
+ return this._fullName.middleName.map((n) => n.value);
2213
+ }
2214
+ /**
2215
+ * Gets the last name part of the `FullName`.
2216
+ *
2217
+ * @param format overrides the how-to formatting of a surname output,
2218
+ * considering its sub-parts.
2219
+ */
2220
+ lastName(format) {
2221
+ return this._fullName.lastName.toString(format);
2222
+ }
2223
+ /**
2224
+ * Gets the initials of the `FullName`.
2225
+ *
2226
+ * @param {options.orderedBy} forces to order by first or last name by
2227
+ * overriding the preset configuration.
2228
+ * @param
2229
+ *
2230
+ * For example, given the names:
2231
+ * - `John Smith` => `['J', 'S']`
2232
+ * - `John Ben Smith` => `['J', 'B', 'S']`.
2233
+ */
2234
+ initials(options) {
2235
+ const initials = [];
2236
+ const firstInits = this._fullName.firstName.initials();
2237
+ const midInits = this._fullName.middleName.map((n) => n.initials()[0]);
2238
+ const lastInits = this._fullName.lastName.initials();
2239
+ const mergedOptions = Object.assign({ orderedBy: this._config.orderedBy, only: types_1.NameType.BIRTH_NAME }, options);
2240
+ const { orderedBy, only } = mergedOptions;
2241
+ if (only !== types_1.NameType.BIRTH_NAME) {
2242
+ if (only === types_1.NameType.FIRST_NAME) {
2243
+ initials.push(...firstInits);
2244
+ }
2245
+ else if (only === types_1.NameType.MIDDLE_NAME) {
2246
+ initials.push(...midInits);
2247
+ }
2248
+ else {
2249
+ initials.push(...lastInits);
2250
+ }
2251
+ }
2252
+ else if (orderedBy === types_1.NameOrder.FIRST_NAME) {
2253
+ initials.push(...firstInits, ...midInits, ...lastInits);
2254
+ }
2255
+ else {
2256
+ initials.push(...lastInits, ...firstInits, ...midInits);
2257
+ }
2258
+ return initials;
2259
+ }
2260
+ /**
2261
+ * Shortens a complex full name to a simple typical name, a combination of
2262
+ * first and last name.
2263
+ *
2264
+ * @param orderedBy forces to order by first or last name by overriding the
2265
+ * preset configuration.
2266
+ *
2267
+ * For a given name such as `Mr Keanu Charles Reeves`, shortening this name
2268
+ * is equivalent to making it `Keanu Reeves`.
2269
+ *
2270
+ * As a shortened name, the namon of the first name is favored over the other
2271
+ * names forming part of the entire first names, if any. Meanwhile, for
2272
+ * the last name, the configured `surname` is prioritized.
2273
+ *
2274
+ * For a given `FirstName FatherName MotherName`, shortening this name when
2275
+ * the surname is set as `mother` is equivalent to making it:
2276
+ * `FirstName MotherName`.
2277
+ */
2278
+ shorten(orderedBy) {
2279
+ orderedBy = orderedBy || this._config.orderedBy;
2280
+ return orderedBy === types_1.NameOrder.FIRST_NAME
2281
+ ? [this._fullName.firstName.value, this._fullName.lastName.toString()].join(' ')
2282
+ : [this._fullName.lastName.toString(), this._fullName.firstName.value].join(' ');
2283
+ }
2284
+ /**
2285
+ * Flattens a long name using the name types as variants.
2286
+ *
2287
+ * While @param limit sets a threshold as a limited number of characters
2288
+ * supported to flatten a `FullName`, @param by indicates which variant
2289
+ * to use when doing so. By default, a full name gets flattened by
2290
+ * `Flat.MIDDLE_NAME`.
2291
+ *
2292
+ * The flattening operation is only executed iff there is a valid entry and
2293
+ * it surpasses the limit set. In the examples below, let us assume that the
2294
+ * name goes beyond the limit value.
2295
+ *
2296
+ * Flattening a long name refers to reducing the name to the following forms.
2297
+ * For example, `John Winston Ono Lennon` flattened by:
2298
+ * * Flat.FIRST_NAME: => 'J. Winston Ono Lennon'
2299
+ * * Flat.MIDDLE_NAME: => 'John W. O. Lennon'
2300
+ * * Flat.LAST_NAME: => 'John Winston Ono L.'
2301
+ * * Flat.FIRST_MID: => 'J. W. O. Lennon'
2302
+ * * Flat.MID_LAST: => 'John W. O. L.'
2303
+ * * Flat.ALL: => 'J. W. O. L.'
2304
+ *
2305
+ * With the help of the @param recursive flag, the above operation can happen
2306
+ * recursively in the same order if the name is still too long. For example,
2307
+ * flattening `John Winston Ono Lennon` using the following params:
2308
+ * `flatten({ limit: 18, by: Flat.FIRST_NAME, recursive: true })`
2309
+ * will result in `John W. O. Lennon` and not `J. Winston Ono Lennon`.
2310
+ *
2311
+ * A shorter version of this method is `zip()`.
2312
+ */
2313
+ flatten(options) {
2314
+ if (this.length <= options.limit)
2315
+ return this.full;
2316
+ const mergedOptions = Object.assign({ limit: 20, by: types_1.Flat.MIDDLE_NAME, withPeriod: true, recursive: false, withMore: false }, options);
2317
+ const { by, limit, recursive, withMore, withPeriod, surname } = mergedOptions;
2318
+ const sep = withPeriod ? '.' : '';
2319
+ const fn = this._fullName.firstName.toString();
2320
+ const mn = this.middleName().join(' ');
2321
+ const ln = this._fullName.lastName.toString();
2322
+ const hasMid = this.hasMiddle;
2323
+ const f = this._fullName.firstName.initials(withMore).join(sep + ' ') + sep;
2324
+ const l = this._fullName.lastName.initials(surname).join(sep + ' ') + sep;
2325
+ const m = hasMid ? this._fullName.middleName.map((n) => n.initials()[0]).join(sep + ' ') + sep : '';
2326
+ let name = [];
2327
+ if (this._config.orderedBy === types_1.NameOrder.FIRST_NAME) {
2328
+ switch (by) {
2329
+ case types_1.Flat.FIRST_NAME:
2330
+ name = hasMid ? [f, mn, ln] : [f, ln];
2353
2331
  break;
2354
- case index_1.Namon.LAST_NAME:
2355
- fullname.lastname = new index_1.Lastname(value);
2332
+ case types_1.Flat.LAST_NAME:
2333
+ name = hasMid ? [fn, mn, l] : [fn, l];
2356
2334
  break;
2357
- case index_1.Namon.MIDDLE_NAME:
2358
- fullname.middlename.push(new index_1.Name(value, index_1.Namon.MIDDLE_NAME));
2335
+ case types_1.Flat.MIDDLE_NAME:
2336
+ name = hasMid ? [fn, m, ln] : [fn, ln];
2359
2337
  break;
2360
- case index_1.Namon.PREFIX:
2361
- fullname.prefix = value;
2338
+ case types_1.Flat.FIRST_MID:
2339
+ name = hasMid ? [f, m, ln] : [f, ln];
2362
2340
  break;
2363
- case index_1.Namon.SUFFIX:
2364
- fullname.suffix = value;
2341
+ case types_1.Flat.MID_LAST:
2342
+ name = hasMid ? [fn, m, l] : [fn, l];
2343
+ break;
2344
+ case types_1.Flat.ALL:
2345
+ name = hasMid ? [f, m, l] : [f, l];
2365
2346
  break;
2366
2347
  }
2367
2348
  }
2368
- return fullname;
2349
+ else {
2350
+ switch (by) {
2351
+ case types_1.Flat.FIRST_NAME:
2352
+ name = hasMid ? [ln, f, mn] : [ln, f];
2353
+ break;
2354
+ case types_1.Flat.LAST_NAME:
2355
+ name = hasMid ? [l, fn, mn] : [l, fn];
2356
+ break;
2357
+ case types_1.Flat.MIDDLE_NAME:
2358
+ name = hasMid ? [ln, fn, m] : [ln, fn];
2359
+ break;
2360
+ case types_1.Flat.FIRST_MID:
2361
+ name = hasMid ? [ln, f, m] : [ln, f];
2362
+ break;
2363
+ case types_1.Flat.MID_LAST:
2364
+ name = hasMid ? [l, fn, m] : [l, fn];
2365
+ break;
2366
+ case types_1.Flat.ALL:
2367
+ name = hasMid ? [l, f, m] : [l, f];
2368
+ break;
2369
+ }
2370
+ }
2371
+ const flat = name.join(' ');
2372
+ if (recursive && flat.length > limit) {
2373
+ const next = by === types_1.Flat.FIRST_NAME
2374
+ ? types_1.Flat.MIDDLE_NAME
2375
+ : by === types_1.Flat.MIDDLE_NAME
2376
+ ? types_1.Flat.LAST_NAME
2377
+ : by === types_1.Flat.LAST_NAME
2378
+ ? types_1.Flat.FIRST_MID
2379
+ : by === types_1.Flat.FIRST_MID
2380
+ ? types_1.Flat.MID_LAST
2381
+ : by === types_1.Flat.MID_LAST
2382
+ ? types_1.Flat.ALL
2383
+ : by === types_1.Flat.ALL
2384
+ ? types_1.Flat.ALL
2385
+ : by;
2386
+ if (next === by)
2387
+ return flat;
2388
+ return this.flatten(Object.assign(Object.assign({}, options), { by: next }));
2389
+ }
2390
+ return flat;
2369
2391
  }
2370
- }
2371
- exports.default = NamaParser;
2372
-
2373
-
2374
- /***/ }),
2375
- /* 29 */
2376
- /***/ (function(module, exports, __webpack_require__) {
2377
-
2378
- "use strict";
2379
-
2380
- Object.defineProperty(exports, "__esModule", { value: true });
2381
- const index_1 = __webpack_require__(4);
2382
- /**
2383
- * Represents a string parser
2384
- * @class
2385
- * @implements {Parser}
2386
- * @classdesc
2387
- * This parser parses a string name using a separator, if set, or simply using
2388
- * the space character <' '> as a basis for the split.
2389
- *
2390
- * **NOTE**:
2391
- * A string name is basically a string type containing the name parts differentiated
2392
- * with the help of a separator. The default separator is the character <space>
2393
- * or <' '>. However, it can be very, very helpful to use a distinct separator
2394
- * (e.g., a colon <:>) to handle multiple names for a `Namon`. That is to say,
2395
- * a piece of name shaped as `De La Cruz` is a last name that needs to be handled
2396
- * as a whole, and therefore requires that a different type of separator to split
2397
- * up the name parts. Alternatively, the `ArrayStringParser` can be used by indicating
2398
- * specifically which part of the name is what. Do note that this parser is actually
2399
- * a wrapper of the `ArrayStringParser`.
2400
- *
2401
- * @example
2402
- * Given the name `Maria De La Cruz`, using this parser without indicating a
2403
- * separator different than <space> will definitely throw an error. So, if the proper
2404
- * proper of doing when `De La Cruz` is the last name:
2405
- * ```
2406
- * > const name = new Namefully('Maria:De La Cruz', { separator: Separator.COLON })
2407
- * > console.log(name.getLastname())
2408
- * De La Cruz
2409
- * ```
2410
- * Or
2411
- * ```
2412
- * > const name = new Namefully(['Maria', 'De La Cruz'])
2413
- * > console.log(name.getLastname())
2414
- * De La Cruz
2415
- * ```
2416
- */
2417
- class StringParser {
2418
2392
  /**
2419
- * Create a parser ready to parse the raw data
2420
- * @param {string} raw data as a string representation
2393
+ * Zips or compacts a name using different forms of variants.
2394
+ *
2395
+ * @see `flatten()` for more details.
2421
2396
  */
2422
- constructor(raw) {
2423
- this.raw = raw;
2397
+ zip(by = types_1.Flat.MID_LAST, withPeriod = true) {
2398
+ return this.flatten({ limit: 0, by, withPeriod });
2424
2399
  }
2425
2400
  /**
2426
- * Parses the raw data into a full name
2427
- * @param options how to parse
2428
- * @returns {Fullname}
2401
+ * Formats the full name as desired.
2402
+ * @param pattern character used to format it.
2403
+ *
2404
+ * string format
2405
+ * -------------
2406
+ * - 'short': typical first + last name
2407
+ * - 'long': birth name (without prefix and suffix)
2408
+ * - 'public': first name combined with the last name's initial.
2409
+ * - 'official': official document format
2410
+ *
2411
+ * char format
2412
+ * -----------
2413
+ * - 'b': birth name
2414
+ * - 'B': capitalized birth name
2415
+ * - 'f': first name
2416
+ * - 'F': capitalized first name
2417
+ * - 'l': last name
2418
+ * - 'L': capitalized last name
2419
+ * - 'm': middle names
2420
+ * - 'M': capitalized middle names
2421
+ * - 'o': official document format
2422
+ * - 'O': official document format in capital letters
2423
+ * - 'p': prefix
2424
+ * - 'P': capitalized prefix
2425
+ * - 's': suffix
2426
+ * - 'S': capitalized suffix
2427
+ *
2428
+ * punctuations
2429
+ * ------------
2430
+ * - '.': period
2431
+ * - ',': comma
2432
+ * - ' ': space
2433
+ * - '-': hyphen
2434
+ * - '_': underscore
2435
+ * - '$': an escape character to select only the initial of the next char.
2436
+ *
2437
+ * Given the name `Joe Jim Smith`, use `format` with the `pattern` string.
2438
+ * - format('l f') => 'Smith Joe'
2439
+ * - format('L, f') => 'SMITH, Joe'
2440
+ * - format('short') => 'Joe Smith'
2441
+ * - format() => 'SMITH, Joe Jim'
2442
+ * - format(r'f $l.') => 'Joe S.'.
2443
+ *
2444
+ * Do note that the escape character is only valid for the birth name parts:
2445
+ * first, middle, and last names.
2429
2446
  */
2430
- parse(options) {
2431
- // given this setting
2432
- const { orderedBy, separator, bypass } = options;
2433
- // then distribute all the elements accordingly
2434
- const nama = this.raw.split(separator);
2435
- const fullname = new index_1.ArrayStringParser(nama).parse({ orderedBy, bypass });
2436
- // finally return high quality of data
2437
- return fullname;
2447
+ format(pattern) {
2448
+ var _a;
2449
+ if (pattern === 'short')
2450
+ return this.short;
2451
+ if (pattern === 'long')
2452
+ return this.long;
2453
+ if (pattern === 'public')
2454
+ return this.public;
2455
+ if (pattern === 'official')
2456
+ pattern = 'o';
2457
+ let group = '';
2458
+ const formatted = [];
2459
+ for (const char of pattern.split('')) {
2460
+ if (constants_1.ALLOWED_TOKENS.indexOf(char) === -1) {
2461
+ throw new error_1.NotAllowedError({
2462
+ source: this.full,
2463
+ operation: 'format',
2464
+ message: `unsupported character <${char}> from ${pattern}.`,
2465
+ });
2466
+ }
2467
+ group += char;
2468
+ if (char === '$')
2469
+ continue;
2470
+ formatted.push((_a = this.map(group)) !== null && _a !== void 0 ? _a : '');
2471
+ group = '';
2472
+ }
2473
+ return formatted.join('').trim();
2438
2474
  }
2439
- }
2440
- exports.default = StringParser;
2441
-
2442
-
2443
- /***/ }),
2444
- /* 30 */
2445
- /***/ (function(module, exports, __webpack_require__) {
2446
-
2447
- "use strict";
2448
-
2449
- Object.defineProperty(exports, "__esModule", { value: true });
2450
- const core_1 = __webpack_require__(3);
2451
- /**
2452
- * Reorganizes the existing global indexes for array of name parts
2453
- * @param orderedBy by first or last name
2454
- * @param argLength length of the provided array
2455
- * @param nameIndex global preset of indexing
2456
- */
2457
- function organizeNameIndex(orderedBy, argLength, nameIndex = core_1.NAME_INDEX) {
2458
- const out = Object.assign({}, nameIndex);
2459
- if (orderedBy === 'firstname') {
2460
- switch (argLength) {
2461
- case 2: // first name + last name
2462
- out.firstname = 0;
2463
- out.lastname = 1;
2464
- break;
2465
- case 3: // first name + middle name + last name
2466
- out.firstname = 0;
2467
- out.middlename = 1;
2468
- out.lastname = 2;
2469
- break;
2470
- case 4: // prefix + first name + middle name + last name
2471
- out.prefix = 0;
2472
- out.firstname = 1;
2473
- out.middlename = 2;
2474
- out.lastname = 3;
2475
- break;
2476
- case 5: // prefix + first name + middle name + last name + suffix
2477
- out.prefix = 0;
2478
- out.firstname = 1;
2479
- out.middlename = 2;
2480
- out.lastname = 3;
2481
- out.suffix = 4;
2482
- break;
2475
+ /**
2476
+ * Flips definitely the name order from the preset/current config.
2477
+ */
2478
+ flip() {
2479
+ if (this._config.orderedBy === types_1.NameOrder.FIRST_NAME) {
2480
+ this._config.updateOrder(types_1.NameOrder.LAST_NAME);
2481
+ console.log(`The name order is now changed to: ${types_1.NameOrder.LAST_NAME}`);
2482
+ }
2483
+ else {
2484
+ this._config.updateOrder(types_1.NameOrder.FIRST_NAME);
2485
+ console.log(`The name order is now changed to: ${types_1.NameOrder.FIRST_NAME}`);
2483
2486
  }
2484
2487
  }
2485
- else {
2486
- switch (argLength) {
2487
- case 2: // last name + first name
2488
- out.lastname = 0;
2489
- out.firstname = 1;
2490
- break;
2491
- case 3: // last name + first name + middle name
2492
- out.lastname = 0;
2493
- out.firstname = 1;
2494
- out.middlename = 2;
2495
- break;
2496
- case 4: // prefix + last name + first name + middle name
2497
- out.prefix = 0;
2498
- out.lastname = 1;
2499
- out.firstname = 2;
2500
- out.middlename = 3;
2501
- break;
2502
- case 5: // prefix + last name + first name + middle name + suffix
2503
- out.prefix = 0;
2504
- out.lastname = 1;
2505
- out.firstname = 2;
2506
- out.middlename = 3;
2507
- out.suffix = 4;
2508
- break;
2488
+ /**
2489
+ * Splits the name parts of a birth name.
2490
+ * @param separator token for the split.
2491
+ */
2492
+ split(separator = /[' -]/g) {
2493
+ return this.birth.replace(separator, ' ').split(' ');
2494
+ }
2495
+ /**
2496
+ * Joins the name parts of a birth name.
2497
+ * @param separator token for the junction.
2498
+ */
2499
+ join(separator = '') {
2500
+ return this.split().join(separator);
2501
+ }
2502
+ /**
2503
+ * Transforms a birth name into UPPERCASE
2504
+ */
2505
+ toUpperCase() {
2506
+ return this.birth.toUpperCase();
2507
+ }
2508
+ /**
2509
+ * Transforms a birth name into lowercase
2510
+ */
2511
+ toLowerCase() {
2512
+ return this.birth.toLowerCase();
2513
+ }
2514
+ /**
2515
+ * Transforms a birth name into camelCase
2516
+ */
2517
+ toCamelCase() {
2518
+ return utils_1.decapitalize(this.toPascalCase());
2519
+ }
2520
+ /**
2521
+ * Transforms a birth name into PascalCase
2522
+ */
2523
+ toPascalCase() {
2524
+ return this.split()
2525
+ .map((n) => utils_1.capitalize(n))
2526
+ .join('');
2527
+ }
2528
+ /**
2529
+ * Transforms a birth name into snake_case
2530
+ */
2531
+ toSnakeCase() {
2532
+ return this.split()
2533
+ .map((n) => n.toLowerCase())
2534
+ .join('_');
2535
+ }
2536
+ /**
2537
+ * Transforms a birth name into hyphen-case
2538
+ */
2539
+ toHyphenCase() {
2540
+ return this.split()
2541
+ .map((n) => n.toLowerCase())
2542
+ .join('-');
2543
+ }
2544
+ /**
2545
+ * Transforms a birth name into dot.case
2546
+ */
2547
+ toDotCase() {
2548
+ return this.split()
2549
+ .map((n) => n.toLowerCase())
2550
+ .join('.');
2551
+ }
2552
+ /**
2553
+ * Transforms a birth name into ToGgLeCaSe
2554
+ */
2555
+ toToggleCase() {
2556
+ return utils_1.toggleCase(this.birth);
2557
+ }
2558
+ build(parser, options) {
2559
+ this._config = config_1.Config.merge(options);
2560
+ this._fullName = parser.parse(this._config);
2561
+ }
2562
+ toParser(raw) {
2563
+ if (raw instanceof parser_1.Parser)
2564
+ return raw;
2565
+ if (typeof raw === 'string')
2566
+ return new parser_1.StringParser(raw);
2567
+ if (utils_1.isStringArray(raw))
2568
+ return new parser_1.ArrayStringParser(raw);
2569
+ if (utils_1.isNameArray(raw))
2570
+ return new parser_1.ArrayNameParser(raw);
2571
+ if (typeof raw === 'object')
2572
+ return new parser_1.NamaParser(raw);
2573
+ throw new error_1.InputError({
2574
+ source: raw,
2575
+ message: 'Cannot parse raw data. Review expected data types.',
2576
+ });
2577
+ }
2578
+ map(char) {
2579
+ var _a, _b;
2580
+ switch (char) {
2581
+ case '.':
2582
+ case ',':
2583
+ case ' ':
2584
+ case '-':
2585
+ case '_':
2586
+ return char;
2587
+ case 'b':
2588
+ return this.birth;
2589
+ case 'B':
2590
+ return this.birth.toUpperCase();
2591
+ case 'f':
2592
+ return this.first;
2593
+ case 'F':
2594
+ return this.first.toUpperCase();
2595
+ case 'l':
2596
+ return this.last;
2597
+ case 'L':
2598
+ return this.last.toUpperCase();
2599
+ case 'm':
2600
+ case 'M':
2601
+ return char === 'm' ? this.middleName().join(' ') : this.middleName().join(' ').toUpperCase();
2602
+ case 'o':
2603
+ case 'O':
2604
+ const sep = this._config.ending ? ',' : '';
2605
+ const names = [];
2606
+ if (this.prefix)
2607
+ names.push(this.prefix);
2608
+ names.push(`${this.last},`.toUpperCase());
2609
+ if (this.hasMiddle) {
2610
+ names.push(this.first, this.middleName().join(' ') + sep);
2611
+ }
2612
+ else {
2613
+ names.push(this.first + sep);
2614
+ }
2615
+ if (this.suffix)
2616
+ names.push(this.suffix);
2617
+ const nama = names.join(' ').trim();
2618
+ return char === 'o' ? nama : nama.toUpperCase();
2619
+ case 'p':
2620
+ return this.prefix;
2621
+ case 'P':
2622
+ return (_a = this.prefix) === null || _a === void 0 ? void 0 : _a.toUpperCase();
2623
+ case 's':
2624
+ return this.suffix;
2625
+ case 'S':
2626
+ return (_b = this.suffix) === null || _b === void 0 ? void 0 : _b.toUpperCase();
2627
+ case '$f':
2628
+ case '$F':
2629
+ return this._fullName.firstName.initials()[0];
2630
+ case '$l':
2631
+ case '$L':
2632
+ return this._fullName.lastName.initials()[0];
2633
+ case '$m':
2634
+ case '$M':
2635
+ return this.hasMiddle ? this.middle[0] : undefined;
2636
+ default:
2637
+ return undefined;
2509
2638
  }
2510
2639
  }
2511
- return out;
2512
2640
  }
2513
- exports.organizeNameIndex = organizeNameIndex;
2514
-
2515
-
2516
- /***/ }),
2517
- /* 31 */
2518
- /***/ (function(module, exports, __webpack_require__) {
2519
-
2520
- "use strict";
2521
-
2522
- Object.defineProperty(exports, "__esModule", { value: true });
2523
- /**
2524
- * Constants
2525
- *
2526
- * Created on March 07, 2020
2527
- * @author Ralph Florent <ralflornt@gmail.com>
2528
- */
2529
- const index_1 = __webpack_require__(1);
2530
- /**
2531
- * The current version of `Namefully`.
2532
- * @constant
2533
- */
2534
- exports.version = '1.0.9';
2535
- /**
2536
- * CONFIG constant
2537
- * @constant
2538
- * @type {Config}
2539
- * @default
2540
- */
2541
- exports.CONFIG = {
2542
- orderedBy: 'firstname',
2543
- separator: index_1.Separator.SPACE,
2544
- titling: 'uk',
2545
- ending: index_1.Separator.SPACE,
2546
- bypass: false,
2547
- lastnameFormat: 'father',
2548
- };
2549
- /**
2550
- * NAME_INDEX constant
2551
- * @constant
2552
- * @type {NameIndex}
2553
- * @default
2554
- */
2555
- exports.NAME_INDEX = {
2556
- prefix: 0,
2557
- firstname: 1,
2558
- middlename: 2,
2559
- lastname: 3,
2560
- suffix: 4,
2561
- };
2641
+ exports.Namefully = Namefully;
2562
2642
 
2563
2643
 
2564
2644
  /***/ })