chilean-rut-formatter 1.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.
package/README.md ADDED
@@ -0,0 +1,150 @@
1
+ # Chilean RUT Formatter
2
+
3
+ [![npm version](https://badge.fury.io/js/chilean-rut-formatter.svg)](https://www.npmjs.com/package/chilean-rut-formatter)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ High-performance TypeScript library for formatting and validating Chilean RUTs (Rol Único Tributario).
7
+
8
+ ## Features
9
+
10
+ - ✅ **Validate** RUTs using the official Module 11 algorithm
11
+ - ✅ **Format** with customizable options (dots, dashes, case)
12
+ - ✅ **Clean** and sanitize user input
13
+ - ✅ **TypeScript** - Full type definitions included
14
+ - ✅ **Zero dependencies** - Lightweight and fast
15
+ - ✅ **Secure** - Input sanitization and DoS protection
16
+ - ✅ **Tree-shakeable** - ESM and CJS support
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install chilean-rut-formatter
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ### Validate a RUT
27
+
28
+ ```typescript
29
+ import { validateRut, isValidRut } from 'chilean-rut-formatter';
30
+
31
+ // Full validation with details
32
+ const result = validateRut('12.345.678-5');
33
+ // { isValid: true, rut: '123456785' }
34
+
35
+ const invalid = validateRut('12345678-0');
36
+ // { isValid: false, error: 'Invalid verification digit' }
37
+
38
+ // Simple boolean check
39
+ isValidRut('12.345.678-5'); // true
40
+ isValidRut('12345678-0'); // false
41
+ ```
42
+
43
+ ### Format a RUT
44
+
45
+ ```typescript
46
+ import { formatRut } from 'chilean-rut-formatter';
47
+
48
+ // Default: with dots and dash
49
+ formatRut('123456785'); // '12.345.678-5'
50
+ formatRut('12345678K'); // '12.345.678-K'
51
+
52
+ // Custom options
53
+ formatRut('123456785', { dots: false }); // '12345678-5'
54
+ formatRut('123456785', { dash: false }); // '12.345.6785'
55
+ formatRut('12345678K', { uppercase: false }); // '12.345.678-k'
56
+
57
+ // Returns empty string if RUT is invalid
58
+ formatRut('12345678-0'); // ''
59
+ ```
60
+
61
+ ### Format Partial Input (Real-time)
62
+
63
+ ```typescript
64
+ import { formatRutPartial } from 'chilean-rut-formatter';
65
+
66
+ // Great for live formatting as user types
67
+ formatRutPartial('1'); // '1'
68
+ formatRutPartial('12'); // '1-2'
69
+ formatRutPartial('12345'); // '1.234-5'
70
+ formatRutPartial('123456789'); // '12.345.678-9'
71
+ ```
72
+
73
+ ### Clean a RUT
74
+
75
+ ```typescript
76
+ import { cleanRut } from 'chilean-rut-formatter';
77
+
78
+ cleanRut('12.345.678-9'); // '123456789'
79
+ cleanRut('12 345 678-k'); // '12345678K'
80
+ cleanRut(' 12#345$678%9 '); // '123456789'
81
+ ```
82
+
83
+ ### Calculate Verification Digit
84
+
85
+ ```typescript
86
+ import { calculateVerificationDigit } from 'chilean-rut-formatter';
87
+
88
+ calculateVerificationDigit('12345678'); // '5'
89
+ calculateVerificationDigit('16612277'); // 'K'
90
+ ```
91
+
92
+ ## API Reference
93
+
94
+ ### `validateRut(rut: string): ValidationResult`
95
+
96
+ Validates a Chilean RUT and returns detailed result.
97
+
98
+ ```typescript
99
+ interface ValidationResult {
100
+ isValid: boolean;
101
+ rut?: string; // Cleaned RUT if valid
102
+ error?: string; // Error message if invalid
103
+ }
104
+ ```
105
+
106
+ ### `isValidRut(rut: string): boolean`
107
+
108
+ Simple boolean validation check.
109
+
110
+ ### `formatRut(rut: string, options?: FormatOptions): string`
111
+
112
+ Formats a valid RUT. Returns empty string if RUT is invalid.
113
+
114
+ ```typescript
115
+ interface FormatOptions {
116
+ dots?: boolean; // Include dots (default: true)
117
+ dash?: boolean; // Include dash (default: true)
118
+ uppercase?: boolean; // Uppercase K (default: true)
119
+ }
120
+ ```
121
+
122
+ ### `formatRutPartial(rut: string, options?: FormatOptions): string`
123
+
124
+ Formats partial RUT input (useful for real-time formatting).
125
+
126
+ ### `cleanRut(input: string): string`
127
+
128
+ Removes all non-valid characters from input.
129
+
130
+ ### `calculateVerificationDigit(rutBody: string): string`
131
+
132
+ Calculates the verification digit for a RUT body.
133
+
134
+ ## Security
135
+
136
+ - **Input Sanitization**: All inputs are cleaned before processing
137
+ - **DoS Protection**: Maximum input length enforced (50 chars)
138
+ - **No eval/Function**: No dynamic code execution
139
+ - **TypeScript Strict Mode**: Full type safety
140
+
141
+ ## Performance
142
+
143
+ - **Zero dependencies**: No external library overhead
144
+ - **Pre-compiled regex**: Patterns compiled once at module load
145
+ - **Early returns**: Fast failure for invalid inputs
146
+ - **Minimal allocations**: Optimized for performance
147
+
148
+ ## License
149
+
150
+ MIT
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Options for formatting a RUT
3
+ */
4
+ interface FormatOptions {
5
+ /** Include dots as thousand separators (e.g., 12.345.678-9). Default: true */
6
+ dots?: boolean;
7
+ /** Include dash before verification digit. Default: true */
8
+ dash?: boolean;
9
+ /** Use uppercase for 'K' verification digit. Default: true */
10
+ uppercase?: boolean;
11
+ }
12
+ /**
13
+ * Result of RUT validation
14
+ */
15
+ interface ValidationResult {
16
+ /** Whether the RUT is valid */
17
+ isValid: boolean;
18
+ /** Clean RUT string (numbers + verification digit) if valid */
19
+ rut?: string;
20
+ /** Error message if invalid */
21
+ error?: string;
22
+ }
23
+ /**
24
+ * Parsed RUT components
25
+ */
26
+ interface ParsedRut {
27
+ /** RUT body (numbers only, without verification digit) */
28
+ body: string;
29
+ /** Verification digit (0-9 or K) */
30
+ verificationDigit: string;
31
+ }
32
+
33
+ /**
34
+ * Cleans a RUT string by removing all non-valid characters.
35
+ * Keeps only numbers and 'K'/'k'.
36
+ *
37
+ * @param input - Raw RUT input string
38
+ * @returns Cleaned RUT string with only valid characters
39
+ *
40
+ * @example
41
+ * cleanRut('12.345.678-9') // '123456789'
42
+ * cleanRut('12345678-K') // '12345678K'
43
+ * cleanRut(' 12-345-678.9 ') // '123456789'
44
+ */
45
+ declare function cleanRut(input: string): string;
46
+
47
+ /**
48
+ * Validates a Chilean RUT (Rol Único Tributario).
49
+ *
50
+ * Uses the official Module 11 algorithm to verify the check digit.
51
+ *
52
+ * @param rut - RUT string to validate (can include dots, dashes, spaces)
53
+ * @returns Validation result with isValid flag and cleaned RUT if valid
54
+ *
55
+ * @example
56
+ * validateRut('12.345.678-5') // { isValid: true, rut: '123456785' }
57
+ * validateRut('12345678-5') // { isValid: true, rut: '123456785' }
58
+ * validateRut('12345678-0') // { isValid: false, error: 'Invalid verification digit' }
59
+ * validateRut('') // { isValid: false, error: 'RUT is required' }
60
+ */
61
+ declare function validateRut(rut: string): ValidationResult;
62
+ /**
63
+ * Simple boolean check for RUT validity.
64
+ *
65
+ * @param rut - RUT string to validate
66
+ * @returns true if RUT is valid, false otherwise
67
+ *
68
+ * @example
69
+ * isValidRut('12.345.678-5') // true
70
+ * isValidRut('12345678-0') // false
71
+ */
72
+ declare function isValidRut(rut: string): boolean;
73
+
74
+ /**
75
+ * Formats a Chilean RUT with the specified options.
76
+ *
77
+ * By default, formats as: 12.345.678-9
78
+ *
79
+ * @param rut - RUT string to format (can include dots, dashes, spaces)
80
+ * @param options - Formatting options
81
+ * @returns Formatted RUT string, or empty string if invalid
82
+ *
83
+ * @example
84
+ * formatRut('123456785') // '12.345.678-5'
85
+ * formatRut('123456785', { dots: false }) // '12345678-5'
86
+ * formatRut('123456785', { dash: false }) // '12.345.6785'
87
+ * formatRut('12345678K', { uppercase: false }) // '12.345.678-k'
88
+ */
89
+ declare function formatRut(rut: string, options?: FormatOptions): string;
90
+ /**
91
+ * Formats a RUT without validation (use with caution).
92
+ * Useful when you need to format user input as they type.
93
+ *
94
+ * @param rut - RUT string to format
95
+ * @param options - Formatting options
96
+ * @returns Formatted RUT string
97
+ *
98
+ * @example
99
+ * formatRutPartial('12345') // '12.345'
100
+ * formatRutPartial('123456789') // '12.345.678-9'
101
+ */
102
+ declare function formatRutPartial(rut: string, options?: FormatOptions): string;
103
+
104
+ /**
105
+ * Calculates the verification digit for a RUT body using Module 11 algorithm.
106
+ *
107
+ * @param rutBody - RUT body (numbers only, without verification digit)
108
+ * @returns Calculated verification digit ('0'-'9' or 'K')
109
+ */
110
+ declare function calculateVerificationDigit(rutBody: string): string;
111
+ /**
112
+ * Parses a cleaned RUT string into body and verification digit.
113
+ *
114
+ * @param cleanedRut - Cleaned RUT string (only numbers and K)
115
+ * @returns Parsed RUT object or null if invalid format
116
+ */
117
+ declare function parseRut(cleanedRut: string): ParsedRut | null;
118
+
119
+ export { type FormatOptions, type ParsedRut, type ValidationResult, calculateVerificationDigit, cleanRut, formatRut, formatRutPartial, isValidRut, parseRut, validateRut };
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Options for formatting a RUT
3
+ */
4
+ interface FormatOptions {
5
+ /** Include dots as thousand separators (e.g., 12.345.678-9). Default: true */
6
+ dots?: boolean;
7
+ /** Include dash before verification digit. Default: true */
8
+ dash?: boolean;
9
+ /** Use uppercase for 'K' verification digit. Default: true */
10
+ uppercase?: boolean;
11
+ }
12
+ /**
13
+ * Result of RUT validation
14
+ */
15
+ interface ValidationResult {
16
+ /** Whether the RUT is valid */
17
+ isValid: boolean;
18
+ /** Clean RUT string (numbers + verification digit) if valid */
19
+ rut?: string;
20
+ /** Error message if invalid */
21
+ error?: string;
22
+ }
23
+ /**
24
+ * Parsed RUT components
25
+ */
26
+ interface ParsedRut {
27
+ /** RUT body (numbers only, without verification digit) */
28
+ body: string;
29
+ /** Verification digit (0-9 or K) */
30
+ verificationDigit: string;
31
+ }
32
+
33
+ /**
34
+ * Cleans a RUT string by removing all non-valid characters.
35
+ * Keeps only numbers and 'K'/'k'.
36
+ *
37
+ * @param input - Raw RUT input string
38
+ * @returns Cleaned RUT string with only valid characters
39
+ *
40
+ * @example
41
+ * cleanRut('12.345.678-9') // '123456789'
42
+ * cleanRut('12345678-K') // '12345678K'
43
+ * cleanRut(' 12-345-678.9 ') // '123456789'
44
+ */
45
+ declare function cleanRut(input: string): string;
46
+
47
+ /**
48
+ * Validates a Chilean RUT (Rol Único Tributario).
49
+ *
50
+ * Uses the official Module 11 algorithm to verify the check digit.
51
+ *
52
+ * @param rut - RUT string to validate (can include dots, dashes, spaces)
53
+ * @returns Validation result with isValid flag and cleaned RUT if valid
54
+ *
55
+ * @example
56
+ * validateRut('12.345.678-5') // { isValid: true, rut: '123456785' }
57
+ * validateRut('12345678-5') // { isValid: true, rut: '123456785' }
58
+ * validateRut('12345678-0') // { isValid: false, error: 'Invalid verification digit' }
59
+ * validateRut('') // { isValid: false, error: 'RUT is required' }
60
+ */
61
+ declare function validateRut(rut: string): ValidationResult;
62
+ /**
63
+ * Simple boolean check for RUT validity.
64
+ *
65
+ * @param rut - RUT string to validate
66
+ * @returns true if RUT is valid, false otherwise
67
+ *
68
+ * @example
69
+ * isValidRut('12.345.678-5') // true
70
+ * isValidRut('12345678-0') // false
71
+ */
72
+ declare function isValidRut(rut: string): boolean;
73
+
74
+ /**
75
+ * Formats a Chilean RUT with the specified options.
76
+ *
77
+ * By default, formats as: 12.345.678-9
78
+ *
79
+ * @param rut - RUT string to format (can include dots, dashes, spaces)
80
+ * @param options - Formatting options
81
+ * @returns Formatted RUT string, or empty string if invalid
82
+ *
83
+ * @example
84
+ * formatRut('123456785') // '12.345.678-5'
85
+ * formatRut('123456785', { dots: false }) // '12345678-5'
86
+ * formatRut('123456785', { dash: false }) // '12.345.6785'
87
+ * formatRut('12345678K', { uppercase: false }) // '12.345.678-k'
88
+ */
89
+ declare function formatRut(rut: string, options?: FormatOptions): string;
90
+ /**
91
+ * Formats a RUT without validation (use with caution).
92
+ * Useful when you need to format user input as they type.
93
+ *
94
+ * @param rut - RUT string to format
95
+ * @param options - Formatting options
96
+ * @returns Formatted RUT string
97
+ *
98
+ * @example
99
+ * formatRutPartial('12345') // '12.345'
100
+ * formatRutPartial('123456789') // '12.345.678-9'
101
+ */
102
+ declare function formatRutPartial(rut: string, options?: FormatOptions): string;
103
+
104
+ /**
105
+ * Calculates the verification digit for a RUT body using Module 11 algorithm.
106
+ *
107
+ * @param rutBody - RUT body (numbers only, without verification digit)
108
+ * @returns Calculated verification digit ('0'-'9' or 'K')
109
+ */
110
+ declare function calculateVerificationDigit(rutBody: string): string;
111
+ /**
112
+ * Parses a cleaned RUT string into body and verification digit.
113
+ *
114
+ * @param cleanedRut - Cleaned RUT string (only numbers and K)
115
+ * @returns Parsed RUT object or null if invalid format
116
+ */
117
+ declare function parseRut(cleanedRut: string): ParsedRut | null;
118
+
119
+ export { type FormatOptions, type ParsedRut, type ValidationResult, calculateVerificationDigit, cleanRut, formatRut, formatRutPartial, isValidRut, parseRut, validateRut };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ 'use strict';var m=/[^0-9kK]/g;function l(t){return typeof t!="string"?"":(t.length>50&&(t=t.slice(0,50)),t.replace(m,"").toUpperCase())}function c(t){let o=[2,3,4,5,6,7],r=0,e=0;for(let a=t.length-1;a>=0;a--){let s=parseInt(t[a],10);r+=s*o[e],e=(e+1)%6;}let n=11-r%11;return n===11?"0":n===10?"K":n.toString()}function u(t){if(t.length<2)return null;let o=t.slice(-1),r=t.slice(0,-1);return !/^\d+$/.test(r)||!/^[0-9K]$/.test(o)?null:{body:r,verificationDigit:o}}var R=2,y=9;function f(t){if(!t||typeof t!="string")return {isValid:false,error:"RUT is required"};let o=l(t);if(o.length<R)return {isValid:false,error:"RUT is too short"};if(o.length>y)return {isValid:false,error:"RUT is too long"};let r=u(o);if(!r)return {isValid:false,error:"Invalid RUT format"};let e=c(r.body);return r.verificationDigit!==e?{isValid:false,error:"Invalid verification digit"}:{isValid:true,rut:o}}function T(t){return f(t).isValid}var p=/\B(?=(\d{3})+(?!\d))/g,d={dots:true,dash:true,uppercase:true};function V(t,o={}){let r={...d,...o},e=l(t),i=u(e);if(!i)return "";let n=c(i.body);if(i.verificationDigit!==n)return "";let a=i.body;r.dots&&(a=i.body.replace(p,"."));let s=i.verificationDigit;r.uppercase||(s=s.toLowerCase());let g=r.dash?"-":"";return `${a}${g}${s}`}function x(t,o={}){let r={...d,...o},e=l(t);if(e.length===0)return "";let i,n;if(e.length>1){let s=e.slice(-1);/[0-9K]/.test(s)?(i=e.slice(0,-1),n=r.uppercase?s:s.toLowerCase()):(i=e,n="");}else i=e,n="";let a=i;if(r.dots&&i.length>0&&(a=i.replace(p,".")),n){let s=r.dash?"-":"";return `${a}${s}${n}`}return a}exports.calculateVerificationDigit=c;exports.cleanRut=l;exports.formatRut=V;exports.formatRutPartial=x;exports.isValidRut=T;exports.parseRut=u;exports.validateRut=f;//# sourceMappingURL=index.js.map
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/clean.ts","../src/utils.ts","../src/validate.ts","../src/format.ts"],"names":["CLEAN_REGEX","cleanRut","input","calculateVerificationDigit","rutBody","multipliers","sum","multiplierIndex","i","digit","result","parseRut","cleanedRut","verificationDigit","body","MIN_RUT_LENGTH","MAX_RUT_LENGTH","validateRut","rut","cleaned","parsed","expectedDigit","isValidRut","DOTS_REGEX","DEFAULT_OPTIONS","formatRut","options","opts","formattedBody","dv","separator","formatRutPartial","lastChar"],"mappings":"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","file":"index.js","sourcesContent":["// Pre-compiled regex for maximum performance\nconst CLEAN_REGEX = /[^0-9kK]/g;\n\n// Maximum allowed input length for security (prevents DoS)\nconst MAX_INPUT_LENGTH = 50;\n\n/**\n * Cleans a RUT string by removing all non-valid characters.\n * Keeps only numbers and 'K'/'k'.\n * \n * @param input - Raw RUT input string\n * @returns Cleaned RUT string with only valid characters\n * \n * @example\n * cleanRut('12.345.678-9') // '123456789'\n * cleanRut('12345678-K') // '12345678K'\n * cleanRut(' 12-345-678.9 ') // '123456789'\n */\nexport function cleanRut(input: string): string {\n // Security: handle non-string inputs gracefully\n if (typeof input !== 'string') {\n return '';\n }\n\n // Security: prevent DoS with extremely long inputs\n if (input.length > MAX_INPUT_LENGTH) {\n input = input.slice(0, MAX_INPUT_LENGTH);\n }\n\n // Remove all non-valid characters and convert to uppercase\n return input.replace(CLEAN_REGEX, '').toUpperCase();\n}\n","import type { ParsedRut } from './types';\n\n/**\n * Calculates the verification digit for a RUT body using Module 11 algorithm.\n * \n * @param rutBody - RUT body (numbers only, without verification digit)\n * @returns Calculated verification digit ('0'-'9' or 'K')\n */\nexport function calculateVerificationDigit(rutBody: string): string {\n // Multiplier sequence for Module 11 algorithm\n const multipliers = [2, 3, 4, 5, 6, 7];\n\n let sum = 0;\n let multiplierIndex = 0;\n\n // Process digits from right to left\n for (let i = rutBody.length - 1; i >= 0; i--) {\n const digit = parseInt(rutBody[i], 10);\n sum += digit * multipliers[multiplierIndex];\n multiplierIndex = (multiplierIndex + 1) % 6; // Cycle through multipliers\n }\n\n // Calculate verification digit\n const remainder = sum % 11;\n const result = 11 - remainder;\n\n // Convert result to verification digit\n if (result === 11) return '0';\n if (result === 10) return 'K';\n return result.toString();\n}\n\n/**\n * Parses a cleaned RUT string into body and verification digit.\n * \n * @param cleanedRut - Cleaned RUT string (only numbers and K)\n * @returns Parsed RUT object or null if invalid format\n */\nexport function parseRut(cleanedRut: string): ParsedRut | null {\n if (cleanedRut.length < 2) {\n return null;\n }\n\n const verificationDigit = cleanedRut.slice(-1);\n const body = cleanedRut.slice(0, -1);\n\n // Body must contain only digits\n if (!/^\\d+$/.test(body)) {\n return null;\n }\n\n // Verification digit must be a digit or K\n if (!/^[0-9K]$/.test(verificationDigit)) {\n return null;\n }\n\n return { body, verificationDigit };\n}\n","import type { ValidationResult } from './types';\nimport { cleanRut } from './clean';\nimport { parseRut, calculateVerificationDigit } from './utils';\n\n// Minimum valid RUT (1-9)\nconst MIN_RUT_LENGTH = 2;\n// Maximum valid RUT length (including verification digit)\nconst MAX_RUT_LENGTH = 9;\n\n/**\n * Validates a Chilean RUT (Rol Único Tributario).\n * \n * Uses the official Module 11 algorithm to verify the check digit.\n * \n * @param rut - RUT string to validate (can include dots, dashes, spaces)\n * @returns Validation result with isValid flag and cleaned RUT if valid\n * \n * @example\n * validateRut('12.345.678-5') // { isValid: true, rut: '123456785' }\n * validateRut('12345678-5') // { isValid: true, rut: '123456785' }\n * validateRut('12345678-0') // { isValid: false, error: 'Invalid verification digit' }\n * validateRut('') // { isValid: false, error: 'RUT is required' }\n */\nexport function validateRut(rut: string): ValidationResult {\n // Handle empty input\n if (!rut || typeof rut !== 'string') {\n return { isValid: false, error: 'RUT is required' };\n }\n\n // Clean the RUT\n const cleaned = cleanRut(rut);\n\n // Check minimum length\n if (cleaned.length < MIN_RUT_LENGTH) {\n return { isValid: false, error: 'RUT is too short' };\n }\n\n // Check maximum length\n if (cleaned.length > MAX_RUT_LENGTH) {\n return { isValid: false, error: 'RUT is too long' };\n }\n\n // Parse the RUT\n const parsed = parseRut(cleaned);\n if (!parsed) {\n return { isValid: false, error: 'Invalid RUT format' };\n }\n\n // Calculate expected verification digit\n const expectedDigit = calculateVerificationDigit(parsed.body);\n\n // Compare with provided verification digit\n if (parsed.verificationDigit !== expectedDigit) {\n return { isValid: false, error: 'Invalid verification digit' };\n }\n\n return { isValid: true, rut: cleaned };\n}\n\n/**\n * Simple boolean check for RUT validity.\n * \n * @param rut - RUT string to validate\n * @returns true if RUT is valid, false otherwise\n * \n * @example\n * isValidRut('12.345.678-5') // true\n * isValidRut('12345678-0') // false\n */\nexport function isValidRut(rut: string): boolean {\n return validateRut(rut).isValid;\n}\n","import type { FormatOptions } from './types';\nimport { cleanRut } from './clean';\nimport { parseRut, calculateVerificationDigit } from './utils';\n\n// Pre-compiled regex for adding dots\nconst DOTS_REGEX = /\\B(?=(\\d{3})+(?!\\d))/g;\n\n/**\n * Default formatting options\n */\nconst DEFAULT_OPTIONS: Required<FormatOptions> = {\n dots: true,\n dash: true,\n uppercase: true,\n};\n\n/**\n * Formats a Chilean RUT with the specified options.\n * \n * By default, formats as: 12.345.678-9\n * \n * @param rut - RUT string to format (can include dots, dashes, spaces)\n * @param options - Formatting options\n * @returns Formatted RUT string, or empty string if invalid\n * \n * @example\n * formatRut('123456785') // '12.345.678-5'\n * formatRut('123456785', { dots: false }) // '12345678-5'\n * formatRut('123456785', { dash: false }) // '12.345.6785'\n * formatRut('12345678K', { uppercase: false }) // '12.345.678-k'\n */\nexport function formatRut(rut: string, options: FormatOptions = {}): string {\n // Merge with defaults\n const opts: Required<FormatOptions> = { ...DEFAULT_OPTIONS, ...options };\n\n // Clean the RUT\n const cleaned = cleanRut(rut);\n\n // Parse and validate\n const parsed = parseRut(cleaned);\n if (!parsed) {\n return '';\n }\n\n // Validate the verification digit\n const expectedDigit = calculateVerificationDigit(parsed.body);\n if (parsed.verificationDigit !== expectedDigit) {\n return '';\n }\n\n // Format the body\n let formattedBody = parsed.body;\n if (opts.dots) {\n formattedBody = parsed.body.replace(DOTS_REGEX, '.');\n }\n\n // Format the verification digit\n let dv = parsed.verificationDigit;\n if (!opts.uppercase) {\n dv = dv.toLowerCase();\n }\n\n // Combine with separator\n const separator = opts.dash ? '-' : '';\n return `${formattedBody}${separator}${dv}`;\n}\n\n/**\n * Formats a RUT without validation (use with caution).\n * Useful when you need to format user input as they type.\n * \n * @param rut - RUT string to format\n * @param options - Formatting options\n * @returns Formatted RUT string\n * \n * @example\n * formatRutPartial('12345') // '12.345'\n * formatRutPartial('123456789') // '12.345.678-9'\n */\nexport function formatRutPartial(rut: string, options: FormatOptions = {}): string {\n const opts: Required<FormatOptions> = { ...DEFAULT_OPTIONS, ...options };\n const cleaned = cleanRut(rut);\n\n if (cleaned.length === 0) {\n return '';\n }\n\n // Separate body and potential verification digit\n let body: string;\n let dv: string;\n\n if (cleaned.length > 1) {\n // Check if last char could be a verification digit (K or any digit)\n const lastChar = cleaned.slice(-1);\n if (/[0-9K]/.test(lastChar)) {\n body = cleaned.slice(0, -1);\n dv = opts.uppercase ? lastChar : lastChar.toLowerCase();\n } else {\n body = cleaned;\n dv = '';\n }\n } else {\n body = cleaned;\n dv = '';\n }\n\n // Format body with dots if needed\n let formattedBody = body;\n if (opts.dots && body.length > 0) {\n formattedBody = body.replace(DOTS_REGEX, '.');\n }\n\n // Add verification digit if present\n if (dv) {\n const separator = opts.dash ? '-' : '';\n return `${formattedBody}${separator}${dv}`;\n }\n\n return formattedBody;\n}\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ var m=/[^0-9kK]/g;function l(t){return typeof t!="string"?"":(t.length>50&&(t=t.slice(0,50)),t.replace(m,"").toUpperCase())}function c(t){let o=[2,3,4,5,6,7],r=0,e=0;for(let a=t.length-1;a>=0;a--){let s=parseInt(t[a],10);r+=s*o[e],e=(e+1)%6;}let n=11-r%11;return n===11?"0":n===10?"K":n.toString()}function u(t){if(t.length<2)return null;let o=t.slice(-1),r=t.slice(0,-1);return !/^\d+$/.test(r)||!/^[0-9K]$/.test(o)?null:{body:r,verificationDigit:o}}var R=2,y=9;function f(t){if(!t||typeof t!="string")return {isValid:false,error:"RUT is required"};let o=l(t);if(o.length<R)return {isValid:false,error:"RUT is too short"};if(o.length>y)return {isValid:false,error:"RUT is too long"};let r=u(o);if(!r)return {isValid:false,error:"Invalid RUT format"};let e=c(r.body);return r.verificationDigit!==e?{isValid:false,error:"Invalid verification digit"}:{isValid:true,rut:o}}function T(t){return f(t).isValid}var p=/\B(?=(\d{3})+(?!\d))/g,d={dots:true,dash:true,uppercase:true};function V(t,o={}){let r={...d,...o},e=l(t),i=u(e);if(!i)return "";let n=c(i.body);if(i.verificationDigit!==n)return "";let a=i.body;r.dots&&(a=i.body.replace(p,"."));let s=i.verificationDigit;r.uppercase||(s=s.toLowerCase());let g=r.dash?"-":"";return `${a}${g}${s}`}function x(t,o={}){let r={...d,...o},e=l(t);if(e.length===0)return "";let i,n;if(e.length>1){let s=e.slice(-1);/[0-9K]/.test(s)?(i=e.slice(0,-1),n=r.uppercase?s:s.toLowerCase()):(i=e,n="");}else i=e,n="";let a=i;if(r.dots&&i.length>0&&(a=i.replace(p,".")),n){let s=r.dash?"-":"";return `${a}${s}${n}`}return a}export{c as calculateVerificationDigit,l as cleanRut,V as formatRut,x as formatRutPartial,T as isValidRut,u as parseRut,f as validateRut};//# sourceMappingURL=index.mjs.map
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/clean.ts","../src/utils.ts","../src/validate.ts","../src/format.ts"],"names":["CLEAN_REGEX","cleanRut","input","calculateVerificationDigit","rutBody","multipliers","sum","multiplierIndex","i","digit","result","parseRut","cleanedRut","verificationDigit","body","MIN_RUT_LENGTH","MAX_RUT_LENGTH","validateRut","rut","cleaned","parsed","expectedDigit","isValidRut","DOTS_REGEX","DEFAULT_OPTIONS","formatRut","options","opts","formattedBody","dv","separator","formatRutPartial","lastChar"],"mappings":"AACA,IAAMA,CAAAA,CAAc,YAiBb,SAASC,CAAAA,CAASC,EAAuB,CAE5C,OAAI,OAAOA,CAAAA,EAAU,QAAA,CACV,EAAA,EAIPA,EAAM,MAAA,CAAS,EAAA,GACfA,EAAQA,CAAAA,CAAM,KAAA,CAAM,EAAG,EAAgB,CAAA,CAAA,CAIpCA,CAAAA,CAAM,OAAA,CAAQF,CAAAA,CAAa,EAAE,EAAE,WAAA,EAAY,CACtD,CCvBO,SAASG,CAAAA,CAA2BC,EAAyB,CAEhE,IAAMC,CAAAA,CAAc,CAAC,CAAA,CAAG,CAAA,CAAG,EAAG,CAAA,CAAG,CAAA,CAAG,CAAC,CAAA,CAEjCC,CAAAA,CAAM,EACNC,CAAAA,CAAkB,CAAA,CAGtB,IAAA,IAASC,CAAAA,CAAIJ,CAAAA,CAAQ,MAAA,CAAS,EAAGI,CAAAA,EAAK,CAAA,CAAGA,IAAK,CAC1C,IAAMC,EAAQ,QAAA,CAASL,CAAAA,CAAQI,CAAC,CAAA,CAAG,EAAE,CAAA,CACrCF,GAAOG,CAAAA,CAAQJ,CAAAA,CAAYE,CAAe,CAAA,CAC1CA,CAAAA,CAAAA,CAAmBA,EAAkB,CAAA,EAAK,EAC9C,CAIA,IAAMG,CAAAA,CAAS,EAAA,CADGJ,EAAM,EAAA,CAIxB,OAAII,IAAW,EAAA,CAAW,GAAA,CACtBA,IAAW,EAAA,CAAW,GAAA,CACnBA,CAAAA,CAAO,QAAA,EAClB,CAQO,SAASC,CAAAA,CAASC,CAAAA,CAAsC,CAC3D,GAAIA,CAAAA,CAAW,OAAS,CAAA,CACpB,OAAO,IAAA,CAGX,IAAMC,CAAAA,CAAoBD,CAAAA,CAAW,MAAM,EAAE,CAAA,CACvCE,EAAOF,CAAAA,CAAW,KAAA,CAAM,EAAG,EAAE,CAAA,CAQnC,OALI,CAAC,OAAA,CAAQ,IAAA,CAAKE,CAAI,CAAA,EAKlB,CAAC,WAAW,IAAA,CAAKD,CAAiB,EAC3B,IAAA,CAGJ,CAAE,IAAA,CAAAC,CAAAA,CAAM,iBAAA,CAAAD,CAAkB,CACrC,CCpDA,IAAME,EAAiB,CAAA,CAEjBC,CAAAA,CAAiB,EAgBhB,SAASC,CAAAA,CAAYC,CAAAA,CAA+B,CAEvD,GAAI,CAACA,GAAO,OAAOA,CAAAA,EAAQ,SACvB,OAAO,CAAE,QAAS,KAAA,CAAO,KAAA,CAAO,iBAAkB,CAAA,CAItD,IAAMC,CAAAA,CAAUlB,EAASiB,CAAG,CAAA,CAG5B,GAAIC,CAAAA,CAAQ,MAAA,CAASJ,EACjB,OAAO,CAAE,OAAA,CAAS,KAAA,CAAO,KAAA,CAAO,kBAAmB,EAIvD,GAAII,CAAAA,CAAQ,OAASH,CAAAA,CACjB,OAAO,CAAE,OAAA,CAAS,KAAA,CAAO,KAAA,CAAO,iBAAkB,CAAA,CAItD,IAAMI,EAAST,CAAAA,CAASQ,CAAO,EAC/B,GAAI,CAACC,EACD,OAAO,CAAE,OAAA,CAAS,KAAA,CAAO,KAAA,CAAO,oBAAqB,EAIzD,IAAMC,CAAAA,CAAgBlB,CAAAA,CAA2BiB,CAAAA,CAAO,IAAI,CAAA,CAG5D,OAAIA,CAAAA,CAAO,iBAAA,GAAsBC,CAAAA,CACtB,CAAE,OAAA,CAAS,KAAA,CAAO,MAAO,4BAA6B,CAAA,CAG1D,CAAE,OAAA,CAAS,IAAA,CAAM,IAAKF,CAAQ,CACzC,CAYO,SAASG,CAAAA,CAAWJ,CAAAA,CAAsB,CAC7C,OAAOD,CAAAA,CAAYC,CAAG,CAAA,CAAE,OAC5B,CClEA,IAAMK,CAAAA,CAAa,uBAAA,CAKbC,CAAAA,CAA2C,CAC7C,IAAA,CAAM,KACN,IAAA,CAAM,IAAA,CACN,UAAW,IACf,CAAA,CAiBO,SAASC,CAAAA,CAAUP,CAAAA,CAAaQ,CAAAA,CAAyB,EAAC,CAAW,CAExE,IAAMC,CAAAA,CAAgC,CAAE,GAAGH,CAAAA,CAAiB,GAAGE,CAAQ,CAAA,CAGjEP,CAAAA,CAAUlB,CAAAA,CAASiB,CAAG,CAAA,CAGtBE,CAAAA,CAAST,EAASQ,CAAO,CAAA,CAC/B,GAAI,CAACC,CAAAA,CACD,OAAO,EAAA,CAIX,IAAMC,CAAAA,CAAgBlB,CAAAA,CAA2BiB,CAAAA,CAAO,IAAI,EAC5D,GAAIA,CAAAA,CAAO,oBAAsBC,CAAAA,CAC7B,OAAO,GAIX,IAAIO,CAAAA,CAAgBR,CAAAA,CAAO,IAAA,CACvBO,CAAAA,CAAK,IAAA,GACLC,EAAgBR,CAAAA,CAAO,IAAA,CAAK,QAAQG,CAAAA,CAAY,GAAG,GAIvD,IAAIM,CAAAA,CAAKT,CAAAA,CAAO,iBAAA,CACXO,CAAAA,CAAK,SAAA,GACNE,EAAKA,CAAAA,CAAG,WAAA,EAAY,CAAA,CAIxB,IAAMC,CAAAA,CAAYH,CAAAA,CAAK,KAAO,GAAA,CAAM,EAAA,CACpC,OAAO,CAAA,EAAGC,CAAa,CAAA,EAAGE,CAAS,CAAA,EAAGD,CAAE,EAC5C,CAcO,SAASE,EAAiBb,CAAAA,CAAaQ,CAAAA,CAAyB,EAAC,CAAW,CAC/E,IAAMC,EAAgC,CAAE,GAAGH,EAAiB,GAAGE,CAAQ,EACjEP,CAAAA,CAAUlB,CAAAA,CAASiB,CAAG,CAAA,CAE5B,GAAIC,CAAAA,CAAQ,SAAW,CAAA,CACnB,OAAO,GAIX,IAAIL,CAAAA,CACAe,EAEJ,GAAIV,CAAAA,CAAQ,MAAA,CAAS,CAAA,CAAG,CAEpB,IAAMa,EAAWb,CAAAA,CAAQ,KAAA,CAAM,EAAE,CAAA,CAC7B,QAAA,CAAS,KAAKa,CAAQ,CAAA,EACtBlB,CAAAA,CAAOK,CAAAA,CAAQ,KAAA,CAAM,CAAA,CAAG,EAAE,CAAA,CAC1BU,CAAAA,CAAKF,EAAK,SAAA,CAAYK,CAAAA,CAAWA,EAAS,WAAA,EAAY,GAEtDlB,CAAAA,CAAOK,CAAAA,CACPU,CAAAA,CAAK,EAAA,EAEb,MACIf,CAAAA,CAAOK,CAAAA,CACPU,EAAK,EAAA,CAIT,IAAID,EAAgBd,CAAAA,CAMpB,GALIa,CAAAA,CAAK,IAAA,EAAQb,CAAAA,CAAK,MAAA,CAAS,IAC3Bc,CAAAA,CAAgBd,CAAAA,CAAK,QAAQS,CAAAA,CAAY,GAAG,GAI5CM,CAAAA,CAAI,CACJ,IAAMC,CAAAA,CAAYH,CAAAA,CAAK,IAAA,CAAO,IAAM,EAAA,CACpC,OAAO,CAAA,EAAGC,CAAa,CAAA,EAAGE,CAAS,GAAGD,CAAE,CAAA,CAC5C,CAEA,OAAOD,CACX","file":"index.mjs","sourcesContent":["// Pre-compiled regex for maximum performance\nconst CLEAN_REGEX = /[^0-9kK]/g;\n\n// Maximum allowed input length for security (prevents DoS)\nconst MAX_INPUT_LENGTH = 50;\n\n/**\n * Cleans a RUT string by removing all non-valid characters.\n * Keeps only numbers and 'K'/'k'.\n * \n * @param input - Raw RUT input string\n * @returns Cleaned RUT string with only valid characters\n * \n * @example\n * cleanRut('12.345.678-9') // '123456789'\n * cleanRut('12345678-K') // '12345678K'\n * cleanRut(' 12-345-678.9 ') // '123456789'\n */\nexport function cleanRut(input: string): string {\n // Security: handle non-string inputs gracefully\n if (typeof input !== 'string') {\n return '';\n }\n\n // Security: prevent DoS with extremely long inputs\n if (input.length > MAX_INPUT_LENGTH) {\n input = input.slice(0, MAX_INPUT_LENGTH);\n }\n\n // Remove all non-valid characters and convert to uppercase\n return input.replace(CLEAN_REGEX, '').toUpperCase();\n}\n","import type { ParsedRut } from './types';\n\n/**\n * Calculates the verification digit for a RUT body using Module 11 algorithm.\n * \n * @param rutBody - RUT body (numbers only, without verification digit)\n * @returns Calculated verification digit ('0'-'9' or 'K')\n */\nexport function calculateVerificationDigit(rutBody: string): string {\n // Multiplier sequence for Module 11 algorithm\n const multipliers = [2, 3, 4, 5, 6, 7];\n\n let sum = 0;\n let multiplierIndex = 0;\n\n // Process digits from right to left\n for (let i = rutBody.length - 1; i >= 0; i--) {\n const digit = parseInt(rutBody[i], 10);\n sum += digit * multipliers[multiplierIndex];\n multiplierIndex = (multiplierIndex + 1) % 6; // Cycle through multipliers\n }\n\n // Calculate verification digit\n const remainder = sum % 11;\n const result = 11 - remainder;\n\n // Convert result to verification digit\n if (result === 11) return '0';\n if (result === 10) return 'K';\n return result.toString();\n}\n\n/**\n * Parses a cleaned RUT string into body and verification digit.\n * \n * @param cleanedRut - Cleaned RUT string (only numbers and K)\n * @returns Parsed RUT object or null if invalid format\n */\nexport function parseRut(cleanedRut: string): ParsedRut | null {\n if (cleanedRut.length < 2) {\n return null;\n }\n\n const verificationDigit = cleanedRut.slice(-1);\n const body = cleanedRut.slice(0, -1);\n\n // Body must contain only digits\n if (!/^\\d+$/.test(body)) {\n return null;\n }\n\n // Verification digit must be a digit or K\n if (!/^[0-9K]$/.test(verificationDigit)) {\n return null;\n }\n\n return { body, verificationDigit };\n}\n","import type { ValidationResult } from './types';\nimport { cleanRut } from './clean';\nimport { parseRut, calculateVerificationDigit } from './utils';\n\n// Minimum valid RUT (1-9)\nconst MIN_RUT_LENGTH = 2;\n// Maximum valid RUT length (including verification digit)\nconst MAX_RUT_LENGTH = 9;\n\n/**\n * Validates a Chilean RUT (Rol Único Tributario).\n * \n * Uses the official Module 11 algorithm to verify the check digit.\n * \n * @param rut - RUT string to validate (can include dots, dashes, spaces)\n * @returns Validation result with isValid flag and cleaned RUT if valid\n * \n * @example\n * validateRut('12.345.678-5') // { isValid: true, rut: '123456785' }\n * validateRut('12345678-5') // { isValid: true, rut: '123456785' }\n * validateRut('12345678-0') // { isValid: false, error: 'Invalid verification digit' }\n * validateRut('') // { isValid: false, error: 'RUT is required' }\n */\nexport function validateRut(rut: string): ValidationResult {\n // Handle empty input\n if (!rut || typeof rut !== 'string') {\n return { isValid: false, error: 'RUT is required' };\n }\n\n // Clean the RUT\n const cleaned = cleanRut(rut);\n\n // Check minimum length\n if (cleaned.length < MIN_RUT_LENGTH) {\n return { isValid: false, error: 'RUT is too short' };\n }\n\n // Check maximum length\n if (cleaned.length > MAX_RUT_LENGTH) {\n return { isValid: false, error: 'RUT is too long' };\n }\n\n // Parse the RUT\n const parsed = parseRut(cleaned);\n if (!parsed) {\n return { isValid: false, error: 'Invalid RUT format' };\n }\n\n // Calculate expected verification digit\n const expectedDigit = calculateVerificationDigit(parsed.body);\n\n // Compare with provided verification digit\n if (parsed.verificationDigit !== expectedDigit) {\n return { isValid: false, error: 'Invalid verification digit' };\n }\n\n return { isValid: true, rut: cleaned };\n}\n\n/**\n * Simple boolean check for RUT validity.\n * \n * @param rut - RUT string to validate\n * @returns true if RUT is valid, false otherwise\n * \n * @example\n * isValidRut('12.345.678-5') // true\n * isValidRut('12345678-0') // false\n */\nexport function isValidRut(rut: string): boolean {\n return validateRut(rut).isValid;\n}\n","import type { FormatOptions } from './types';\nimport { cleanRut } from './clean';\nimport { parseRut, calculateVerificationDigit } from './utils';\n\n// Pre-compiled regex for adding dots\nconst DOTS_REGEX = /\\B(?=(\\d{3})+(?!\\d))/g;\n\n/**\n * Default formatting options\n */\nconst DEFAULT_OPTIONS: Required<FormatOptions> = {\n dots: true,\n dash: true,\n uppercase: true,\n};\n\n/**\n * Formats a Chilean RUT with the specified options.\n * \n * By default, formats as: 12.345.678-9\n * \n * @param rut - RUT string to format (can include dots, dashes, spaces)\n * @param options - Formatting options\n * @returns Formatted RUT string, or empty string if invalid\n * \n * @example\n * formatRut('123456785') // '12.345.678-5'\n * formatRut('123456785', { dots: false }) // '12345678-5'\n * formatRut('123456785', { dash: false }) // '12.345.6785'\n * formatRut('12345678K', { uppercase: false }) // '12.345.678-k'\n */\nexport function formatRut(rut: string, options: FormatOptions = {}): string {\n // Merge with defaults\n const opts: Required<FormatOptions> = { ...DEFAULT_OPTIONS, ...options };\n\n // Clean the RUT\n const cleaned = cleanRut(rut);\n\n // Parse and validate\n const parsed = parseRut(cleaned);\n if (!parsed) {\n return '';\n }\n\n // Validate the verification digit\n const expectedDigit = calculateVerificationDigit(parsed.body);\n if (parsed.verificationDigit !== expectedDigit) {\n return '';\n }\n\n // Format the body\n let formattedBody = parsed.body;\n if (opts.dots) {\n formattedBody = parsed.body.replace(DOTS_REGEX, '.');\n }\n\n // Format the verification digit\n let dv = parsed.verificationDigit;\n if (!opts.uppercase) {\n dv = dv.toLowerCase();\n }\n\n // Combine with separator\n const separator = opts.dash ? '-' : '';\n return `${formattedBody}${separator}${dv}`;\n}\n\n/**\n * Formats a RUT without validation (use with caution).\n * Useful when you need to format user input as they type.\n * \n * @param rut - RUT string to format\n * @param options - Formatting options\n * @returns Formatted RUT string\n * \n * @example\n * formatRutPartial('12345') // '12.345'\n * formatRutPartial('123456789') // '12.345.678-9'\n */\nexport function formatRutPartial(rut: string, options: FormatOptions = {}): string {\n const opts: Required<FormatOptions> = { ...DEFAULT_OPTIONS, ...options };\n const cleaned = cleanRut(rut);\n\n if (cleaned.length === 0) {\n return '';\n }\n\n // Separate body and potential verification digit\n let body: string;\n let dv: string;\n\n if (cleaned.length > 1) {\n // Check if last char could be a verification digit (K or any digit)\n const lastChar = cleaned.slice(-1);\n if (/[0-9K]/.test(lastChar)) {\n body = cleaned.slice(0, -1);\n dv = opts.uppercase ? lastChar : lastChar.toLowerCase();\n } else {\n body = cleaned;\n dv = '';\n }\n } else {\n body = cleaned;\n dv = '';\n }\n\n // Format body with dots if needed\n let formattedBody = body;\n if (opts.dots && body.length > 0) {\n formattedBody = body.replace(DOTS_REGEX, '.');\n }\n\n // Add verification digit if present\n if (dv) {\n const separator = opts.dash ? '-' : '';\n return `${formattedBody}${separator}${dv}`;\n }\n\n return formattedBody;\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "chilean-rut-formatter",
3
+ "version": "1.0.0",
4
+ "description": "High-performance library for formatting and validating Chilean RUTs (Rol Único Tributario)",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "test": "vitest run",
21
+ "test:watch": "vitest",
22
+ "lint": "tsc --noEmit",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "keywords": [
26
+ "rut",
27
+ "chile",
28
+ "chilean",
29
+ "rut-validator",
30
+ "rut-formatter",
31
+ "tax-id",
32
+ "validation"
33
+ ],
34
+ "author": "",
35
+ "license": "MIT",
36
+ "devDependencies": {
37
+ "tsup": "^8.0.0",
38
+ "typescript": "^5.3.0",
39
+ "vitest": "^1.2.0"
40
+ },
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/your-username/chilean-rut-formatter"
44
+ },
45
+ "engines": {
46
+ "node": ">=16"
47
+ }
48
+ }