us-ssn-tools 1.0.0 → 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.
@@ -1,15 +1,33 @@
1
1
  export interface NormalizeSsnOptions {
2
- allowNoDashes?: boolean;
2
+ /**
3
+ * If true, formats prefixes while typing.
4
+ * - dashed mode: "1234" -> "123-4"
5
+ * - digits-only mode: returns digits as-is
6
+ *
7
+ * Default: true
8
+ */
3
9
  allowPartial?: boolean;
10
+ /**
11
+ * If true, return digits only (no dashes inserted).
12
+ * If false, insert dashes in ###-##-#### style.
13
+ *
14
+ * Default: false
15
+ */
16
+ digitsOnly?: boolean;
17
+ /**
18
+ * If true, cap extracted digits at 9.
19
+ * If false, allow any number of digits (useful for UI behavior testing).
20
+ *
21
+ * Default: true
22
+ */
23
+ enforceLength?: boolean;
4
24
  }
5
- export type NormalizeSsnOk = {
6
- ok: true;
7
- digits: string;
8
- normalized: string;
9
- };
10
- export type NormalizeSsnErr = {
11
- ok: false;
12
- message: string;
13
- };
14
- export type NormalizeSsnResult = NormalizeSsnOk | NormalizeSsnErr;
15
- export declare function normalizeSsnInput(input: string, opts?: NormalizeSsnOptions): NormalizeSsnResult;
25
+ /**
26
+ * Best-effort SSN normalization for UI display.
27
+ * - Returns a string only (no validity info).
28
+ * - Never throws.
29
+ * - Extracts digits from input and optionally inserts dashes.
30
+ * - Optionally caps to 9 digits (enforceLength).
31
+ * - Keeps behavior predictable for "typing-as-you-go".
32
+ */
33
+ export declare function normalizeSsn(input: string, opts?: NormalizeSsnOptions): string;
package/dist/normalize.js CHANGED
@@ -1,62 +1,43 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.normalizeSsnInput = normalizeSsnInput;
3
+ exports.normalizeSsn = normalizeSsn;
4
4
  const utils_1 = require("./utils");
