namefully 1.1.0 → 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 (156) hide show
  1. package/dist/example/index.js +2734 -0
  2. package/dist/lib/config.d.ts +121 -0
  3. package/dist/lib/config.js +189 -0
  4. package/dist/lib/config.js.map +1 -0
  5. package/dist/lib/constants.d.ts +4 -0
  6. package/dist/lib/constants.js +31 -0
  7. package/dist/lib/constants.js.map +1 -0
  8. package/dist/lib/error.d.ts +172 -0
  9. package/dist/lib/error.js +210 -0
  10. package/dist/lib/error.js.map +1 -0
  11. package/dist/lib/example/example.d.ts +1 -0
  12. package/dist/lib/full-name.d.ts +71 -0
  13. package/dist/lib/full-name.js +147 -0
  14. package/dist/lib/full-name.js.map +1 -0
  15. package/dist/lib/index.d.ts +16 -6
  16. package/dist/lib/index.js +29 -8
  17. package/dist/lib/index.js.map +1 -1
  18. package/dist/lib/name.d.ts +177 -0
  19. package/dist/lib/name.js +322 -0
  20. package/dist/lib/name.js.map +1 -0
  21. package/dist/lib/namefully.d.ts +285 -208
  22. package/dist/lib/namefully.js +576 -576
  23. package/dist/lib/namefully.js.map +1 -1
  24. package/dist/lib/parser.d.ts +46 -0
  25. package/dist/lib/parser.js +173 -0
  26. package/dist/lib/parser.js.map +1 -0
  27. package/dist/lib/src/config.d.ts +121 -0
  28. package/dist/lib/src/constants.d.ts +4 -0
  29. package/dist/lib/src/error.d.ts +172 -0
  30. package/dist/lib/src/full-name.d.ts +71 -0
  31. package/dist/lib/src/index.d.ts +20 -0
  32. package/dist/lib/src/name.d.ts +177 -0
  33. package/dist/lib/src/namefully.d.ts +379 -0
  34. package/dist/lib/src/parser.d.ts +46 -0
  35. package/dist/lib/src/types.d.ts +127 -0
  36. package/dist/lib/src/utils.d.ts +63 -0
  37. package/dist/lib/src/validator.d.ts +66 -0
  38. package/dist/lib/types.d.ts +127 -0
  39. package/dist/lib/types.js +181 -0
  40. package/dist/lib/types.js.map +1 -0
  41. package/dist/lib/utils.d.ts +63 -0
  42. package/dist/lib/utils.js +138 -0
  43. package/dist/lib/utils.js.map +1 -0
  44. package/dist/lib/validator.d.ts +66 -0
  45. package/dist/lib/validator.js +332 -0
  46. package/dist/lib/validator.js.map +1 -0
  47. package/dist/umd/namefully.js +2118 -2700
  48. package/dist/umd/namefully.js.map +1 -1
  49. package/dist/umd/namefully.min.js +1 -1
  50. package/dist/umd/namefully.min.js.LICENSE.txt +1 -18
  51. package/dist/umd/namefully.min.js.map +1 -1
  52. package/package.json +50 -54
  53. package/readme.md +132 -162
  54. package/changelog.md +0 -134
  55. package/dist/lib/core/constants.d.ts +0 -48
  56. package/dist/lib/core/constants.js +0 -101
  57. package/dist/lib/core/constants.js.map +0 -1
  58. package/dist/lib/core/core.d.ts +0 -17
  59. package/dist/lib/core/core.js +0 -24
  60. package/dist/lib/core/core.js.map +0 -1
  61. package/dist/lib/core/index.d.ts +0 -9
  62. package/dist/lib/core/index.js +0 -13
  63. package/dist/lib/core/index.js.map +0 -1
  64. package/dist/lib/core/parsers/array-name.parser.d.ts +0 -41
  65. package/dist/lib/core/parsers/array-name.parser.js +0 -86
  66. package/dist/lib/core/parsers/array-name.parser.js.map +0 -1
  67. package/dist/lib/core/parsers/array-string.parser.d.ts +0 -47
  68. package/dist/lib/core/parsers/array-string.parser.js +0 -95
  69. package/dist/lib/core/parsers/array-string.parser.js.map +0 -1
  70. package/dist/lib/core/parsers/index.d.ts +0 -11
  71. package/dist/lib/core/parsers/index.js +0 -11
  72. package/dist/lib/core/parsers/index.js.map +0 -1
  73. package/dist/lib/core/parsers/nama.parser.d.ts +0 -33
  74. package/dist/lib/core/parsers/nama.parser.js +0 -74
  75. package/dist/lib/core/parsers/nama.parser.js.map +0 -1
  76. package/dist/lib/core/parsers/parser.d.ts +0 -28
  77. package/dist/lib/core/parsers/parser.js +0 -3
  78. package/dist/lib/core/parsers/parser.js.map +0 -1
  79. package/dist/lib/core/parsers/string.parser.d.ts +0 -60
  80. package/dist/lib/core/parsers/string.parser.js +0 -62
  81. package/dist/lib/core/parsers/string.parser.js.map +0 -1
  82. package/dist/lib/core/utils.d.ts +0 -52
  83. package/dist/lib/core/utils.js +0 -178
  84. package/dist/lib/core/utils.js.map +0 -1
  85. package/dist/lib/models/enums.d.ts +0 -106
  86. package/dist/lib/models/enums.js +0 -114
  87. package/dist/lib/models/enums.js.map +0 -1
  88. package/dist/lib/models/firstname.d.ts +0 -77
  89. package/dist/lib/models/firstname.js +0 -131
  90. package/dist/lib/models/firstname.js.map +0 -1
  91. package/dist/lib/models/fullname.d.ts +0 -73
  92. package/dist/lib/models/fullname.js +0 -99
  93. package/dist/lib/models/fullname.js.map +0 -1
  94. package/dist/lib/models/index.d.ts +0 -13
  95. package/dist/lib/models/index.js +0 -16
  96. package/dist/lib/models/index.js.map +0 -1
  97. package/dist/lib/models/lastname.d.ts +0 -80
  98. package/dist/lib/models/lastname.js +0 -157
  99. package/dist/lib/models/lastname.js.map +0 -1
  100. package/dist/lib/models/misc.d.ts +0 -108
  101. package/dist/lib/models/misc.js +0 -3
  102. package/dist/lib/models/misc.js.map +0 -1
  103. package/dist/lib/models/name.d.ts +0 -76
  104. package/dist/lib/models/name.js +0 -115
  105. package/dist/lib/models/name.js.map +0 -1
  106. package/dist/lib/models/summary.d.ts +0 -26
  107. package/dist/lib/models/summary.js +0 -61
  108. package/dist/lib/models/summary.js.map +0 -1
  109. package/dist/lib/validators/array-name.validator.d.ts +0 -25
  110. package/dist/lib/validators/array-name.validator.js +0 -75
  111. package/dist/lib/validators/array-name.validator.js.map +0 -1
  112. package/dist/lib/validators/array-string.validator.d.ts +0 -43
  113. package/dist/lib/validators/array-string.validator.js +0 -76
  114. package/dist/lib/validators/array-string.validator.js.map +0 -1
  115. package/dist/lib/validators/common/validation-error.d.ts +0 -19
  116. package/dist/lib/validators/common/validation-error.js +0 -26
  117. package/dist/lib/validators/common/validation-error.js.map +0 -1
  118. package/dist/lib/validators/common/validation-rule.d.ts +0 -72
  119. package/dist/lib/validators/common/validation-rule.js +0 -76
  120. package/dist/lib/validators/common/validation-rule.js.map +0 -1
  121. package/dist/lib/validators/common/validation-type.d.ts +0 -24
  122. package/dist/lib/validators/common/validation-type.js +0 -28
  123. package/dist/lib/validators/common/validation-type.js.map +0 -1
  124. package/dist/lib/validators/firstname.validator.d.ts +0 -20
  125. package/dist/lib/validators/firstname.validator.js +0 -29
  126. package/dist/lib/validators/firstname.validator.js.map +0 -1
  127. package/dist/lib/validators/fullname.validator.d.ts +0 -21
  128. package/dist/lib/validators/fullname.validator.js +0 -38
  129. package/dist/lib/validators/fullname.validator.js.map +0 -1
  130. package/dist/lib/validators/index.d.ts +0 -21
  131. package/dist/lib/validators/index.js +0 -35
  132. package/dist/lib/validators/index.js.map +0 -1
  133. package/dist/lib/validators/lastname.validator.d.ts +0 -20
  134. package/dist/lib/validators/lastname.validator.js +0 -29
  135. package/dist/lib/validators/lastname.validator.js.map +0 -1
  136. package/dist/lib/validators/middlename.validator.d.ts +0 -20
  137. package/dist/lib/validators/middlename.validator.js +0 -38
  138. package/dist/lib/validators/middlename.validator.js.map +0 -1
  139. package/dist/lib/validators/nama.validator.d.ts +0 -21
  140. package/dist/lib/validators/nama.validator.js +0 -44
  141. package/dist/lib/validators/nama.validator.js.map +0 -1
  142. package/dist/lib/validators/namon.validator.d.ts +0 -20
  143. package/dist/lib/validators/namon.validator.js +0 -29
  144. package/dist/lib/validators/namon.validator.js.map +0 -1
  145. package/dist/lib/validators/prefix.validator.d.ts +0 -14
  146. package/dist/lib/validators/prefix.validator.js +0 -31
  147. package/dist/lib/validators/prefix.validator.js.map +0 -1
  148. package/dist/lib/validators/string-name.validator.d.ts +0 -20
  149. package/dist/lib/validators/string-name.validator.js +0 -29
  150. package/dist/lib/validators/string-name.validator.js.map +0 -1
  151. package/dist/lib/validators/suffix.validator.d.ts +0 -14
  152. package/dist/lib/validators/suffix.validator.js +0 -31
  153. package/dist/lib/validators/suffix.validator.js.map +0 -1
  154. package/dist/lib/validators/validator.d.ts +0 -13
  155. package/dist/lib/validators/validator.js +0 -9
  156. package/dist/lib/validators/validator.js.map +0 -1
