namefully 2.1.0 → 2.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.
- package/dist/cjs/builder.js +5 -2
- package/dist/cjs/config.js +10 -5
- package/dist/cjs/constants.js +3 -2
- package/dist/cjs/data.js +5 -2
- package/dist/cjs/fullname.js +52 -7
- package/dist/cjs/namefully.js +44 -22
- package/dist/cjs/parser.js +28 -12
- package/dist/esm/builder.js +5 -2
- package/dist/esm/config.d.ts +4 -10
- package/dist/esm/config.js +10 -5
- package/dist/esm/constants.d.ts +2 -1
- package/dist/esm/constants.js +2 -1
- package/dist/esm/data.d.ts +3 -13
- package/dist/esm/data.js +5 -2
- package/dist/esm/fullname.d.ts +33 -0
- package/dist/esm/fullname.js +50 -6
- package/dist/esm/name.d.ts +9 -3
- package/dist/esm/namefully.d.ts +5 -2
- package/dist/esm/namefully.js +44 -22
- package/dist/esm/parser.d.ts +9 -6
- package/dist/esm/parser.js +28 -13
- package/dist/namefully.js +140 -49
- package/dist/namefully.min.js +1 -1
- package/package.json +2 -2
- package/readme.md +28 -4
package/dist/esm/fullname.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Config } from './config.js';
|
|
2
2
|
import { Validators } from './validator.js';
|
|
3
|
+
import { ZERO_WIDTH_SPACE } from './constants.js';
|
|
3
4
|
import { Namon, Title } from './types.js';
|
|
4
5
|
import { NameError, UnknownError } from './error.js';
|
|
5
6
|
import { FirstName, LastName, Name } from './name.js';
|
|
@@ -31,14 +32,18 @@ export class FullName {
|
|
|
31
32
|
get suffix() {
|
|
32
33
|
return this.#suffix;
|
|
33
34
|
}
|
|
35
|
+
get isMono() {
|
|
36
|
+
return this instanceof Mononym;
|
|
37
|
+
}
|
|
34
38
|
static parse(json, config) {
|
|
35
39
|
try {
|
|
40
|
+
const { prefix, firstName: fn, middleName: mn, lastName: ln, suffix } = json;
|
|
36
41
|
return new FullName(config)
|
|
37
|
-
.setPrefix(
|
|
38
|
-
.setFirstName(
|
|
39
|
-
.setMiddleName(
|
|
40
|
-
.setLastName(
|
|
41
|
-
.setSuffix(
|
|
42
|
+
.setPrefix(prefix)
|
|
43
|
+
.setFirstName(typeof fn === 'string' ? fn : new FirstName(fn.value, ...(fn.more ?? [])))
|
|
44
|
+
.setMiddleName(typeof mn === 'string' ? [mn] : (mn ?? []))
|
|
45
|
+
.setLastName(typeof ln === 'string' ? ln : new LastName(ln.father, ln.mother))
|
|
46
|
+
.setSuffix(suffix);
|
|
42
47
|
}
|
|
43
48
|
catch (error) {
|
|
44
49
|
if (error instanceof NameError)
|
|
@@ -56,7 +61,7 @@ export class FullName {
|
|
|
56
61
|
if (!this.#config.bypass)
|
|
57
62
|
Validators.prefix.validate(name);
|
|
58
63
|
const prefix = name instanceof Name ? name.value : name;
|
|
59
|
-
this.#prefix = Name.prefix(this.#config.title === Title.US ? `${prefix}.` : prefix);
|
|
64
|
+
this.#prefix = Name.prefix(this.#config.title === Title.US && !prefix.endsWith('.') ? `${prefix}.` : prefix);
|
|
60
65
|
return this;
|
|
61
66
|
}
|
|
62
67
|
setFirstName(name) {
|
|
@@ -97,6 +102,11 @@ export class FullName {
|
|
|
97
102
|
return !!this.#suffix;
|
|
98
103
|
return namon.equal(Namon.MIDDLE_NAME) ? this.#middleName.length > 0 : true;
|
|
99
104
|
}
|
|
105
|
+
toString() {
|
|
106
|
+
if (this.isMono)
|
|
107
|
+
return this.value;
|
|
108
|
+
return Array.from(this.toIterable(true)).join(' ');
|
|
109
|
+
}
|
|
100
110
|
*toIterable(flat = false) {
|
|
101
111
|
if (this.#prefix)
|
|
102
112
|
yield this.#prefix;
|
|
@@ -117,3 +127,37 @@ export class FullName {
|
|
|
117
127
|
yield* this.toIterable(true);
|
|
118
128
|
}
|
|
119
129
|
}
|
|
130
|
+
export class Mononym extends FullName {
|
|
131
|
+
#namon;
|
|
132
|
+
#type;
|
|
133
|
+
constructor(name, options) {
|
|
134
|
+
super(options ?? { name: 'mononym', mono: true });
|
|
135
|
+
this.#namon = name.toString();
|
|
136
|
+
this.type = name instanceof Name ? name.type : Namon.FIRST_NAME;
|
|
137
|
+
}
|
|
138
|
+
set type(type) {
|
|
139
|
+
this.#type = typeof type === 'string' ? (Namon.cast(type) ?? Namon.FIRST_NAME) : type;
|
|
140
|
+
this.#build(this.#namon);
|
|
141
|
+
}
|
|
142
|
+
get type() {
|
|
143
|
+
return this.#type;
|
|
144
|
+
}
|
|
145
|
+
get value() {
|
|
146
|
+
return this.#namon;
|
|
147
|
+
}
|
|
148
|
+
#build(name) {
|
|
149
|
+
this.setFirstName(ZERO_WIDTH_SPACE).setLastName(ZERO_WIDTH_SPACE).setMiddleName([]).setPrefix(null).setSuffix(null);
|
|
150
|
+
if (this.#type.equal(Namon.FIRST_NAME))
|
|
151
|
+
this.setFirstName(name);
|
|
152
|
+
else if (this.#type.equal(Namon.LAST_NAME))
|
|
153
|
+
this.setLastName(name);
|
|
154
|
+
else if (this.#type.equal(Namon.MIDDLE_NAME))
|
|
155
|
+
this.setMiddleName([name]);
|
|
156
|
+
else if (this.#type.equal(Namon.PREFIX))
|
|
157
|
+
this.setPrefix(name);
|
|
158
|
+
else if (this.#type.equal(Namon.SUFFIX))
|
|
159
|
+
this.setSuffix(name);
|
|
160
|
+
else
|
|
161
|
+
throw new NameError(name, 'invalid mononym type');
|
|
162
|
+
}
|
|
163
|
+
}
|
package/dist/esm/name.d.ts
CHANGED
|
@@ -112,8 +112,14 @@ export declare function isNameArray(value?: unknown): value is Name[];
|
|
|
112
112
|
/** JSON signature for `FullName` data. */
|
|
113
113
|
export interface JsonName {
|
|
114
114
|
prefix?: string;
|
|
115
|
-
firstName: string
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
firstName: string | {
|
|
116
|
+
value: string;
|
|
117
|
+
more?: string[];
|
|
118
|
+
};
|
|
119
|
+
middleName?: string | string[];
|
|
120
|
+
lastName: string | {
|
|
121
|
+
father: string;
|
|
122
|
+
mother?: string;
|
|
123
|
+
};
|
|
118
124
|
suffix?: string;
|
|
119
125
|
}
|
package/dist/esm/namefully.d.ts
CHANGED
|
@@ -32,8 +32,8 @@ import { Parser } from './parser.js';
|
|
|
32
32
|
* this: `John Smith`, where `John` is the first name piece and `Smith`, the last
|
|
33
33
|
* name piece.
|
|
34
34
|
*
|
|
35
|
-
* @see {@link https://www.fbiic.gov/public/2008/nov/Naming_practice_guide_UK_2006.pdf}
|
|
36
|
-
*
|
|
35
|
+
* @see {@link https://www.fbiic.gov/public/2008/nov/Naming_practice_guide_UK_2006.pdf} for
|
|
36
|
+
* more info on name standards.
|
|
37
37
|
*
|
|
38
38
|
* **IMPORTANT**: Keep in mind that the order of appearance (or name order) matters
|
|
39
39
|
* and may be altered through configurable parameters, which will be seen later.
|
|
@@ -86,6 +86,8 @@ export declare class Namefully {
|
|
|
86
86
|
static parse(text: string, index?: NameIndex): Promise<Namefully>;
|
|
87
87
|
/** The configuration dictating this name's behavior. */
|
|
88
88
|
get config(): Config;
|
|
89
|
+
/** Whether the name is a single word name. */
|
|
90
|
+
get isMono(): boolean;
|
|
89
91
|
/** The number of characters of the `birthName`, including spaces. */
|
|
90
92
|
get length(): number;
|
|
91
93
|
/** The prefix part of the name set. */
|
|
@@ -354,4 +356,5 @@ export type NameOptions = Partial<{
|
|
|
354
356
|
ending: boolean;
|
|
355
357
|
bypass: boolean;
|
|
356
358
|
surname: Surname | 'father' | 'mother' | 'hyphenated' | 'all';
|
|
359
|
+
mono: boolean | Namon;
|
|
357
360
|
}>;
|
package/dist/esm/namefully.js
CHANGED
|
@@ -23,7 +23,12 @@ export class Namefully {
|
|
|
23
23
|
get config() {
|
|
24
24
|
return this.#fullName.config;
|
|
25
25
|
}
|
|
26
|
+
get isMono() {
|
|
27
|
+
return this.#fullName.isMono;
|
|
28
|
+
}
|
|
26
29
|
get length() {
|
|
30
|
+
if (this.isMono)
|
|
31
|
+
return this.#fullName.toString().length;
|
|
27
32
|
return this.birth.length;
|
|
28
33
|
}
|
|
29
34
|
get prefix() {
|
|
@@ -113,6 +118,8 @@ export class Namefully {
|
|
|
113
118
|
return this.#fullName.has(namon);
|
|
114
119
|
}
|
|
115
120
|
fullName(orderedBy) {
|
|
121
|
+
if (this.isMono)
|
|
122
|
+
return this.#fullName.toString();
|
|
116
123
|
const sep = this.config.ending ? ',' : '';
|
|
117
124
|
const names = [];
|
|
118
125
|
if (this.prefix)
|
|
@@ -121,13 +128,21 @@ export class Namefully {
|
|
|
121
128
|
names.push(this.first, ...this.middleName(), this.last + sep);
|
|
122
129
|
}
|
|
123
130
|
else {
|
|
124
|
-
names.push(this.last
|
|
131
|
+
names.push(this.last);
|
|
132
|
+
if (this.hasMiddle) {
|
|
133
|
+
names.push(this.first, this.middleName().join(' ') + sep);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
names.push(this.first + sep);
|
|
137
|
+
}
|
|
125
138
|
}
|
|
126
139
|
if (this.suffix)
|
|
127
140
|
names.push(this.suffix);
|
|
128
141
|
return names.join(' ').trim();
|
|
129
142
|
}
|
|
130
143
|
birthName(orderedBy) {
|
|
144
|
+
if (this.isMono)
|
|
145
|
+
return this.#fullName.toString();
|
|
131
146
|
orderedBy ??= this.config.orderedBy;
|
|
132
147
|
return orderedBy === NameOrder.FIRST_NAME
|
|
133
148
|
? [this.first, ...this.middleName(), this.last].join(' ')
|
|
@@ -143,6 +158,8 @@ export class Namefully {
|
|
|
143
158
|
return this.#fullName.lastName.toString(format);
|
|
144
159
|
}
|
|
145
160
|
initials(options) {
|
|
161
|
+
if (this.isMono)
|
|
162
|
+
return [this.#fullName.toString()[0]];
|
|
146
163
|
const { orderedBy = this.config.orderedBy, only = NameType.BIRTH_NAME, asJson } = options ?? {};
|
|
147
164
|
const firstInits = this.#fullName.firstName.initials();
|
|
148
165
|
const midInits = this.#fullName.middleName.map((n) => n.value[0]);
|
|
@@ -160,6 +177,8 @@ export class Namefully {
|
|
|
160
177
|
}
|
|
161
178
|
}
|
|
162
179
|
shorten(orderedBy) {
|
|
180
|
+
if (this.isMono)
|
|
181
|
+
return this.#fullName.toString();
|
|
163
182
|
orderedBy ??= this.config.orderedBy;
|
|
164
183
|
const { firstName, lastName } = this.#fullName;
|
|
165
184
|
return orderedBy === NameOrder.FIRST_NAME
|
|
@@ -170,6 +189,8 @@ export class Namefully {
|
|
|
170
189
|
const { by = Flat.MIDDLE_NAME, limit = 20, recursive = false, withMore = false, withPeriod = true, surname, } = options;
|
|
171
190
|
if (this.length <= limit)
|
|
172
191
|
return this.full;
|
|
192
|
+
if (this.isMono)
|
|
193
|
+
return `${this.initials()}${withPeriod ? '.' : ''}`;
|
|
173
194
|
const { firstName, lastName, middleName } = this.#fullName;
|
|
174
195
|
const sep = withPeriod ? '.' : '';
|
|
175
196
|
const hasMid = this.hasMiddle;
|
|
@@ -317,6 +338,28 @@ export class Namefully {
|
|
|
317
338
|
toToggleCase() {
|
|
318
339
|
return toggleCase(this.birth);
|
|
319
340
|
}
|
|
341
|
+
serialize() {
|
|
342
|
+
const { config, firstName: fn, lastName: ln } = this.#fullName;
|
|
343
|
+
return {
|
|
344
|
+
names: {
|
|
345
|
+
prefix: this.prefix,
|
|
346
|
+
firstName: fn.hasMore ? { value: fn.value, more: fn.more } : fn.value,
|
|
347
|
+
middleName: this.hasMiddle ? this.middleName() : undefined,
|
|
348
|
+
lastName: ln.hasMother ? { father: ln.father, mother: ln.mother } : ln.value,
|
|
349
|
+
suffix: this.suffix,
|
|
350
|
+
},
|
|
351
|
+
config: {
|
|
352
|
+
name: config.name,
|
|
353
|
+
orderedBy: config.orderedBy,
|
|
354
|
+
separator: config.separator.token,
|
|
355
|
+
title: config.title,
|
|
356
|
+
ending: config.ending,
|
|
357
|
+
bypass: config.bypass,
|
|
358
|
+
surname: config.surname,
|
|
359
|
+
mono: config.mono instanceof Namon ? config.mono.key : config.mono,
|
|
360
|
+
},
|
|
361
|
+
};
|
|
362
|
+
}
|
|
320
363
|
#toParser(raw) {
|
|
321
364
|
if (raw instanceof Parser)
|
|
322
365
|
return raw;
|
|
@@ -388,27 +431,6 @@ export class Namefully {
|
|
|
388
431
|
return ALLOWED_FORMAT_TOKENS.includes(char) ? char : undefined;
|
|
389
432
|
}
|
|
390
433
|
}
|
|
391
|
-
serialize() {
|
|
392
|
-
const { config, firstName: fn, lastName: ln } = this.#fullName;
|
|
393
|
-
return {
|
|
394
|
-
names: {
|
|
395
|
-
prefix: this.prefix,
|
|
396
|
-
firstName: fn.hasMore ? { value: fn.value, more: fn.more } : fn.value,
|
|
397
|
-
middleName: this.hasMiddle ? this.middleName() : undefined,
|
|
398
|
-
lastName: ln.hasMother ? { father: ln.father, mother: ln.mother } : ln.value,
|
|
399
|
-
suffix: this.suffix,
|
|
400
|
-
},
|
|
401
|
-
config: {
|
|
402
|
-
name: config.name,
|
|
403
|
-
orderedBy: config.orderedBy,
|
|
404
|
-
separator: config.separator.token,
|
|
405
|
-
title: config.title,
|
|
406
|
-
ending: config.ending,
|
|
407
|
-
bypass: config.bypass,
|
|
408
|
-
surname: config.surname,
|
|
409
|
-
},
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
434
|
}
|
|
413
435
|
export default (names, options) => {
|
|
414
436
|
return new Namefully(names, options);
|
package/dist/esm/parser.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Config } from './config.js';
|
|
2
2
|
import { NameIndex } from './utils.js';
|
|
3
|
-
import { FullName } from './fullname.js';
|
|
3
|
+
import { FullName, Mononym } from './fullname.js';
|
|
4
4
|
import { Name, JsonName } from './name.js';
|
|
5
5
|
/**
|
|
6
6
|
* A parser signature that helps to organize the names accordingly.
|
|
@@ -12,6 +12,11 @@ export declare abstract class Parser<T = unknown> {
|
|
|
12
12
|
* @param raw data to be parsed
|
|
13
13
|
*/
|
|
14
14
|
constructor(raw: T);
|
|
15
|
+
/**
|
|
16
|
+
* Parses raw data into a `FullName` while applying some options.
|
|
17
|
+
* @param options for additional configuration to apply.
|
|
18
|
+
*/
|
|
19
|
+
abstract parse(options?: Partial<Config>): FullName;
|
|
15
20
|
/**
|
|
16
21
|
* Builds a dynamic `Parser` on the fly and throws a `NameError` when unable
|
|
17
22
|
* to do so. The built parser only knows how to operate birth names.
|
|
@@ -19,11 +24,6 @@ export declare abstract class Parser<T = unknown> {
|
|
|
19
24
|
static build(text: string, index?: NameIndex): Parser;
|
|
20
25
|
/** Builds asynchronously a dynamic `Parser`. */
|
|
21
26
|
static buildAsync(text: string, index?: NameIndex): Promise<Parser>;
|
|
22
|
-
/**
|
|
23
|
-
* Parses the raw data into a `FullName` while considering some options.
|
|
24
|
-
* @param options for additional configuration to apply.
|
|
25
|
-
*/
|
|
26
|
-
abstract parse(options?: Partial<Config>): FullName;
|
|
27
27
|
}
|
|
28
28
|
export declare class StringParser extends Parser<string> {
|
|
29
29
|
parse(options: Partial<Config>): FullName;
|
|
@@ -37,3 +37,6 @@ export declare class NamaParser extends Parser<JsonName> {
|
|
|
37
37
|
export declare class ArrayNameParser extends Parser<Name[]> {
|
|
38
38
|
parse(options: Partial<Config>): FullName;
|
|
39
39
|
}
|
|
40
|
+
export declare class MonoParser extends Parser<string | Name> {
|
|
41
|
+
parse(options: Partial<Config>): Mononym;
|
|
42
|
+
}
|
package/dist/esm/parser.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Config } from './config.js';
|
|
2
2
|
import { NameIndex } from './utils.js';
|
|
3
3
|
import { InputError } from './error.js';
|
|
4
|
-
import { FullName } from './fullname.js';
|
|
4
|
+
import { FullName, Mononym } from './fullname.js';
|
|
5
5
|
import { Namon, Separator } from './types.js';
|
|
6
6
|
import { FirstName, LastName, Name } from './name.js';
|
|
7
|
-
import { ArrayStringValidator, ArrayNameValidator,
|
|
7
|
+
import { ArrayStringValidator, ArrayNameValidator, Validators } from './validator.js';
|
|
8
8
|
export class Parser {
|
|
9
9
|
raw;
|
|
10
10
|
constructor(raw) {
|
|
@@ -20,10 +20,7 @@ export class Parser {
|
|
|
20
20
|
return new ArrayNameParser(names);
|
|
21
21
|
}
|
|
22
22
|
if (length < 2) {
|
|
23
|
-
throw new InputError({
|
|
24
|
-
source: text,
|
|
25
|
-
message: 'cannot build from invalid input',
|
|
26
|
-
});
|
|
23
|
+
throw new InputError({ source: text, message: 'expecting at least 2 name parts' });
|
|
27
24
|
}
|
|
28
25
|
else if (length === 2 || length === 3) {
|
|
29
26
|
return new StringParser(text);
|
|
@@ -47,13 +44,15 @@ export class StringParser extends Parser {
|
|
|
47
44
|
parse(options) {
|
|
48
45
|
const config = Config.merge(options);
|
|
49
46
|
const names = this.raw.split(config.separator.token);
|
|
50
|
-
return new ArrayStringParser(names).parse(
|
|
47
|
+
return new ArrayStringParser(names).parse(config);
|
|
51
48
|
}
|
|
52
49
|
}
|
|
53
50
|
export class ArrayStringParser extends Parser {
|
|
54
51
|
parse(options) {
|
|
55
52
|
const config = Config.merge(options);
|
|
56
|
-
|
|
53
|
+
if (this.raw.length === 1 && config.mono) {
|
|
54
|
+
return new MonoParser(this.raw[0]).parse(config);
|
|
55
|
+
}
|
|
57
56
|
const raw = this.raw.map((n) => n.trim());
|
|
58
57
|
const index = NameIndex.when(config.orderedBy, raw.length);
|
|
59
58
|
const validator = new ArrayStringValidator(index);
|
|
@@ -64,8 +63,9 @@ export class ArrayStringParser extends Parser {
|
|
|
64
63
|
validator.validate(raw);
|
|
65
64
|
}
|
|
66
65
|
const { firstName, lastName, middleName, prefix, suffix } = index;
|
|
67
|
-
fullName
|
|
68
|
-
|
|
66
|
+
const fullName = new FullName(config)
|
|
67
|
+
.setFirstName(new FirstName(raw[firstName]))
|
|
68
|
+
.setLastName(new LastName(raw[lastName]));
|
|
69
69
|
if (raw.length >= 3)
|
|
70
70
|
fullName.setMiddleName(raw[middleName].split(config.separator.token));
|
|
71
71
|
if (raw.length >= 4)
|
|
@@ -89,10 +89,10 @@ export class NamaParser extends Parser {
|
|
|
89
89
|
return [namon, value];
|
|
90
90
|
}));
|
|
91
91
|
if (config.bypass) {
|
|
92
|
-
|
|
92
|
+
Validators.nama.validateKeys(names);
|
|
93
93
|
}
|
|
94
94
|
else {
|
|
95
|
-
|
|
95
|
+
Validators.nama.validate(names);
|
|
96
96
|
}
|
|
97
97
|
return FullName.parse(this.raw, config);
|
|
98
98
|
}
|
|
@@ -100,8 +100,13 @@ export class NamaParser extends Parser {
|
|
|
100
100
|
export class ArrayNameParser extends Parser {
|
|
101
101
|
parse(options) {
|
|
102
102
|
const config = Config.merge(options);
|
|
103
|
+
if (this.raw.length === 1 && config.mono) {
|
|
104
|
+
return new MonoParser(this.raw[0]).parse(options);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
ArrayNameValidator.create().validate(this.raw);
|
|
108
|
+
}
|
|
103
109
|
const fullName = new FullName(config);
|
|
104
|
-
ArrayNameValidator.create().validate(this.raw);
|
|
105
110
|
for (const name of this.raw) {
|
|
106
111
|
if (name.isPrefix) {
|
|
107
112
|
fullName.setPrefix(name);
|
|
@@ -123,3 +128,13 @@ export class ArrayNameParser extends Parser {
|
|
|
123
128
|
return fullName;
|
|
124
129
|
}
|
|
125
130
|
}
|
|
131
|
+
export class MonoParser extends Parser {
|
|
132
|
+
parse(options) {
|
|
133
|
+
const config = Config.merge(options);
|
|
134
|
+
if (config.bypass)
|
|
135
|
+
Validators.namon.validate(this.raw);
|
|
136
|
+
const type = config.mono instanceof Namon ? config.mono : Namon.FIRST_NAME;
|
|
137
|
+
const name = this.raw instanceof Name ? this.raw : new Name(this.raw.trim(), type);
|
|
138
|
+
return new Mononym(name, config);
|
|
139
|
+
}
|
|
140
|
+
}
|