bysquare 2.9.0 → 2.11.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 CHANGED
@@ -22,9 +22,10 @@ transformed into images depends on how you implement it. See
22
22
 
23
23
  ## Installation
24
24
 
25
- **NOTE**: This package is native [ESM][mozzila-esm] and no longer provides a
26
- CommonJS export. If your project uses CommonJS, you will have to convert to ESM
27
- or use the dynamic [`import()`][mozzila-import] function.
25
+ > [!NOTE]
26
+ > This package is native [ESM][mozzila-esm] and no longer provides a
27
+ > CommonJS export. If your project uses CommonJS, you will have to convert to ESM
28
+ > or use the dynamic [`import()`][mozzila-import] function.
28
29
 
29
30
  [mozzila-esm]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
30
31
  [mozzila-import]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import
@@ -49,23 +50,17 @@ Since `v1.28+` import from npm registry using `npm:` prefix.
49
50
  import {
50
51
  decode,
51
52
  encode,
52
- } from "npm:bysquare@2.8.0";
53
+ } from "npm:bysquare@latest";
53
54
  ```
54
55
 
55
56
  ### Browser
56
57
 
57
58
  ```html
58
59
  <script type="module">
59
- import { encode, decode } from "https://esm.sh/bysquare@2.8.0/";
60
+ import { encode, decode } from "https://esm.sh/bysquare@latest";
60
61
  </script>
61
62
  ```
62
63
 
63
- ## How it works
64
-
65
- ### Encoding sequence
66
-
67
- ![logic](./docs/uml/logic.svg)
68
-
69
64
  ## Usage
70
65
 
71
66
  ### Encode
@@ -143,6 +138,12 @@ qrstring argument should be a valid QR code string.
143
138
  npx bysquare --decode <qrstring>
144
139
  ```
145
140
 
141
+ ## How it works
142
+
143
+ ### Encoding sequence
144
+
145
+ ![logic](./docs/uml/logic.svg)
146
+
146
147
  ## Platform support
147
148
 
148
149
  I mainly focus on LTS versions of Node.js and try to use the most idiomatic
@@ -163,6 +164,12 @@ to use without additional setup, showing its improved maturity.
163
164
 
164
165
  The latest version of Chrome, Firefox, and Safari.
165
166
 
167
+ ## Troubleshooting & Recommendations
168
+
169
+ ### Encoded data are without diacritics
170
+
171
+ The library removes all diacritics from the input data to ensure maximum compatibility, as not all banks support diacritics, which may lead to errors. If you need to retain diacritics, disable deburr option when encoding data - `encode(model, { deburr: false })`.
172
+
166
173
  ## Related
167
174
 
168
175
  - <https://bysquare.com/>
@@ -0,0 +1,2 @@
1
+ export declare function encode(input: Uint8Array, addPadding?: boolean): string;
2
+ export declare function decode(input: string, isLoose?: boolean): Uint8Array;
@@ -0,0 +1,53 @@
1
+ const base32Hex = {
2
+ chars: "0123456789ABCDEFGHIJKLMNOPQRSTUV",
3
+ bits: 5,
4
+ mask: 0b11111, // Mask to extract 5 bits
5
+ };
6
+ export function encode(input, addPadding = true) {
7
+ const output = Array();
8
+ let buffer = 0;
9
+ let bitsLeft = 0;
10
+ for (let i = 0; i < input.length; i++) {
11
+ buffer = (buffer << 8) | input[i];
12
+ bitsLeft += 8;
13
+ while (bitsLeft >= base32Hex.bits) {
14
+ bitsLeft -= base32Hex.bits;
15
+ const index = (buffer >> bitsLeft) & base32Hex.mask;
16
+ output.push(base32Hex.chars[index]);
17
+ }
18
+ }
19
+ if (bitsLeft > 0) {
20
+ const maskedValue = (buffer << (base32Hex.bits - bitsLeft)) & base32Hex.mask;
21
+ output.push(base32Hex.chars[maskedValue]);
22
+ }
23
+ let base32hex = output.join("");
24
+ if (addPadding) {
25
+ const paddedLength = Math.ceil(base32hex.length / 8) * 8;
26
+ base32hex = base32hex.padEnd(paddedLength, "=");
27
+ }
28
+ return base32hex;
29
+ }
30
+ export function decode(input, isLoose = false) {
31
+ if (isLoose) {
32
+ input = input.toUpperCase();
33
+ const paddingNeeded = (8 - (input.length % 8)) % 8;
34
+ input += "=".repeat(paddingNeeded);
35
+ }
36
+ input = input.replace(/=+$/, "");
37
+ const output = Array();
38
+ let buffer = 0;
39
+ let bitsLeft = 0;
40
+ for (let i = 0; i < input.length; i++) {
41
+ const index = base32Hex.chars.indexOf(input[i]);
42
+ if (index === -1) {
43
+ throw new Error("Invalid base32hex string");
44
+ }
45
+ buffer = (buffer << base32Hex.bits) | index;
46
+ bitsLeft += base32Hex.bits;
47
+ if (bitsLeft >= 8) {
48
+ bitsLeft -= 8;
49
+ output.push((buffer >> bitsLeft) & 0xFF);
50
+ }
51
+ }
52
+ return Uint8Array.from(output);
53
+ }
package/dist/cli.js CHANGED
@@ -15,6 +15,14 @@ const args = parseArgs({
15
15
  type: "boolean",
16
16
  short: "e",
17
17
  },
18
+ validate: {
19
+ type: "boolean",
20
+ short: "v",
21
+ },
22
+ deburr: {
23
+ type: "boolean",
24
+ short: "b",
25
+ },
18
26
  help: {
19
27
  type: "boolean",
20
28
  short: "h",
@@ -48,7 +56,10 @@ if (process.stdin.isTTY) {
48
56
  }
49
57
  }
50
58
  if (file.endsWith(".json")) {
51
- console.log(encode(JSON.parse(data)));
59
+ console.log(encode(JSON.parse(data), {
60
+ validate: Boolean(args.values.validate),
61
+ deburr: Boolean(args.values.deburr),
62
+ }));
52
63
  }
53
64
  process.exit(0);
54
65
  }
