@empyria/name 0.1.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/.oxfmtrc.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "./node_modules/oxfmt/configuration_schema.json",
3
+ "ignorePatterns": [],
4
+ "useTabs": true,
5
+ "tabWidth": 4,
6
+ "singleQuote": true,
7
+ "trailingComma": "all",
8
+ "semi": false
9
+ }
package/.oxlintrc.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "ignorePatterns": ["node_modules", ".nx", "coverage", "**/tmp/**"]
3
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Imre Fazekas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # @empyria/name
2
+
3
+ Name and title manipulation utilities for **Empyria**, a nanoservice framework built
4
+ primarily on Bun.
5
+
6
+ Provides a curated list of honorifics/titles (`TITLE_LIST`/`TITLES`) spanning common,
7
+ formal, academic, and religious usage, plus `findTitle` to resolve free-text input
8
+ (any case, punctuation, or transliterable script) to its canonical form. The generic
9
+ string helpers `TRANS`, `capitalise`, and `shortify`, and `transliterate`/`slugify`
10
+ from the [`transliteration`](https://www.npmjs.com/package/transliteration) package,
11
+ are re-exported here for convenience since name/title handling relies on them heavily.
12
+
13
+ ## Requirements
14
+
15
+ - Bun `>=1.4.0` or Node.js `>=26`
16
+ - Plain ESM, no build step, no TypeScript
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ bun add @empyria/name
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```js
27
+ import { findTitle, TITLES, capitalise, slugify } from '@empyria/name'
28
+
29
+ findTitle('dr.') // 'Dr'
30
+ findTitle('Vice-Chancellor') // 'Vice-Chancellor'
31
+ findTitle('Wizard') // undefined — not a recognised title
32
+
33
+ TITLES.DR // 'Dr'
34
+
35
+ capitalise('jean') // 'Jean'
36
+ slugify('Jean Pierre') // 'jean-pierre'
37
+ ```
38
+
39
+ ## Modules
40
+
41
+ | Module | Purpose |
42
+ | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
43
+ | [index.js](./index.js) | Package entry point; re-exports [lib/Name.js](./lib/Name.js). |
44
+ | [lib/Name.js](./lib/Name.js) | `TITLE_LIST`/`TITLES` (the full title catalog), `findTitle`, plus `TRANS`/`capitalise`/`shortify`/`transliterate`/`slugify` re-exported from `@empyria/classification`/`transliteration` for convenience. |
45
+
46
+ Tests live under [test/](./test/), one file per module, separate from the `lib/` sources.
47
+
48
+ ## Scripts
49
+
50
+ ```bash
51
+ bun run format # check formatting (oxfmt)
52
+ bun run format:fix # apply formatting
53
+ bun run lint # lint (oxlint)
54
+ bun run lint:fix # lint and fix
55
+ bun run test # run tests with coverage
56
+ ```
57
+
58
+ ## License
59
+
60
+ MIT © Imre Fazekas
package/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './lib/Name.js'
2
+
3
+ export * from './lib/Chunker.js'
package/lib/Chunker.js ADDED
@@ -0,0 +1,4 @@
1
+ // Re-exported from @empyria/classification, which owns the canonical implementation (this
2
+ // package already depends on it) — kept here as its own module so `chunkDocument` stays
3
+ // importable from this package too, without maintaining a second copy that can drift.
4
+ export { chunkDocument } from '@empyria/classification'
package/lib/Name.js ADDED
@@ -0,0 +1,102 @@
1
+ import { transliterate, slugify } from 'transliteration'
2
+
3
+ import { enumise, TRANS, capitalise, shortify } from '@empyria/classification'
4
+
5
+ export const TITLE_LIST = [
6
+ // Common titles
7
+ 'Master',
8
+ 'Mr',
9
+ 'Messrs',
10
+ 'Miss',
11
+ 'Mrs',
12
+ 'Ms',
13
+ 'Mx',
14
+ // Formal titles
15
+ 'Sir',
16
+ 'Gentleman',
17
+ 'Sire',
18
+ 'Mistress',
19
+ 'Madame',
20
+ 'Dame',
21
+ 'Lord',
22
+ 'Esq',
23
+ 'Esquire',
24
+ 'Excellency',
25
+ 'Excellence',
26
+ 'Her Honour',
27
+ 'His Honour',
28
+ 'The Right Honourable',
29
+ 'The Most Honourable',
30
+ 'The Much Honoured',
31
+ 'King',
32
+ 'Queen',
33
+ 'Prince',
34
+ 'Princess',
35
+ // Academic and professional titles
36
+ 'Dr',
37
+ 'Professor',
38
+ 'KC', // King's Counsel
39
+ 'Cl', // Counsel
40
+ 'Counsel',
41
+ 'SCl', // Senior Counsel
42
+ 'Senior Counsel',
43
+ 'Chancellor',
44
+ 'Vice-Chancellor',
45
+ 'Principal',
46
+ 'President',
47
+ 'Warden',
48
+ 'Dean',
49
+ 'Regent',
50
+ 'Rector',
51
+ 'Provost',
52
+ // Religious titles
53
+ 'His Holiness',
54
+ 'His All Holiness',
55
+ 'His Beatitude',
56
+ 'His Excellency',
57
+ 'His Most Eminent Highness',
58
+ 'His Eminence',
59
+ 'Most Reverend Eminence',
60
+ 'The Most Reverend',
61
+ 'His Grace',
62
+ 'His Lordship',
63
+ 'The Reverend',
64
+ 'Father',
65
+ 'Pastor',
66
+ 'Brother',
67
+ 'Sister',
68
+ 'Elder',
69
+ 'Rabbi',
70
+ 'Cantor',
71
+ 'Chief Rabbi',
72
+ 'Grand Rabbi',
73
+ 'Rebbetzin',
74
+ transliterate('Imām'),
75
+ transliterate('Shaykh'),
76
+ transliterate('Muftī'),
77
+ transliterate('Hāfiz'),
78
+ transliterate('Hāfizah'),
79
+ transliterate('Qārī'),
80
+ transliterate('Mawlānā'),
81
+ transliterate('Hājī'),
82
+ 'Sayyid',
83
+ 'Sayyidah',
84
+ 'Sharif',
85
+ 'Ayatollah',
86
+ 'Seghatoleslam',
87
+ 'Mohyeddin',
88
+ 'Eminent',
89
+ transliterate('Rōshi'),
90
+ 'Sensei',
91
+ 'Venerable',
92
+ ]
93
+ export const TITLES = enumise(TITLE_LIST)
94
+
95
+ export function findTitle(_title) {
96
+ if (!_title) return undefined
97
+
98
+ const title = transliterate(_title.replace(/[^a-z0-9\s-]/gi, '')).toUpperCase()
99
+ return TITLE_LIST.find((t) => transliterate(t).toUpperCase() === title)
100
+ }
101
+
102
+ export { transliterate, slugify, TRANS, capitalise, shortify }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@empyria/name",
3
+ "version": "0.1.0",
4
+ "description": "Name and title manipulation library for Empyria",
5
+ "license": "MIT",
6
+ "author": "Imre Fazekas <imre.fazekas@icloud.com>",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/empyria-nano/name.git"
10
+ },
11
+ "type": "module",
12
+ "main": "./index.js",
13
+ "scripts": {
14
+ "format": "bun oxfmt --check",
15
+ "format:fix": "bun oxfmt",
16
+ "lint": "bun oxlint",
17
+ "lint:fix": "bun oxlint --fix",
18
+ "test": "bun test --coverage",
19
+ "test:watch": "bun test --watch"
20
+ },
21
+ "dependencies": {
22
+ "@empyria/classification": "0.1.5",
23
+ "@empyria/common": "0.1.8",
24
+ "transliteration": "^2.6.1"
25
+ },
26
+ "devDependencies": {
27
+ "oxfmt": "0.66.0",
28
+ "oxlint": "1.81.0"
29
+ },
30
+ "engines": {
31
+ "bun": ">=1.4.0",
32
+ "node": ">=26"
33
+ },
34
+ "packageManager": "bun@1.4.2"
35
+ }
@@ -0,0 +1,75 @@
1
+ import { describe, test, expect } from 'bun:test'
2
+ import {
3
+ TITLE_LIST,
4
+ TITLES,
5
+ findTitle,
6
+ TRANS,
7
+ capitalise,
8
+ shortify,
9
+ transliterate,
10
+ slugify,
11
+ } from '../lib/Name.js'
12
+
13
+ describe('TITLE_LIST', () => {
14
+ test('has no duplicate entries', () => {
15
+ expect(new Set(TITLE_LIST).size).toBe(TITLE_LIST.length)
16
+ })
17
+ })
18
+
19
+ describe('TITLES', () => {
20
+ test('enumises every title in TITLE_LIST', () => {
21
+ expect(TITLES.DR).toBe('Dr')
22
+ expect(TITLES.MR).toBe('Mr')
23
+ })
24
+ })
25
+
26
+ describe('findTitle', () => {
27
+ test('finds a plain title regardless of case', () => {
28
+ expect(findTitle('dr')).toBe('Dr')
29
+ expect(findTitle('DR')).toBe('Dr')
30
+ })
31
+
32
+ test('ignores surrounding punctuation', () => {
33
+ expect(findTitle('Dr.')).toBe('Dr')
34
+ })
35
+
36
+ test('matches a multi-word title', () => {
37
+ expect(findTitle('the right honourable')).toBe('The Right Honourable')
38
+ })
39
+
40
+ test('matches a hyphenated title', () => {
41
+ expect(findTitle('Vice-Chancellor')).toBe('Vice-Chancellor')
42
+ expect(findTitle('vice chancellor')).toBeUndefined()
43
+ })
44
+
45
+ test('returns undefined for an unknown title', () => {
46
+ expect(findTitle('Wizard')).toBeUndefined()
47
+ })
48
+
49
+ test('returns undefined for falsy input', () => {
50
+ expect(findTitle('')).toBeUndefined()
51
+ expect(findTitle(null)).toBeUndefined()
52
+ })
53
+ })
54
+
55
+ describe('re-exported string helpers (from @empyria/classification)', () => {
56
+ test('TRANS transliterates, strips whitespace, and upper-cases', () => {
57
+ expect(TRANS('hello world')).toBe('HELLOWORLD')
58
+ })
59
+
60
+ test('capitalise upper-cases only the first character', () => {
61
+ expect(capitalise('hello')).toBe('Hello')
62
+ })
63
+
64
+ test('shortify truncates and appends an ellipsis when over the limit', () => {
65
+ expect(shortify('hello world', 5)).toBe('hello...')
66
+ })
67
+
68
+ test('transliterate is re-exported from the transliteration package', () => {
69
+ expect(typeof transliterate).toBe('function')
70
+ })
71
+
72
+ test('slugify is re-exported from the transliteration package', () => {
73
+ expect(slugify('Jean Pierre')).toBe('jean-pierre')
74
+ })
75
+ })