fi-pin 0.0.8 → 0.0.9

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 CHANGED
@@ -8,17 +8,25 @@
8
8
 
9
9
  This module provides functions to validate Finnish person IDs (Henkilötunnus) and determine the gender based on the ID. A valid Finnish person ID consists of 11 characters in the format `DDMMYYCZZZQ`, where:
10
10
 
11
- - `DDMMYY` represents the date of birth
12
- - `C` is the century sign ('+' for 1800s, '-' for 1900s, 'A' for 2000s)
13
- - `ZZZ` is an individual number (odd numbers are males, even numbers are females)
14
- - `Q` is a checksum character
11
+ - `DDMMYY` represents the date of birth.
12
+ - `C` is the century sign ('+' for 1800s, '-' for 1900s, 'A' for 2000s).
13
+ - `ZZZ` is an individual number (odd numbers are males, even numbers are females).
14
+ - `Q` is a checksum character.
15
15
 
16
16
  ## Installation
17
17
 
18
+ To install the module, run the following command:
19
+
18
20
  ```bash
19
21
  npm install fi-pin
20
22
  ```
21
23
 
24
+ or direct import from unpkg (i.e., on a web page):
25
+
26
+ ```typescript
27
+ import {isValidPersonId, isMale, isFemale} from 'https://unpkg.com/fi-pin@latest/dist/index.mjs';
28
+ ```
29
+
22
30
  ## Usage
23
31
 
