Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: add types #7

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dist/example.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {};
13 changes: 13 additions & 0 deletions dist/example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var _1 = __importDefault(require("."));
console.log((0, _1.default)({
name: 'Red Cross of Belgium',
iban: 'BE72000000001616',
amount: 123.45,
unstructuredReference: 'Urgency fund',
information: 'Sample QR code'
}));
12 changes: 12 additions & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type QrCodeData = {
name: string;
iban: string;
bic?: string;
amount?: number;
purposeCode?: string;
structuredReference?: string;
unstructuredReference?: string;
information?: string;
};
declare const generateQrCode: (data: QrCodeData) => string;
export = generateQrCode;
86 changes: 86 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"use strict";
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can of course gitignore dist/ folder. I just left it there to be able to install this package from Github.

var iban_1 = require("iban");
var SERVICE_TAG = 'BCD';
var VERSION = '002';
var CHARACTER_SET = 1;
var IDENTIFICATION_CODE = 'SCT';
var assertNonEmptyString = function (val, name) {
if (typeof val !== 'string' || !val) {
throw new Error(name + ' must be a non-empty string.');
}
};
var generateQrCode = function (data) {
if (!data)
throw new Error('data must be an object.');
// > AT-21 Name of the Beneficiary
assertNonEmptyString(data.name, 'data.name');
if (data.name.length > 70)
throw new Error('data.name must have <=70 characters');
// > AT-23 BIC of the Beneficiary Bank
if (data.bic) {
assertNonEmptyString(data.bic, 'data.bic');
if (data.bic.length > 11)
throw new Error('data.bic must have <=11 characters');
// todo: validate more?
}
// > AT-20 Account number of the Beneficiary
// > Only IBAN is allowed.
assertNonEmptyString(data.iban, 'data.iban');
if (!(0, iban_1.isValid)(data.iban)) {
throw new Error('data.iban must be a valid iban code.');
}
// > AT-04 Amount of the Credit Transfer in Euro
// > Amount must be 0.01 or more and 999999999.99 or less
if (data.amount !== null) {
if (typeof data.amount !== 'number')
throw new Error('data.amount must be a number or null.');
if (data.amount < 0.01 || data.amount > 999999999.99) {
throw new Error('data.amount must be >=0.01 and <=999999999.99.');
}
}
// > AT-44 Purpose of the Credit Transfer
if (data.purposeCode) {
assertNonEmptyString(data.purposeCode, 'data.purposeCode');
if (data.purposeCode.length > 4)
throw new Error('data.purposeCode must have <=4 characters');
// todo: validate against AT-44
}
// > AT-05 Remittance Information (Structured)
// > Creditor Reference (ISO 11649 RF Creditor Reference may be used)
if (data.structuredReference) {
assertNonEmptyString(data.structuredReference, 'data.structuredReference');
if (data.structuredReference.length > 35)
throw new Error('data.structuredReference must have <=35 characters');
// todo: validate against AT-05
}
// > AT-05 Remittance Information (Unstructured)
if (data.unstructuredReference) {
assertNonEmptyString(data.unstructuredReference, 'data.unstructuredReference');
if (data.unstructuredReference.length > 140)
throw new Error('data.unstructuredReference must have <=140 characters');
}
if ('structuredReference' in data && 'unstructuredReference' in data) {
throw new Error('Use either data.structuredReference or data.unstructuredReference.');
}
// > Beneficiary to originator information
if (data.information) {
assertNonEmptyString(data.information, 'data.information');
if (data.information.length > 70)
throw new Error('data.information must have <=70 characters');
}
return [
SERVICE_TAG,
VERSION,
CHARACTER_SET,
IDENTIFICATION_CODE,
data.bic,
data.name,
(0, iban_1.electronicFormat)(data.iban),
data.amount === null ? '' : 'EUR' + data.amount.toFixed(2),
data.purposeCode || '',
data.structuredReference || '',
data.unstructuredReference || '',
data.information || '',
].join('\n');
};
module.exports = generateQrCode;
1 change: 1 addition & 0 deletions dist/test.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {};
46 changes: 46 additions & 0 deletions dist/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var assert_1 = require("assert");
var _1 = __importDefault(require("."));
var ex1 = {
name: 'Red Cross of Belgium',
iban: 'BE72000000001616',
bic: 'BPOTBEB1',
amount: 123.45,
reference: 'Urgency fund',
purposeCode: 'abc',
structuredReference: '123',
information: 'foo bar'
};
(0, assert_1.strictEqual)((0, _1.default)(ex1), "BCD\n002\n1\nSCT\nBPOTBEB1\nRed Cross of Belgium\nBE72000000001616\nEUR123.45\nabc\n123\n\nfoo bar");
// missing data.iban
{
var ex2_1 = __assign({}, ex1);
delete ex2_1.iban;
(0, assert_1.throws)(function () {
(0, _1.default)(ex2_1);
}, 'throws with missing data.iban');
}
// invalid data.iban
{
(0, assert_1.throws)(function () {
(0, _1.default)(__assign(__assign({}, ex1), { iban: 'BE00000000000000' }));
}, 'throws with invalid data.iban');
}
// omitted amount
(0, assert_1.strictEqual)((0, _1.default)(__assign(__assign({}, ex1), { amount: null })), "BCD\n002\n1\nSCT\nBPOTBEB1\nRed Cross of Belgium\nBE72000000001616\n\nabc\n123\n\nfoo bar");
console.info('seems to work ✓');
4 changes: 1 addition & 3 deletions example.js → example.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
'use strict'

