@justair/justair-library 6.0.0 → 6.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/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/utils/splitName.d.ts +5 -0
- package/dist/utils/splitName.d.ts.map +1 -0
- package/dist/utils/tests/splitName.test.d.ts +2 -0
- package/dist/utils/tests/splitName.test.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/index.js +3 -0
- package/src/utils/splitName.js +60 -0
- package/src/utils/tests/splitName.test.js +108 -0
package/dist/index.d.ts
CHANGED
|
@@ -70,5 +70,6 @@ import { SamplesAudit } from "./models/samples.js";
|
|
|
70
70
|
import { sampleParameterReferenceConcentrations } from "./models/samples.js";
|
|
71
71
|
import { PARAMETERS } from "./constants/pollutants.js";
|
|
72
72
|
import { HEAVY_METALS } from "./constants/pollutants.js";
|
|
73
|
-
|
|
73
|
+
import { splitName } from "./utils/splitName.js";
|
|
74
|
+
export { Database, adminSchema, Admin, configurationsSchema, Configurations, measurementsSchema, Measurements, monitorRequestsSchema, MonitorRequests, monitorsSchema, Monitors, organizationsSchema, Organizations, usersSchema, Users, eventsSchema, Events, lightMonitorSchema, LightMonitors, monitorSuppliersSchema, MonitorSuppliers, contextsSchema, Contexts, parametersSchema, Parameters, announcementSchema, Announcements, jobsSchema, Jobs, apiKeySchema, ApiKey, UsageMetrics, usageMetricsSchema, Audit, auditSchema, EventsAudit, eventsAuditSchema, MonitorAudit, monitorAuditSchema, parametersEnum, deploymentTypesEnum, AlertsAudit, Alerts, alertsSchema, alertsAuditSchema, Features, featuresSchema, dataCompletenessSchema, DataCompleteness, networkMetricsSchema, NetworkMetrics, rateOfChangeSchema, RateOfChange, sitesSchema, Sites, sampleSitesSchema, SampleSites, sampleSiteAuditSchema, SampleSiteAudit, sampleParametersEnum, samplesSchema, Samples, samplesAuditSchema, SamplesAudit, sampleParameterReferenceConcentrations, PARAMETERS, HEAVY_METALS, splitName };
|
|
74
75
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAiFA;;;iBAEC;yBA3BwB,oBAAoB;qBADxB,gBAAgB;4BAvDF,mBAAmB;sBAAnB,mBAAmB;qCAI/C,4BAA4B;+BAA5B,4BAA4B;mCAM5B,0BAA0B;6BAA1B,0BAA0B;sCAI1B,6BAA6B;gCAA7B,6BAA6B;+BAQ7B,sBAAsB;yBAAtB,sBAAsB;oCACsB,2BAA2B;8BAA3B,2BAA2B;4BAQ3C,mBAAmB;sBAAnB,mBAAmB;6BAM/C,oBAAoB;uBAApB,oBAAoB;mCAbuB,2BAA2B;8BAA3B,2BAA2B;uCAItE,8BAA8B;iCAA9B,8BAA8B;+BACI,sBAAsB;yBAAtB,sBAAsB;iCAClB,wBAAwB;2BAAxB,wBAAwB;mCAQnB,2BAA2B;8BAA3B,2BAA2B;2BAC5C,kBAAkB;qBAAlB,kBAAkB;6BACd,oBAAoB;uBAApB,oBAAoB;6BACR,0BAA0B;mCAA1B,0BAA0B;sBA/BpE,0BAA0B;4BAA1B,0BAA0B;4BA2B1B,oBAAoB;kCAApB,oBAAoB;6BAfpB,sBAAsB;mCAAtB,sBAAsB;+BAAtB,sBAAsB;oCAAtB,sBAAsB;4BAyBtB,oBAAoB;uBAApB,oBAAoB;6BAApB,oBAAoB;kCAApB,oBAAoB;yBACc,sBAAsB;+BAAtB,sBAAsB;uCAIxD,8BAA8B;iCAA9B,8BAA8B;qCACgB,4BAA4B;+BAA5B,4BAA4B;mCAChC,0BAA0B;6BAA1B,0BAA0B;4BAOxC,mBAAmB;sBAAnB,mBAAmB;kCAS/C,yBAAyB;4BAAzB,yBAAyB;sCAAzB,yBAAyB;gCAAzB,yBAAyB;qCAAzB,yBAAyB;8BASzB,qBAAqB;wBAArB,qBAAqB;mCAArB,qBAAqB;6BAArB,qBAAqB;uDAArB,qBAAqB;2BAtBa,2BAA2B;6BAA3B,2BAA2B;0BAC1C,sBAAsB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"splitName.d.ts","sourceRoot":"","sources":["../../src/utils/splitName.js"],"names":[],"mappings":"AAsBA;;;EAqCC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"splitName.test.d.ts","sourceRoot":"","sources":["../../../src/utils/tests/splitName.test.js"],"names":[],"mappings":""}
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -56,6 +56,7 @@ import { RateOfChange, rateOfChangeSchema } from "./models/rateOfChange.js";
|
|
|
56
56
|
import Database from "./config/db.js"; // Import the new Database class
|
|
57
57
|
import CustomLogger from "./config/logger.js";
|
|
58
58
|
import { PARAMETERS, HEAVY_METALS } from "./constants/pollutants.js";
|
|
59
|
+
import { splitName } from "./utils/splitName.js";
|
|
59
60
|
|
|
60
61
|
// Sites related imports
|
|
61
62
|
import { sitesSchema, Sites } from "./models/sites.js";
|
|
@@ -154,4 +155,6 @@ export {
|
|
|
154
155
|
// Pollutant constants
|
|
155
156
|
PARAMETERS,
|
|
156
157
|
HEAVY_METALS,
|
|
158
|
+
// Utilities
|
|
159
|
+
splitName,
|
|
157
160
|
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Splits a single-field legacy `name` into { firstName, lastName }.
|
|
2
|
+
// Mirrors the parsing table from JA-2387. Used by the one-time migration
|
|
3
|
+
// script and by user/admin creation in JustAirUserService and JustAirService
|
|
4
|
+
// until V2 signup collects firstName and lastName directly.
|
|
5
|
+
|
|
6
|
+
const TITLES = new Set([
|
|
7
|
+
"dr",
|
|
8
|
+
"mr",
|
|
9
|
+
"mrs",
|
|
10
|
+
"ms",
|
|
11
|
+
"miss",
|
|
12
|
+
"prof",
|
|
13
|
+
"sir",
|
|
14
|
+
"madam",
|
|
15
|
+
"rev",
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
const isTitle = (word) =>
|
|
19
|
+
TITLES.has(word.replace(/\.$/, "").toLowerCase());
|
|
20
|
+
|
|
21
|
+
const isInitial = (word) => /^[A-Za-z]\.?$/.test(word);
|
|
22
|
+
|
|
23
|
+
export function splitName(rawName) {
|
|
24
|
+
if (!rawName || typeof rawName !== "string") {
|
|
25
|
+
return { firstName: "", lastName: "" };
|
|
26
|
+
}
|
|
27
|
+
const trimmed = rawName.trim();
|
|
28
|
+
if (!trimmed) return { firstName: "", lastName: "" };
|
|
29
|
+
|
|
30
|
+
const w = trimmed.split(/\s+/);
|
|
31
|
+
|
|
32
|
+
if (w.length === 1) return { firstName: w[0], lastName: "" };
|
|
33
|
+
if (w.length === 2) return { firstName: w[0], lastName: w[1] };
|
|
34
|
+
|
|
35
|
+
if (w.length === 3) {
|
|
36
|
+
if (isTitle(w[0]))
|
|
37
|
+
return { firstName: `${w[0]} ${w[1]}`, lastName: w[2] };
|
|
38
|
+
if (isInitial(w[1]))
|
|
39
|
+
return { firstName: `${w[0]} ${w[1]}`, lastName: w[2] };
|
|
40
|
+
return { firstName: w[0], lastName: `${w[1]} ${w[2]}` };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (w.length === 4) {
|
|
44
|
+
if (isTitle(w[0]))
|
|
45
|
+
return {
|
|
46
|
+
firstName: `${w[0]} ${w[1]}`,
|
|
47
|
+
lastName: `${w[2]} ${w[3]}`,
|
|
48
|
+
};
|
|
49
|
+
if (isInitial(w[0]))
|
|
50
|
+
return {
|
|
51
|
+
firstName: `${w[0]} ${w[1]}`,
|
|
52
|
+
lastName: `${w[2]} ${w[3]}`,
|
|
53
|
+
};
|
|
54
|
+
return { firstName: w[0], lastName: w.slice(1).join(" ") };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 5+ words: not specified in JA-2387 table. Default to first word +
|
|
58
|
+
// remainder, consistent with the 4-word "other" rule.
|
|
59
|
+
return { firstName: w[0], lastName: w.slice(1).join(" ") };
|
|
60
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { splitName } from "../splitName.js";
|
|
2
|
+
|
|
3
|
+
describe("splitName", () => {
|
|
4
|
+
describe("empty / invalid", () => {
|
|
5
|
+
test.each([null, undefined, "", " ", 0, {}, []])(
|
|
6
|
+
"returns empty strings for %p",
|
|
7
|
+
(input) => {
|
|
8
|
+
expect(splitName(input)).toEqual({ firstName: "", lastName: "" });
|
|
9
|
+
},
|
|
10
|
+
);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe("1 word", () => {
|
|
14
|
+
test("treats single word as firstName", () => {
|
|
15
|
+
expect(splitName("Derrick")).toEqual({
|
|
16
|
+
firstName: "Derrick",
|
|
17
|
+
lastName: "",
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe("2 words", () => {
|
|
23
|
+
test("splits into firstName and lastName", () => {
|
|
24
|
+
expect(splitName("Darren Riley")).toEqual({
|
|
25
|
+
firstName: "Darren",
|
|
26
|
+
lastName: "Riley",
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("preserves hyphenated last name", () => {
|
|
31
|
+
expect(splitName("Nate Rauh-Bieri")).toEqual({
|
|
32
|
+
firstName: "Nate",
|
|
33
|
+
lastName: "Rauh-Bieri",
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe("3 words", () => {
|
|
39
|
+
test("title prefix joins into firstName", () => {
|
|
40
|
+
expect(splitName("Dr. Jane Smith")).toEqual({
|
|
41
|
+
firstName: "Dr. Jane",
|
|
42
|
+
lastName: "Smith",
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("middle initial joins into firstName", () => {
|
|
47
|
+
expect(splitName("John A. Smith")).toEqual({
|
|
48
|
+
firstName: "John A.",
|
|
49
|
+
lastName: "Smith",
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("middle initial without period also joins", () => {
|
|
54
|
+
expect(splitName("John A Smith")).toEqual({
|
|
55
|
+
firstName: "John A",
|
|
56
|
+
lastName: "Smith",
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("other 3-word names go first word / last two", () => {
|
|
61
|
+
expect(splitName("Mary Van Witt")).toEqual({
|
|
62
|
+
firstName: "Mary",
|
|
63
|
+
lastName: "Van Witt",
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("4 words", () => {
|
|
69
|
+
test("title prefix splits to two-word first / two-word last", () => {
|
|
70
|
+
expect(splitName("Dr. Jane Mary Smith")).toEqual({
|
|
71
|
+
firstName: "Dr. Jane",
|
|
72
|
+
lastName: "Mary Smith",
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("leading initial splits to two-word first / two-word last", () => {
|
|
77
|
+
expect(splitName("J. Mary Anne Smith")).toEqual({
|
|
78
|
+
firstName: "J. Mary",
|
|
79
|
+
lastName: "Anne Smith",
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("other 4-word names put first word in firstName, rest in lastName", () => {
|
|
84
|
+
expect(splitName("Mary Anne Van Witt")).toEqual({
|
|
85
|
+
firstName: "Mary",
|
|
86
|
+
lastName: "Anne Van Witt",
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("5+ words", () => {
|
|
92
|
+
test("falls back to first word + remainder", () => {
|
|
93
|
+
expect(splitName("Mary Anne Elizabeth Van Witt")).toEqual({
|
|
94
|
+
firstName: "Mary",
|
|
95
|
+
lastName: "Anne Elizabeth Van Witt",
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe("whitespace handling", () => {
|
|
101
|
+
test("collapses multiple spaces", () => {
|
|
102
|
+
expect(splitName(" Darren Riley ")).toEqual({
|
|
103
|
+
firstName: "Darren",
|
|
104
|
+
lastName: "Riley",
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
});
|