@konce-pt/validators 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 konce.pt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @konce-pt/validators
2
+
3
+ Walidatory polskiego pionu dla [Koncept UI](https://gitlab.com/konce-pt/koncept-ui):
4
+ NIP, REGON, PESEL, IBAN, kod pocztowy i numer rachunku bankowego (NRB).
5
+ Czysty TypeScript, **zero zależności runtime**.
6
+
7
+ ```bash
8
+ npm i @konce-pt/validators
9
+ ```
10
+
11
+ ```ts
12
+ import { isValidNip, isValidPesel, peselDate, peselSex } from '@konce-pt/validators';
13
+
14
+ isValidNip('123-456-32-18'); // true (separatory tolerowane)
15
+ isValidPesel('44051401359'); // true
16
+ peselDate('44051401359'); // Date 1944-05-14
17
+ peselSex('44051401359'); // 'male'
18
+ ```
19
+
20
+ ## API
21
+
22
+ | Funkcja | Zwraca | Opis |
23
+ |---|---|---|
24
+ | `isValidNip(value)` | `boolean` | NIP — 10 cyfr, suma kontrolna mod 11 |
25
+ | `isValidRegon(value)` | `boolean` | REGON — 9 lub 14 cyfr |
26
+ | `isValidPesel(value)` | `boolean` | PESEL — 11 cyfr, mod 10 + poprawna data |
27
+ | `peselDate(value)` | `Date \| null` | Data urodzenia zakodowana w PESEL-u |
28
+ | `peselSex(value)` | `'male' \| 'female' \| null` | Płeć z PESEL-u |
29
+ | `isValidIban(value)` | `boolean` | IBAN — mod 97, długość per kraj (PL = 28) |
30
+ | `isValidNrb(value)` | `boolean` | Polski rachunek NRB — 26 cyfr |
31
+ | `isValidPostalCodePl(value)` | `boolean` | Kod pocztowy `NN-NNN` |
32
+
33
+ Wszystkie funkcje są czyste i synchroniczne. Separatory (spacje, myślniki) są tolerowane
34
+ w NIP/REGON/PESEL/NRB/IBAN.
35
+
36
+ ## Licencja
37
+
38
+ MIT © konce.pt
package/dist/iban.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Waliduje IBAN po regule mod 97. Ignoruje spacje, wielkość liter bez znaczenia.
3
+ * Jeśli kraj jest znany, sprawdza też wymaganą długość (np. PL = 28).
4
+ */
5
+ export declare function isValidIban(value: string): boolean;
package/dist/iban.js ADDED
@@ -0,0 +1,33 @@
1
+ // Długości IBAN dla wybranych krajów (podzbiór). Brak wpisu = tylko ogólna walidacja mod 97.
2
+ const IBAN_LENGTHS = {
3
+ PL: 28, DE: 22, GB: 22, FR: 27, ES: 24, IT: 27, NL: 18, CZ: 24, SK: 24, AT: 20,
4
+ BE: 16, CH: 21, DK: 18, IE: 22, LT: 20, LV: 21, EE: 20, PT: 25, SE: 24, NO: 15,
5
+ };
6
+ function mod97(iban) {
7
+ // Przenosimy 4 pierwsze znaki na koniec i zamieniamy litery na liczby (A=10..Z=35),
8
+ // licząc resztę mod 97 kawałkami, by nie przekroczyć zakresu liczb.
9
+ const rearranged = iban.slice(4) + iban.slice(0, 4);
10
+ let remainder = 0;
11
+ for (const ch of rearranged) {
12
+ const chunk = ch >= 'A' && ch <= 'Z' ? String(ch.charCodeAt(0) - 55) : ch;
13
+ for (const digit of chunk) {
14
+ remainder = (remainder * 10 + Number(digit)) % 97;
15
+ }
16
+ }
17
+ return remainder;
18
+ }
19
+ /**
20
+ * Waliduje IBAN po regule mod 97. Ignoruje spacje, wielkość liter bez znaczenia.
21
+ * Jeśli kraj jest znany, sprawdza też wymaganą długość (np. PL = 28).
22
+ */
23
+ export function isValidIban(value) {
24
+ const iban = value.replace(/\s/g, '').toUpperCase();
25
+ if (!/^[A-Z]{2}[0-9]{2}[A-Z0-9]+$/.test(iban))
26
+ return false;
27
+ if (iban.length < 15 || iban.length > 34)
28
+ return false;
29
+ const expected = IBAN_LENGTHS[iban.slice(0, 2)];
30
+ if (expected !== undefined && iban.length !== expected)
31
+ return false;
32
+ return mod97(iban) === 1;
33
+ }
@@ -0,0 +1,6 @@
1
+ export { isValidNip } from './nip.ts';
2
+ export { isValidRegon } from './regon.ts';
3
+ export { isValidPesel, peselDate, peselSex, type Sex } from './pesel.ts';
4
+ export { isValidIban } from './iban.ts';
5
+ export { isValidNrb } from './nrb.ts';
6
+ export { isValidPostalCodePl } from './postal-code.ts';
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ // @konce-pt/validators — walidatory polskiego pionu. Czysty TS, zero zależności runtime.
2
+ export { isValidNip } from "./nip.js";
3
+ export { isValidRegon } from "./regon.js";
4
+ export { isValidPesel, peselDate, peselSex } from "./pesel.js";
5
+ export { isValidIban } from "./iban.js";
6
+ export { isValidNrb } from "./nrb.js";
7
+ export { isValidPostalCodePl } from "./postal-code.js";
@@ -0,0 +1,6 @@
1
+ /** Usuwa spacje i myślniki — typowe separatory w NIP/REGON/PESEL/NRB. */
2
+ export declare function stripSeparators(value: string): string;
3
+ /** Czy ciąg składa się wyłącznie z cyfr (i jest niepusty). */
4
+ export declare function isAllDigits(value: string): boolean;
5
+ /** Suma iloczynów kolejnych cyfr i wag. Wagi wyznaczają długość liczenia. */
6
+ export declare function weightedSum(digits: string, weights: readonly number[]): number;
@@ -0,0 +1,17 @@
1
+ // Wspólne helpery walidatorów. Nie eksportowane z paczki (implementacja wewnętrzna).
2
+ /** Usuwa spacje i myślniki — typowe separatory w NIP/REGON/PESEL/NRB. */
3
+ export function stripSeparators(value) {
4
+ return value.replace(/[\s-]/g, '');
5
+ }
6
+ /** Czy ciąg składa się wyłącznie z cyfr (i jest niepusty). */
7
+ export function isAllDigits(value) {
8
+ return value.length > 0 && /^[0-9]+$/.test(value);
9
+ }
10
+ /** Suma iloczynów kolejnych cyfr i wag. Wagi wyznaczają długość liczenia. */
11
+ export function weightedSum(digits, weights) {
12
+ let sum = 0;
13
+ for (let i = 0; i < weights.length; i++) {
14
+ sum += Number(digits[i]) * weights[i];
15
+ }
16
+ return sum;
17
+ }
package/dist/nip.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Waliduje polski NIP (10 cyfr) po sumie kontrolnej mod 11.
3
+ * Akceptuje separatory (spacje, myślniki), np. `123-456-32-18`.
4
+ */
5
+ export declare function isValidNip(value: string): boolean;
package/dist/nip.js ADDED
@@ -0,0 +1,15 @@
1
+ import { stripSeparators, isAllDigits, weightedSum } from "./internal.js";
2
+ const NIP_WEIGHTS = [6, 5, 7, 2, 3, 4, 5, 6, 7];
3
+ /**
4
+ * Waliduje polski NIP (10 cyfr) po sumie kontrolnej mod 11.
5
+ * Akceptuje separatory (spacje, myślniki), np. `123-456-32-18`.
6
+ */
7
+ export function isValidNip(value) {
8
+ const nip = stripSeparators(value);
9
+ if (nip.length !== 10 || !isAllDigits(nip))
10
+ return false;
11
+ const control = weightedSum(nip, NIP_WEIGHTS) % 11;
12
+ if (control === 10)
13
+ return false; // niemożliwa cyfra kontrolna
14
+ return control === Number(nip[9]);
15
+ }
package/dist/nrb.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Waliduje polski numer rachunku bankowego NRB (26 cyfr) — to samo, co „numer
3
+ * rachunku VAT". Poprawność liczona przez regułę IBAN dla `PL` + 26 cyfr.
4
+ * Akceptuje separatory (spacje, myślniki).
5
+ */
6
+ export declare function isValidNrb(value: string): boolean;
package/dist/nrb.js ADDED
@@ -0,0 +1,13 @@
1
+ import { stripSeparators, isAllDigits } from "./internal.js";
2
+ import { isValidIban } from "./iban.js";
3
+ /**
4
+ * Waliduje polski numer rachunku bankowego NRB (26 cyfr) — to samo, co „numer
5
+ * rachunku VAT". Poprawność liczona przez regułę IBAN dla `PL` + 26 cyfr.
6
+ * Akceptuje separatory (spacje, myślniki).
7
+ */
8
+ export function isValidNrb(value) {
9
+ const nrb = stripSeparators(value);
10
+ if (nrb.length !== 26 || !isAllDigits(nrb))
11
+ return false;
12
+ return isValidIban('PL' + nrb);
13
+ }
@@ -0,0 +1,16 @@
1
+ export type Sex = 'male' | 'female';
2
+ /**
3
+ * Waliduje polski PESEL (11 cyfr): suma kontrolna mod 10 oraz poprawność
4
+ * zakodowanej daty urodzenia (miesiąc niesie stulecie).
5
+ */
6
+ export declare function isValidPesel(value: string): boolean;
7
+ /**
8
+ * Data urodzenia zakodowana w PESEL-u lub `null`, gdy PESEL ma złą długość,
9
+ * niecyfrowe znaki albo niepoprawną datę. Nie sprawdza sumy kontrolnej.
10
+ */
11
+ export declare function peselDate(value: string): Date | null;
12
+ /**
13
+ * Płeć zakodowana w PESEL-u (przedostatnia cyfra: parzysta = kobieta) lub `null`
14
+ * przy złej długości/niecyfrowych znakach. Nie sprawdza sumy kontrolnej.
15
+ */
16
+ export declare function peselSex(value: string): Sex | null;
package/dist/pesel.js ADDED
@@ -0,0 +1,65 @@
1
+ import { stripSeparators, isAllDigits, weightedSum } from "./internal.js";
2
+ const PESEL_WEIGHTS = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3];
3
+ /**
4
+ * Waliduje polski PESEL (11 cyfr): suma kontrolna mod 10 oraz poprawność
5
+ * zakodowanej daty urodzenia (miesiąc niesie stulecie).
6
+ */
7
+ export function isValidPesel(value) {
8
+ const pesel = stripSeparators(value);
9
+ if (pesel.length !== 11 || !isAllDigits(pesel))
10
+ return false;
11
+ const control = (10 - (weightedSum(pesel, PESEL_WEIGHTS) % 10)) % 10;
12
+ if (control !== Number(pesel[10]))
13
+ return false;
14
+ return peselDate(pesel) !== null;
15
+ }
16
+ /**
17
+ * Data urodzenia zakodowana w PESEL-u lub `null`, gdy PESEL ma złą długość,
18
+ * niecyfrowe znaki albo niepoprawną datę. Nie sprawdza sumy kontrolnej.
19
+ */
20
+ export function peselDate(value) {
21
+ const pesel = stripSeparators(value);
22
+ if (pesel.length !== 11 || !isAllDigits(pesel))
23
+ return null;
24
+ const yy = Number(pesel.slice(0, 2));
25
+ let month = Number(pesel.slice(2, 4));
26
+ const day = Number(pesel.slice(4, 6));
27
+ let century;
28
+ if (month >= 1 && month <= 12)
29
+ century = 1900;
30
+ else if (month >= 21 && month <= 32) {
31
+ century = 2000;
32
+ month -= 20;
33
+ }
34
+ else if (month >= 41 && month <= 52) {
35
+ century = 2100;
36
+ month -= 40;
37
+ }
38
+ else if (month >= 61 && month <= 72) {
39
+ century = 2200;
40
+ month -= 60;
41
+ }
42
+ else if (month >= 81 && month <= 92) {
43
+ century = 1800;
44
+ month -= 80;
45
+ }
46
+ else
47
+ return null;
48
+ const year = century + yy;
49
+ const date = new Date(year, month - 1, day);
50
+ // Odrzuca przepełnienia (np. 31 lutego przesunięte na marzec).
51
+ if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
52
+ return null;
53
+ }
54
+ return date;
55
+ }
56
+ /**
57
+ * Płeć zakodowana w PESEL-u (przedostatnia cyfra: parzysta = kobieta) lub `null`
58
+ * przy złej długości/niecyfrowych znakach. Nie sprawdza sumy kontrolnej.
59
+ */
60
+ export function peselSex(value) {
61
+ const pesel = stripSeparators(value);
62
+ if (pesel.length !== 11 || !isAllDigits(pesel))
63
+ return null;
64
+ return Number(pesel[9]) % 2 === 0 ? 'female' : 'male';
65
+ }
@@ -0,0 +1,2 @@
1
+ /** Waliduje polski kod pocztowy w formacie `NN-NNN` (np. `00-950`). */
2
+ export declare function isValidPostalCodePl(value: string): boolean;
@@ -0,0 +1,4 @@
1
+ /** Waliduje polski kod pocztowy w formacie `NN-NNN` (np. `00-950`). */
2
+ export function isValidPostalCodePl(value) {
3
+ return /^[0-9]{2}-[0-9]{3}$/.test(value.trim());
4
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Waliduje polski REGON — 9-cyfrowy (podmiot) lub 14-cyfrowy (jednostka lokalna).
3
+ * Dla 14 cyfr sprawdza także poprawność 9-cyfrowego prefiksu.
4
+ */
5
+ export declare function isValidRegon(value: string): boolean;
package/dist/regon.js ADDED
@@ -0,0 +1,25 @@
1
+ import { stripSeparators, isAllDigits, weightedSum } from "./internal.js";
2
+ const REGON9_WEIGHTS = [8, 9, 2, 3, 4, 5, 6, 7];
3
+ const REGON14_WEIGHTS = [2, 4, 8, 5, 0, 9, 7, 3, 6, 1, 2, 4, 8];
4
+ function controlDigit(digits, weights) {
5
+ const mod = weightedSum(digits, weights) % 11;
6
+ return mod === 10 ? 0 : mod;
7
+ }
8
+ /**
9
+ * Waliduje polski REGON — 9-cyfrowy (podmiot) lub 14-cyfrowy (jednostka lokalna).
10
+ * Dla 14 cyfr sprawdza także poprawność 9-cyfrowego prefiksu.
11
+ */
12
+ export function isValidRegon(value) {
13
+ const regon = stripSeparators(value);
14
+ if (!isAllDigits(regon))
15
+ return false;
16
+ if (regon.length === 9) {
17
+ return controlDigit(regon, REGON9_WEIGHTS) === Number(regon[8]);
18
+ }
19
+ if (regon.length === 14) {
20
+ if (controlDigit(regon.slice(0, 9), REGON9_WEIGHTS) !== Number(regon[8]))
21
+ return false;
22
+ return controlDigit(regon, REGON14_WEIGHTS) === Number(regon[13]);
23
+ }
24
+ return false;
25
+ }
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@konce-pt/validators",
3
+ "version": "0.2.0",
4
+ "description": "Polish-domain validators for Koncept UI — NIP, REGON, PESEL, IBAN, postal code, bank account (NRB). Pure TypeScript, zero runtime dependencies.",
5
+ "license": "MIT",
6
+ "author": "konce.pt",
7
+ "homepage": "https://gitlab.com/konce-pt/koncept-ui#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://gitlab.com/konce-pt/koncept-ui.git",
11
+ "directory": "packages/validators"
12
+ },
13
+ "bugs": {
14
+ "url": "https://gitlab.com/konce-pt/koncept-ui/-/issues"
15
+ },
16
+ "keywords": [
17
+ "validators",
18
+ "nip",
19
+ "regon",
20
+ "pesel",
21
+ "iban",
22
+ "nrb",
23
+ "polish",
24
+ "poland",
25
+ "koncept-ui"
26
+ ],
27
+ "type": "module",
28
+ "sideEffects": false,
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "module": "./dist/index.js",
33
+ "types": "./dist/index.d.ts",
34
+ "exports": {
35
+ ".": {
36
+ "types": "./dist/index.d.ts",
37
+ "default": "./dist/index.js"
38
+ }
39
+ },
40
+ "devDependencies": {
41
+ "typescript": "~6.0.3"
42
+ },
43
+ "nx": {
44
+ "targets": {
45
+ "build": {
46
+ "outputs": [
47
+ "{projectRoot}/dist"
48
+ ],
49
+ "cache": true
50
+ },
51
+ "test": {
52
+ "cache": true
53
+ }
54
+ }
55
+ },
56
+ "scripts": {
57
+ "build": "tsc -p tsconfig.build.json",
58
+ "test": "node --test \"src/**/*.test.ts\"",
59
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\""
60
+ }
61
+ }