const generateQrCode = require('.')
import generateQrCode from '.'

console.log(generateQrCode({
name: 'Red Cross of Belgium',
Expand Down
91 changes: 0 additions & 91 deletions index.js

This file was deleted.

102 changes: 102 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { isValid, electronicFormat } from 'iban'

const SERVICE_TAG = 'BCD'
const VERSION = '002'
const CHARACTER_SET = 1
const IDENTIFICATION_CODE = 'SCT'

const assertNonEmptyString = (val: unknown, name: string) => {
if (typeof val !== 'string' || !val) {
throw new Error(name + ' must be a non-empty string.')
}
}

type QrCodeData = {
name: string
iban: string
bic?: string
amount?: number
purposeCode?: string
structuredReference?: string
unstructuredReference?: string
information?: string
}

const generateQrCode = (data: QrCodeData) => {
if (!data) throw new Error('data must be an object.')

// > AT-21 Name of the Beneficiary
assertNonEmptyString(data.name, 'data.name')
if (data.name.length > 70) throw new Error('data.name must have <=70 characters')

// > AT-23 BIC of the Beneficiary Bank
if (data.bic) {
assertNonEmptyString(data.bic, 'data.bic')
if (data.bic.length > 11) throw new Error('data.bic must have <=11 characters')
// todo: validate more?
}

// > AT-20 Account number of the Beneficiary
// > Only IBAN is allowed.
assertNonEmptyString(data.iban, 'data.iban')
if (!isValid(data.iban)) {
throw new Error('data.iban must be a valid iban code.')
}

// > AT-04 Amount of the Credit Transfer in Euro
// > Amount must be 0.01 or more and 999999999.99 or less
if (data.amount !== null) {
if (typeof data.amount !== 'number') throw new Error('data.amount must be a number or null.')
if (data.amount < 0.01 || data.amount > 999999999.99) {
throw new Error('data.amount must be >=0.01 and <=999999999.99.')
}
}

// > AT-44 Purpose of the Credit Transfer
if (data.purposeCode) {
assertNonEmptyString(data.purposeCode, 'data.purposeCode')
if (data.purposeCode.length > 4) throw new Error('data.purposeCode must have <=4 characters')
// todo: validate against AT-44
}

// > AT-05 Remittance Information (Structured)
// > Creditor Reference (ISO 11649 RF Creditor Reference may be used)
if (data.structuredReference) {
assertNonEmptyString(data.structuredReference, 'data.structuredReference')
if (data.structuredReference.length > 35)
throw new Error('data.structuredReference must have <=35 characters')
// todo: validate against AT-05
}
// > AT-05 Remittance Information (Unstructured)
if (data.unstructuredReference) {
assertNonEmptyString(data.unstructuredReference, 'data.unstructuredReference')
if (data.unstructuredReference.length > 140)
throw new Error('data.unstructuredReference must have <=140 characters')
}
if ('structuredReference' in data && 'unstructuredReference' in data) {
throw new Error('Use either data.structuredReference or data.unstructuredReference.')
}

// > Beneficiary to originator information
if (data.information) {
assertNonEmptyString(data.information, 'data.information')
if (data.information.length > 70) throw new Error('data.information must have <=70 characters')
}

return [
SERVICE_TAG,
VERSION,
CHARACTER_SET,
IDENTIFICATION_CODE,
data.bic,
data.name,
electronicFormat(data.iban),
data.amount === null ? '' : 'EUR' + data.amount.toFixed(2),
data.purposeCode || '',
data.structuredReference || '',
data.unstructuredReference || '',
data.information || '',
].join('\n')
}

export = generateQrCode
Loading