namefully 1.2.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/cjs/builder.js +82 -0
  2. package/dist/cjs/config.js +100 -0
  3. package/dist/{lib → cjs}/constants.js +1 -1
  4. package/dist/{lib → cjs}/error.js +8 -5
  5. package/dist/cjs/fullname.js +102 -0
  6. package/dist/{lib → cjs}/index.js +18 -12
  7. package/dist/cjs/name.js +218 -0
  8. package/dist/cjs/namefully.js +391 -0
  9. package/dist/cjs/package.json +1 -0
  10. package/dist/cjs/parser.js +135 -0
  11. package/dist/{lib → cjs}/types.js +40 -36
  12. package/dist/{lib → cjs}/utils.js +29 -17
  13. package/dist/cjs/validator.js +266 -0
  14. package/dist/esm/builder.d.ts +73 -0
  15. package/dist/esm/builder.js +78 -0
  16. package/dist/{types → esm}/config.d.ts +1 -1
  17. package/dist/esm/config.js +96 -0
  18. package/dist/{types → esm}/constants.d.ts +1 -1
  19. package/dist/esm/constants.js +27 -0
  20. package/dist/{types → esm}/error.d.ts +2 -3
  21. package/dist/esm/error.js +87 -0
  22. package/dist/{types/full-name.d.ts → esm/fullname.d.ts} +3 -3
  23. package/dist/esm/fullname.js +98 -0
  24. package/dist/esm/index.d.ts +25 -0
  25. package/dist/esm/index.js +12 -0
  26. package/dist/{types → esm}/name.d.ts +2 -1
  27. package/dist/esm/name.js +211 -0
  28. package/dist/{types → esm}/namefully.d.ts +23 -13
  29. package/dist/esm/namefully.js +387 -0
  30. package/dist/esm/package.json +1 -0
  31. package/dist/{types → esm}/parser.d.ts +7 -6
  32. package/dist/esm/parser.js +127 -0
  33. package/dist/esm/types.js +106 -0
  34. package/dist/{types → esm}/utils.d.ts +4 -3
  35. package/dist/esm/utils.js +96 -0
  36. package/dist/{types → esm}/validator.d.ts +3 -3
  37. package/dist/esm/validator.js +259 -0
  38. package/dist/namefully.js +1580 -0
  39. package/dist/namefully.min.js +1 -0
  40. package/package.json +52 -32
  41. package/readme.md +63 -35
  42. package/dist/lib/config.js +0 -112
  43. package/dist/lib/full-name.js +0 -115
  44. package/dist/lib/name.js +0 -230
  45. package/dist/lib/namefully.js +0 -410
  46. package/dist/lib/parser.js +0 -138
  47. package/dist/lib/validator.js +0 -301
  48. package/dist/types/index.d.ts +0 -21
  49. package/dist/umd/namefully.js +0 -1832
  50. package/dist/umd/namefully.min.js +0 -1
  51. /package/dist/{types → esm}/types.d.ts +0 -0