5
- function normalizeSsnInput(input, opts = {}) {
6
- var _a, _b;
7
- const allowNoDashes = (_a = opts.allowNoDashes) !== null && _a !== void 0 ? _a : true;
8
- const allowPartial = (_b = opts.allowPartial) !== null && _b !== void 0 ? _b : false;
9
- const raw = input;
10
- // Full (non-partial) normalization
11
- if (!allowPartial) {
12
- if (/^\d{3}-\d{2}-\d{4}$/.test(raw)) {
13
- return {
14
- ok: true,
15
- digits: raw.replace(/-/g, ''),
16
- normalized: raw,
17
- };
18
- }
19
- if (allowNoDashes && /^\d{9}$/.test(raw)) {
20
- return {
21
- ok: true,
22
- digits: raw,
23
- normalized: `${raw.slice(0, 3)}-${raw.slice(3, 5)}-${raw.slice(5)}`,
24
- };
25
- }
26
- return { ok: false, message: 'Invalid SSN format.' };
27
- }
28
- // ---- Partial / typing-as-you-go normalization ----
29
- if (!/^[0-9-]*$/.test(raw)) {
30
- return { ok: false, message: "Only digits and '-' are allowed." };
31
- }
5
+ /**
6
+ * Best-effort SSN normalization for UI display.
7
+ * - Returns a string only (no validity info).
8
+ * - Never throws.
9
+ * - Extracts digits from input and optionally inserts dashes.
10
+ * - Optionally caps to 9 digits (enforceLength).
11
+ * - Keeps behavior predictable for "typing-as-you-go".
12
+ */
13
+ function normalizeSsn(input, opts = {}) {
14
+ var _a, _b, _c;
15
+ const allowPartial = (_a = opts.allowPartial) !== null && _a !== void 0 ? _a : true;
16
+ const digitsOnly = (_b = opts.digitsOnly) !== null && _b !== void 0 ? _b : false;
17
+ const enforceLength = (_c = opts.enforceLength) !== null && _c !== void 0 ? _c : true;
18
+ // Extract digits, optionally cap to 9 for SSN-shaped output.
32
19
  let digits = '';
33
- let sawDashAt3 = false;
34
- let sawDashAt5 = false;
35
- for (const ch of raw) {
20
+ for (const ch of input) {
36
21
  if (ch >= '0' && ch <= '9') {
37
22
  digits += ch;
38
- if (digits.length > 9) {
39
- return { ok: false, message: 'SSN is too long.' };
40
- }
41
- continue;
42
- }
43
- // ch === '-'
44
- if (!allowNoDashes) {
45
- return { ok: false, message: 'Dashes are not allowed.' };
46
- }
47
- if (digits.length === 3 && !sawDashAt3) {
48
- sawDashAt3 = true;
49
- }
50
- else if (digits.length === 5 && !sawDashAt5) {
51
- sawDashAt5 = true;
52
- }
53
- else {
54
- return { ok: false, message: 'Dash is in an invalid position.' };
23
+ if (enforceLength && digits.length === 9)
24
+ break;
55
25
  }
56
26
  }
57
- return {
58
- ok: true,
59
- digits,
60
- normalized: (0, utils_1.formatSsnFromDigits)(digits),
61
- };
27
+ if (digitsOnly) {
28
+ // digits-only output: just return the extracted digits (possibly >9 if enforceLength=false)
29
+ return digits;
30
+ }
31
+ // dashed output
32
+ if (allowPartial) {
33
+ // Typing mode: format prefix. If digits > 9 and enforceLength=false,
34
+ // we format the SSN-shaped prefix and append the rest after the serial.
35
+ return (0, utils_1.formatSsnWithOverflow)(digits);
36
+ }
37
+ // Non-partial mode: only format if we have a full 9 digits; otherwise return input unchanged.
38
+ // (Prevents jumpy formatting in contexts where you don't want as-you-type behavior.)
39
+ if (digits.length === 9 || (enforceLength && digits.length === 9)) {
40
+ return (0, utils_1.formatSsnFromDigits)(digits.slice(0, 9));
41
+ }
42
+ return input;
62
43
  }
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,9 @@
1
1
  /**
2
- * Format SSN from digits. Used for UI formatting.
2
+ * Format SSN from digits. Used for UI
3
3
  */
4
4
  export declare function formatSsnFromDigits(digits: string): string;
5
+ /**
6
+ * Formats digits as ###-##-#### and if there are extra digits, appends them after the serial.
7
+ * Example: "12345678999" -> "123-45-678999"
8
+ */
9
+ export declare function formatSsnWithOverflow(digits: string): string;
package/dist/utils.js CHANGED
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.formatSsnFromDigits = formatSsnFromDigits;
4
+ exports.formatSsnWithOverflow = formatSsnWithOverflow;
4
5
  /**
5
- * Format SSN from digits. Used for UI formatting.
6
+ * Format SSN from digits. Used for UI
6
7
  */
7
8
  function formatSsnFromDigits(digits) {
8
9
  if (digits.length <= 3)
@@ -11,3 +12,12 @@ function formatSsnFromDigits(digits) {
11
12
  return `${digits.slice(0, 3)}-${digits.slice(3)}`;
12
13
  return `${digits.slice(0, 3)}-${digits.slice(3, 5)}-${digits.slice(5)}`;
13
14
  }
15
+ /**
16
+ * Formats digits as ###-##-#### and if there are extra digits, appends them after the serial.
17
+ * Example: "12345678999" -> "123-45-678999"
18
+ */
19
+ function formatSsnWithOverflow(digits) {
20
+ if (digits.length <= 9)
21
+ return formatSsnFromDigits(digits);
22
+ return `${formatSsnFromDigits(digits.slice(0, 9))}${digits.slice(9)}`;
23
+ }
@@ -1,43 +1,25 @@
1
- export type SsnValidationFailureReason = 'INVALID_FORMAT' | 'INVALID_AREA' | 'INVALID_GROUP' | 'INVALID_SERIAL' | 'PUBLICLY_ADVERTISED';
2
- export type SsnRuleMode = 'pre2011' | 'post2011' | 'both';
3
- export type SsnValidationOkResult = {
4
- ok: true;
5
- normalized: string;
6
- };
7
- export type SsnValidationErrorResult = {
8
- ok: false;
9
- error: SsnValidationFailureReason;
10
- message: string;
11
- };
12
- export type SsnValidationResult = SsnValidationOkResult | SsnValidationErrorResult;
1
+ export type SsnRuleMode = 'pre2011' | 'post2011';
13
2
  export interface ValidateSsnOptions {
14
3
  /**
15
- * If true, accept either "#########" or "###-##-####" as input.
16
- * If false, require exact "###-##-####" (or partial prefix of it if allowPartial=true).
4
+ * If true, input must be in ###-##-#### (or a valid prefix of it when allowPartial=true).
5
+ * If false, accepts either ###-##-#### or ######### (and prefixes).
6
+ *
7
+ * Default: true
17
8
  */
18
- allowNoDashes?: boolean;
9
+ requireDashes?: boolean;
19
10
  /**
20
- * Which rule-set(s) to accept.
21
- * - "pre2011": apply stricter pre–Jun 25 2011 area rules (734–749, >=773 invalid)
22
- * - "post2011": do NOT apply those extra area restrictions
23
- * - "both": accept either (default)
11
+ * Pre-2011 is stricter on area numbers (734-749 and >= 773 are invalid).
12
+ * Post-2011 uses only the base area rules (000, 666, 900-999 invalid).
24
13
  *
25
- * Note: base rules (area 000/666/900-999, group 00, serial 0000, public list) still apply.
14
+ * Default: "post2011"
26
15
  */
27
16
  ruleMode?: SsnRuleMode;
28
17
  /**
29
- * If true, allow "checking-as-you-go":
30
- * - partial prefixes are accepted as long as they could still become valid
31
- * - returned normalized string is the sanitized, dash-normalized prefix
18
+ * If true, accept prefixes that are still potentially valid as the user types.
19
+ * If false, require a complete SSN.
20
+ *
21
+ * Default: false
32
22
  */
33
23
  allowPartial?: boolean;
34
24
  }
35
- /**
36
- * Validates a US SSN with support for:
37
- * - strict full validation
38
- * - optional acceptance of no-dash input
39
- * - rule modes: pre2011 | post2011 | both (default)
40
- * - optional "checking-as-you-go" partial validation
41
- */ export declare function validateSsn(input: string, opts?: ValidateSsnOptions): SsnValidationResult;
42
- /** Convenience boolean wrapper */
43
25
  export declare function isValidSsn(input: string, opts?: ValidateSsnOptions): boolean;
package/dist/validate.js CHANGED
@@ -1,179 +1,144 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateSsn = validateSsn;
4
3
  exports.isValidSsn = isValidSsn;
5
- const normalize_1 = require("./normalize");
6
4
  const PUBLICLY_ADVERTISED = new Set([
7
5
  '078-05-1120',
8
6
  '721-07-4426',
9
7
  '219-09-9999',
10
8
  ]);
11
- /**
12
- * Validates a US SSN with support for:
13
- * - strict full validation
14
- * - optional acceptance of no-dash input
15
- * - rule modes: pre2011 | post2011 | both (default)
16
- * - optional "checking-as-you-go" partial validation
17
- */ function validateSsn(input, opts = {}) {
9
+ function isValidSsn(input, opts = {}) {
18
10
  var _a, _b, _c;
19
- const allowNoDashes = (_a = opts.allowNoDashes) !== null && _a !== void 0 ? _a : true;
20
- const ruleMode = (_b = opts.ruleMode) !== null && _b !== void 0 ? _b : 'both';
11
+ const requireDashes = (_a = opts.requireDashes) !== null && _a !== void 0 ? _a : true;
12
+ const ruleMode = (_b = opts.ruleMode) !== null && _b !== void 0 ? _b : 'post2011';
21
13
  const allowPartial = (_c = opts.allowPartial) !== null && _c !== void 0 ? _c : false;
22
- const normalized = (0, normalize_1.normalizeSsnInput)(input, {
23
- allowNoDashes,
24
- allowPartial,
25
- });
26
- if (!normalized.ok) {
27
- return {
28
- ok: false,
29
- error: 'INVALID_FORMAT',
30
- message: normalized.message,
31
- };
14
+ // 1) Format/prefix checks + digit extraction
15
+ const parsed = parseSsnInput(input, { requireDashes, allowPartial });
16
+ if (!parsed.ok)
17
+ return false;
18
+ const digits = parsed.digits;
19
+ // In strict (non-partial) mode, require exactly 9 digits.
20
+ if (!allowPartial && digits.length !== 9)
21
+ return false;
22
+ // 2) Rule checks (apply progressively in partial mode)
23
+ // Area (first 3)
24
+ if (digits.length >= 3) {
25
+ const area = Number(digits.slice(0, 3));
26
+ if (!isValidArea(area, ruleMode))
27
+ return false;
32
28
  }
33
- const digits = normalized.digits;
34
- const area = digits.slice(0, 3);
35
- const group = digits.slice(3, 5);
36
- const serial = digits.slice(5, 9);
37
- if (!allowPartial && PUBLICLY_ADVERTISED.has(normalized.normalized)) {
38
- return {
39
- ok: false,
40
- error: 'PUBLICLY_ADVERTISED',
41
- message: 'This SSN is a known publicly advertised (and invalid) value.',
42
- };
29
+ // Group (next 2)
30
+ if (digits.length >= 5) {
31
+ const group = Number(digits.slice(3, 5));
32
+ if (group === 0)
33
+ return false; // "00"
43
34
  }
44
- const ruleCheck = allowPartial
45
- ? validatePartialSegments(area, group, serial, ruleMode)
46
- : validateFullSegments(area, group, serial, ruleMode);
47
- if (!ruleCheck.ok)
48
- return ruleCheck;
49
- return { ok: true, normalized: normalized.normalized };
50
- }
51
- /** Convenience boolean wrapper */
52
- function isValidSsn(input, opts) {
53
- return validateSsn(input, opts).ok;
54
- }
55
- function normalizePrefix(digits) {
56
- // digits: 0..9 chars
57
- if (digits.length <= 3)
58
- return digits;
59
- if (digits.length <= 5)
60
- return `${digits.slice(0, 3)}-${digits.slice(3)}`;
61
- return `${digits.slice(0, 3)}-${digits.slice(3, 5)}-${digits.slice(5)}`;
62
- }
63
- /* -------------------------- Rules -------------------------- */
64
- function validateFullSegments(area, group, serial, ruleMode) {
65
- const areaNum = Number(area);
66
- const groupNum = Number(group);
67
- const serialNum = Number(serial);
68
- // Base Rule 2: area cannot be 000, 666, or 900–999
69
- if (areaNum === 0 || areaNum === 666 || areaNum >= 900) {
70
- return {
71
- ok: false,
72
- error: 'INVALID_AREA',
73
- message: 'Area number is not allowed (000, 666, and 900–999 are invalid).',
74
- };
75
- }
76
- // Ruleset selection:
77
- // - pre2011: apply extra reserved ranges
78
- // - post2011: do not
79
- // - both: accept if EITHER passes (so we only fail if it violates post rules AND pre rules)
80
- const violatesPre2011 = (areaNum >= 734 && areaNum <= 749) || areaNum >= 773;
81
- if (ruleMode === 'pre2011' && violatesPre2011) {
82
- return {
83
- ok: false,
84
- error: 'INVALID_AREA',
85
- message: 'Area number is not allowed under pre–June 25, 2011 rules (734–749 and >= 773 are invalid).',
86
- };
87
- }
88
- if (ruleMode === 'both') {
89
- // If it violates pre2011, it's still acceptable as post2011.
90
- // So no action needed.
35
+ // Serial (last 4)
36
+ if (digits.length === 9) {
37
+ const serial = Number(digits.slice(5, 9));
38
+ if (serial === 0)
39
+ return false; // "0000"
40
+ // Publicly advertised SSNs are always invalid
41
+ const dashed = `${digits.slice(0, 3)}-${digits.slice(3, 5)}-${digits.slice(5)}`;
42
+ if (PUBLICLY_ADVERTISED.has(dashed))
43
+ return false;
91
44
  }
92
- // Rule 3: group cannot be 00
93
- if (groupNum === 0) {
94
- return {
95
- ok: false,
96
- error: 'INVALID_GROUP',
97
- message: 'Group number may not be 00.',
98
- };
99
- }
100
- // Rule 4: serial cannot be 0000
101
- if (serialNum === 0) {
102
- return {
103
- ok: false,
104
- error: 'INVALID_SERIAL',
105
- message: 'Serial number may not be 0000.',
106
- };
107
- }
108
- // Rule 7: publicly advertised checked in validateSsn (full only)
109
- return { ok: true, normalized: `${area}-${group}-${serial}` };
45
+ // If partial, any prefix that passed the progressive checks is considered valid so far.
46
+ return true;
110
47
  }
111
- function validatePartialSegments(area, group, serial, ruleMode) {
112
- // AREA checks while typing:
113
- // - if first digit is '9', area can never be valid (since 900–999 invalid)
114
- if (area.length >= 1 && area[0] === '9') {
115
- return {
116
- ok: false,
117
- error: 'INVALID_AREA',
118
- message: 'Area numbers starting with 9 are not allowed.',
119
- };
48
+ /* ---------------- helpers ---------------- */
49
+ function isValidArea(area, ruleMode) {
50
+ // Base rules (always)
51
+ if (area === 0)
52
+ return false; // 000
53
+ if (area === 666)
54
+ return false;
55
+ if (area >= 900)
56
+ return false;
57
+ // Pre-2011 additional rules
58
+ if (ruleMode === 'pre2011') {
59
+ if (area >= 734 && area <= 749)
60
+ return false;
61
+ if (area >= 773)
62
+ return false;
120
63
  }
121
- // - if area is complete (3 digits), enforce base rule 2 and (optionally) pre2011 when in pre-only mode
122
- if (area.length === 3) {
123
- const areaNum = Number(area);
124
- if (areaNum === 0 || areaNum === 666 || areaNum >= 900) {
125
- return {
126
- ok: false,
127
- error: 'INVALID_AREA',
128
- message: 'Area number is not allowed (000, 666, and 900–999 are invalid).',
129
- };
64
+ return true;
65
+ }
66
+ function parseSsnInput(input, opts) {
67
+ const { requireDashes, allowPartial } = opts;
68
+ if (!allowPartial) {
69
+ // Full input only
70
+ if (/^\d{3}-\d{2}-\d{4}$/.test(input)) {
71
+ return { ok: true, digits: input.replace(/-/g, '') };
130
72
  }
131
- const violatesPre2011 = (areaNum >= 734 && areaNum <= 749) || areaNum >= 773;
132
- if (ruleMode === 'pre2011' && violatesPre2011) {
133
- return {
134
- ok: false,
135
- error: 'INVALID_AREA',
136
- message: 'Area number is not allowed under pre–June 25, 2011 rules (734–749 and >= 773 are invalid).',
137
- };
73
+ if (!requireDashes && /^\d{9}$/.test(input)) {
74
+ return { ok: true, digits: input };
138
75
  }
139
- // ruleMode "both" accepts either; "post2011" ignores extra restrictions.
76
+ return { ok: false };
140
77
  }
141
- // GROUP checks while typing:
142
- // Only enforce once group is complete (2 digits)
143
- if (group.length === 2) {
144
- const groupNum = Number(group);
145
- if (groupNum === 0) {
146
- return {
147
- ok: false,
148
- error: 'INVALID_GROUP',
149
- message: 'Group number may not be 00.',
150
- };
78
+ // Partial / typing-as-you-go
79
+ if (requireDashes) {
80
+ // Must be a prefix of ###-##-####
81
+ // Allowed prefixes include:
82
+ // "", "1", "12", "123", "123-", "123-4", "123-45", "123-45-", "123-45-6", ...
83
+ if (!/^[0-9-]*$/.test(input))
84
+ return { ok: false };
85
+ // Enforce dash positions and ordering as user types.
86
+ // Build digits while ensuring '-' only appears right after 3 and 5 digits (and at most once each).
87
+ let digits = '';
88
+ let sawDashAt3 = false;
89
+ let sawDashAt5 = false;
90
+ for (const ch of input) {
91
+ if (ch >= '0' && ch <= '9') {
92
+ if (digits.length >= 9)
93
+ return { ok: false };
94
+ digits += ch;
95
+ continue;
96
+ }
97
+ // ch === '-'
98
+ if (digits.length === 3 && !sawDashAt3) {
99
+ sawDashAt3 = true;
100
+ }
101
+ else if (digits.length === 5 && !sawDashAt5) {
102
+ sawDashAt5 = true;
103
+ }
104
+ else {
105
+ return { ok: false };
106
+ }
151
107
  }
108
+ // Also disallow typing digits past 3 without having placed the first dash (since requireDashes=true).
109
+ // The loop above already enforces this implicitly: "1234" contains no dash; it's allowed as digits,
110
+ // but would be a prefix of digits-only, not of dashed format. If you want "1234" to be invalid
111
+ // when requireDashes=true, enforce it here:
112
+ if (digits.length > 3 && !sawDashAt3)
113
+ return { ok: false };
114
+ if (digits.length > 5 && !sawDashAt5)
115
+ return { ok: false };
116
+ return { ok: true, digits };
152
117
  }
153
- // SERIAL checks while typing:
154
- // Only enforce once serial is complete (4 digits)
155
- if (serial.length === 4) {
156
- const serialNum = Number(serial);
157
- if (serialNum === 0) {
158
- return {
159
- ok: false,
160
- error: 'INVALID_SERIAL',
161
- message: 'Serial number may not be 0000.',
162
- };
118
+ // requireDashes === false in partial mode:
119
+ // accept either digits-only prefixes or dashed prefixes (as long as dashes are in valid positions)
120
+ if (!/^[0-9-]*$/.test(input))
121
+ return { ok: false };
122
+ let digits = '';
123
+ let sawDashAt3 = false;
124
+ let sawDashAt5 = false;
125
+ for (const ch of input) {
126
+ if (ch >= '0' && ch <= '9') {
127
+ if (digits.length >= 9)
128
+ return { ok: false };
129
+ digits += ch;
130
+ continue;
131
+ }
132
+ // '-' present: enforce positions (same as dashed typing), but do not require them.
133
+ if (digits.length === 3 && !sawDashAt3) {
134
+ sawDashAt3 = true;
135
+ }
136
+ else if (digits.length === 5 && !sawDashAt5) {
137
+ sawDashAt5 = true;
163
138
  }
164
- // Now that we have a full SSN in partial mode, also block publicly advertised.
165
- const fullNormalized = `${area}-${group}-${serial}`;
166
- if (PUBLICLY_ADVERTISED.has(fullNormalized)) {
167
- return {
168
- ok: false,
169
- error: 'PUBLICLY_ADVERTISED',
170
- message: 'This SSN is a known publicly advertised (and invalid) value.',
171
- };
139
+ else {
140
+ return { ok: false };
172
141
  }
173
142
  }
174
- // If we haven't hit a definitive violation yet, it's valid "so far".
175
- return {
176
- ok: true,
177
- normalized: normalizePrefix((area + group + serial).slice(0, 9)),
178
- };
143
+ return { ok: true, digits };
179
144
  }
package/dist/yup.d.ts CHANGED
@@ -1,9 +1,14 @@
1
1
  import * as yup from 'yup';
2
2
  import { type ValidateSsnOptions } from './validate';
3
3
  /**
4
- * Yup schema for "typing": normalizes to a prefix and allows partial validity.
5
- * Note: transform runs before test in Yup.
4
+ * Yup schema for "typing":
5
+ * - transforms the input to a normalized prefix (UI-friendly)
6
+ * - validates "valid so far" (allowPartial=true)
6
7
  */
7
8
  export declare function yupSsnTyping(opts?: Omit<ValidateSsnOptions, 'allowPartial'>): yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
8
- /** Yup schema for full submit */
9
+ /**
10
+ * Yup schema for full submit:
11
+ * - transforms into a canonical SSN representation
12
+ * - validates strictly (allowPartial=false)
13
+ */
9
14
  export declare function yupSsnSubmit(opts?: Omit<ValidateSsnOptions, 'allowPartial'>): yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
package/dist/yup.js CHANGED
@@ -36,45 +36,56 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.yupSsnTyping = yupSsnTyping;
37
37
  exports.yupSsnSubmit = yupSsnSubmit;
38
38
  const yup = __importStar(require("yup"));
39
+ const normalize_1 = require("./normalize");
39
40
  const validate_1 = require("./validate");
40
41
  /**
41
- * Yup schema for "typing": normalizes to a prefix and allows partial validity.
42
- * Note: transform runs before test in Yup.
42
+ * Yup schema for "typing":
43
+ * - transforms the input to a normalized prefix (UI-friendly)
44
+ * - validates "valid so far" (allowPartial=true)
43
45
  */
44
46
  function yupSsnTyping(opts = {}) {
45
47
  return yup
46
48
  .string()
47
49
  .transform((value) => {
48
50
  const v = (value !== null && value !== void 0 ? value : '').toString();
49
- const res = (0, validate_1.validateSsn)(v, Object.assign(Object.assign({}, opts), { allowPartial: true }));
50
- return res.ok ? res.normalized : v; // keep original if invalid; test will fail
51
+ // Normalize for UI: prefix formatting as the user types.
52
+ // Keep dashed output (digitsOnly=false) by default.
53
+ return (0, normalize_1.normalizeSsn)(v, {
54
+ allowPartial: true,
55
+ digitsOnly: false,
56
+ enforceLength: false,
57
+ });
51
58
  })
52
59
  .test('ssn-typing-valid', 'Invalid SSN', function (value) {
53
60
  const v = (value !== null && value !== void 0 ? value : '').toString();
54
- const res = (0, validate_1.validateSsn)(v, Object.assign(Object.assign({}, opts), { allowPartial: true }));
55
- return res.ok
56
- ? true
57
- : this.createError({
58
- message: res.message,
59
- });
61
+ const ok = (0, validate_1.isValidSsn)(v, Object.assign(Object.assign({}, opts), { allowPartial: true }));
62
+ return ok ? true : this.createError({ message: 'Invalid SSN' });
60
63
  });
61
64
  }
62
- /** Yup schema for full submit */
65
+ /**
66
+ * Yup schema for full submit:
67
+ * - transforms into a canonical SSN representation
68
+ * - validates strictly (allowPartial=false)
69
+ */
63
70
  function yupSsnSubmit(opts = {}) {
64
71
  return yup
65
72
  .string()
66
73
  .transform((value) => {
74
+ var _a;
67
75
  const v = (value !== null && value !== void 0 ? value : '').toString();
68
- const res = (0, validate_1.validateSsn)(v, Object.assign(Object.assign({}, opts), { allowPartial: false }));
69
- return res.ok ? res.normalized : v;
76
+ // For submit, normalize to canonical form.
77
+ // If requireDashes is true (default), return dashed.
78
+ // If requireDashes is false, you might prefer digitsOnly, but we keep dashed for consistency.
79
+ const digitsOnly = ((_a = opts.requireDashes) !== null && _a !== void 0 ? _a : true) ? false : true;
80
+ return (0, normalize_1.normalizeSsn)(v, {
81
+ allowPartial: false,
82
+ digitsOnly,
83
+ enforceLength: true, // for submit, capping to 9 is usually desired
84
+ });
70
85
  })
71
86
  .test('ssn-submit-valid', 'Invalid SSN', function (value) {
72
87
  const v = (value !== null && value !== void 0 ? value : '').toString();
73
- const res = (0, validate_1.validateSsn)(v, Object.assign(Object.assign({}, opts), { allowPartial: false }));
74
- return res.ok
75
- ? true
76
- : this.createError({
77
- message: res.message,
78
- });
88
+ const ok = (0, validate_1.isValidSsn)(v, Object.assign(Object.assign({}, opts), { allowPartial: false }));
89
+ return ok ? true : this.createError({ message: 'Invalid SSN' });
79
90
  });
80
91
  }