@justair/justair-library 6.0.0 → 6.1.0-alpha.b95f600

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 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
- 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 };
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
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAgFA;;;iBAEC;yBA1BwB,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;4BAMxC,mBAAmB;sBAAnB,mBAAmB;kCAS/C,yBAAyB;4BAAzB,yBAAyB;sCAAzB,yBAAyB;gCAAzB,yBAAyB;qCAAzB,yBAAyB;8BASzB,qBAAqB;wBAArB,qBAAqB;mCAArB,qBAAqB;6BAArB,qBAAqB;uDAArB,qBAAqB;2BArBa,2BAA2B;6BAA3B,2BAA2B"}
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,5 @@
1
+ export function splitName(rawName: any): {
2
+ firstName: string;
3
+ lastName: string;
4
+ };
5
+ //# sourceMappingURL=splitName.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"splitName.d.ts","sourceRoot":"","sources":["../../src/utils/splitName.js"],"names":[],"mappings":"AAsBA;;;EAqCC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=splitName.test.d.ts.map
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justair/justair-library",
3
- "version": "6.0.0",
3
+ "version": "6.1.0-alpha.b95f600",
4
4
  "description": "JustAir Internal Library",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
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
+ });