24
32
  ```typescript
package/dist/index.d.mts CHANGED
@@ -1,52 +1,56 @@
1
1
  /**
2
2
  * Parse string to integer
3
3
  * @throws TypeError if value is not a number
4
- * @param value - string to parse
5
- * @returns value as number
4
+ * @param {string | undefined} value - string to parse
5
+ * @returns {number} value as number
6
+ * @since v0.0.7
6
7
  */
7
8
  declare function parseStringToInt(value: string | undefined): number;
8
9
  /**
9
10
  * Validate that value is a string
10
11
  * @throws TypeError if value is not a string
11
- * @param value - value to validate
12
- * @returns value as string
12
+ * @param {unknown} value - value to validate
13
+ * @returns {string} value as string
14
+ * @since v0.0.7
13
15
  */
14
16
  declare function validateString(value: unknown): string;
15
17
  /**
16
- * Get checksum for check sum index number
17
- * @param index - index number to lookup checksum character
18
- * @returns checksum character from checksum index map
18
+ * Returns the checksum character from the checksum index map.
19
+ * @param {number} index The index of the checksum character.
20
+ * @returns {string} The checksum character at the specified index, or undefined if the index is out of bounds.
21
+ * @throws {RangeError} If the index is less than 0 or greater than or equal to checkSumMapLength.
22
+ * @since v0.0.7
19
23
  */
20
- declare function getCheckSum(index: number): string | undefined;
24
+ declare function getCheckSum(index: number): string;
21
25
  /**
22
- * Validate if a string is a valid Finnish person ID
26
+ * Validates whether a string is a valid Finnish person ID.
23
27
  *
24
28
  * A valid Finnish person ID consists of 11 characters in the format DDMMYYCZZZQ, where:
25
- * - DDMMYY represents the date of birth
26
- * - C is the century sign ('+' for 1800s, '-' for 1900s, 'A' for 2000s)
27
- * - ZZZ is an individual number (odd numbers are males, even numbers are females)
28
- * - Q is a checksum character
29
+ * - DDMMYY represents the date of birth.
30
+ * - C is the century sign ('+' for 1800s, '-' for 1900s, 'A' for 2000s).
31
+ * - ZZZ is an individual number (odd numbers are males, even numbers are females).
32
+ * - Q is a checksum character.
29
33
  *
30
34
  * The checksum character is calculated based on the first 10 characters.
31
- * @param personId - The person ID string to validate
32
- * @template BRAND - Optional: brand type for more strict type (i.e. use Zod branded type or custom type)
33
- * @returns true if the person ID is valid, false otherwise
35
+ * @param {string} personId The person ID string to validate.
36
+ * @template BRAND Optional brand type for a more strict type (e.g., use Zod branded type or custom type).
37
+ * @returns {boolean} True if the person ID is valid, false otherwise.
34
38
  * @example
35
39
  * isValidPersonId('131052-308T') // true
36
40
  * isValidPersonId('131052-3082') // false
37
41
  * const personId = '131052-308T';
38
- * if(isValidPersonId<z.BRAND<'PersonID'>>(personId)) { // personId type is now: string & z.BRAND<'PersonID'>
42
+ * if (isValidPersonId<z.BRAND<'PersonID'>>(personId)) { // personId type is now: string & z.BRAND<'PersonID'>
39
43
  * // personId type is now: string & z.BRAND<'PersonID'>
40
44
  * }
41
45
  * @since v0.0.1
42
46
  */
43
47
  declare function isValidPersonId<BRAND = string>(personId: string): personId is string & BRAND;
44
48
  /**
45
- * Check if personId belongs to a Finnish male
46
- * @throws TypeError if personId is not valid
47
- * @param personId - Finnish personId string
48
- * @template BRAND - Optional: brand type for more strict type (i.e. use Zod branded type or custom type)
49
- * @returns true if the personId belongs to a male, false otherwise
49
+ * Checks whether a person ID belongs to a Finnish male.
50
+ * @param {string} personId The Finnish person ID string.
51
+ * @template BRAND Optional brand type for a more strict type (e.g., use Zod branded type or custom type).
52
+ * @returns {boolean} True if the person ID belongs to a male, false otherwise.
53
+ * @throws {TypeError} If the person ID is not valid.
50
54
  * @example
51
55
  * isMale('131052-309U') // true
52
56
  * isMale('131052-308T') // false
@@ -55,11 +59,11 @@ declare function isValidPersonId<BRAND = string>(personId: string): personId is
55
59
  */
56
60
  declare function isMale<BRAND = string>(personId: string): personId is string & BRAND;
57
61
  /**
58
- * Check if personId belongs to a Finnish female
59
- * @throws TypeError if personId is not valid
60
- * @param personId - Finnish personId string
61
- * @template BRAND - Optional: brand type for more strict type (i.e. use Zod branded type or custom type)
62
- * @returns true if the personId belongs to a female, false otherwise
62
+ * Checks whether a person ID belongs to a Finnish female.
63
+ * @param {string} personId The Finnish person ID string.
64
+ * @template BRAND Optional brand type for a more strict type (e.g., use Zod branded type or custom type).
65
+ * @returns {boolean} True if the person ID belongs to a female, false otherwise.
66
+ * @throws {TypeError} If the person ID is not valid.
63
67
  * @example
64
68
  * isFemale('131052-308T') // true
65
69
  * isFemale('131052-309U') // false
package/dist/index.d.ts CHANGED
@@ -1,52 +1,56 @@
1
1
  /**
2
2
  * Parse string to integer
3
3
  * @throws TypeError if value is not a number
4
- * @param value - string to parse
5
- * @returns value as number
4
+ * @param {string | undefined} value - string to parse
5
+ * @returns {number} value as number
6
+ * @since v0.0.7
6
7
  */
7
8
  declare function parseStringToInt(value: string | undefined): number;
8
9
  /**
9
10
  * Validate that value is a string
10
11
  * @throws TypeError if value is not a string
11
- * @param value - value to validate
12
- * @returns value as string
12
+ * @param {unknown} value - value to validate
13
+ * @returns {string} value as string
14
+ * @since v0.0.7
13
15
  */
14
16
  declare function validateString(value: unknown): string;
15
17
  /**
16
- * Get checksum for check sum index number
17
- * @param index - index number to lookup checksum character
18
- * @returns checksum character from checksum index map
18
+ * Returns the checksum character from the checksum index map.
19
+ * @param {number} index The index of the checksum character.
20
+ * @returns {string} The checksum character at the specified index, or undefined if the index is out of bounds.
21
+ * @throws {RangeError} If the index is less than 0 or greater than or equal to checkSumMapLength.
22
+ * @since v0.0.7
19
23
  */
20
- declare function getCheckSum(index: number): string | undefined;
24
+ declare function getCheckSum(index: number): string;
21
25
  /**
22
- * Validate if a string is a valid Finnish person ID
26
+ * Validates whether a string is a valid Finnish person ID.
23
27
  *
24
28
  * A valid Finnish person ID consists of 11 characters in the format DDMMYYCZZZQ, where:
25
- * - DDMMYY represents the date of birth
26
- * - C is the century sign ('+' for 1800s, '-' for 1900s, 'A' for 2000s)
27
- * - ZZZ is an individual number (odd numbers are males, even numbers are females)
28
- * - Q is a checksum character
29
+ * - DDMMYY represents the date of birth.
30
+ * - C is the century sign ('+' for 1800s, '-' for 1900s, 'A' for 2000s).
31
+ * - ZZZ is an individual number (odd numbers are males, even numbers are females).
32
+ * - Q is a checksum character.
29
33
  *
30
34
  * The checksum character is calculated based on the first 10 characters.
31
- * @param personId - The person ID string to validate
32
- * @template BRAND - Optional: brand type for more strict type (i.e. use Zod branded type or custom type)
33
- * @returns true if the person ID is valid, false otherwise
35
+ * @param {string} personId The person ID string to validate.
36
+ * @template BRAND Optional brand type for a more strict type (e.g., use Zod branded type or custom type).
37
+ * @returns {boolean} True if the person ID is valid, false otherwise.
34
38
  * @example
35
39
  * isValidPersonId('131052-308T') // true
36
40
  * isValidPersonId('131052-3082') // false
37
41
  * const personId = '131052-308T';
38
- * if(isValidPersonId<z.BRAND<'PersonID'>>(personId)) { // personId type is now: string & z.BRAND<'PersonID'>
42
+ * if (isValidPersonId<z.BRAND<'PersonID'>>(personId)) { // personId type is now: string & z.BRAND<'PersonID'>
39
43
  * // personId type is now: string & z.BRAND<'PersonID'>
40
44
  * }
41
45
  * @since v0.0.1
42
46
  */
43
47
  declare function isValidPersonId<BRAND = string>(personId: string): personId is string & BRAND;
44
48
  /**
45
- * Check if personId belongs to a Finnish male
46
- * @throws TypeError if personId is not valid
47
- * @param personId - Finnish personId string
48
- * @template BRAND - Optional: brand type for more strict type (i.e. use Zod branded type or custom type)
49
- * @returns true if the personId belongs to a male, false otherwise
49
+ * Checks whether a person ID belongs to a Finnish male.
50
+ * @param {string} personId The Finnish person ID string.
51
+ * @template BRAND Optional brand type for a more strict type (e.g., use Zod branded type or custom type).
52
+ * @returns {boolean} True if the person ID belongs to a male, false otherwise.
53
+ * @throws {TypeError} If the person ID is not valid.
50
54
  * @example
51
55
  * isMale('131052-309U') // true
52
56
  * isMale('131052-308T') // false
@@ -55,11 +59,11 @@ declare function isValidPersonId<BRAND = string>(personId: string): personId is
55
59
  */
56
60
  declare function isMale<BRAND = string>(personId: string): personId is string & BRAND;
57
61
  /**
58
- * Check if personId belongs to a Finnish female
59
- * @throws TypeError if personId is not valid
60
- * @param personId - Finnish personId string
61
- * @template BRAND - Optional: brand type for more strict type (i.e. use Zod branded type or custom type)
62
- * @returns true if the personId belongs to a female, false otherwise
62
+ * Checks whether a person ID belongs to a Finnish female.
63
+ * @param {string} personId The Finnish person ID string.
64
+ * @template BRAND Optional brand type for a more strict type (e.g., use Zod branded type or custom type).
65
+ * @returns {boolean} True if the person ID belongs to a female, false otherwise.
66
+ * @throws {TypeError} If the person ID is not valid.
63
67
  * @example
64
68
  * isFemale('131052-308T') // true
65
69
  * isFemale('131052-309U') // false
package/dist/index.js CHANGED
@@ -18,8 +18,8 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
20
  // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
23
  getCheckSum: () => getCheckSum,
24
24
  isFemale: () => isFemale,
25
25
  isMale: () => isMale,
@@ -27,7 +27,7 @@ __export(src_exports, {
27
27
  parseStringToInt: () => parseStringToInt,
28
28
  validateString: () => validateString
29
29
  });
30
- module.exports = __toCommonJS(src_exports);
30
+ module.exports = __toCommonJS(index_exports);
31
31
  var checksumCharacterSet = "0123456789ABCDEFHJKLMNPRSTUVWXY";
32
32
  var checkSumMapLength = checksumCharacterSet.length;
33
33
  function parseStringToInt(value) {
@@ -47,10 +47,11 @@ function validateString(value) {
47
47
  return value;
48
48
  }
49
49
  function getCheckSum(index) {
50
- if (index < 0 || index >= checkSumMapLength) {
50
+ const checkSumChar = checksumCharacterSet[index];
51
+ if (!checkSumChar) {
51
52
  throw new RangeError(`Index out of bounds: ${index.toString()} (valid range: 0-${String(checkSumMapLength - 1)})`);
52
53
  }
53
- return checksumCharacterSet[index];
54
+ return checkSumChar;
54
55
  }
55
56
  function isValidPersonId(personId) {
56
57
  if (typeof personId !== "string" || personId.length !== 11) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["const checksumCharacterSet = '0123456789ABCDEFHJKLMNPRSTUVWXY';\nconst checkSumMapLength = checksumCharacterSet.length; // is always 31\n\n/**\n * Parse string to integer\n * @throws TypeError if value is not a number\n * @param value - string to parse\n * @returns value as number\n */\nexport function parseStringToInt(value: string | undefined): number {\n\tif (!value) {\n\t\tthrow new TypeError('Value is undefined');\n\t}\n\tconst parsedValue = parseInt(value, 10);\n\tif (isNaN(parsedValue)) {\n\t\tthrow new TypeError(`Value is not a number: ${value}`);\n\t}\n\treturn parsedValue;\n}\n\n/**\n * Validate that value is a string\n * @throws TypeError if value is not a string\n * @param value - value to validate\n * @returns value as string\n */\nexport function validateString(value: unknown): string {\n\tif (typeof value !== 'string') {\n\t\tthrow new TypeError(`${String(value)} not a string`);\n\t}\n\treturn value;\n}\n\n/**\n * Get checksum for check sum index number\n * @param index - index number to lookup checksum character\n * @returns checksum character from checksum index map\n */\nexport function getCheckSum(index: number): string | undefined {\n\tif (index < 0 || index >= checkSumMapLength) {\n\t\tthrow new RangeError(`Index out of bounds: ${index.toString()} (valid range: 0-${String(checkSumMapLength - 1)})`);\n\t}\n\treturn checksumCharacterSet[index];\n}\n\n/**\n * Validate if a string is a valid Finnish person ID\n *\n * A valid Finnish person ID consists of 11 characters in the format DDMMYYCZZZQ, where:\n * - DDMMYY represents the date of birth\n * - C is the century sign ('+' for 1800s, '-' for 1900s, 'A' for 2000s)\n * - ZZZ is an individual number (odd numbers are males, even numbers are females)\n * - Q is a checksum character\n *\n * The checksum character is calculated based on the first 10 characters.\n * @param personId - The person ID string to validate\n * @template BRAND - Optional: brand type for more strict type (i.e. use Zod branded type or custom type)\n * @returns true if the person ID is valid, false otherwise\n * @example\n * isValidPersonId('131052-308T') // true\n * isValidPersonId('131052-3082') // false\n * const personId = '131052-308T';\n * if(isValidPersonId<z.BRAND<'PersonID'>>(personId)) { // personId type is now: string & z.BRAND<'PersonID'>\n * // personId type is now: string & z.BRAND<'PersonID'>\n * }\n * @since v0.0.1\n */\nexport function isValidPersonId<BRAND = string>(personId: string): personId is string & BRAND {\n\tif (typeof personId !== 'string' || personId.length !== 11) {\n\t\treturn false;\n\t}\n\tconst upperPersonId = personId.toUpperCase();\n\ttry {\n\t\treturn upperPersonId[10] === getCheckSum(parseStringToInt(upperPersonId.slice(0, 6) + upperPersonId.slice(7, 10)) % checkSumMapLength);\n\t} catch (_error) {\n\t\treturn false;\n\t}\n}\n\n/**\n * Check if personId belongs to a Finnish male\n * @throws TypeError if personId is not valid\n * @param personId - Finnish personId string\n * @template BRAND - Optional: brand type for more strict type (i.e. use Zod branded type or custom type)\n * @returns true if the personId belongs to a male, false otherwise\n * @example\n * isMale('131052-309U') // true\n * isMale('131052-308T') // false\n * isMale<z.BRAND<'PersonIdMale'>>(personId) // if true, personId type is now: string & z.BRAND<'PersonIdMale'>\n * @since v0.0.1\n */\nexport function isMale<BRAND = string>(personId: string): personId is string & BRAND {\n\tif (!isValidPersonId(personId)) {\n\t\tthrow new TypeError(`${String(personId)} is not valid person id`);\n\t}\n\treturn parseStringToInt(personId.slice(7, 10)) % 2 === 1; // check if the individual number is odd\n}\n\n/**\n * Check if personId belongs to a Finnish female\n * @throws TypeError if personId is not valid\n * @param personId - Finnish personId string\n * @template BRAND - Optional: brand type for more strict type (i.e. use Zod branded type or custom type)\n * @returns true if the personId belongs to a female, false otherwise\n * @example\n * isFemale('131052-308T') // true\n * isFemale('131052-309U') // false\n * isFemale<z.BRAND<'PersonIdFemale'>>(personId) // if true, personId type is now: string & z.BRAND<'PersonIdFemale'>\n * @since v0.0.1\n */\nexport function isFemale<BRAND = string>(personId: string): personId is string & BRAND {\n\treturn !isMale(personId);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAM,uBAAuB;AAC7B,IAAM,oBAAoB,qBAAqB;AAQxC,SAAS,iBAAiB,OAAmC;AACnE,MAAI,CAAC,OAAO;AACX,UAAM,IAAI,UAAU,oBAAoB;AAAA,EACzC;AACA,QAAM,cAAc,SAAS,OAAO,EAAE;AACtC,MAAI,MAAM,WAAW,GAAG;AACvB,UAAM,IAAI,UAAU,0BAA0B,KAAK,EAAE;AAAA,EACtD;AACA,SAAO;AACR;AAQO,SAAS,eAAe,OAAwB;AACtD,MAAI,OAAO,UAAU,UAAU;AAC9B,UAAM,IAAI,UAAU,GAAG,OAAO,KAAK,CAAC,eAAe;AAAA,EACpD;AACA,SAAO;AACR;AAOO,SAAS,YAAY,OAAmC;AAC9D,MAAI,QAAQ,KAAK,SAAS,mBAAmB;AAC5C,UAAM,IAAI,WAAW,wBAAwB,MAAM,SAAS,CAAC,oBAAoB,OAAO,oBAAoB,CAAC,CAAC,GAAG;AAAA,EAClH;AACA,SAAO,qBAAqB,KAAK;AAClC;AAwBO,SAAS,gBAAgC,UAA8C;AAC7F,MAAI,OAAO,aAAa,YAAY,SAAS,WAAW,IAAI;AAC3D,WAAO;AAAA,EACR;AACA,QAAM,gBAAgB,SAAS,YAAY;AAC3C,MAAI;AACH,WAAO,cAAc,EAAE,MAAM,YAAY,iBAAiB,cAAc,MAAM,GAAG,CAAC,IAAI,cAAc,MAAM,GAAG,EAAE,CAAC,IAAI,iBAAiB;AAAA,EACtI,SAAS,QAAQ;AAChB,WAAO;AAAA,EACR;AACD;AAcO,SAAS,OAAuB,UAA8C;AACpF,MAAI,CAAC,gBAAgB,QAAQ,GAAG;AAC/B,UAAM,IAAI,UAAU,GAAG,OAAO,QAAQ,CAAC,yBAAyB;AAAA,EACjE;AACA,SAAO,iBAAiB,SAAS,MAAM,GAAG,EAAE,CAAC,IAAI,MAAM;AACxD;AAcO,SAAS,SAAyB,UAA8C;AACtF,SAAO,CAAC,OAAO,QAAQ;AACxB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["const checksumCharacterSet = '0123456789ABCDEFHJKLMNPRSTUVWXY';\nconst checkSumMapLength = checksumCharacterSet.length; // is always 31\n\n/**\n * Parse string to integer\n * @throws TypeError if value is not a number\n * @param {string | undefined} value - string to parse\n * @returns {number} value as number\n * @since v0.0.7\n */\nexport function parseStringToInt(value: string | undefined): number {\n\tif (!value) {\n\t\tthrow new TypeError('Value is undefined');\n\t}\n\tconst parsedValue = parseInt(value, 10);\n\tif (isNaN(parsedValue)) {\n\t\tthrow new TypeError(`Value is not a number: ${value}`);\n\t}\n\treturn parsedValue;\n}\n\n/**\n * Validate that value is a string\n * @throws TypeError if value is not a string\n * @param {unknown} value - value to validate\n * @returns {string} value as string\n * @since v0.0.7\n */\nexport function validateString(value: unknown): string {\n\tif (typeof value !== 'string') {\n\t\tthrow new TypeError(`${String(value)} not a string`);\n\t}\n\treturn value;\n}\n\n/**\n * Returns the checksum character from the checksum index map.\n * @param {number} index The index of the checksum character.\n * @returns {string} The checksum character at the specified index, or undefined if the index is out of bounds.\n * @throws {RangeError} If the index is less than 0 or greater than or equal to checkSumMapLength.\n * @since v0.0.7\n */\nexport function getCheckSum(index: number): string {\n\tconst checkSumChar = checksumCharacterSet[index];\n\tif (!checkSumChar) {\n\t\tthrow new RangeError(`Index out of bounds: ${index.toString()} (valid range: 0-${String(checkSumMapLength - 1)})`);\n\t}\n\treturn checkSumChar;\n}\n\n/**\n * Validates whether a string is a valid Finnish person ID.\n *\n * A valid Finnish person ID consists of 11 characters in the format DDMMYYCZZZQ, where:\n * - DDMMYY represents the date of birth.\n * - C is the century sign ('+' for 1800s, '-' for 1900s, 'A' for 2000s).\n * - ZZZ is an individual number (odd numbers are males, even numbers are females).\n * - Q is a checksum character.\n *\n * The checksum character is calculated based on the first 10 characters.\n * @param {string} personId The person ID string to validate.\n * @template BRAND Optional brand type for a more strict type (e.g., use Zod branded type or custom type).\n * @returns {boolean} True if the person ID is valid, false otherwise.\n * @example\n * isValidPersonId('131052-308T') // true\n * isValidPersonId('131052-3082') // false\n * const personId = '131052-308T';\n * if (isValidPersonId<z.BRAND<'PersonID'>>(personId)) { // personId type is now: string & z.BRAND<'PersonID'>\n * // personId type is now: string & z.BRAND<'PersonID'>\n * }\n * @since v0.0.1\n */\nexport function isValidPersonId<BRAND = string>(personId: string): personId is string & BRAND {\n\tif (typeof personId !== 'string' || personId.length !== 11) {\n\t\treturn false;\n\t}\n\tconst upperPersonId = personId.toUpperCase();\n\ttry {\n\t\treturn upperPersonId[10] === getCheckSum(parseStringToInt(upperPersonId.slice(0, 6) + upperPersonId.slice(7, 10)) % checkSumMapLength);\n\t} catch (_error) {\n\t\treturn false;\n\t}\n}\n\n/**\n * Checks whether a person ID belongs to a Finnish male.\n * @param {string} personId The Finnish person ID string.\n * @template BRAND Optional brand type for a more strict type (e.g., use Zod branded type or custom type).\n * @returns {boolean} True if the person ID belongs to a male, false otherwise.\n * @throws {TypeError} If the person ID is not valid.\n * @example\n * isMale('131052-309U') // true\n * isMale('131052-308T') // false\n * isMale<z.BRAND<'PersonIdMale'>>(personId) // if true, personId type is now: string & z.BRAND<'PersonIdMale'>\n * @since v0.0.1\n */\nexport function isMale<BRAND = string>(personId: string): personId is string & BRAND {\n\tif (!isValidPersonId(personId)) {\n\t\tthrow new TypeError(`${String(personId)} is not valid person id`);\n\t}\n\treturn parseStringToInt(personId.slice(7, 10)) % 2 === 1; // check if the individual number is odd\n}\n\n/**\n * Checks whether a person ID belongs to a Finnish female.\n * @param {string} personId The Finnish person ID string.\n * @template BRAND Optional brand type for a more strict type (e.g., use Zod branded type or custom type).\n * @returns {boolean} True if the person ID belongs to a female, false otherwise.\n * @throws {TypeError} If the person ID is not valid.\n * @example\n * isFemale('131052-308T') // true\n * isFemale('131052-309U') // false\n * isFemale<z.BRAND<'PersonIdFemale'>>(personId) // if true, personId type is now: string & z.BRAND<'PersonIdFemale'>\n * @since v0.0.1\n */\nexport function isFemale<BRAND = string>(personId: string): personId is string & BRAND {\n\treturn !isMale(personId);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAM,uBAAuB;AAC7B,IAAM,oBAAoB,qBAAqB;AASxC,SAAS,iBAAiB,OAAmC;AACnE,MAAI,CAAC,OAAO;AACX,UAAM,IAAI,UAAU,oBAAoB;AAAA,EACzC;AACA,QAAM,cAAc,SAAS,OAAO,EAAE;AACtC,MAAI,MAAM,WAAW,GAAG;AACvB,UAAM,IAAI,UAAU,0BAA0B,KAAK,EAAE;AAAA,EACtD;AACA,SAAO;AACR;AASO,SAAS,eAAe,OAAwB;AACtD,MAAI,OAAO,UAAU,UAAU;AAC9B,UAAM,IAAI,UAAU,GAAG,OAAO,KAAK,CAAC,eAAe;AAAA,EACpD;AACA,SAAO;AACR;AASO,SAAS,YAAY,OAAuB;AAClD,QAAM,eAAe,qBAAqB,KAAK;AAC/C,MAAI,CAAC,cAAc;AAClB,UAAM,IAAI,WAAW,wBAAwB,MAAM,SAAS,CAAC,oBAAoB,OAAO,oBAAoB,CAAC,CAAC,GAAG;AAAA,EAClH;AACA,SAAO;AACR;AAwBO,SAAS,gBAAgC,UAA8C;AAC7F,MAAI,OAAO,aAAa,YAAY,SAAS,WAAW,IAAI;AAC3D,WAAO;AAAA,EACR;AACA,QAAM,gBAAgB,SAAS,YAAY;AAC3C,MAAI;AACH,WAAO,cAAc,EAAE,MAAM,YAAY,iBAAiB,cAAc,MAAM,GAAG,CAAC,IAAI,cAAc,MAAM,GAAG,EAAE,CAAC,IAAI,iBAAiB;AAAA,EACtI,SAAS,QAAQ;AAChB,WAAO;AAAA,EACR;AACD;AAcO,SAAS,OAAuB,UAA8C;AACpF,MAAI,CAAC,gBAAgB,QAAQ,GAAG;AAC/B,UAAM,IAAI,UAAU,GAAG,OAAO,QAAQ,CAAC,yBAAyB;AAAA,EACjE;AACA,SAAO,iBAAiB,SAAS,MAAM,GAAG,EAAE,CAAC,IAAI,MAAM;AACxD;AAcO,SAAS,SAAyB,UAA8C;AACtF,SAAO,CAAC,OAAO,QAAQ;AACxB;","names":[]}
package/dist/index.mjs CHANGED
@@ -18,10 +18,11 @@ function validateString(value) {
18
18
  return value;
19
19
  }
20
20
  function getCheckSum(index) {
21
- if (index < 0 || index >= checkSumMapLength) {
21
+ const checkSumChar = checksumCharacterSet[index];
22
+ if (!checkSumChar) {
22
23
  throw new RangeError(`Index out of bounds: ${index.toString()} (valid range: 0-${String(checkSumMapLength - 1)})`);
23
24
  }
24
- return checksumCharacterSet[index];
25
+ return checkSumChar;
25
26
  }
26
27
  function isValidPersonId(personId) {
27
28
  if (typeof personId !== "string" || personId.length !== 11) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["const checksumCharacterSet = '0123456789ABCDEFHJKLMNPRSTUVWXY';\nconst checkSumMapLength = checksumCharacterSet.length; // is always 31\n\n/**\n * Parse string to integer\n * @throws TypeError if value is not a number\n * @param value - string to parse\n * @returns value as number\n */\nexport function parseStringToInt(value: string | undefined): number {\n\tif (!value) {\n\t\tthrow new TypeError('Value is undefined');\n\t}\n\tconst parsedValue = parseInt(value, 10);\n\tif (isNaN(parsedValue)) {\n\t\tthrow new TypeError(`Value is not a number: ${value}`);\n\t}\n\treturn parsedValue;\n}\n\n/**\n * Validate that value is a string\n * @throws TypeError if value is not a string\n * @param value - value to validate\n * @returns value as string\n */\nexport function validateString(value: unknown): string {\n\tif (typeof value !== 'string') {\n\t\tthrow new TypeError(`${String(value)} not a string`);\n\t}\n\treturn value;\n}\n\n/**\n * Get checksum for check sum index number\n * @param index - index number to lookup checksum character\n * @returns checksum character from checksum index map\n */\nexport function getCheckSum(index: number): string | undefined {\n\tif (index < 0 || index >= checkSumMapLength) {\n\t\tthrow new RangeError(`Index out of bounds: ${index.toString()} (valid range: 0-${String(checkSumMapLength - 1)})`);\n\t}\n\treturn checksumCharacterSet[index];\n}\n\n/**\n * Validate if a string is a valid Finnish person ID\n *\n * A valid Finnish person ID consists of 11 characters in the format DDMMYYCZZZQ, where:\n * - DDMMYY represents the date of birth\n * - C is the century sign ('+' for 1800s, '-' for 1900s, 'A' for 2000s)\n * - ZZZ is an individual number (odd numbers are males, even numbers are females)\n * - Q is a checksum character\n *\n * The checksum character is calculated based on the first 10 characters.\n * @param personId - The person ID string to validate\n * @template BRAND - Optional: brand type for more strict type (i.e. use Zod branded type or custom type)\n * @returns true if the person ID is valid, false otherwise\n * @example\n * isValidPersonId('131052-308T') // true\n * isValidPersonId('131052-3082') // false\n * const personId = '131052-308T';\n * if(isValidPersonId<z.BRAND<'PersonID'>>(personId)) { // personId type is now: string & z.BRAND<'PersonID'>\n * // personId type is now: string & z.BRAND<'PersonID'>\n * }\n * @since v0.0.1\n */\nexport function isValidPersonId<BRAND = string>(personId: string): personId is string & BRAND {\n\tif (typeof personId !== 'string' || personId.length !== 11) {\n\t\treturn false;\n\t}\n\tconst upperPersonId = personId.toUpperCase();\n\ttry {\n\t\treturn upperPersonId[10] === getCheckSum(parseStringToInt(upperPersonId.slice(0, 6) + upperPersonId.slice(7, 10)) % checkSumMapLength);\n\t} catch (_error) {\n\t\treturn false;\n\t}\n}\n\n/**\n * Check if personId belongs to a Finnish male\n * @throws TypeError if personId is not valid\n * @param personId - Finnish personId string\n * @template BRAND - Optional: brand type for more strict type (i.e. use Zod branded type or custom type)\n * @returns true if the personId belongs to a male, false otherwise\n * @example\n * isMale('131052-309U') // true\n * isMale('131052-308T') // false\n * isMale<z.BRAND<'PersonIdMale'>>(personId) // if true, personId type is now: string & z.BRAND<'PersonIdMale'>\n * @since v0.0.1\n */\nexport function isMale<BRAND = string>(personId: string): personId is string & BRAND {\n\tif (!isValidPersonId(personId)) {\n\t\tthrow new TypeError(`${String(personId)} is not valid person id`);\n\t}\n\treturn parseStringToInt(personId.slice(7, 10)) % 2 === 1; // check if the individual number is odd\n}\n\n/**\n * Check if personId belongs to a Finnish female\n * @throws TypeError if personId is not valid\n * @param personId - Finnish personId string\n * @template BRAND - Optional: brand type for more strict type (i.e. use Zod branded type or custom type)\n * @returns true if the personId belongs to a female, false otherwise\n * @example\n * isFemale('131052-308T') // true\n * isFemale('131052-309U') // false\n * isFemale<z.BRAND<'PersonIdFemale'>>(personId) // if true, personId type is now: string & z.BRAND<'PersonIdFemale'>\n * @since v0.0.1\n */\nexport function isFemale<BRAND = string>(personId: string): personId is string & BRAND {\n\treturn !isMale(personId);\n}\n"],"mappings":";AAAA,IAAM,uBAAuB;AAC7B,IAAM,oBAAoB,qBAAqB;AAQxC,SAAS,iBAAiB,OAAmC;AACnE,MAAI,CAAC,OAAO;AACX,UAAM,IAAI,UAAU,oBAAoB;AAAA,EACzC;AACA,QAAM,cAAc,SAAS,OAAO,EAAE;AACtC,MAAI,MAAM,WAAW,GAAG;AACvB,UAAM,IAAI,UAAU,0BAA0B,KAAK,EAAE;AAAA,EACtD;AACA,SAAO;AACR;AAQO,SAAS,eAAe,OAAwB;AACtD,MAAI,OAAO,UAAU,UAAU;AAC9B,UAAM,IAAI,UAAU,GAAG,OAAO,KAAK,CAAC,eAAe;AAAA,EACpD;AACA,SAAO;AACR;AAOO,SAAS,YAAY,OAAmC;AAC9D,MAAI,QAAQ,KAAK,SAAS,mBAAmB;AAC5C,UAAM,IAAI,WAAW,wBAAwB,MAAM,SAAS,CAAC,oBAAoB,OAAO,oBAAoB,CAAC,CAAC,GAAG;AAAA,EAClH;AACA,SAAO,qBAAqB,KAAK;AAClC;AAwBO,SAAS,gBAAgC,UAA8C;AAC7F,MAAI,OAAO,aAAa,YAAY,SAAS,WAAW,IAAI;AAC3D,WAAO;AAAA,EACR;AACA,QAAM,gBAAgB,SAAS,YAAY;AAC3C,MAAI;AACH,WAAO,cAAc,EAAE,MAAM,YAAY,iBAAiB,cAAc,MAAM,GAAG,CAAC,IAAI,cAAc,MAAM,GAAG,EAAE,CAAC,IAAI,iBAAiB;AAAA,EACtI,SAAS,QAAQ;AAChB,WAAO;AAAA,EACR;AACD;AAcO,SAAS,OAAuB,UAA8C;AACpF,MAAI,CAAC,gBAAgB,QAAQ,GAAG;AAC/B,UAAM,IAAI,UAAU,GAAG,OAAO,QAAQ,CAAC,yBAAyB;AAAA,EACjE;AACA,SAAO,iBAAiB,SAAS,MAAM,GAAG,EAAE,CAAC,IAAI,MAAM;AACxD;AAcO,SAAS,SAAyB,UAA8C;AACtF,SAAO,CAAC,OAAO,QAAQ;AACxB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["const checksumCharacterSet = '0123456789ABCDEFHJKLMNPRSTUVWXY';\nconst checkSumMapLength = checksumCharacterSet.length; // is always 31\n\n/**\n * Parse string to integer\n * @throws TypeError if value is not a number\n * @param {string | undefined} value - string to parse\n * @returns {number} value as number\n * @since v0.0.7\n */\nexport function parseStringToInt(value: string | undefined): number {\n\tif (!value) {\n\t\tthrow new TypeError('Value is undefined');\n\t}\n\tconst parsedValue = parseInt(value, 10);\n\tif (isNaN(parsedValue)) {\n\t\tthrow new TypeError(`Value is not a number: ${value}`);\n\t}\n\treturn parsedValue;\n}\n\n/**\n * Validate that value is a string\n * @throws TypeError if value is not a string\n * @param {unknown} value - value to validate\n * @returns {string} value as string\n * @since v0.0.7\n */\nexport function validateString(value: unknown): string {\n\tif (typeof value !== 'string') {\n\t\tthrow new TypeError(`${String(value)} not a string`);\n\t}\n\treturn value;\n}\n\n/**\n * Returns the checksum character from the checksum index map.\n * @param {number} index The index of the checksum character.\n * @returns {string} The checksum character at the specified index, or undefined if the index is out of bounds.\n * @throws {RangeError} If the index is less than 0 or greater than or equal to checkSumMapLength.\n * @since v0.0.7\n */\nexport function getCheckSum(index: number): string {\n\tconst checkSumChar = checksumCharacterSet[index];\n\tif (!checkSumChar) {\n\t\tthrow new RangeError(`Index out of bounds: ${index.toString()} (valid range: 0-${String(checkSumMapLength - 1)})`);\n\t}\n\treturn checkSumChar;\n}\n\n/**\n * Validates whether a string is a valid Finnish person ID.\n *\n * A valid Finnish person ID consists of 11 characters in the format DDMMYYCZZZQ, where:\n * - DDMMYY represents the date of birth.\n * - C is the century sign ('+' for 1800s, '-' for 1900s, 'A' for 2000s).\n * - ZZZ is an individual number (odd numbers are males, even numbers are females).\n * - Q is a checksum character.\n *\n * The checksum character is calculated based on the first 10 characters.\n * @param {string} personId The person ID string to validate.\n * @template BRAND Optional brand type for a more strict type (e.g., use Zod branded type or custom type).\n * @returns {boolean} True if the person ID is valid, false otherwise.\n * @example\n * isValidPersonId('131052-308T') // true\n * isValidPersonId('131052-3082') // false\n * const personId = '131052-308T';\n * if (isValidPersonId<z.BRAND<'PersonID'>>(personId)) { // personId type is now: string & z.BRAND<'PersonID'>\n * // personId type is now: string & z.BRAND<'PersonID'>\n * }\n * @since v0.0.1\n */\nexport function isValidPersonId<BRAND = string>(personId: string): personId is string & BRAND {\n\tif (typeof personId !== 'string' || personId.length !== 11) {\n\t\treturn false;\n\t}\n\tconst upperPersonId = personId.toUpperCase();\n\ttry {\n\t\treturn upperPersonId[10] === getCheckSum(parseStringToInt(upperPersonId.slice(0, 6) + upperPersonId.slice(7, 10)) % checkSumMapLength);\n\t} catch (_error) {\n\t\treturn false;\n\t}\n}\n\n/**\n * Checks whether a person ID belongs to a Finnish male.\n * @param {string} personId The Finnish person ID string.\n * @template BRAND Optional brand type for a more strict type (e.g., use Zod branded type or custom type).\n * @returns {boolean} True if the person ID belongs to a male, false otherwise.\n * @throws {TypeError} If the person ID is not valid.\n * @example\n * isMale('131052-309U') // true\n * isMale('131052-308T') // false\n * isMale<z.BRAND<'PersonIdMale'>>(personId) // if true, personId type is now: string & z.BRAND<'PersonIdMale'>\n * @since v0.0.1\n */\nexport function isMale<BRAND = string>(personId: string): personId is string & BRAND {\n\tif (!isValidPersonId(personId)) {\n\t\tthrow new TypeError(`${String(personId)} is not valid person id`);\n\t}\n\treturn parseStringToInt(personId.slice(7, 10)) % 2 === 1; // check if the individual number is odd\n}\n\n/**\n * Checks whether a person ID belongs to a Finnish female.\n * @param {string} personId The Finnish person ID string.\n * @template BRAND Optional brand type for a more strict type (e.g., use Zod branded type or custom type).\n * @returns {boolean} True if the person ID belongs to a female, false otherwise.\n * @throws {TypeError} If the person ID is not valid.\n * @example\n * isFemale('131052-308T') // true\n * isFemale('131052-309U') // false\n * isFemale<z.BRAND<'PersonIdFemale'>>(personId) // if true, personId type is now: string & z.BRAND<'PersonIdFemale'>\n * @since v0.0.1\n */\nexport function isFemale<BRAND = string>(personId: string): personId is string & BRAND {\n\treturn !isMale(personId);\n}\n"],"mappings":";AAAA,IAAM,uBAAuB;AAC7B,IAAM,oBAAoB,qBAAqB;AASxC,SAAS,iBAAiB,OAAmC;AACnE,MAAI,CAAC,OAAO;AACX,UAAM,IAAI,UAAU,oBAAoB;AAAA,EACzC;AACA,QAAM,cAAc,SAAS,OAAO,EAAE;AACtC,MAAI,MAAM,WAAW,GAAG;AACvB,UAAM,IAAI,UAAU,0BAA0B,KAAK,EAAE;AAAA,EACtD;AACA,SAAO;AACR;AASO,SAAS,eAAe,OAAwB;AACtD,MAAI,OAAO,UAAU,UAAU;AAC9B,UAAM,IAAI,UAAU,GAAG,OAAO,KAAK,CAAC,eAAe;AAAA,EACpD;AACA,SAAO;AACR;AASO,SAAS,YAAY,OAAuB;AAClD,QAAM,eAAe,qBAAqB,KAAK;AAC/C,MAAI,CAAC,cAAc;AAClB,UAAM,IAAI,WAAW,wBAAwB,MAAM,SAAS,CAAC,oBAAoB,OAAO,oBAAoB,CAAC,CAAC,GAAG;AAAA,EAClH;AACA,SAAO;AACR;AAwBO,SAAS,gBAAgC,UAA8C;AAC7F,MAAI,OAAO,aAAa,YAAY,SAAS,WAAW,IAAI;AAC3D,WAAO;AAAA,EACR;AACA,QAAM,gBAAgB,SAAS,YAAY;AAC3C,MAAI;AACH,WAAO,cAAc,EAAE,MAAM,YAAY,iBAAiB,cAAc,MAAM,GAAG,CAAC,IAAI,cAAc,MAAM,GAAG,EAAE,CAAC,IAAI,iBAAiB;AAAA,EACtI,SAAS,QAAQ;AAChB,WAAO;AAAA,EACR;AACD;AAcO,SAAS,OAAuB,UAA8C;AACpF,MAAI,CAAC,gBAAgB,QAAQ,GAAG;AAC/B,UAAM,IAAI,UAAU,GAAG,OAAO,QAAQ,CAAC,yBAAyB;AAAA,EACjE;AACA,SAAO,iBAAiB,SAAS,MAAM,GAAG,EAAE,CAAC,IAAI,MAAM;AACxD;AAcO,SAAS,SAAyB,UAA8C;AACtF,SAAO,CAAC,OAAO,QAAQ;AACxB;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fi-pin",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "Finnish Personal Identification Number validate + gender check",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -13,26 +13,29 @@
13
13
  }
14
14
  },
15
15
  "devDependencies": {
16
- "@stylistic/eslint-plugin": "^2.10.0",
17
- "@stylistic/eslint-plugin-ts": "^2.10.0",
18
- "@types/node": "^18.19.61",
19
- "@typescript-eslint/eslint-plugin": "^8.12.2",
20
- "@typescript-eslint/parser": "^8.12.2",
21
- "@vitest/coverage-v8": "^2.1.4",
22
- "c8": "^10.1.2",
23
- "eslint": "^8.57.1",
24
- "eslint-config-prettier": "^9.1.0",
25
- "eslint-config-standard": "^17.1.0",
26
- "eslint-plugin-deprecation": "^3.0.0",
27
- "eslint-plugin-jsdoc": "^50.4.3",
28
- "eslint-plugin-prettier": "^5.2.1",
29
- "eslint-plugin-sonarjs": "^0.23.0",
16
+ "@cspell/eslint-plugin": "^8.18.0",
17
+ "@eslint/js": "^9.23.0",
18
+ "@stylistic/eslint-plugin": "^4.2.0",
19
+ "@stylistic/eslint-plugin-ts": "^4.2.0",
20
+ "@types/node": "^22.13.14",
21
+ "@typescript-eslint/eslint-plugin": "^8.28.0",
22
+ "@typescript-eslint/parser": "^8.28.0",
23
+ "@vitest/coverage-v8": "^3.0.9",
24
+ "c8": "^10.1.3",
25
+ "eslint": "^9.23.0",
26
+ "eslint-config-prettier": "^10.1.1",
27
+ "eslint-import-resolver-typescript": "^4.2.5",
28
+ "eslint-plugin-import": "^2.31.0",
29
+ "eslint-plugin-jsdoc": "^50.6.9",
30
+ "eslint-plugin-prettier": "^5.2.5",
31
+ "eslint-plugin-sonarjs": "^3.0.2",
30
32
  "source-map-support": "^0.5.21",
31
- "tsup": "^8.3.5",
32
- "typescript": "^5.6.3",
33
- "vite": "^5.4.10",
34
- "vitest": "^2.1.4",
35
- "zod": "^3.23.8"
33
+ "tsup": "^8.4.0",
34
+ "typescript": "^5.8.2",
35
+ "typescript-eslint": "^8.28.0",
36
+ "vite": "^6.2.3",
37
+ "vitest": "^3.0.9",
38
+ "zod": "^3.24.2"
36
39
  },
37
40
  "mocha": {
38
41
  "exit": true,