@@ -0,0 +1,87 @@
1
+ import { isStringArray } from './utils.js';
2
+ export var NameErrorType;
3
+ (function (NameErrorType) {
4
+ NameErrorType[NameErrorType["INPUT"] = 0] = "INPUT";
5
+ NameErrorType[NameErrorType["VALIDATION"] = 1] = "VALIDATION";
6
+ NameErrorType[NameErrorType["NOT_ALLOWED"] = 2] = "NOT_ALLOWED";
7
+ NameErrorType[NameErrorType["UNKNOWN"] = 3] = "UNKNOWN";
8
+ })(NameErrorType || (NameErrorType = {}));
9
+ export class NameError extends Error {
10
+ source;
11
+ type;
12
+ constructor(source, message, type = NameErrorType.UNKNOWN) {
13
+ super(message);
14
+ this.source = source;
15
+ this.type = type;
16
+ this.name = 'NameError';
17
+ }
18
+ get sourceAsString() {
19
+ let input = '';
20
+ if (!this.source)
21
+ input = '<undefined>';
22
+ if (typeof this.source === 'string')
23
+ input = this.source;
24
+ if (isStringArray(this.source))
25
+ input = this.source.join(' ');
26
+ return input;
27
+ }
28
+ get hasMessage() {
29
+ return this.message.trim().length > 0;
30
+ }
31
+ toString() {
32
+ let report = `${this.name} (${this.sourceAsString})`;
33
+ if (this.hasMessage)
34
+ report = `${report}: ${this.message}`;
35
+ return report;
36
+ }
37
+ }
38
+ export class InputError extends NameError {
39
+ constructor(error) {
40
+ super(error.source, error.message, NameErrorType.INPUT);
41
+ this.name = 'InputError';
42
+ }
43
+ }
44
+ export class ValidationError extends NameError {
45
+ nameType;
46
+ constructor(error) {
47
+ super(error.source, error.message, NameErrorType.VALIDATION);
48
+ this.nameType = error.nameType;
49
+ this.name = 'ValidationError';
50
+ }
51
+ toString() {
52
+ let report = `${this.name} (${this.nameType}='${this.sourceAsString}')`;
53
+ if (this.hasMessage)
54
+ report = `${report}: ${this.message}`;
55
+ return report;
56
+ }
57
+ }
58
+ export class NotAllowedError extends NameError {
59
+ operation;
60
+ constructor(error) {
61
+ super(error.source, error.message, NameErrorType.NOT_ALLOWED);
62
+ this.operation = error.operation;
63
+ this.name = 'NotAllowedError';
64
+ }
65
+ toString() {
66
+ let report = `${this.name} (${this.sourceAsString})`;
67
+ if (this.operation && this.operation.trim().length > 0)
68
+ report = `${report} - ${this.operation}`;
69
+ if (this.hasMessage)
70
+ report = `${report}: ${this.message}`;
71
+ return report;
72
+ }
73
+ }
74
+ export class UnknownError extends NameError {
75
+ origin;
76
+ constructor(error) {
77
+ super(error.source, error.message, NameErrorType.UNKNOWN);
78
+ this.origin = error.error;
79
+ this.name = 'UnknownError';
80
+ }
81
+ toString() {
82
+ let report = super.toString();
83
+ if (this.origin)
84
+ report += `\n${this.origin.toString()}`;
85
+ return report;
86
+ }
87
+ }
@@ -1,6 +1,6 @@
1
- import { Config } from './config';
2
- import { FirstName, LastName, Name, JsonName } from './name';
3
- import { Nullable, Namon } from './types';
1
+ import { Config } from './config.js';
2
+ import { FirstName, LastName, Name, JsonName } from './name.js';
3
+ import { Nullable, Namon } from './types.js';
4
4
  /**
5
5
  * The core component of this utility.
6
6
  *
@@ -0,0 +1,98 @@
1
+ import { Config } from './config.js';
2
+ import { NameError, UnknownError } from './error.js';
3
+ import { FirstName, LastName, Name } from './name.js';
4
+ import { Namon, Title } from './types.js';
5
+ import { Validators } from './validator.js';
6
+ export class FullName {
7
+ #prefix;
8
+ #firstName;
9
+ #middleName = [];
10
+ #lastName;
11
+ #suffix;
12
+ #config;
13
+ constructor(options) {
14
+ this.#config = Config.merge(options);
15
+ }
16
+ get config() {
17
+ return this.#config;
18
+ }
19
+ get prefix() {
20
+ return this.#prefix;
21
+ }
22
+ get firstName() {
23
+ return this.#firstName;
24
+ }
25
+ get lastName() {
26
+ return this.#lastName;
27
+ }
28
+ get middleName() {
29
+ return this.#middleName;
30
+ }
31
+ get suffix() {
32
+ return this.#suffix;
33
+ }
34
+ static parse(json, config) {
35
+ try {
36
+ const fullName = new FullName(config);
37
+ fullName.setPrefix(json.prefix);
38
+ fullName.setFirstName(json.firstName);
39
+ fullName.setMiddleName(json.middleName ?? []);
40
+ fullName.setLastName(json.lastName);
41
+ fullName.setSuffix(json.suffix);
42
+ return fullName;
43
+ }
44
+ catch (error) {
45
+ if (error instanceof NameError)
46
+ throw error;
47
+ throw new UnknownError({
48
+ source: Object.values(json).join(' '),
49
+ message: 'could not parse JSON content',
50
+ error: error instanceof Error ? error : new Error(String(error)),
51
+ });
52
+ }
53
+ }
54
+ setPrefix(name) {
55
+ if (!name)
56
+ return this;
57
+ if (!this.#config.bypass)
58
+ Validators.prefix.validate(name);
59
+ const prefix = name instanceof Name ? name.value : name;
60
+ this.#prefix = Name.prefix(this.#config.title === Title.US ? `${prefix}.` : prefix);
61
+ return this;
62
+ }
63
+ setFirstName(name) {
64
+ if (!this.#config.bypass)
65
+ Validators.firstName.validate(name);
66
+ this.#firstName = name instanceof FirstName ? name : new FirstName(name);
67
+ return this;
68
+ }
69
+ setLastName(name) {
70
+ if (!this.#config.bypass)
71
+ Validators.lastName.validate(name);
72
+ this.#lastName = name instanceof LastName ? name : new LastName(name);
73
+ return this;
74
+ }
75
+ setMiddleName(names) {
76
+ if (!Array.isArray(names))
77
+ return this;
78
+ if (!this.#config.bypass)
79
+ Validators.middleName.validate(names);
80
+ this.#middleName = names.map((name) => (name instanceof Name ? name : Name.middle(name)));
81
+ return this;
82
+ }
83
+ setSuffix(name) {
84
+ if (!name)
85
+ return this;
86
+ if (!this.#config.bypass)
87
+ Validators.suffix.validate(name);
88
+ this.#suffix = Name.suffix(name instanceof Name ? name.value : name);
89
+ return this;
90
+ }
91
+ has(namon) {
92
+ if (namon.equal(Namon.PREFIX))
93
+ return !!this.#prefix;
94
+ if (namon.equal(Namon.SUFFIX))
95
+ return !!this.#suffix;
96
+ return namon.equal(Namon.MIDDLE_NAME) ? this.#middleName.length > 0 : true;
97
+ }
98
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Welcome to namefully!
3
+ *
4
+ * `namefully` is a JavaScript utility for handling personal names.
5
+ *
6
+ * Sources
7
+ * - repo: https://github.com/ralflorent/namefully
8
+ * - docs: https://namefully.netlify.app
9
+ * - npm: https://npmjs.com/package/namefully
10
+ * - jsr: https://jsr.io/@ralflorent/namefully
11
+ *
12
+ * @license MIT
13
+ */
14
+ import namefully from './namefully.js';
15
+ export * from './builder.js';
16
+ export * from './config.js';
17
+ export { VERSION as version } from './constants.js';
18
+ export * from './error.js';
19
+ export * from './fullname.js';
20
+ export * from './name.js';
21
+ export * from './namefully.js';
22
+ export { Parser } from './parser.js';
23
+ export * from './types.js';
24
+ export { NameIndex } from './utils.js';
25
+ export default namefully;
@@ -0,0 +1,12 @@
1
+ import namefully from './namefully.js';
2
+ export * from './builder.js';
3
+ export * from './config.js';
4
+ export { VERSION as version } from './constants.js';
5
+ export * from './error.js';
6
+ export * from './fullname.js';
7
+ export * from './name.js';
8
+ export * from './namefully.js';
9
+ export { Parser } from './parser.js';
10
+ export * from './types.js';
11
+ export { NameIndex } from './utils.js';
12
+ export default namefully;
@@ -1,4 +1,4 @@
1
- import { CapsRange, Namon, Surname } from './types';
1
+ import { CapsRange, Namon, Surname } from './types.js';
2
2
  /**
3
3
  * Representation of a string type name with some extra capabilities.
4
4
  */