@@ -1,723 +1,723 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.Namefully = void 0;
13
+ const config_1 = require("./config");
14
+ const constants_1 = require("./constants");
15
+ const error_1 = require("./error");
16
+ const parser_1 = require("./parser");
17
+ const types_1 = require("./types");
18
+ const utils_1 = require("./utils");
3
19
  /**
4
- * Welcome to namefully!
20
+ * A helper for organizing person names in a particular order, way, or shape.
5
21
  *
6
- * namefully is a JS utility for handing person names.
22
+ * Though `namefully` is easy to use, it does not magically guess which part of
23
+ * the name is what (prefix, suffix, first, last, or middle names). It relies
24
+ * actually on how the name parts are indicated (i.e., their roles) so that
25
+ * it can perform internally certain operations and saves us some extra
26
+ * calculations/processing. In addition, `Namefully` can be created using
27
+ * distinct raw data shapes. This is intended to give some flexibility to the
28
+ * developer so that he or she is not bound to a particular data format.
29
+ * By following closely the API reference to know how to harness its usability,
30
+ * this utility aims to save time in formatting names.
7
31
  *
8
- * Sources
9
- * - repo: https://github.com/ralflorent/namefully
10
- * - docs: https://namefully.netlify.app
11
- * - npm: https://npmjs.com/package/namefully
32
+ * `namefully` also works like a trapdoor. Once a raw data is provided and
33
+ * validated, a developer can only *access* in a vast amount of, yet effective
34
+ * ways the name info. *No editing* is possible. If the name is mistaken, a new
35
+ * instance of `Namefully` must be created. In other words, it's immutable.
36
+ * Remember, this utility's primary objective is to help manipulate a person name.
12
37
  *
13
- * Created on March 03, 2020
14
- * @author Ralph Florent <ralflornt@gmail.com>
15
- * @license MIT
16
- */
17
- const core_1 = require("./core");
18
- const models_1 = require("./models");
19
- const validators_1 = require("./validators");
20
- /**
21
- * Person name handler
22
- * @class
23
- *
24
- * `Namefully` does not magically guess which part of the name is what. It relies
25
- * actually on how the developer indicates the roles of the name parts so that
26
- * it, internally, can perform certain operations and saves the developer some
27
- * calculations/processings. Nevertheless, Namefully can be constructed using
28
- * distinct raw data shape. This is intended to give some flexibility to the
29
- * developer so that he or she is not bound to a particular data format. Please,
30
- * do follow closely the APIs to know how to properly use it in order to avoid
31
- * some errors (mainly validation's).
38
+ * Note that the name standards used for the current version of this library
39
+ * are as follows:
40
+ * `[prefix] firstName [middleName] lastName [suffix]`
41
+ * The opening `[` and closing `]` symbols mean that these parts are optional.
42
+ * In other words, the most basic and typical case is a name that looks like
43
+ * this: `John Smith`, where `John` is the first name piece and `Smith`, the last
44
+ * name piece.
32
45
  *
33
- * `Namefully` also works like a trap door. Once a raw data is provided and
34
- * validated, a developer can only ACCESS in a vast amount of, yet effective ways
35
- * the name info. NO EDITING is possible. If the name is mistaken, a new instance
36
- * of `Namefully` must be created. Remember, this utility's primary objective is
37
- * to help to **handle** a person name.
38
- *
39
- * Note that the name standards used for the current version of this library are
40
- * as follows:
41
- * [Prefix] Firstname [Middlename] Lastname [Suffix]
42
- * The opening `[` and closing `]` brackets mean that these parts are optional.
43
- * In other words, the most basic and typical case is a name that looks like this:
44
- * `John Smith`, where `John` is the first name and `Smith`, the last name.
45
46
  * @see https://departments.weber.edu/qsupport&training/Data_Standards/Name.htm
46
47
  * for more info on name standards.
47
48
  *
48
- * **IMPORTANT**: Keep in mind that the order of appearance matters and can be
49
- * altered through configured parameters, which we will be seeing later on. By
50
- * default, the order of appearance is as shown above and will be used as a basis
51
- * for future examples and use cases.
49
+ * **IMPORTANT**: Keep in mind that the order of appearance (or name order) matters
50
+ * and may be altered through configured parameters, which will be seen later.
51
+ * By default, the order of appearance is as shown above and will be used as a
52
+ * basis for future examples and use cases.
52
53
  *
53
54
  * Once imported, all that is required to do is to create an instance of
54
55
  * `Namefully` and the rest will follow.
55
56
  *
56
57
  * Some terminologies used across the library are:
57
- * - namon: 1 piece of a name (e.g., firstname)
58
- * - nama: 2+ pieces of a name (e.g., firstname + lastname)
58
+ * - namon: 1 piece of name (e.g., first name)
59
+ * - nama: 2+ pieces of name (e.g., first name + last name)
59
60
  *
60
- * Happy handling!
61
+ * Happy name handling 😊!
61
62
  */