@@ -80,6 +91,12 @@ if (process.stdin.isTTY) {
80
91
  " -e, --encode",
81
92
  " Encode JSON data from one or more files and print the corresponding QR code.",
82
93
  "",
94
+ " -v, --validate",
95
+ " Validate JSON data from one or more files before encoding.",
96
+ "",
97
+ " -b, --deburr",
98
+ " Deburr JSON data from one or more files before encoding.",
99
+ "",
83
100
  " -h, --help",
84
101
  " Display the help message and exit.",
85
102
  "",
@@ -0,0 +1 @@
1
+ export declare function crc32(data: string): number;
package/dist/crc32.js ADDED
@@ -0,0 +1,63 @@
1
+ // Computed CRC32 lookup table
2
+ // const CRC32_TABLE = new Uint32Array(256);
3
+ // for (let i = 0; i < CRC32_TABLE.length; i++) {
4
+ // let crc = i;
5
+ // for (let j = 0; j < 8; j++) {
6
+ // crc = (crc >>> 1) ^ (0xEDB88320 * (crc & 1));
7
+ // }
8
+ // CRC32_TABLE[i] = crc;
9
+ // }
10
+ // dprint-ignore
11
+ const CRC32_TABLE = [
12
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
13
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
14
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
15
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
16
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
17
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
18
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
19
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
20
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
21
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
22
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
23
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
24
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
25
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
26
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
27
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
28
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
29
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
30
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
31
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
32
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
33
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
34
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
35
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
36
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
37
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
38
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
39
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
40
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
41
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
42
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
43
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
44
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
45
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
46
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
47
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
48
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
49
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
50
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
51
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
52
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
53
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
54
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
55
+ ];
56
+ export function crc32(data) {
57
+ let crc = 0 ^ (-1);
58
+ const encoded = new TextEncoder().encode(data);
59
+ for (let i = 0; i < encoded.length; i++) {
60
+ crc = (crc >>> 8) ^ CRC32_TABLE[(crc ^ encoded[i]) & 0xFF];
61
+ }
62
+ return (crc ^ (-1)) >>> 0;
63
+ }
package/dist/deburr.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export declare function deburrLetter(key: string): string;
2
2
  /**
3
- * @desc Deburrs string by converting Latin-1 Supplement and Latin Extended-A letters to basic Latin letters and removing [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
3
+ * Deburrs string by converting Latin-1 Supplement and Latin Extended-A letters to basic Latin letters and removing [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
4
4
  */
5
5
  export declare function deburr(text: string): string;
package/dist/deburr.js CHANGED
@@ -1,5 +1,5 @@
1
- /** Used to map Latin Unicode letters to basic Latin letters. */
2
1
  /** dprint-ignore */
2
+ /** Used to map Latin Unicode letters to basic Latin letters. */
3
3
  const deburredLettersMap = {
4
4
  // Latin-1 Supplement block.
5
5
  '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
@@ -59,11 +59,17 @@ const deburredLettersMap = {
59
59
  export function deburrLetter(key) {
60
60
  return deburredLettersMap[key];
61
61
  }
62
- /** Used to match Latin Unicode letters (excluding mathematical operators). */
62
+ /**
63
+ * Used to match Latin Unicode letters (excluding mathematical operators).
64
+ */
63
65
  const reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
64
- /** Used to compose unicode character classes. */
66
+ /**
67
+ * Used to compose unicode character classes.
68
+ */
65
69
  const rsComboMarksRange = "\\u0300-\\u036f\\ufe20-\\ufe23", rsComboSymbolsRange = "\\u20d0-\\u20f0";
66
- /** Used to compose unicode capture groups. */
70
+ /**
71
+ * Used to compose unicode capture groups.
72
+ */
67
73
  const rsCombo = "[" + rsComboMarksRange + rsComboSymbolsRange + "]";
68
74
  /**
69
75
  * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
@@ -71,7 +77,7 @@ const rsCombo = "[" + rsComboMarksRange + rsComboSymbolsRange + "]";
71
77
  */
72
78
  const reComboMark = RegExp(rsCombo, "g");
73
79
  /**
74
- * @desc Deburrs string by converting Latin-1 Supplement and Latin Extended-A letters to basic Latin letters and removing [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
80
+ * Deburrs string by converting Latin-1 Supplement and Latin Extended-A letters to basic Latin letters and removing [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
75
81
  */
76
82
  export function deburr(text) {
77
83
  return text.replace(reLatin, deburrLetter).replace(reComboMark, "");
package/dist/decode.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { decompress } from "lzma1";
2
- import { base32hex } from "rfc4648";
2
+ import * as base32hex from "./base32hex.js";
3
3
  import { CurrencyCode, PaymentOptions, Version, } from "./index.js";
4
4
  function cleanUndefined(obj) {
5
5
  Object.keys(obj).forEach((key) => {
@@ -133,7 +133,7 @@ export function deserialize(qr) {
133
133
  * the input header array into four nibbles representing the bysquare header
134
134
  * values.
135
135
  *
136
- * @param header 2-bytes sie
136
+ * @param header 2-bytes size
137
137
  */
138
138
  function bysquareHeaderDecoder(header) {
139
139
  const bytes = (header[0] << 8) | header[1];
@@ -164,16 +164,11 @@ export const parse = decode;
164
164
  * @see 3.16.
165
165
  */
166
166
  export function decode(qr) {
167
- let bytes;
168
- try {
169
- bytes = base32hex.parse(qr, { loose: true });
170
- }
171
- catch (error) {
172
- throw new DecodeError(error, "Unable to decode QR string base32hex encoding");
173
- }
167
+ const bytes = base32hex.decode(qr);
174
168
  const bysquareHeader = bytes.slice(0, 2);
175
- if ((bysquareHeaderDecoder(bysquareHeader).version > Version["1.1.0"])) {
176
- throw new Error("Unsupported Bysquare version");
169
+ const decodedBysquareHeader = bysquareHeaderDecoder(bysquareHeader);
170
+ if ((decodedBysquareHeader.version > Version["1.1.0"])) {
171
+ throw new Error(`Unsupported Bysquare version '${decodedBysquareHeader.version}' in header detected. Only '0' and '1' values are supported`);
177
172
  }
178
173
  /**
179
174
  * The process of decompressing data requires the addition of an LZMA header
@@ -223,17 +218,17 @@ export function decode(qr) {
223
218
  * not very reliable, there is room for improvement for the future.
224
219
  */
225
220
  export function detect(qr) {
226
- let parsed;
221
+ let decoded;
227
222
  try {
228
- parsed = base32hex.parse(qr, { loose: true });
223
+ decoded = base32hex.decode(qr, true);
229
224
  }
230
- catch {
225
+ catch (error) {
231
226
  return false;
232
227
  }
233
- if (parsed.byteLength < 2) {
228
+ if (decoded.byteLength < 2) {
234
229
  return false;
235
230
  }
236
- const bysquareHeader = parsed.subarray(0, 2);
231
+ const bysquareHeader = decoded.subarray(0, 2);
237
232
  const header = bysquareHeaderDecoder(bysquareHeader);
238
233
  const isValid = [
239
234
  header.bysquareType,
package/dist/encode.d.ts CHANGED
@@ -47,7 +47,13 @@ type Options = {
47
47
  *
48
48
  * @default true
49
49
  */
50
- deburr: boolean;
50
+ deburr?: boolean;
51
+ /**
52
+ * If true, validates the data model before encoding it.
53
+ *
54
+ * @default true
55
+ */
56
+ validate?: boolean;
51
57
  };
52
58
  /** @deprecated */
53
59
  export declare const generate: typeof encode;
package/dist/encode.js CHANGED
@@ -1,8 +1,10 @@
1
- import crc32 from "crc-32";
2
1
  import { compress } from "lzma1";
3
- import { base32hex } from "rfc4648";
2
+ import * as base32hex from "./base32hex.js";
3
+ import { crc32 } from "./crc32.js";
4
4
  import { deburr } from "./deburr.js";
5
- import { PaymentOptions, } from "./types.js";
5
+ import { PaymentOptions, Version, } from "./types.js";
6
+ import { validateDataModel } from "./validations.js";
7
+ const MAX_COMPRESSED_SIZE = 131_072; // 2^17
6
8
  /**
7
9
  * Returns a 2 byte buffer that represents the header of the bysquare
8
10
  * specification
@@ -24,9 +26,17 @@ header = [
24
26
  0x00, 0x00,
25
27
  0x00, 0x00
26
28
  ]) {
27
- const isValid = header.every((nibble) => 0 <= nibble && nibble <= 15);
28
- if (!isValid) {
29
- throw new Error("Invalid header byte value, valid range <0,15>");
29
+ if (header[0] < 0 || header[0] > 15) {
30
+ throw new Error(`Invalid BySquareType value '${header[0]}' in header, valid range <0,15>`);
31
+ }
32
+ if (header[1] < 0 || header[1] > 15) {
33
+ throw new Error(`Invalid Version value '${header[1]}' in header, valid range <0,15>`);
34
+ }
35
+ if (header[2] < 0 || header[2] > 15) {
36
+ throw new Error(`Invalid DocumentType value '${header[2]}' in header, valid range <0,15>`);
37
+ }
38
+ if (header[3] < 0 || header[3] > 15) {
39
+ throw new Error(`Invalid Reserved value '${header[3]}' in header, valid range <0,15>`);
30
40
  }
31
41
  const [bySquareType, version, documentType, reserved,] = header;
32
42
  // Combine 4-nibbles to 2-bytes
@@ -41,8 +51,8 @@ header = [
41
51
  * combination with CRC32 in bytes.
42
52
  */
43
53
  export function headerDataLength(length) {
44
- if (length >= 131072 /** 2^17 */) {
45
- throw new Error("The maximum compressed data size has been reached");
54
+ if (length >= MAX_COMPRESSED_SIZE) {
55
+ throw new Error(`Data size ${length} exceeds limit of ${MAX_COMPRESSED_SIZE} bytes`);
46
56
  }
47
57
  const header = new ArrayBuffer(2);
48
58
  new DataView(header).setUint16(0, length, true);
@@ -55,7 +65,7 @@ export function headerDataLength(length) {
55
65
  */
56
66
  export function addChecksum(serialized) {
57
67
  const checksum = new ArrayBuffer(4);
58
- new DataView(checksum).setUint32(0, crc32.str(serialized), true);
68
+ new DataView(checksum).setUint32(0, crc32(serialized), true);
59
69
  const byteArray = new TextEncoder().encode(serialized);
60
70
  return Uint8Array.from([
61
71
  ...new Uint8Array(checksum),
@@ -142,25 +152,26 @@ export const generate = encode;
142
152
  /**
143
153
  * Generate QR string ready for encoding into text QR code
144
154
  */
145
- export function encode(model, options = { deburr: true }) {
146
- if (options.deburr) {
155
+ export function encode(model, options) {
156
+ const { deburr = true, validate = true } = options ?? {};
157
+ if (deburr) {
147
158
  removeDiacritics(model);
148
159
  }
160
+ if (validate) {
161
+ validateDataModel(model);
162
+ }
149
163
  const payload = serialize(model);
150
164
  const withChecksum = addChecksum(payload);
151
165
  const compressed = Uint8Array.from(compress(withChecksum));
152
166
  const _lzmaHeader = Uint8Array.from(compressed.subarray(0, 13));
153
167
  const lzmaBody = Uint8Array.from(compressed.subarray(13));
154
168
  const output = Uint8Array.from([
155
- // FIXME:
156
- // for now other implementation of bysquare doesn't recognize header if
157
- // version is specified like TatraBanka
169
+ // NOTE: Newer version 1.1.0 is not supported by all apps (e.g., TatraBanka).
170
+ // We recommend using version "1.0.0" for better compatibility.
158
171
  // ...headerBysquare([0x00, Version["1.1.0"], 0x00, 0x00]),
159
- ...headerBysquare([0x00, 0x00, 0x00, 0x00]),
172
+ ...headerBysquare([0x00, Version["1.0.0"], 0x00, 0x00]),
160
173
  ...headerDataLength(withChecksum.byteLength),
161
174
  ...lzmaBody,
162
175
  ]);
163
- return base32hex.stringify(output, {
164
- pad: false,
165
- });
176
+ return base32hex.encode(output, false);
166
177
  }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { decode, detect, parse } from "./decode.js";
2
2
  export { encode, generate } from "./encode.js";
3
+ export { validateDataModel, ValidationErrorMessage } from "./validations.js";
3
4
  export * from "./types.js";
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export { decode, detect, parse } from "./decode.js";
2
2
  export { encode, generate } from "./encode.js";
3
+ export { validateDataModel, ValidationErrorMessage } from "./validations.js";
3
4
  export * from "./types.js";
package/dist/types.d.ts CHANGED
@@ -6,20 +6,22 @@
6
6
  */
7
7
  export declare enum Version {
8
8
  /**
9
- * 2013-02-22
10
- * Created this document from original by square specifications
9
+ * Created this document from original by square specifications.
10
+ *
11
+ * **Released Date:** 2013-02-22
11
12
  */
12
13
  "1.0.0" = 0,
13
14
  /**
14
- * 2015-06-24
15
15
  * Added fields for beneficiary name and address
16
+ *
17
+ * **Released Date:** 2015-06-24
16
18
  */
17
19
  "1.1.0" = 1
18
20
  }
19
21
  /**
20
22
  * Kalendárny mesiac.
21
23
  */
22
- export declare enum MonthClassifier {
24
+ export declare enum Month {
23
25
  January = 1,
24
26
  February = 2,
25
27
  March = 4,
@@ -60,13 +62,22 @@ export type Day = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 1
60
62
  * Možnosti platby sa dajú kombinovať. Oddeľujú sa medzerou a treba uviesť vždy
61
63
  * aspoň jednu z možností:
62
64
  *
63
- * - paymentorder: platobný príkaz
64
- * - standingorder: trvalý príkaz, údaje sa vyplnia do StandingOrderExt
65
- * - directdebit: inkaso, údaje sa vyplnia do DirectDebitExt
65
+ * - `PaymentOrder`: platobný príkaz
66
+ * - `StandingOrder`: trvalý príkaz, údaje sa vyplnia do StandingOrderExt
67
+ * - `DirectDebit`: inkaso, údaje sa vyplnia do DirectDebitExt
66
68
  */
67
69
  export declare enum PaymentOptions {
70
+ /**
71
+ * Platobný príkaz
72
+ */
68
73
  PaymentOrder = 1,
74
+ /**
75
+ * Trvalý príkaz, údaje sa vyplnia do StandingOrderExt
76
+ */
69
77
  StandingOrder = 2,
78
+ /**
79
+ * Inkaso, údaje sa vyplnia do DirectDebitExt
80
+ */
70
81
  DirectDebit = 4
71
82
  }
72
83
  /**
@@ -74,121 +85,140 @@ export declare enum PaymentOptions {
74
85
  */
75
86
  export type BankAccount = {
76
87
  /**
88
+ * Medzinárodné číslo bankového účtu vo formáte IBAN. Príklad:
89
+ *
77
90
  * Maximálna dĺžka 34
78
- * Pattern: [A-Z]{2}[0-9]{2}[A-Z0-9]{0,30}
79
91
  *
80
- * Medzinárodné číslo bankového účtu vo formáte IBAN. Príklad:
81
- * "SK8209000000000011424060". Viac na
82
- * http://www.sbaonline.sk/sk/projekty/financne-vzdelavanie/slovnik-bankovych-pojmov/iii/.
92
+ * Pattern: `[A-Z]{2}[0-9]{2}[A-Z0-9]{0,30}`
93
+ *
94
+ * @example `"SK8209000000000011424060"`
83
95
  */
84
96
  iban: string;
85
97
  /**
86
- * Formát ISO 9362 (swift) 8 or 11 characters long
87
- * Pattern: [A-Z]{4}[A-Z]{2}[A-Z\d]{2}([A-Z\d]{3})?
88
- *
89
98
  * Medzinárodný bankový identifikačný kód (z ang. Bank Identification Code).
90
- * Viac na http://www.sbaonline.sk/sk/projekty/financne-vzdelavanie/slovnik-bankovych-pojmov/bbb/bic
99
+ *
100
+ * Formát [ISO 9362](https://en.wikipedia.org/wiki/ISO_9362) (swift) 8 or 11 characters long
101
+ *
102
+ * Pattern: `[A-Z]{4}[A-Z]{2}[A-Z\d]{2}([A-Z\d]{3})?`
103
+ *
104
+ * @example "TATRSKBX"
91
105
  */
92
106
  bic?: string;
93
107
  };
94
108
  /**
95
109
  * Inksaná schéma. Uvádza ja jedna z možností:
96
110
  *
97
- * SEPA - Inkaso zodpovedá schéme
98
- * SEPA. other - iné
111
+ * - SEPA - Inkaso zodpovedá schéme
112
+ * - SEPA. other - iné
99
113
  */
100
114
  export declare enum DirectDebitScheme {
115
+ /**
116
+ * other - iné
117
+ */
101
118
  Other = 0,
119
+ /**
120
+ * SEPA - Inkaso zodpovedá schéme
121
+ */
102
122
  Sepa = 1
103
123
  }
104
124
  /**
105
- * Maximálna dĺžka 1
106
- *
107
125
  * Typ inkasa. Uvádza ja jedna z možností:
108
126
  *
109
- * one-off - jednorázové inkaso
110
- * recurrent - opakované inkaso
127
+ * Maximálna dĺžka 1
128
+ *
129
+ * - one-off - jednorázové inkaso
130
+ * - recurrent - opakované inkaso
111
131
  */
112
132
  export declare enum DirectDebitType {
133
+ /**
134
+ * Jednorázové inkaso
135
+ */
113
136
  OneOff = 0,
137
+ /**
138
+ * Opakované inkaso
139
+ */
114
140
  Recurrent = 1
115
141
  }
116
142
  export type Beneficiary = {
117
143
  /**
118
- * Maximálna dĺžka 70
119
- *
120
144
  * Rozšírenie o meno príjemcu
145
+ *
146
+ * Maximálna dĺžka 70
121
147
  */
122
148
  name?: string;
123
149
  /**
124
- * Maximálna dĺžka 70
125
- *
126
150
  * Rozšírenie o adresu príjemcu
151
+ *
152
+ * Maximálna dĺžka 70
127
153
  */
128
154
  street?: string;
129
155
  /**
130
- * Maximálna dĺžka 70
131
- *
132
156
  * Rozšírenie o adresu príjemcu (druhý riadok)
157
+ *
158
+ * Maximálna dĺžka 70
133
159
  */
134
160
  city?: string;
135
161
  };
136
162
  export type SimplePayment = {
137
163
  /**
138
- * Maximálna dĺžka 15
139
- *
140
164
  * Čiastka platby. Povolené sú len kladné hodnoty. Desatinná čast je
141
165
  * oddelená bodkou. Môže ostať nevyplnené, napríklad pre dobrovoľný
142
- * príspevok (donations). Príklad: Tisíc sa uvádza ako "1000". Jedna celá
143
- * deväťdesiatdeväť sa uvádza ako "1.99". Desať celých peťdesiat sa uvádza
144
- * ako "10.5". Nula celá nula osem sa uvádza ako "0.08".
166
+ * príspevok (donations).
167
+ *
168
+ * Príklad: Tisíc sa uvádza ako `1000`. Jedna celá
169
+ * deväťdesiatdeväť sa uvádza ako `1.99`. Desať celých peťdesiat sa uvádza
170
+ * ako `10.5`. Nula celá nula osem sa uvádza ako `0.08`.
171
+ *
172
+ * Maximálna dĺžka 15
145
173
  */
146
174
  amount?: number;
147
175
  /**
176
+ * Mena v [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) formáte (3 písmená).
177
+ *
148
178
  * Pattern: [A-Z]{3}
149
179
  *
150
- * Mena v ISO 4217 formáte (3 písmená). Príklad: "EUR"
180
+ * @example "EUR"
151
181
  */
152
182
  currencyCode: string | CurrencyCode;
153
183
  /**
154
- * Formát YYYYMMDD
184
+ * Dátum splatnosti vo formáte [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) `"RRRR-MM-DD"`.
185
+ * Vprípade trvalého príkazu označuje dátum prvej platby.
155
186
  *
156
- * Dátum splatnosti vo formáte ISO 8601 "RRRR-MM-DD". Nepovinný údaj. V
157
- * prípade trvalého príkazu označuje dátum prvej platby.
187
+ * Formát `YYYY-MM-DD`
158
188
  */
159
189
  paymentDueDate?: string;
160
190
  /**
191
+ * Variabilný symbol je maximálne 10 miestne číslo.
192
+ *
161
193
  * Maximálna dĺžka 10
162
194
  * Pattern: [0-9]{0,10}
163
- *
164
- * Variabilný symbol je maximálne 10 miestne číslo. Nepovinný údaj.
165
195
  */
166
196
  variableSymbol?: string;
167
197
  /**
198
+ * Konštantný symbol je 4 miestne identifikačné číslo.
199
+ *
168
200
  * Maximálna dĺžka 4
169
201
  * Pattern: [0-9]{0,4}
170
- *
171
- * Konštantný symbol je 4 miestne identifikačné číslo. Nepovinný údaj.
172
202
  */
173
203
  constantSymbol?: string;
174
204
  /**
205
+ * Špecifický symbol je maximálne 10 miestne číslo.
206
+ *
175
207
  * Maximálna dĺžka 10
176
208
  * Pattern: [0-9]{0,10}
177
- *
178
- * Špecifický symbol je maximálne 10 miestne číslo. Nepovinný údaj.
179
209
  */
180
210
  specificSymbol?: string;
181
211
  /**
182
- * Maximálna dĺžka 35
183
- *
184
212
  * Referenčná informácia prijímateľa podľa SEPA.
213
+ *
214
+ * Maximálna dĺžka 35
185
215
  */
186
216
  originatorsReferenceInformation?: string;
187
217
  /**
188
- * Maximálna dĺžka 140
189
- *
190
218
  * Správa pre prijímateľa. Údaje o platbe, na základe ktorých príjemca bude
191
- * môcť platbu identifikovať. Odporúča sa maximálne 140 Unicode znakov.
219
+ * môcť platbu identifikovať.
220
+ *
221
+ * Maximálna dĺžka 140
192
222
  */
193
223
  paymentNote?: string;
194
224
  /**
@@ -214,7 +244,7 @@ export type StandingOrder = SimplePayment & {
214
244
  /**
215
245
  * Medzerou oddelený zoznam mesiacov, v ktoré sa má platba uskutočniť.
216
246
  */
217
- month?: MonthClassifier;
247
+ month?: Month;
218
248
  /**
219
249
  * Opakovanie (periodicita) trvalého príkazu.
220
250
  */
@@ -222,7 +252,7 @@ export type StandingOrder = SimplePayment & {
222
252
  /**
223
253
  * Dátum poslednej platby v trvalom príkaze.
224
254
  *
225
- * Formát YYYYMMDD
255
+ * Formát `YYYYMMDD`
226
256
  */
227
257
  lastDate?: string;
228
258
  };
@@ -234,34 +264,34 @@ export type DirectDebit = SimplePayment & {
234
264
  directDebitScheme?: DirectDebitScheme;
235
265
  directDebitType?: DirectDebitType;
236
266
  /**
237
- * Maximálna dĺžka 35
238
- *
239
267
  * Identifikácia mandátu medzi veriteľom a dlžníkom podľa SEPA.
268
+ *
269
+ * Maximálna dĺžka 35
240
270
  */
241
271
  mandateId?: string;
242
272
  /**
243
- * Maximálna dĺžka 35
244
- *
245
273
  * Identifikácia veriteľa podľa SEPA.
274
+ *
275
+ * Maximálna dĺžka 35
246
276
  */
247
277
  creditorId?: string;
248
278
  /**
249
- * Maximálna dĺžka 35
250
- *
251
279
  * Identifikácia zmluvy medzi veriteľom a dlžníkom podľa SEPA.
280
+ *
281
+ * Maximálna dĺžka 35
252
282
  */
253
283
  contractId?: string;
254
284
  /**
255
- * Maximálna dĺžka 15
256
- *
257
285
  * Maximálna čiastka inkasa.
286
+ *
287
+ * Maximálna dĺžka 15
258
288
  */
259
289
  maxAmount?: number;
260
290
  /**
261
- * Maximálna dĺžka 8
262
- * Formát YYYYMMDD
263
- *
264
291
  * Dátum platnosti inkasa. Platnosť inkasa zaníka dňom tohto dátumu.
292
+ *
293
+ * Maximálna dĺžka 8
294
+ * Formát `YYYYMMDD`
265
295
  */
266
296
  validTillDate?: string;
267
297
  };
@@ -271,10 +301,10 @@ export type DirectDebit = SimplePayment & {
271
301
  export type Payment = PaymentOrder | StandingOrder | DirectDebit;
272
302
  export type DataModel = {
273
303
  /**
274
- * Maximálna dĺžka 10
275
- *
276
304
  * Číslo faktúry v prípade, že údaje sú súčasťou faktúry, alebo
277
305
  * identifikátor pre intérne potreby vystavovateľa.
306
+ *
307
+ * Maximálna dĺžka 10
278
308
  */
279
309
  invoiceId?: string;
280
310
  /**
@@ -284,7 +314,7 @@ export type DataModel = {
284
314
  payments: Payment[];
285
315
  };
286
316
  /**
287
- * ISO-4217
317
+ * [ISO-4217](https://en.wikipedia.org/wiki/ISO_4217)
288
318
  */
289
319
  export declare enum CurrencyCode {
290
320
  AED = "AED",
package/dist/types.js CHANGED
@@ -7,34 +7,36 @@
7
7
  export var Version;
8
8
  (function (Version) {
9
9
  /**
10
- * 2013-02-22
11
- * Created this document from original by square specifications
10
+ * Created this document from original by square specifications.
11
+ *
12
+ * **Released Date:** 2013-02-22
12
13
  */
13
14
  Version[Version["1.0.0"] = 0] = "1.0.0";
14
15
  /**
15
- * 2015-06-24
16
16
  * Added fields for beneficiary name and address
17
+ *
18
+ * **Released Date:** 2015-06-24
17
19
  */
18
20
  Version[Version["1.1.0"] = 1] = "1.1.0";
19
21
  })(Version || (Version = {}));
20
22
  /**
21
23
  * Kalendárny mesiac.
22
24
  */
23
- export var MonthClassifier;
24
- (function (MonthClassifier) {
25
- MonthClassifier[MonthClassifier["January"] = 1] = "January";
26
- MonthClassifier[MonthClassifier["February"] = 2] = "February";
27
- MonthClassifier[MonthClassifier["March"] = 4] = "March";
28
- MonthClassifier[MonthClassifier["April"] = 8] = "April";
29
- MonthClassifier[MonthClassifier["May"] = 16] = "May";
30
- MonthClassifier[MonthClassifier["June"] = 32] = "June";
31
- MonthClassifier[MonthClassifier["July"] = 64] = "July";
32
- MonthClassifier[MonthClassifier["August"] = 128] = "August";
33
- MonthClassifier[MonthClassifier["September"] = 256] = "September";
34
- MonthClassifier[MonthClassifier["October"] = 512] = "October";
35
- MonthClassifier[MonthClassifier["November"] = 1024] = "November";
36
- MonthClassifier[MonthClassifier["December"] = 2048] = "December";
37
- })(MonthClassifier || (MonthClassifier = {}));
25
+ export var Month;
26
+ (function (Month) {
27
+ Month[Month["January"] = 1] = "January";
28
+ Month[Month["February"] = 2] = "February";
29
+ Month[Month["March"] = 4] = "March";
30
+ Month[Month["April"] = 8] = "April";
31
+ Month[Month["May"] = 16] = "May";
32
+ Month[Month["June"] = 32] = "June";
33
+ Month[Month["July"] = 64] = "July";
34
+ Month[Month["August"] = 128] = "August";
35
+ Month[Month["September"] = 256] = "September";
36
+ Month[Month["October"] = 512] = "October";
37
+ Month[Month["November"] = 1024] = "November";
38
+ Month[Month["December"] = 2048] = "December";
39
+ })(Month || (Month = {}));
38
40
  /**
39
41
  * Deň platby vyplývajúci z opakovania (Periodicity). Deň v mesiaci je číslo
40
42
  * medzi 1 a 31. Deň v týždni je číslo medzi 1 a 7 (1 = pondelok, 2=utorok, …, 7
@@ -55,42 +57,63 @@ export var Periodicity;
55
57
  * Možnosti platby sa dajú kombinovať. Oddeľujú sa medzerou a treba uviesť vždy
56
58
  * aspoň jednu z možností:
57
59
  *
58
- * - paymentorder: platobný príkaz
59
- * - standingorder: trvalý príkaz, údaje sa vyplnia do StandingOrderExt
60
- * - directdebit: inkaso, údaje sa vyplnia do DirectDebitExt
60
+ * - `PaymentOrder`: platobný príkaz
61
+ * - `StandingOrder`: trvalý príkaz, údaje sa vyplnia do StandingOrderExt
62
+ * - `DirectDebit`: inkaso, údaje sa vyplnia do DirectDebitExt
61
63
  */
62
64
  export var PaymentOptions;
63
65
  (function (PaymentOptions) {
66
+ /**
67
+ * Platobný príkaz
68
+ */
64
69
  PaymentOptions[PaymentOptions["PaymentOrder"] = 1] = "PaymentOrder";
70
+ /**
71
+ * Trvalý príkaz, údaje sa vyplnia do StandingOrderExt
72
+ */
65
73
  PaymentOptions[PaymentOptions["StandingOrder"] = 2] = "StandingOrder";
74
+ /**
75
+ * Inkaso, údaje sa vyplnia do DirectDebitExt
76
+ */
66
77
  PaymentOptions[PaymentOptions["DirectDebit"] = 4] = "DirectDebit";
67
78
  })(PaymentOptions || (PaymentOptions = {}));
68
79
  /**
69
80
  * Inksaná schéma. Uvádza ja jedna z možností:
70
81
  *
71
- * SEPA - Inkaso zodpovedá schéme
72
- * SEPA. other - iné
82
+ * - SEPA - Inkaso zodpovedá schéme
83
+ * - SEPA. other - iné
73
84
  */
74
85
  export var DirectDebitScheme;
75
86
  (function (DirectDebitScheme) {
87
+ /**
88
+ * other - iné
89
+ */
76
90
  DirectDebitScheme[DirectDebitScheme["Other"] = 0] = "Other";
91
+ /**
92
+ * SEPA - Inkaso zodpovedá schéme
93
+ */
77
94
  DirectDebitScheme[DirectDebitScheme["Sepa"] = 1] = "Sepa";
78
95
  })(DirectDebitScheme || (DirectDebitScheme = {}));
79
96
  /**
80
- * Maximálna dĺžka 1
81
- *
82
97
  * Typ inkasa. Uvádza ja jedna z možností:
83
98
  *
84
- * one-off - jednorázové inkaso
85
- * recurrent - opakované inkaso
99
+ * Maximálna dĺžka 1
100
+ *
101
+ * - one-off - jednorázové inkaso
102
+ * - recurrent - opakované inkaso
86
103
  */
87
104
  export var DirectDebitType;
88
105
  (function (DirectDebitType) {
106
+ /**
107
+ * Jednorázové inkaso
108
+ */
89
109
  DirectDebitType[DirectDebitType["OneOff"] = 0] = "OneOff";
110
+ /**
111
+ * Opakované inkaso
112
+ */
90
113
  DirectDebitType[DirectDebitType["Recurrent"] = 1] = "Recurrent";
91
114
  })(DirectDebitType || (DirectDebitType = {}));
92
115
  /**
93
- * ISO-4217
116
+ * [ISO-4217](https://en.wikipedia.org/wiki/ISO_4217)
94
117
  */
95
118
  export var CurrencyCode;
96
119
  (function (CurrencyCode) {
@@ -0,0 +1,41 @@
1
+ import { BankAccount, DataModel, SimplePayment } from "./types.js";
2
+ export declare enum ValidationErrorMessage {
3
+ IBAN = "Invalid IBAN. Make sure ISO 13616 format is used.",
4
+ BIC = "Invalid BIC. Make sure ISO 9362 format is used.",
5
+ CurrencyCode = "Invalid currency code. Make sure ISO 4217 format is used.",
6
+ Date = "Invalid date. Make sure ISO 8601 format is used."
7
+ }
8
+ /**
9
+ * This error will be thrown in case of a validation issue. It provides message with error description and specific path to issue in dataModel object.
10
+ */
11
+ export declare class ValidationError extends Error {
12
+ name: string;
13
+ path: string;
14
+ /**
15
+ * @param message - explains, what is wrong on the specific field
16
+ * @param path - navigates to the specific field in DataModel, where error occurred
17
+ */
18
+ constructor(message: ValidationErrorMessage, path: string);
19
+ }
20
+ /**
21
+ * validates bankAccount fields:
22
+ * - iban (ISO 13616)
23
+ * - bic (ISO 9362)
24
+ */
25
+ export declare function validateBankAccount(bankAccount: BankAccount, path: string): void;
26
+ /**
27
+ * validate simple payment fields:
28
+ * - currencyCode (ISO 4217)
29
+ * - paymentDueDate (ISO 8601)
30
+ * - bankAccounts
31
+ *
32
+ * @see validateBankAccount
33
+ */
34
+ export declare function validateSimplePayment(simplePayment: SimplePayment, path: string): void;
35
+ /**
36
+ * Validate `payments` field of dataModel.
37
+ *
38
+ * @see validateSimplePayment
39
+ * @see ValidationError
40
+ */
41
+ export declare function validateDataModel(dataModel: DataModel): DataModel;
@@ -0,0 +1,67 @@
1
+ import validator from "validator";
2
+ export var ValidationErrorMessage;
3
+ (function (ValidationErrorMessage) {
4
+ ValidationErrorMessage["IBAN"] = "Invalid IBAN. Make sure ISO 13616 format is used.";
5
+ ValidationErrorMessage["BIC"] = "Invalid BIC. Make sure ISO 9362 format is used.";
6
+ ValidationErrorMessage["CurrencyCode"] = "Invalid currency code. Make sure ISO 4217 format is used.";
7
+ ValidationErrorMessage["Date"] = "Invalid date. Make sure ISO 8601 format is used.";
8
+ })(ValidationErrorMessage || (ValidationErrorMessage = {}));
9
+ /**
10
+ * This error will be thrown in case of a validation issue. It provides message with error description and specific path to issue in dataModel object.
11
+ */
12
+ export class ValidationError extends Error {
13
+ name = "ValidationError";
14
+ path;
15
+ /**
16
+ * @param message - explains, what is wrong on the specific field
17
+ * @param path - navigates to the specific field in DataModel, where error occurred
18
+ */
19
+ constructor(message, path) {
20
+ super(String(message));
21
+ this.path = path;
22
+ }
23
+ }
24
+ /**
25
+ * validates bankAccount fields:
26
+ * - iban (ISO 13616)
27
+ * - bic (ISO 9362)
28
+ */
29
+ export function validateBankAccount(bankAccount, path) {
30
+ if (!validator.isIBAN(bankAccount.iban)) {
31
+ throw new ValidationError(ValidationErrorMessage.IBAN, `${path}.iban`);
32
+ }
33
+ if (bankAccount.bic && !validator.isBIC(bankAccount.bic)) {
34
+ throw new ValidationError(ValidationErrorMessage.BIC, `${path}.bic`);
35
+ }
36
+ }
37
+ /**
38
+ * validate simple payment fields:
39
+ * - currencyCode (ISO 4217)
40
+ * - paymentDueDate (ISO 8601)
41
+ * - bankAccounts
42
+ *
43
+ * @see validateBankAccount
44
+ */
45
+ export function validateSimplePayment(simplePayment, path) {
46
+ for (const [index, bankAccount] of simplePayment.bankAccounts.entries()) {
47
+ validateBankAccount(bankAccount, `${path}.bankAccounts[${index}]`);
48
+ }
49
+ if (simplePayment.currencyCode && !validator.isISO4217(simplePayment.currencyCode)) {
50
+ throw new ValidationError(ValidationErrorMessage.CurrencyCode, `${path}.currencyCode`);
51
+ }
52
+ if (simplePayment.paymentDueDate && !validator.isDate(simplePayment.paymentDueDate)) {
53
+ throw new ValidationError(ValidationErrorMessage.Date, `${path}.paymentDueDate`);
54
+ }
55
+ }
56
+ /**
57
+ * Validate `payments` field of dataModel.
58
+ *
59
+ * @see validateSimplePayment
60
+ * @see ValidationError
61
+ */
62
+ export function validateDataModel(dataModel) {
63
+ for (const [index, payment] of dataModel.payments.entries()) {
64
+ validateSimplePayment(payment, `payments[${index}]`);
65
+ }
66
+ return dataModel;
67
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bysquare",
3
3
  "description": "It's a national standard for payment QR codes adopted by Slovak Banking Association (SBA)",
4
- "version": "2.9.0",
4
+ "version": "2.11.0",
5
5
  "license": "Apache-2.0",
6
6
  "funding": "https://github.com/sponsors/xseman",
7
7
  "homepage": "https://github.com/xseman/bysquare#readme",
@@ -20,19 +20,20 @@
20
20
  "prebuild": "tsc --build --clean",
21
21
  "build": "tsc --build",
22
22
  "fmt": "dprint fmt",
23
+ "fmt:check": "dprint check",
23
24
  "typecheck": "tsc --noEmit",
24
25
  "version": "git checkout develop && npm test",
25
26
  "postversion": "echo 'Now run npm run build && npm publish'",
26
- "test": "TS_NODE_TRANSPILE_ONLY=true node --test --loader=ts-node/esm --no-warnings src/*.test.ts",
27
+ "test": "TS_NODE_TRANSPILE_ONLY=true node --test --experimental-test-coverage --loader=ts-node/esm --no-warnings src/*.test.ts",
27
28
  "test:watch": "TS_NODE_TRANSPILE_ONLY=true node --test --watch --loader=ts-node/esm --no-warnings src/*.test.ts"
28
29
  },
29
30
  "dependencies": {
30
- "crc-32": "~1.2.0",
31
- "lzma1": "0.0.2",
32
- "rfc4648": "~1.5.0"
31
+ "lzma1": "0.0.3",
32
+ "validator": "^13.12.0"
33
33
  },
34
34
  "devDependencies": {
35
- "@types/node": ">=18.18.2",
35
+ "@types/node": "^22.5.0",
36
+ "@types/validator": "^13.12.0",
36
37
  "dprint": "~0.47.0",
37
38
  "ts-node": "~10.9.0",
38
39
  "typescript": "~5.5.0"
@@ -51,7 +52,7 @@
51
52
  "!dist/*.test.*"
52
53
  ],
53
54
  "engines": {
54
- "node": ">=18.18.2",
55
+ "node": ">=16",
55
56
  "npm": ">=7"
56
57
  }
57
58
  }