@@ -114,6 +114,7 @@ export declare class LastName extends Name {
114
114
  format?: Surname;
115
115
  }): LastName;
116
116
  }
117
+ export declare function isNameArray(value?: unknown): boolean;
117
118
  /**
118
119
  * JSON signature for `FullName` data.
119
120
  */
@@ -0,0 +1,211 @@
1
+ import { InputError } from './error.js';
2
+ import { CapsRange, Namon, Surname } from './types.js';
3
+ import { capitalize, decapitalize } from './utils.js';
4
+ export class Name {
5
+ type;
6
+ #namon;
7
+ initial;
8
+ capsRange;
9
+ constructor(value, type, capsRange) {
10
+ this.type = type;
11
+ this.capsRange = capsRange ?? CapsRange.INITIAL;
12
+ this.value = value;
13
+ if (capsRange)
14
+ this.caps(capsRange);
15
+ }
16
+ set value(newValue) {
17
+ this.validate(newValue);
18
+ this.#namon = newValue;
19
+ this.initial = newValue[0];
20
+ }
21
+ get value() {
22
+ return this.#namon;
23
+ }
24
+ get length() {
25
+ return this.#namon.length;
26
+ }
27
+ get isPrefix() {
28
+ return this.type === Namon.PREFIX;
29
+ }
30
+ get isFirstName() {
31
+ return this.type === Namon.FIRST_NAME;
32
+ }
33
+ get isMiddleName() {
34
+ return this.type === Namon.MIDDLE_NAME;
35
+ }
36
+ get isLastName() {
37
+ return this.type === Namon.LAST_NAME;
38
+ }
39
+ get isSuffix() {
40
+ return this.type === Namon.SUFFIX;
41
+ }
42
+ static prefix(value) {
43
+ return new this(value, Namon.PREFIX);
44
+ }
45
+ static first(value) {
46
+ return new this(value, Namon.FIRST_NAME);
47
+ }
48
+ static middle(value) {
49
+ return new this(value, Namon.MIDDLE_NAME);
50
+ }
51
+ static last(value) {
52
+ return new this(value, Namon.LAST_NAME);
53
+ }
54
+ static suffix(value) {
55
+ return new this(value, Namon.SUFFIX);
56
+ }
57
+ initials() {
58
+ return [this.initial];
59
+ }
60
+ toString() {
61
+ return this.#namon;
62
+ }
63
+ equal(other) {
64
+ return other instanceof Name && other.value === this.value && other.type === this.type;
65
+ }
66
+ caps(range) {
67
+ this.value = capitalize(this.#namon, range ?? this.capsRange);
68
+ return this;
69
+ }
70
+ decaps(range) {
71
+ this.value = decapitalize(this.#namon, range ?? this.capsRange);
72
+ return this;
73
+ }
74
+ validate(name) {
75
+ if (name && name?.trim()?.length < 2) {
76
+ throw new InputError({ source: name, message: 'must be 2+ characters' });
77
+ }
78
+ }
79
+ }
80
+ export class FirstName extends Name {
81
+ #more;
82
+ constructor(value, ...more) {
83
+ super(value, Namon.FIRST_NAME);
84
+ more.forEach((n) => this.validate(n));
85
+ this.#more = more;
86
+ }
87
+ get hasMore() {
88
+ return this.#more.length > 0;
89
+ }
90
+ get length() {
91
+ return super.length + (this.hasMore ? this.#more.reduce((acc, n) => acc + n).length : 0);
92
+ }
93
+ get asNames() {
94
+ const names = [Name.first(this.value)];
95
+ if (this.hasMore) {
96
+ names.push(...this.#more.map((n) => Name.first(n)));
97
+ }
98
+ return names;
99
+ }
100
+ get more() {
101
+ return this.#more;
102
+ }
103
+ toString(withMore = false) {
104
+ return withMore && this.hasMore ? `${this.value} ${this.#more.join(' ')}`.trim() : this.value;
105
+ }
106
+ initials(withMore = false) {
107
+ const inits = [this.initial];
108
+ if (withMore && this.hasMore) {
109
+ inits.push(...this.#more.map((n) => n[0]));
110
+ }
111
+ return inits;
112
+ }
113
+ caps(range) {
114
+ range = range || this.capsRange;
115
+ this.value = capitalize(this.value, range);
116
+ if (this.hasMore)
117
+ this.#more = this.#more.map((n) => capitalize(n, range));
118
+ return this;
119
+ }
120
+ decaps(range) {
121
+ range = range || this.capsRange;
122
+ this.value = decapitalize(this.value, range);
123
+ if (this.hasMore)
124
+ this.#more = this.#more.map((n) => decapitalize(n, range));
125
+ return this;
126
+ }
127
+ copyWith(values) {
128
+ return new FirstName(values?.first ?? this.value, ...(values?.more ?? this.#more));
129
+ }
130
+ }
131
+ export class LastName extends Name {
132
+ format;
133
+ #mother;
134
+ constructor(father, mother, format = Surname.FATHER) {
135
+ super(father, Namon.LAST_NAME);
136
+ this.format = format;
137
+ this.validate(mother);
138
+ this.#mother = mother;
139
+ }
140
+ get father() {
141
+ return this.value;
142
+ }
143
+ get mother() {
144
+ return this.#mother;
145
+ }
146
+ get hasMother() {
147
+ return !!this.#mother;
148
+ }
149
+ get length() {
150
+ return super.length + (this.#mother?.length ?? 0);
151
+ }
152
+ get asNames() {
153
+ const names = [Name.last(this.value)];
154
+ if (this.#mother)
155
+ names.push(Name.last(this.#mother));
156
+ return names;
157
+ }
158
+ toString(format) {
159
+ format = format ?? this.format;
160
+ switch (format) {
161
+ case Surname.FATHER:
162
+ return this.value;
163
+ case Surname.MOTHER:
164
+ return this.mother ?? '';
165
+ case Surname.HYPHENATED:
166
+ return this.hasMother ? `${this.value}-${this.#mother}` : this.value;
167
+ case Surname.ALL:
168
+ return this.hasMother ? `${this.value} ${this.#mother}` : this.value;
169
+ }
170
+ }
171
+ initials(format) {
172
+ format = format || this.format;
173
+ const inits = [];
174
+ switch (format) {
175
+ case Surname.MOTHER:
176
+ if (this.#mother)
177
+ inits.push(this.#mother[0]);
178
+ break;
179
+ case Surname.HYPHENATED:
180
+ case Surname.ALL:
181
+ inits.push(this.initial);
182
+ if (this.#mother)
183
+ inits.push(this.#mother[0]);
184
+ break;
185
+ case Surname.FATHER:
186
+ default:
187
+ inits.push(this.initial);
188
+ }
189
+ return inits;
190
+ }
191
+ caps(range) {
192
+ range = range || this.capsRange;
193
+ this.value = capitalize(this.value, range);
194
+ if (this.hasMother)
195
+ this.#mother = capitalize(this.#mother, range);
196
+ return this;
197
+ }
198
+ decaps(range) {
199
+ range = range || this.capsRange;
200
+ this.value = decapitalize(this.value, range);
201
+ if (this.hasMother)
202
+ this.#mother = decapitalize(this.#mother, range);
203
+ return this;
204
+ }
205
+ copyWith(values) {
206
+ return new LastName(values?.father ?? this.value, values?.mother ?? this.mother, values?.format ?? this.format);
207
+ }
208
+ }
209
+ export function isNameArray(value) {
210
+ return Array.isArray(value) && value.length > 0 && value.every((e) => e instanceof Name);
211
+ }
@@ -1,7 +1,8 @@
1
- import { Config } from './config';
2
- import { Name, JsonName } from './name';
3
- import { Parser } from './parser';
4
- import { Flat, NameOrder, NameType, Namon, Nullable, Surname } from './types';
1
+ import { Config } from './config.js';
2
+ import { Name, JsonName } from './name.js';
3
+ import { Parser } from './parser.js';
4
+ import { Flat, NameOrder, NameType, Namon, Nullable, Surname } from './types.js';
5
+ import { NameIndex } from './utils.js';
5
6
  /**
6
7
  * A helper for organizing person names in a particular order, way, or shape.
7
8
  *
@@ -29,7 +30,7 @@ import { Flat, NameOrder, NameType, Namon, Nullable, Surname } from './types';
29
30
  * this: `John Smith`, where `John` is the first name piece and `Smith`, the last
30
31
  * name piece.
31
32
  *
32
- * @see https://departments.weber.edu/qsupport&training/Data_Standards/Name.htm
33
+ * @see https://www.fbiic.gov/public/2008/nov/Naming_practice_guide_UK_2006.pdf
33
34
  * for more info on name standards.
34
35
  *
35
36
  * **IMPORTANT**: Keep in mind that the order of appearance (or name order) matters
@@ -48,8 +49,7 @@ import { Flat, NameOrder, NameType, Namon, Nullable, Surname } from './types';
48
49
  */
49
50
  export declare class Namefully {
50
51
  #private;
51
- /**
52
- * Creates a name with distinguishable parts from a raw string content.
52
+ /** Creates a name with distinguishable parts from a raw string content.
53
53
  * @param names element to parse.
54
54
  * @param options additional settings.
55
55
  *
@@ -64,7 +64,7 @@ export declare class Namefully {
64
64
  * It works like `parse` except that this function returns `null` where `parse`
65
65
  * would throw a `NameError`.
66
66
  */
67
- static tryParse(text: string): Namefully | undefined;
67
+ static tryParse(text: string, index?: NameIndex): Namefully | undefined;
68
68
  /**
69
69
  * Constructs a `Namefully` instance from a text.
70
70
  *
@@ -80,23 +80,23 @@ export declare class Namefully {
80
80
  * Keep in mind that prefix and suffix are not considered during the parsing
81
81
  * process.
82
82
  */
83
- static parse(text: string): Promise<Namefully>;
83
+ static parse(text: string, index?: NameIndex): Promise<Namefully>;
84
84
  /** The current configuration. */
85
85
  get config(): Config;
86
86
  /** The number of characters of the `birthName`, including spaces. */
87
87
  get length(): number;
88
88
  /** The prefix part. */
89
- get prefix(): Nullable<string>;
89
+ get prefix(): string | undefined;
90
90
  /** The firt name part. */
91
91
  get first(): string;
92
92
  /** The first middle name part if any. */
93
- get middle(): Nullable<string>;
93
+ get middle(): string | undefined;
94
94
  /** Returns true if any middle name has been set. */
95
95
  get hasMiddle(): boolean;
96
96
  /** The last name part. */
97
97
  get last(): string;
98
98
  /** The suffix part. */
99
- get suffix(): Nullable<string>;
99
+ get suffix(): string | undefined;
100
100
  /** The birth name part. */
101
101
  get birth(): string;
102
102
  /** The shortest version of a person name. */
@@ -107,6 +107,8 @@ export declare class Namefully {
107
107
  get full(): string;
108
108
  /** The first name combined with the last name's initial. */
109
109
  get public(): string;
110
+ /** The combination of prefix and last name. */
111
+ get salutation(): string;
110
112
  /** Returns the full name as set. */
111
113
  toString(): string;
112
114
  /** Fetches the raw form of a name piece. */
@@ -171,7 +173,8 @@ export declare class Namefully {
171
173
  initials(options?: {
172
174
  orderedBy?: NameOrder;
173
175
  only?: NameType;
174
- }): string[];
176
+ asJson?: boolean;
177
+ }): string[] | Record<string, string[]>;
175
178
  /**
176
179
  * Shortens a complex full name to a simple typical name, a combination of
177
180
  * first and last name.
@@ -311,3 +314,10 @@ export declare class Namefully {
311
314
  /** Transforms a birth name into ToGgLeCaSe. */
312
315
  toToggleCase(): string;
313
316
  }
317
+ /**
318
+ * A default export for the `namefully` utility.
319
+ * @param names element to parse.
320
+ * @param options additional settings.
321
+ */
322
+ declare const _default: (names: string | string[] | Name[] | JsonName | Parser, options?: Partial<Config>) => Namefully;
323
+ export default _default;