62
63
  class Namefully {
63
64
  /**
64
- * Constructs an instance of the utility and helps to benefit from many helpers
65
- * @param {string | string[] | Name[] | Nama | Fullname} raw element to parse or
66
- * construct the pieces of the name
67
- * @param {Config} options to configure how to run the utility
65
+ * Creates a name with distinguishable parts from a raw string content.
66
+ * @param names element to parse.
67
+ * @param options additional settings.
68
+ *
69
+ * An optional configuration may be provided with specifics on how to treat
70
+ * a full name during its course. By default, all name parts are validated
71
+ * against some basic validation rules to avoid common runtime exceptions.
68
72
  */
69
- constructor(raw, options) {
70
- // well, first thing first
71
- this.configure(options);
72
- // let's try to parse this, baby!
73
- this.build(raw);
73
+ constructor(names, options) {
74
+ this.build(this.toParser(names), options);
74
75
  }
75
76
  /**
76
- * Gets the full name ordered as configured
77
- * @param {NameOrder} orderedBy force to order by first or last
78
- * name by overriding the preset configuration
77
+ * Constructs a `Namefully` instance from a text.
79
78
  *
80
- * @see {format} to alter manually the order of appearance of the full name.
81
- * For example, ::format('l f m') outputs `lastname firstname middlename`.
82
- */
83
- getFullname(orderedBy) {
84
- orderedBy = this.parseNameOrder(orderedBy);
85
- const { titling, ending } = this.config;
86
- const pxSep = titling === 'us' ? models_1.Separator.PERIOD : models_1.Separator.EMPTY; // Mr[.]
87
- const sxSep = ending ? ',' : models_1.Separator.EMPTY; // [,] PhD
88
- const nama = [];
89
- if (this.fullname.prefix)
90
- nama.push(models_1.Separator.EMPTY.concat(this.fullname.prefix, pxSep));
91
- if (orderedBy === 'firstname') {
92
- nama.push(this.getFirstname());
93
- nama.push(...this.getMiddlenames());
94
- nama.push(models_1.Separator.EMPTY.concat(this.getLastname(), sxSep));
95
- }
96
- else {
97
- nama.push(this.getLastname());
98
- nama.push(this.getFirstname());
99
- nama.push(this.getMiddlenames().join(models_1.Separator.SPACE).concat(sxSep));
100
- }
101
- if (this.fullname.suffix)
102
- nama.push(this.fullname.suffix);
103
- return nama.join(models_1.Separator.SPACE);
104
- }
105
- /**
106
- * Gets the birth name ordered as configured, no prefix or suffix
107
- * @param {NameOrder} orderedBy force to order by first or last
108
- * name by overriding the preset configuration
109
- */
110
- getBirthname(orderedBy) {
111
- orderedBy = this.parseNameOrder(orderedBy);
112
- const nama = [];
113
- if (orderedBy === 'firstname') {
114
- nama.push(this.getFirstname());
115
- nama.push(...this.getMiddlenames());
116
- nama.push(this.getLastname());
79
+ * It works like `parse` except that this function returns `null` where `parse`
80
+ * would throw a `NameError`.
81
+ */
82
+ static tryParse(text) {
83
+ try {
84
+ return new this(parser_1.Parser.build(text));
117
85
  }
118
- else {
119
- nama.push(this.getLastname());
120
- nama.push(this.getFirstname());
121
- nama.push(...this.getMiddlenames());
86
+ catch (error) {
87
+ return undefined;
122
88
  }
123
- return nama.join(models_1.Separator.SPACE);
124
89
  }
125
90
  /**
126
- * Gets the first name part of the full name
127
- * @param {boolean} includeAll whether to include other pieces of the first
128
- * name
91
+ * Constructs a `Namefully` instance from a text.
92
+ *
93
+ * It throws a `NameError` if the text cannot be parsed. Use `tryParse`
94
+ * instead if a `null` return is preferred over a throwable error.
95
+ *
96
+ * This operation is computed asynchronously, which gives more flexibility at
97
+ * the time of catching the error (and stack trace if any). The acceptable
98
+ * text format is a string composed of two or more name pieces. For instance,
99
+ * `John Lennon`, or `John Winston Ono Lennon` are parsable names and follow
100
+ * the basic name standard rules (i.e., first-middle-last).
101
+ *
102
+ * Keep in mind that prefix and suffix are not considered during the parsing
103
+ * process.
104
+ */
105
+ static parse(text) {
106
+ return __awaiter(this, void 0, void 0, function* () {
107
+ return parser_1.Parser.buildAsync(text).then((parser) => new Namefully(parser));
108
+ });
109
+ }
110
+ /**
111
+ * The current configuration.
112
+ */
113
+ get config() {
114
+ return this._config;
115
+ }
116
+ /**
117
+ * The number of characters of the `birthName`, including spaces.
118
+ */
119
+ get length() {
120
+ return this.birth.length;
121
+ }
122
+ /**
123
+ * The prefix part.
124
+ */
125
+ get prefix() {
126
+ var _a;
127
+ return (_a = this._fullName.prefix) === null || _a === void 0 ? void 0 : _a.toString();
128
+ }
129
+ /**
130
+ * The firt name.
131
+ */
132
+ get first() {
133
+ return this.firstName();
134
+ }
135
+ /**
136
+ * The first middle name if any.
137
+ */
138
+ get middle() {
139
+ return this.hasMiddle ? this.middleName()[0] : undefined;
140
+ }
141
+ /**
142
+ * Returns true if any middle name has been set.
143
+ */
144
+ get hasMiddle() {
145
+ return this._fullName.has(types_1.Namon.MIDDLE_NAME);
146
+ }
147
+ /**
148
+ * The last name.
149
+ */
150
+ get last() {
151
+ return this.lastName();
152
+ }
153
+ /**
154
+ * The suffix part.
129
155
  */
130
- getFirstname(includeAll = true) {
131
- return this.fullname.firstname.tostring(includeAll);
156
+ get suffix() {
157
+ var _a;
158
+ return (_a = this._fullName.suffix) === null || _a === void 0 ? void 0 : _a.toString();
132
159
  }
133
160
  /**
134
- * Gets the last name part of the full name
135
- * @param {LastnameFormat} [format] overrides the how-to format of a surname
136
- * output, considering its subparts.
161
+ * The birth name.
137
162
  */
138
- getLastname(format) {
139
- return this.fullname.lastname.tostring(format);
163
+ get birth() {
164
+ return this.birthName();
140
165
  }
141
166
  /**
142
- * Gets the middle names part of the full name
167
+ * The shortest version of a person name.
143
168
  */
144
- getMiddlenames() {
145
- return this.hasMiddlename() ? this.fullname.middlename.map(n => n.namon) : [];
169
+ get short() {
170
+ return this.shorten();
146
171
  }
147
172
  /**
148
- * Gets the prefix part of the full name
173
+ * The longest version of a person name.
149
174
  */
150
- getPrefix() {
151
- return this.fullname.prefix
152
- ? this.fullname.prefix.concat(this.config.titling === 'us'
153
- ? models_1.Separator.PERIOD
154
- : models_1.Separator.EMPTY) : models_1.Separator.EMPTY;
175
+ get long() {
176
+ return this.birth;
155
177
  }
156
178
  /**
157
- * Gets the suffix part of the full name
179
+ * The entire name set.
158
180
  */
159
- getSuffix() {
160
- return this.fullname.suffix || models_1.Separator.EMPTY;
181
+ get full() {
182
+ return this.fullName();
161
183
  }
162
184
  /**
163
- * Gets the initials of the full name
164
- * @param {NameOrder} orderedBy force to order by first or last name by
165
- * overriding the preset configuration
166
- * @param {boolean} [withMid] whether to include middle names's
185
+ * The first name combined with the last name's initial.
186
+ */
187
+ get public() {
188
+ return this.format('f $l');
189
+ }
190
+ /**
191
+ * Returns the full name as set.
192
+ */
193
+ toString() {
194
+ return this.full;
195
+ }
196
+ /**
197
+ * Fetches the raw form of a name piece.
198
+ */
199
+ get(namon) {
200
+ if (namon.equal(types_1.Namon.PREFIX))
201
+ return this._fullName.prefix;
202
+ if (namon.equal(types_1.Namon.FIRST_NAME))
203
+ return this._fullName.firstName;
204
+ if (namon.equal(types_1.Namon.MIDDLE_NAME))
205
+ return this._fullName.middleName;
206
+ if (namon.equal(types_1.Namon.LAST_NAME))
207
+ return this._fullName.lastName;
208
+ if (namon.equal(types_1.Namon.SUFFIX))
209
+ return this._fullName.suffix;
210
+ return undefined;
211
+ }
212
+ /**
213
+ * Whether this name is equal to another one from a raw-string perspective.
214
+ */
215
+ equal(other) {
216
+ return this.toString() === other.toString();
217
+ }
218
+ /**
219
+ * Gets a JSON representation of the full name.
220
+ */
221
+ toJson() {
222
+ return {
223
+ prefix: this.prefix,
224
+ firstName: this.first,
225
+ middleName: this.middleName(),
226
+ lastName: this.last,
227
+ suffix: this.suffix,
228
+ };
229
+ }
230
+ /**
231
+ * Confirms that a name part has been set.
232
+ */
233
+ has(namon) {
234
+ return this._fullName.has(namon);
235
+ }
236
+ /**
237
+ * Gets the full name ordered as configured.
167
238
  *
168
- * @example
169
- * Given the names:
170
- * - `John Smith` => ['J', 'S']
171
- * - `John Ben Smith` => ['J', 'S']
172
- * when `withMid` is set to true:
173
- * - `John Ben Smith` => ['J', 'B', 'S']
239
+ * The name order `orderedBy` forces to order by first or last name by
240
+ * overriding the preset configuration.
174
241
  *
175
- * **NOTE**:
176
- * Ordered by last name obeys the following format:
177
- * `lastname firstname [middlename]`
178
- * which means that if no middle name was set, setting `withMid` to true
179
- * will output nothing and warn the end user about it.
180
- */
181
- getInitials(orderedBy, withMid = false) {
182
- orderedBy = this.parseNameOrder(orderedBy);
183
- const midInits = this.fullname.middlename ?
184
- this.fullname.middlename.map(n => n.getInitials()) : [];
185
- if (withMid && !this.hasMiddlename()) {
186
- console.warn('No initials for middle names since none was set.');
187
- }
188
- const initials = [];
189
- if (orderedBy === 'firstname') {
190
- initials.push(...this.fullname.firstname.getInitials());
191
- if (withMid)
192
- midInits.forEach(m => initials.push(...m));
193
- initials.push(...this.fullname.lastname.getInitials());
242
+ * `Namefully.format` may also be used to alter manually the order of appearance
243
+ * of full name.
244
+ *
245
+ * For example:
246
+ * ```ts
247
+ * const name = new Namefully('Jon Stark Snow');
248
+ * console.log(name.fullName(NameOrder.LAST_NAME)); // "Snow Jon Stark"
249
+ * console.log(name.format('l f m')); // "Snow Jon Stark"
250
+ * ```
251
+ */
252
+ fullName(orderedBy) {
253
+ const sep = this._config.ending ? ',' : '';
254
+ const names = [];
255
+ orderedBy = orderedBy || this._config.orderedBy;
256
+ if (this.prefix)
257
+ names.push(this.prefix);
258
+ if (orderedBy === types_1.NameOrder.FIRST_NAME) {
259
+ names.push(this.first, ...this.middleName(), this.last + sep);
194
260
  }
195
261
  else {
196
- initials.push(...this.fullname.lastname.getInitials());
197
- initials.push(...this.fullname.firstname.getInitials());
198
- if (withMid)
199
- midInits.forEach(m => initials.push(...m));
262
+ names.push(this.last, this.first, this.middleName().join(' ') + sep);
200
263
  }
201
- return initials;
264
+ if (this.suffix)
265
+ names.push(this.suffix);
266
+ return names.join(' ').trim();
202
267
  }
203
268
  /**
204
- * Gives some descriptive statistics that summarize the central tendency,
205
- * dispersion and shape of the characters' distribution.
206
- * @param what which variant to use when describe a name part
269
+ * Gets the birth name ordered as configured, no `prefix` or `suffix`.
207
270
  *
208
- * Treated as a categorical dataset, the summary contains the following info:
209
- * `count` : the number of *unrestricted* characters of the name;
210
- * `frequency` : the highest frequency within the characters;
211
- * `top` : the character with the highest frequency;
212
- * `unique` : the count of unique characters of the name;
213
- * `distribution` : the characters' distribution.
271
+ * @param orderedBy forces to order by first or last name by overriding the
272
+ * preset configuration.
273
+ */
274
+ birthName(orderedBy) {
275
+ orderedBy = orderedBy || this._config.orderedBy;
276
+ return orderedBy === types_1.NameOrder.FIRST_NAME
277
+ ? [this.first, ...this.middleName(), this.last].join(' ')
278
+ : [this.last, this.first, ...this.middleName()].join(' ');
279
+ }
280
+ /**
281
+ * Gets the first name part of the `FullName`.
214
282
  *
215
- * @example
216
- * Given the name "Thomas Alva Edison", the summary will output as follows:
283
+ * @param withMore determines whether to include other pieces of the first
284
+ * name.
285
+ */
286
+ firstName(withMore = true) {
287
+ return this._fullName.firstName.toString(withMore);
288
+ }
289
+ /**
290
+ * Gets the middle name part of the `FullName`.
291
+ */
292
+ middleName() {
293
+ return this._fullName.middleName.map((n) => n.value);
294
+ }
295
+ /**
296
+ * Gets the last name part of the `FullName`.
217
297
  *
218
- * Descriptive statistics for "Thomas Alva Edison"
219
- * count : 16
220
- * frequency: 3
221
- * top : A
222
- * unique : 12
223
- * distribution: { T: 1, H: 1, O: 2, M: 1, A: 2, S: 2, ' ': 2, L: 1, V: 1,
224
- * E: 1, D: 1, I: 1, N: 1 }
298
+ * @param format overrides the how-to formatting of a surname output,
299
+ * considering its sub-parts.
300
+ */
301
+ lastName(format) {
302
+ return this._fullName.lastName.toString(format);
303
+ }
304
+ /**
305
+ * Gets the initials of the `FullName`.
225
306
  *
226
- * **NOTE:**
227
- * During the setup, a set of restricted characters can be defined to be removed
228
- * from the stats. By default, the only restricted character is the `space`.
229
- * That is why the `count` for the example below result in `16` instead of
230
- * `16`.
231
- * Another thing to consider is that the summary is case *insensitive*. Note
232
- * that the letter `a` has the top frequency, be it `3`.
233
- */
234
- describe(what) {
235
- what = core_1.allowShortNameType(what);
236
- switch (what) {
237
- case 'firstname':
238
- return this.fullname.firstname.describe();
239
- case 'lastname':
240
- return this.fullname.lastname.describe();
241
- case 'middlename':
242
- if (!this.hasMiddlename()) {
243
- console.warn('No Summary for middle names since none was set.');
244
- return null;
245
- }
246
- return new models_1.Summary(this.fullname.middlename
247
- .map(n => n.namon)
248
- .join(models_1.Separator.SPACE));
249
- default:
250
- return this.summary;
307
+ * @param {options.orderedBy} forces to order by first or last name by
308
+ * overriding the preset configuration.
309
+ * @param
310
+ *
311
+ * For example, given the names:
312
+ * - `John Smith` => `['J', 'S']`
313
+ * - `John Ben Smith` => `['J', 'B', 'S']`.
314
+ */
315
+ initials(options) {
316
+ const initials = [];
317
+ const firstInits = this._fullName.firstName.initials();
318
+ const midInits = this._fullName.middleName.map((n) => n.initials()[0]);
319
+ const lastInits = this._fullName.lastName.initials();
320
+ const mergedOptions = Object.assign({ orderedBy: this._config.orderedBy, only: types_1.NameType.BIRTH_NAME }, options);
321
+ const { orderedBy, only } = mergedOptions;
322
+ if (only !== types_1.NameType.BIRTH_NAME) {
323
+ if (only === types_1.NameType.FIRST_NAME) {
324
+ initials.push(...firstInits);
325
+ }
326
+ else if (only === types_1.NameType.MIDDLE_NAME) {
327
+ initials.push(...midInits);
328
+ }
329
+ else {
330
+ initials.push(...lastInits);
331
+ }
332
+ }
333
+ else if (orderedBy === types_1.NameOrder.FIRST_NAME) {
334
+ initials.push(...firstInits, ...midInits, ...lastInits);
335
+ }
336
+ else {
337
+ initials.push(...lastInits, ...firstInits, ...midInits);
251
338
  }
339
+ return initials;
252
340
  }
253
341
  /**
254
342
  * Shortens a complex full name to a simple typical name, a combination of
255
- * first name and last name.
256
- * @param {NameOrder} orderedBy force to order by first or last
257
- * name by overriding the preset configuration
343
+ * first and last name.
344
+ *
345
+ * @param orderedBy forces to order by first or last name by overriding the
346
+ * preset configuration.
258
347
  *
259
- * @example
260
348
  * For a given name such as `Mr Keanu Charles Reeves`, shortening this name
261
349
  * is equivalent to making it `Keanu Reeves`.
262
350
  *
263
351
  * As a shortened name, the namon of the first name is favored over the other
264
352
  * names forming part of the entire first names, if any. Meanwhile, for
265
- * the last name, the configured `lastnameFormat` is prioritized.
353
+ * the last name, the configured `surname` is prioritized.
266
354
  *
267
- * @example
268
- * For a given `Firstname Fathername Mothername`, shortening this name when
269
- * the lastnameFormat is set as `mother` is equivalent to making it:
270
- * `Firstname Mothername`.
355
+ * For a given `FirstName FatherName MotherName`, shortening this name when
356
+ * the surname is set as `mother` is equivalent to making it:
357
+ * `FirstName MotherName`.
271
358
  */
272
359
  shorten(orderedBy) {
273
- orderedBy = orderedBy || this.config.orderedBy; // override config
274
- const { firstname, lastname } = this.fullname;
275
- return orderedBy === 'firstname'
276
- ? [firstname.namon, lastname.tostring()].join(models_1.Separator.SPACE)
277
- : [lastname.tostring(), firstname.namon].join(models_1.Separator.SPACE);
278
- }
279
- /**
280
- * Compresses a name by using different forms of variants
281
- * @param {number} [limit] a threshold to limit the number of characters
282
- * @param {'firstname'|'lastname'|'middlename'|'firstmid'|'midlast'} [by]
283
- * a variant to use when compressing the long name. The last two variants
284
- * represent respectively the combination of `firstname + middlename` and
285
- * `middlename + lastname`.
286
- * @param {boolean} [warning] should warn when the set limit is violated
360
+ orderedBy = orderedBy || this._config.orderedBy;
361
+ return orderedBy === types_1.NameOrder.FIRST_NAME
362
+ ? [this._fullName.firstName.value, this._fullName.lastName.toString()].join(' ')
363
+ : [this._fullName.lastName.toString(), this._fullName.firstName.value].join(' ');
364
+ }
365
+ /**
366
+ * Flattens a long name using the name types as variants.
367
+ *
368
+ * While @param limit sets a threshold as a limited number of characters
369
+ * supported to flatten a `FullName`, @param by indicates which variant
370
+ * to use when doing so. By default, a full name gets flattened by
371
+ * `Flat.MIDDLE_NAME`.
287
372
  *
288
- * @example
289
- * The compressing operation is only executed iff there is valid entry and it
290
- * surpasses the limit set. In the examples below, let us assume that the
373
+ * The flattening operation is only executed iff there is a valid entry and
374
+ * it surpasses the limit set. In the examples below, let us assume that the
291
375
  * name goes beyond the limit value.
292
376
  *
293
- * Compressing a long name refers to reducing the name to the following forms:
294
- * 1. by firstname: 'John Moe Beau Lennon' => 'J. Moe Beau Lennon'
295
- * 2. by middlename: 'John Moe Beau Lennon' => 'John M. B. Lennon'
296
- * 3. by lastname: 'John Moe Beau Lennon' => 'John Moe Beau L.'
297
- * 4. by firstmid: 'John Moe Beau Lennon' => 'J. M. B. Lennon'
298
- * 5. by midlast: 'John Moe Beau Lennon' => 'John M. B. L.'
377
+ * Flattening a long name refers to reducing the name to the following forms.
378
+ * For example, `John Winston Ono Lennon` flattened by:
379
+ * * Flat.FIRST_NAME: => 'J. Winston Ono Lennon'
380
+ * * Flat.MIDDLE_NAME: => 'John W. O. Lennon'
381
+ * * Flat.LAST_NAME: => 'John Winston Ono L.'
382
+ * * Flat.FIRST_MID: => 'J. W. O. Lennon'
383
+ * * Flat.MID_LAST: => 'John W. O. L.'
384
+ * * Flat.ALL: => 'J. W. O. L.'
299
385
  *
300
- * By default, it compresses by 'firstmid' variant: 'J. M. B. Lennon'.
301
- */
302
- compress(limit = 20, by = 'mn', warning = true) {
303
- if (this.getFullname().length <= limit) // no need to compress
304
- return this.getFullname();
305
- const { firstname: fn, lastname: ln, middlename } = this.fullname;
306
- const mn = this.getMiddlenames().join(models_1.Separator.SPACE);
307
- const hasmid = Array.isArray(middlename) && middlename.length > 0;
308
- const sep = models_1.Separator.PERIOD;
309
- const firsts = fn.getInitials().join(sep).concat(sep);
310
- const lasts = ln.getInitials().join(sep).concat(sep);
311
- const mids = hasmid
312
- ? middlename.map(n => n.getInitials()).join(sep).concat(sep)
313
- : models_1.Separator.EMPTY;
314
- let cname = '';
315
- if (this.config.orderedBy === 'firstname') {
386
+ * With the help of the @param recursive flag, the above operation can happen
387
+ * recursively in the same order if the name is still too long. For example,
388
+ * flattening `John Winston Ono Lennon` using the following params:
389
+ * `flatten({ limit: 18, by: Flat.FIRST_NAME, recursive: true })`
390
+ * will result in `John W. O. Lennon` and not `J. Winston Ono Lennon`.
391
+ *
392
+ * A shorter version of this method is `zip()`.
393
+ */
394
+ flatten(options) {
395
+ if (this.length <= options.limit)
396
+ return this.full;
397
+ const mergedOptions = Object.assign({ limit: 20, by: types_1.Flat.MIDDLE_NAME, withPeriod: true, recursive: false, withMore: false }, options);
398
+ const { by, limit, recursive, withMore, withPeriod, surname } = mergedOptions;
399
+ const sep = withPeriod ? '.' : '';
400
+ const fn = this._fullName.firstName.toString();
401
+ const mn = this.middleName().join(' ');
402
+ const ln = this._fullName.lastName.toString();
403
+ const hasMid = this.hasMiddle;
404
+ const f = this._fullName.firstName.initials(withMore).join(sep + ' ') + sep;
405
+ const l = this._fullName.lastName.initials(surname).join(sep + ' ') + sep;
406
+ const m = hasMid ? this._fullName.middleName.map((n) => n.initials()[0]).join(sep + ' ') + sep : '';
407
+ let name = [];
408
+ if (this._config.orderedBy === types_1.NameOrder.FIRST_NAME) {
316
409
  switch (by) {
317
- case 'firstname':
318
- case 'fn':
319
- cname = hasmid ?
320
- [firsts, mn, ln.tostring()].join(models_1.Separator.SPACE) :
321
- [firsts, ln.tostring()].join(models_1.Separator.SPACE);
410
+ case types_1.Flat.FIRST_NAME:
411
+ name = hasMid ? [f, mn, ln] : [f, ln];
322
412
  break;
323
- case 'lastname':
324
- case 'ln':
325
- cname = hasmid ?
326
- [fn.tostring(), mn, lasts].join(models_1.Separator.SPACE) :
327
- [fn.tostring(), lasts].join(models_1.Separator.SPACE);
413
+ case types_1.Flat.LAST_NAME:
414
+ name = hasMid ? [fn, mn, l] : [fn, l];
328
415
  break;
329
- case 'middlename':
330
- case 'mn':
331
- cname = hasmid ?
332
- [fn.tostring(), mids, ln.tostring()].join(models_1.Separator.SPACE) :
333
- [fn.tostring(), ln.tostring()].join(models_1.Separator.SPACE);
416
+ case types_1.Flat.MIDDLE_NAME:
417
+ name = hasMid ? [fn, m, ln] : [fn, ln];
334
418
  break;
335
- case 'firstmid':
336
- case 'fm':
337
- cname = hasmid ?
338
- [firsts, mids, ln.tostring()].join(models_1.Separator.SPACE) :
339
- [firsts, ln.tostring()].join(models_1.Separator.SPACE);
419
+ case types_1.Flat.FIRST_MID:
420
+ name = hasMid ? [f, m, ln] : [f, ln];
340
421
  break;
341
- case 'midlast':
342
- case 'ml':
343
- cname = hasmid ?
344
- [fn.tostring(), mids, lasts].join(models_1.Separator.SPACE) :
345
- [fn.tostring(), lasts].join(models_1.Separator.SPACE);
422
+ case types_1.Flat.MID_LAST:
423
+ name = hasMid ? [fn, m, l] : [fn, l];
424
+ break;
425
+ case types_1.Flat.ALL:
426
+ name = hasMid ? [f, m, l] : [f, l];
346
427
  break;
347
428
  }
348
429
  }
349
430
  else {
350
431
  switch (by) {
351
- case 'firstname':
352
- case 'fn':
353
- cname = hasmid ?
354
- [ln.tostring(), firsts, mn].join(models_1.Separator.SPACE) :
355
- [ln.tostring(), firsts].join(models_1.Separator.SPACE);
432
+ case types_1.Flat.FIRST_NAME:
433
+ name = hasMid ? [ln, f, mn] : [ln, f];
434
+ break;
435
+ case types_1.Flat.LAST_NAME:
436
+ name = hasMid ? [l, fn, mn] : [l, fn];
356
437
  break;
357
- case 'lastname':
358
- case 'ln':
359
- cname = hasmid ?
360
- [lasts, fn.tostring(), mn].join(models_1.Separator.SPACE) :
361
- [lasts, fn.tostring()].join(models_1.Separator.SPACE);
438
+ case types_1.Flat.MIDDLE_NAME:
439
+ name = hasMid ? [ln, fn, m] : [ln, fn];
362
440
  break;
363
- case 'middlename':
364
- case 'mn':
365
- cname = hasmid ?
366
- [ln.tostring(), fn.tostring(), mids].join(models_1.Separator.SPACE) :
367
- [ln.tostring(), fn.tostring()].join(models_1.Separator.SPACE);
441
+ case types_1.Flat.FIRST_MID:
442
+ name = hasMid ? [ln, f, m] : [ln, f];
368
443
  break;
369
- case 'firstmid':
370
- case 'fm':
371
- cname = hasmid ?
372
- [ln.tostring(), firsts, mids].join(models_1.Separator.SPACE) :
373
- [ln.tostring(), firsts].join(models_1.Separator.SPACE);
444
+ case types_1.Flat.MID_LAST:
445
+ name = hasMid ? [l, fn, m] : [l, fn];
374
446
  break;
375
- case 'midlast':
376
- case 'ml':
377
- cname = hasmid ?
378
- [lasts, fn.tostring(), mids].join(models_1.Separator.SPACE) :
379
- [lasts, fn.tostring()].join(models_1.Separator.SPACE);
447
+ case types_1.Flat.ALL:
448
+ name = hasMid ? [l, f, m] : [l, f];
380
449
  break;
381
450
  }
382
451
  }
383
- if (warning && cname.length > limit)
384
- console.warn(`The compressed name <${cname}> still surpasses the set limit ${limit}`);
385
- return cname;
386
- }
387
- /**
388
- * Zips or compresses a name by using different forms of variants
389
- * @param by a variant to use when compressing the long name. The last two
390
- * variants represent respectively the combination of `firstname + middlename`
391
- * and `middlename + lastname`.
392
- */
393
- zip(by = 'mn') {
394
- let v;
395
- if (by === 'fn' || by === 'firstname')
396
- v = 'firstname';
397
- if (by === 'mn' || by === 'middlename')
398
- v = 'middlename';
399
- if (by === 'ln' || by === 'lastname')
400
- v = 'lastname';
401
- if (by === 'fm' || by === 'firstmid')
402
- v = 'firstmid';
403
- if (by === 'ml' || by === 'midlast')
404
- v = 'midlast';
405
- return this.compress(0, v, false);
406
- }
407
- /**
408
- * Suggests possible (randomly) usernames closest to the name
452
+ const flat = name.join(' ');
453
+ if (recursive && flat.length > limit) {
454
+ const next = by === types_1.Flat.FIRST_NAME
455
+ ? types_1.Flat.MIDDLE_NAME
456
+ : by === types_1.Flat.MIDDLE_NAME
457
+ ? types_1.Flat.LAST_NAME
458
+ : by === types_1.Flat.LAST_NAME
459
+ ? types_1.Flat.FIRST_MID
460
+ : by === types_1.Flat.FIRST_MID
461
+ ? types_1.Flat.MID_LAST
462
+ : by === types_1.Flat.MID_LAST
463
+ ? types_1.Flat.ALL
464
+ : by === types_1.Flat.ALL
465
+ ? types_1.Flat.ALL
466
+ : by;
467
+ if (next === by)
468
+ return flat;
469
+ return this.flatten(Object.assign(Object.assign({}, options), { by: next }));
470
+ }
471
+ return flat;
472
+ }
473
+ /**
474
+ * Zips or compacts a name using different forms of variants.
409
475
  *
410
- * **NOTE**
411
- * The validity of these usernames are not checked against any social media
412
- * or web app online.
413
- */
414
- username() {
415
- const unames = [];
416
- const { firstname, lastname } = this.fullname;
417
- const p = models_1.Separator.PERIOD;
418
- const fn = firstname.tostring().toLowerCase();
419
- const ln = lastname.father.toLowerCase();
420
- // Given `John Smith`
421
- unames.push(fn + ln); // johnsmith
422
- unames.push(ln + fn); // smithjohn
423
- unames.push(fn[0] + ln); // jsmith
424
- unames.push(ln[0] + fn); // sjohn
425
- unames.push(fn[0] + p + ln); // j.smith
426
- unames.push(ln[0] + p + fn); // s.john
427
- unames.push(fn.slice(0, 2) + ln); // josmith
428
- unames.push(ln.slice(0, 2) + fn); // smjohn
429
- unames.push(fn.slice(0, 2) + p + ln); // jo.smith
430
- unames.push(ln.slice(0, 2) + p + fn); // sm.john
431
- return unames;
432
- }
433
- /**
434
- * Formats the name as desired
435
- * @param {string} how to format the full name
476
+ * @see `flatten()` for more details.
477
+ */
478
+ zip(by = types_1.Flat.MID_LAST, withPeriod = true) {
479
+ return this.flatten({ limit: 0, by, withPeriod });
480
+ }
481
+ /**
482
+ * Formats the full name as desired.
483
+ * @param pattern character used to format it.
436
484
  *
437
- * How to format it?
438
485
  * string format
439
486
  * -------------
440
- * 'short': typical first + last name
441
- * 'long': birth name (without prefix and suffix)
487
+ * - 'short': typical first + last name
488
+ * - 'long': birth name (without prefix and suffix)
489
+ * - 'public': first name combined with the last name's initial.
490
+ * - 'official': official document format
442
491
  *
443
492
  * char format
444
493
  * -----------
445
- * 'b': birth name
446
- * 'B': capitalized birth name
447
- * 'f': first name
448
- * 'F': capitalized first name
449
- * 'l': last name (official)
450
- * 'L': capitalized last name
451
- * 'm': middle names
452
- * 'M': capitalized middle names
453
- * 'o': official document format
454
- * 'O': official document format in capital letters
455
- * 'p': prefix
456
- * 'P': capitalized prefix
457
- * 's': suffix
458
- * 'S': capitalized suffix
494
+ * - 'b': birth name
495
+ * - 'B': capitalized birth name
496
+ * - 'f': first name
497
+ * - 'F': capitalized first name
498
+ * - 'l': last name
499
+ * - 'L': capitalized last name
500
+ * - 'm': middle names
501
+ * - 'M': capitalized middle names
502
+ * - 'o': official document format
503
+ * - 'O': official document format in capital letters
504
+ * - 'p': prefix
505
+ * - 'P': capitalized prefix
506
+ * - 's': suffix
507
+ * - 'S': capitalized suffix
459
508
  *
460
509
  * punctuations
461
510
  * ------------
462
- * '.': period
463
- * ',': comma
464
- * ' ': space
465
- * '-': hyphen
466
- * '_': underscore
511
+ * - '.': period
512
+ * - ',': comma
513
+ * - ' ': space
514
+ * - '-': hyphen
515
+ * - '_': underscore
516
+ * - '$': an escape character to select only the initial of the next char.
467
517
  *
468
- * @example
469
- * Given the name `Joe Jim Smith`, call the `format` with the how string.
518
+ * Given the name `Joe Jim Smith`, use `format` with the `pattern` string.
470
519
  * - format('l f') => 'Smith Joe'
471
520
  * - format('L, f') => 'SMITH, Joe'
472
521
  * - format('short') => 'Joe Smith'
473
522
  * - format() => 'SMITH, Joe Jim'
523
+ * - format(r'f $l.') => 'Joe S.'.
524
+ *
525
+ * Do note that the escape character is only valid for the birth name parts:
526
+ * first, middle, and last names.
474
527
  */
475
- format(how = 'official') {
476
- if (how === 'short')
477
- return this.shorten();
478
- if (how === 'long')
479
- return this.getBirthname();
480
- if (how === 'official')
481
- how = 'o';
528
+ format(pattern) {
529
+ var _a;
530
+ if (pattern === 'short')
531
+ return this.short;
532
+ if (pattern === 'long')
533
+ return this.long;
534
+ if (pattern === 'public')
535
+ return this.public;
536
+ if (pattern === 'official')
537
+ pattern = 'o';
538
+ let group = '';
482
539
  const formatted = [];
483
- const tokens = [
484
- '.', ',', ' ', '-', '_', 'b', 'B', 'f', 'F', 'l', 'L', 'm', 'M',
485
- 'n', 'N', 'o', 'O', 'p', 'P', 's', 'S'
486
- ];
487
- for (const c of how) {
488
- if (tokens.indexOf(c) === -1)
489
- throw new Error(`<${c}> is an invalid character for the formatting.`);
490
- formatted.push(this.map(c));
540
+ for (const char of pattern.split('')) {
541
+ if (constants_1.ALLOWED_TOKENS.indexOf(char) === -1) {
542
+ throw new error_1.NotAllowedError({
543
+ source: this.full,
544
+ operation: 'format',
545
+ message: `unsupported character <${char}> from ${pattern}.`,
546
+ });
547
+ }
548
+ group += char;
549
+ if (char === '$')
550
+ continue;
551
+ formatted.push((_a = this.map(group)) !== null && _a !== void 0 ? _a : '');
552
+ group = '';
491
553
  }
492
- return formatted.join(models_1.Separator.EMPTY).trim();
554
+ return formatted.join('').trim();
493
555
  }
494
556
  /**
495
- * Returns the count of characters of the birth name, excluding punctuations
557
+ * Flips definitely the name order from the preset/current config.
496
558
  */
497
- size() {
498
- return new models_1.Summary(this.getBirthname(), [...core_1.RESTRICTED_CHARS]).count;
559
+ flip() {
560
+ if (this._config.orderedBy === types_1.NameOrder.FIRST_NAME) {
561
+ this._config.updateOrder(types_1.NameOrder.LAST_NAME);
562
+ console.log(`The name order is now changed to: ${types_1.NameOrder.LAST_NAME}`);
563
+ }
564
+ else {
565
+ this._config.updateOrder(types_1.NameOrder.FIRST_NAME);
566
+ console.log(`The name order is now changed to: ${types_1.NameOrder.FIRST_NAME}`);
567
+ }
499
568
  }
500
569
  /**
501
- * Returns an ascii representation of each characters of a name as specified
502
- * @param options use specifics to shape conversion
570
+ * Splits the name parts of a birth name.
571
+ * @param separator token for the split.
503
572
  */
504
- ascii(options = {}) {
505
- const { exceptions: restrictions } = options;
506
- const nameType = core_1.allowShortNameType(options.nameType);
507
- const { firstname, lastname, middlename } = this.fullname;
508
- switch (nameType) {
509
- case 'firstname':
510
- return firstname.ascii(restrictions);
511
- case 'lastname':
512
- return lastname.ascii(restrictions);
513
- case 'middlename':
514
- if (!this.hasMiddlename())
515
- console.warn(`No ASCII conversion for middle names since none was set.`);
516
- return middlename
517
- .map(n => n.ascii(restrictions)) // convert
518
- .reduce((acc, value) => acc.concat(value), []); // then flatten
519
- default:
520
- const firsts = firstname.ascii(restrictions);
521
- const mids = middlename
522
- .map(n => n.ascii(restrictions))
523
- .reduce((acc, value) => acc.concat(value), []);
524
- const lasts = lastname.ascii(restrictions);
525
- if (this.config.orderedBy === 'firstname') {
526
- return firsts.concat(mids, lasts);
527
- }
528
- return lasts.concat(firsts, mids);
529
- }
573
+ split(separator = /[' -]/g) {
574
+ return this.birth.replace(separator, ' ').split(' ');
530
575
  }
531
576
  /**
532
- * Transforms a birth name to a specific case
533
- * @param case which case to convert a birth name to
534
- */
535
- to(_case) {
536
- const birthname = this.getBirthname();
537
- const nama = birthname
538
- .replace(/[' -]/g, models_1.Separator.SPACE)
539
- .split(models_1.Separator.SPACE);
540
- switch (_case) {
541
- case 'upper':
542
- return birthname.toUpperCase();
543
- case 'lower':
544
- return birthname.toLowerCase();
545
- case 'camel':
546
- case 'pascal':
547
- const pascalCase = nama.map(n => core_1.capitalize(n)).join(models_1.Separator.EMPTY);
548
- return _case === 'camel' ? core_1.decapitalize(pascalCase) : pascalCase;
549
- case 'snake':
550
- return nama.map(n => n.toLowerCase()).join(models_1.Separator.UNDERSCORE);
551
- case 'hyphen':
552
- return nama.map(n => n.toLowerCase()).join(models_1.Separator.HYPHEN);
553
- case 'dot':
554
- return nama.map(n => n.toLowerCase()).join(models_1.Separator.PERIOD);
555
- case 'toggle':
556
- return core_1.toggleCase(birthname);
557
- default:
558
- return models_1.Separator.EMPTY;
559
- }
577
+ * Joins the name parts of a birth name.
578
+ * @param separator token for the junction.
579
+ */
580
+ join(separator = '') {
581
+ return this.split().join(separator);
560
582
  }
561
583
  /**
562
- * Returns a password-like representation of a name
563
- * @param {NameType} [what] which name part
564
- */
565
- passwd(what) {
566
- what = core_1.allowShortNameType(what);
567
- switch (what) {
568
- case 'firstname':
569
- return this.fullname.firstname.passwd();
570
- case 'lastname':
571
- return this.fullname.lastname.passwd();
572
- case 'middlename':
573
- if (!this.hasMiddlename())
574
- console.warn('No password for middle names since none was set.');
575
- return this.fullname.middlename
576
- .map(n => n.passwd())
577
- .join(models_1.Separator.EMPTY);
578
- default:
579
- return core_1.generatePassword(this.getBirthname());
580
- }
584
+ * Transforms a birth name into UPPERCASE
585
+ */
586
+ toUpperCase() {
587
+ return this.birth.toUpperCase();
588
+ }
589
+ /**
590
+ * Transforms a birth name into lowercase
591
+ */
592
+ toLowerCase() {
593
+ return this.birth.toLowerCase();
594
+ }
595
+ /**
596
+ * Transforms a birth name into camelCase
597
+ */
598
+ toCamelCase() {
599
+ return utils_1.decapitalize(this.toPascalCase());
600
+ }
601
+ /**
602
+ * Transforms a birth name into PascalCase
603
+ */
604
+ toPascalCase() {
605
+ return this.split()
606
+ .map((n) => utils_1.capitalize(n))
607
+ .join('');
608
+ }
609
+ /**
610
+ * Transforms a birth name into snake_case
611
+ */
612
+ toSnakeCase() {
613
+ return this.split()
614
+ .map((n) => n.toLowerCase())
615
+ .join('_');
581
616
  }
582
- hasMiddlename() {
583
- return Array.isArray(this.fullname.middlename) && this.fullname.middlename.length > 0;
617
+ /**
618
+ * Transforms a birth name into hyphen-case
619
+ */
620
+ toHyphenCase() {
621
+ return this.split()
622
+ .map((n) => n.toLowerCase())
623
+ .join('-');
624
+ }
625
+ /**
626
+ * Transforms a birth name into dot.case
627
+ */
628
+ toDotCase() {
629
+ return this.split()
630
+ .map((n) => n.toLowerCase())
631
+ .join('.');
584
632
  }
585
- configure(options) {
586
- // consider using deepmerge if objects no longer stay shallow
587
- this.config = Object.assign(Object.assign({}, core_1.CONFIG), options); // if options, it overrides CONFIG
588
- this.config.orderedBy = core_1.allowShortNameOrder(this.config.orderedBy);
633
+ /**
634
+ * Transforms a birth name into ToGgLeCaSe
635
+ */
636
+ toToggleCase() {
637
+ return utils_1.toggleCase(this.birth);
589
638
  }
590
- initialize(parser) {
591
- const { orderedBy, separator, bypass, lastnameFormat } = this.config;
592
- this.fullname = parser.parse({ orderedBy, separator, bypass, lastnameFormat });
639
+ build(parser, options) {
640
+ this._config = config_1.Config.merge(options);
641
+ this._fullName = parser.parse(this._config);
593
642
  }
594
- parseNameOrder(orderedBy) {
595
- orderedBy = orderedBy || this.config.orderedBy; // override config
596
- return core_1.allowShortNameOrder(orderedBy);
643
+ toParser(raw) {
644
+ if (raw instanceof parser_1.Parser)
645
+ return raw;
646
+ if (typeof raw === 'string')
647
+ return new parser_1.StringParser(raw);
648
+ if (utils_1.isStringArray(raw))
649
+ return new parser_1.ArrayStringParser(raw);
650
+ if (utils_1.isNameArray(raw))
651
+ return new parser_1.ArrayNameParser(raw);
652
+ if (typeof raw === 'object')
653
+ return new parser_1.NamaParser(raw);
654
+ throw new error_1.InputError({
655
+ source: raw,
656
+ message: 'Cannot parse raw data. Review expected data types.',
657
+ });
597
658
  }
598
- map(c) {
599
- const { firstname, lastname, middlename, prefix, suffix } = this.fullname;
600
- switch (c) {
659
+ map(char) {
660
+ var _a, _b;
661
+ switch (char) {
601
662
  case '.':
602
- return models_1.Separator.PERIOD;
603
663
  case ',':
604
- return models_1.Separator.COMMA;
605
664
  case ' ':
606
- return models_1.Separator.SPACE;
607
665
  case '-':
608
- return models_1.Separator.HYPHEN;
609
666
  case '_':
610
- return models_1.Separator.UNDERSCORE;
667
+ return char;
611
668
  case 'b':
612
- return this.getBirthname();
669
+ return this.birth;
613
670
  case 'B':
614
- return this.getBirthname().toUpperCase();
671
+ return this.birth.toUpperCase();
615
672
  case 'f':
616
- return firstname.tostring();
673
+ return this.first;
617
674
  case 'F':
618
- return firstname.tostring().toUpperCase();
675
+ return this.first.toUpperCase();
619
676
  case 'l':
620
- return lastname.tostring();
677
+ return this.last;
621
678
  case 'L':
622
- return lastname.tostring().toUpperCase();
679
+ return this.last.toUpperCase();
623
680
  case 'm':
624
- if (!this.hasMiddlename()) {
625
- console.warn('No formatting for middle names since none was set.');
626
- return models_1.Separator.EMPTY;
627
- }
628
- return this.fullname.middlename.map(n => n.namon).join(models_1.Separator.SPACE);
629
681
  case 'M':
630
- if (!this.hasMiddlename()) {
631
- console.warn('No formatting for middle names since none was set.');
632
- return models_1.Separator.EMPTY;
633
- }
634
- return middlename.map(n => n.namon.toUpperCase()).join(models_1.Separator.SPACE);
682
+ return char === 'm' ? this.middleName().join(' ') : this.middleName().join(' ').toUpperCase();
635
683
  case 'o':
636
684
  case 'O':
637
- const { titling, ending } = this.config;
638
- const pxSep = titling === 'us' ? models_1.Separator.PERIOD : models_1.Separator.EMPTY;
639
- const sxSep = ending ? ',' : models_1.Separator.EMPTY;
640
- const nama = [];
641
- if (prefix)
642
- nama.push(prefix.concat(pxSep));
643
- nama.push(lastname.tostring().concat(models_1.Separator.COMMA).toUpperCase());
644
- if (this.hasMiddlename()) {
645
- nama.push(firstname.tostring());
646
- nama.push(middlename.map(n => n.namon).join(models_1.Separator.SPACE).concat(sxSep));
685
+ const sep = this._config.ending ? ',' : '';
686
+ const names = [];
687
+ if (this.prefix)
688
+ names.push(this.prefix);
689
+ names.push(`${this.last},`.toUpperCase());
690
+ if (this.hasMiddle) {
691
+ names.push(this.first, this.middleName().join(' ') + sep);
647
692
  }
648
693
  else {
649
- nama.push(firstname.tostring().concat(sxSep));
694
+ names.push(this.first + sep);
650
695
  }
651
- nama.push(suffix || models_1.Separator.EMPTY);
652
- const official = nama.join(models_1.Separator.SPACE).trim();
653
- return c === 'o' ? official : official.toUpperCase();
696
+ if (this.suffix)
697
+ names.push(this.suffix);
698
+ const nama = names.join(' ').trim();
699
+ return char === 'o' ? nama : nama.toUpperCase();
654
700
  case 'p':
655
- return prefix || models_1.Separator.EMPTY;
701
+ return this.prefix;
656
702
  case 'P':
657
- return prefix ? prefix.toUpperCase() : models_1.Separator.EMPTY;
703
+ return (_a = this.prefix) === null || _a === void 0 ? void 0 : _a.toUpperCase();
658
704
  case 's':
659
- return suffix || models_1.Separator.EMPTY;
705
+ return this.suffix;
660
706
  case 'S':
661
- return suffix ? suffix.toUpperCase() : models_1.Separator.EMPTY;
662
- }
663
- }
664
- build(raw) {
665
- if (this.config.parser) {
666
- this.initialize(this.config.parser);
667
- }
668
- else if (typeof raw === 'string') { // check for string type
669
- this.initialize(new core_1.StringParser(raw));
670
- }
671
- else if (Array.isArray(raw) && raw.length) { // check for T[]
672
- if (typeof raw[0] === 'string') { // check for string[]
673
- for (const key of raw)
674
- if (typeof key !== 'string')
675
- throw new Error(`Cannot parse raw data as array of 'string'`);
676
- this.initialize(new core_1.ArrayStringParser(raw));
677
- }
678
- else if (raw[0] instanceof models_1.Name) { // check for Name[]
679
- for (const obj of raw)
680
- if (!(obj instanceof models_1.Name))
681
- throw new Error(`Cannot parse raw data as array of 'Name'`);
682
- this.initialize(new core_1.ArrayNameParser(raw));
683
- }
684
- else {
685
- // typescript should stop them, but let's be paranoid (for JS developers)
686
- throw new Error(`Cannot parse raw data as arrays that are not of 'Name' or string`);
687
- }
688
- }
689
- else if (raw instanceof Object) { // check for json object
690
- for (const [key, value] of Object.entries(raw)) { // make sure keys are correct
691
- if (['firstname', 'lastname', 'middlename', 'prefix', 'suffix'].indexOf(key) === -1)
692
- throw new Error(`Cannot parse raw data as json object that does not contains keys of` +
693
- `'${Object.keys(models_1.Namon)}'`);
694
- // make sure the values are proper string or object
695
- if (typeof value !== 'string' && typeof value !== 'object')
696
- throw new Error(`Cannot parse raw data. The key <${key}> should be a 'string|object' type`);
697
- }
698
- if (typeof raw['firstname'] === 'string') // this key must always exist
699
- this.initialize(new core_1.NamaParser(raw));
700
- else
701
- this.fullname = raw;
702
- }
703
- else {
704
- // typescript should stop them, but let's be paranoid again (for JS developers)
705
- throw new Error(`Cannot parse raw data. Review the data type expected.`);
707
+ return (_b = this.suffix) === null || _b === void 0 ? void 0 : _b.toUpperCase();
708
+ case '$f':
709
+ case '$F':
710
+ return this._fullName.firstName.initials()[0];
711
+ case '$l':
712
+ case '$L':
713
+ return this._fullName.lastName.initials()[0];
714
+ case '$m':
715
+ case '$M':
716
+ return this.hasMiddle ? this.middle[0] : undefined;
717
+ default:
718
+ return undefined;
706
719
  }
707
- // paranoid coder mode: on :P
708
- if (!this.config.bypass)
709
- new validators_1.FullnameValidator().validate(this.fullname);
710
- this.summary = new models_1.Summary(this.getFullname());
711
720
  }
712
721
  }
713
722
  exports.Namefully = Namefully;
714
- Namefully.prototype.full = Namefully.prototype.getFullname;
715
- Namefully.prototype.birth = Namefully.prototype.getBirthname;
716
- Namefully.prototype.fn = Namefully.prototype.getFirstname;
717
- Namefully.prototype.ln = Namefully.prototype.getLastname;
718
- Namefully.prototype.mn = Namefully.prototype.getMiddlenames;
719
- Namefully.prototype.px = Namefully.prototype.getPrefix;
720
- Namefully.prototype.sx = Namefully.prototype.getSuffix;
721
- Namefully.prototype.inits = Namefully.prototype.getInitials;
722
- Namefully.prototype.stats = Namefully.prototype.describe;
723
723
  //# sourceMappingURL=namefully.js.map