diff --git a/.changeset/two-buses-glow.md b/.changeset/two-buses-glow.md
new file mode 100644
index 000000000..ddffad865
--- /dev/null
+++ b/.changeset/two-buses-glow.md
@@ -0,0 +1,5 @@
+---
+'@lion/input-iban': minor
+---
+
+add country blacklisting validator
diff --git a/packages/input-iban/README.md b/packages/input-iban/README.md
index d380cb4f0..d4a5db9be 100644
--- a/packages/input-iban/README.md
+++ b/packages/input-iban/README.md
@@ -8,7 +8,7 @@ Its purpose is to provide a way for users to fill in an IBAN (International Bank
```js script
import { html } from 'lit-html';
import { loadDefaultFeedbackMessages } from '@lion/validate-messages';
-import { IsCountryIBAN } from './src/validators.js';
+import { IsCountryIBAN, IsNotCountryIBAN } from './src/validators.js';
import './lion-input-iban.js';
@@ -90,3 +90,27 @@ export const countryRestrictions = () => html`
Demo instructions: you can use NL20 INGB 0001 2345 67
`;
```
+
+### Blacklisted Country
+
+By default, we validate the input to ensure the IBAN is valid.
+To get the default feedback message for this default validator, use `loadDefaultFeedbackMessages` from `@lion/form-core`.
+
+In the example below, we show how to use an additional validator that blocks IBANs from certain countries.
+
+You can pass a single string value, or an array of strings.
+
+```js preview-story
+export const blacklistedCountry = () => html`
+
+
+ Demo instructions: Try RO 89 RZBR 6997 3728 4864 5577 and watch it fail
+`;
+```
diff --git a/packages/input-iban/index.js b/packages/input-iban/index.js
index 9405bd43a..4e430deae 100644
--- a/packages/input-iban/index.js
+++ b/packages/input-iban/index.js
@@ -1,4 +1,4 @@
export { LionInputIban } from './src/LionInputIban.js';
export { formatIBAN } from './src/formatters.js';
export { parseIBAN } from './src/parsers.js';
-export { IsIBAN, IsCountryIBAN } from './src/validators.js';
+export { IsIBAN, IsCountryIBAN, IsNotCountryIBAN } from './src/validators.js';
diff --git a/packages/input-iban/src/validators.js b/packages/input-iban/src/validators.js
index 28f398c9b..efa958b19 100644
--- a/packages/input-iban/src/validators.js
+++ b/packages/input-iban/src/validators.js
@@ -1,7 +1,7 @@
/* eslint-disable max-classes-per-file */
import { localize } from '@lion/localize';
-import { Validator } from '@lion/form-core';
+import { Unparseable, Validator } from '@lion/form-core';
import { isValidIBAN } from 'ibantools';
let loaded = false;
@@ -124,7 +124,7 @@ export class IsCountryIBAN extends IsIBAN {
}
/**
- * @param {?} [value]
+ * @param {string} value
* @returns {Boolean}
*/
execute(value) {
@@ -150,6 +150,61 @@ export class IsCountryIBAN extends IsIBAN {
*/
static async getMessage(data) {
await loadTranslations();
- return localize.msg('lion-validate+iban:error.IsCountryIBAN', data);
+ // If modelValue is Unparseable, the IsIBAN message is the more appropriate feedback
+ return data?.modelValue instanceof Unparseable
+ ? localize.msg('lion-validate+iban:error.IsIBAN', data)
+ : localize.msg('lion-validate+iban:error.IsCountryIBAN', data);
+ }
+}
+
+export class IsNotCountryIBAN extends IsIBAN {
+ static get validatorName() {
+ return 'IsNotCountryIBAN';
+ }
+
+ /**
+ * @param {string} value
+ * @returns {Boolean}
+ */
+ execute(value) {
+ let isInvalid = false;
+ const notIBAN = super.execute(value);
+
+ if (typeof this.param === 'string') {
+ if (value.slice(0, 2) === this.param) {
+ isInvalid = true;
+ }
+ } else if (Array.isArray(this.param)) {
+ isInvalid = this.param.some(country => value.slice(0, 2) === country);
+ }
+
+ if (notIBAN) {
+ isInvalid = true;
+ }
+ return isInvalid;
+ }
+
+ /**
+ * @param {object} [data]
+ * @param {*} [data.modelValue]
+ * @param {string} [data.fieldName]
+ * @param {*} [data.params]
+ * @param {string} [data.type]
+ * @param {Object.} [data.config]
+ * @param {string} [data.name]
+ * @returns {Promise}
+ */
+ static async getMessage(data) {
+ await loadTranslations();
+ const _data = {
+ ...data,
+ userSuppliedCountryCode:
+ typeof data?.modelValue === 'string' ? data?.modelValue.slice(0, 2) : '',
+ };
+
+ // If modelValue is Unparseable, the IsIBAN message is the more appropriate feedback
+ return data?.modelValue instanceof Unparseable
+ ? localize.msg('lion-validate+iban:error.IsIBAN', _data)
+ : localize.msg('lion-validate+iban:error.IsNotCountryIBAN', _data);
}
}
diff --git a/packages/input-iban/test/validators.test.js b/packages/input-iban/test/validators.test.js
index 44caec309..2c6e6e07e 100644
--- a/packages/input-iban/test/validators.test.js
+++ b/packages/input-iban/test/validators.test.js
@@ -1,6 +1,6 @@
import { expect } from '@open-wc/testing';
-import { IsIBAN, IsCountryIBAN } from '../src/validators.js';
+import { IsIBAN, IsCountryIBAN, IsNotCountryIBAN } from '../src/validators.js';
import '../lion-input-iban.js';
@@ -9,6 +9,7 @@ describe('IBAN validation', () => {
const validator = new IsIBAN();
expect(validator.execute('NL17INGB0002822608')).to.be.false;
expect(validator.execute('DE89370400440532013000')).to.be.false;
+ expect(validator.execute('foo')).to.be.true;
});
it('provides IsCountryIBAN to limit IBANs from specific countries', () => {
@@ -17,6 +18,29 @@ describe('IBAN validation', () => {
expect(nlValidator.execute('NL17INGB0002822608')).to.be.false;
expect(deValidator.execute('DE89370400440532013000')).to.be.false;
expect(nlValidator.execute('DE89370400440532013000')).to.be.true;
- expect(nlValidator.execute('foo')).to.be.true;
+ expect(deValidator.execute('NL17INGB0002822608')).to.be.true;
+ });
+
+ it('provides IsNotCountryIBAN to prevent IBANs from specific countries', () => {
+ const nlValidator = new IsNotCountryIBAN('NL');
+ const deValidator = new IsNotCountryIBAN('DE');
+ expect(nlValidator.execute('NL17INGB0002822608')).to.be.true;
+ expect(deValidator.execute('DE89370400440532013000')).to.be.true;
+ expect(nlValidator.execute('DE89370400440532013000')).to.be.false;
+ expect(deValidator.execute('NL17INGB0002822608')).to.be.false;
+ });
+
+ it('accepts an array for IsNotCountryIBAN to prevent IBANs from multiple countries', () => {
+ const nlValidator = new IsNotCountryIBAN(['NL', 'FR']);
+ const deValidator = new IsNotCountryIBAN(['DE', 'SK']);
+ expect(nlValidator.execute('NL17INGB0002822608')).to.be.true;
+ expect(nlValidator.execute('FR1420041010050500013M02606')).to.be.true;
+ expect(nlValidator.execute('DE89370400440532013000')).to.be.false;
+ expect(nlValidator.execute('SK3112000000198742637541')).to.be.false;
+
+ expect(deValidator.execute('NL17INGB0002822608')).to.be.false;
+ expect(deValidator.execute('FR1420041010050500013M02606')).to.be.false;
+ expect(deValidator.execute('DE89370400440532013000')).to.be.true;
+ expect(deValidator.execute('SK3112000000198742637541')).to.be.true;
});
});
diff --git a/packages/input-iban/translations/bg.js b/packages/input-iban/translations/bg.js
index d57af8633..e4ac23695 100644
--- a/packages/input-iban/translations/bg.js
+++ b/packages/input-iban/translations/bg.js
@@ -16,5 +16,20 @@ export default {
'RO {Румънски}\n' +
'other {{params}}\n' +
'} {fieldName}.',
+ IsNotCountryIBAN:
+ '{userSuppliedCountryCode, select,\n' +
+ 'AT {Австрийски}\n' +
+ 'BE {Белгийски}\n' +
+ 'CZ {Чешки}\n' +
+ 'DE {Немски}\n' +
+ 'ES {Испански}\n' +
+ 'FR {Френски}\n' +
+ 'HU {Унгарски}\n' +
+ 'IT {Италиански}\n' +
+ 'NL {Нидерландски}\n' +
+ 'PL {Полски}\n' +
+ 'RO {Румънски}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} {fieldName} не е позволено.',
},
};
diff --git a/packages/input-iban/translations/cs.js b/packages/input-iban/translations/cs.js
index ec50c8059..440785373 100644
--- a/packages/input-iban/translations/cs.js
+++ b/packages/input-iban/translations/cs.js
@@ -16,5 +16,20 @@ export default {
'RO {Rumun}\n' +
'other {{params}}\n' +
'} {fieldName}.',
+ IsNotCountryIBAN:
+ '{userSuppliedCountryCode, select,\n' +
+ 'AT {Rakušan}\n' +
+ 'BE {Belgičan}\n' +
+ 'CZ {Čech}\n' +
+ 'DE {Němec}\n' +
+ 'ES {Španěl}\n' +
+ 'FR {Francouz}\n' +
+ 'HU {Maďar}\n' +
+ 'IT {Ital}\n' +
+ 'NL {Holanďan}\n' +
+ 'PL {Polák}\n' +
+ 'RO {Rumun}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} {fieldName} není povoleno.',
},
};
diff --git a/packages/input-iban/translations/de.js b/packages/input-iban/translations/de.js
index 388d1718d..3b3e60e05 100644
--- a/packages/input-iban/translations/de.js
+++ b/packages/input-iban/translations/de.js
@@ -16,5 +16,20 @@ export default {
'RO {Rumänisch}\n' +
'other {{params}}\n' +
'} {fieldName} ein.',
+ IsNotCountryIBAN:
+ '{userSuppliedCountryCode, select,\n' +
+ 'AT {Österreichisch}\n' +
+ 'BE {Belgisch}\n' +
+ 'CZ {Tschechisch}\n' +
+ 'DE {Deutsch}\n' +
+ 'ES {Spanisch}\n' +
+ 'FR {Französisch}\n' +
+ 'HU {Ungarisch}\n' +
+ 'IT {Italienisch}\n' +
+ 'NL {Niederländisch}\n' +
+ 'PL {Polnisch}\n' +
+ 'RO {Rumänisch}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} {fieldName} ist nicht erlaubt.',
},
};
diff --git a/packages/input-iban/translations/en.js b/packages/input-iban/translations/en.js
index 8357f20c6..f02792778 100644
--- a/packages/input-iban/translations/en.js
+++ b/packages/input-iban/translations/en.js
@@ -16,5 +16,20 @@ export default {
'RO {Romanian}\n' +
'other {{params}}\n' +
'} {fieldName}.',
+ IsNotCountryIBAN:
+ '{userSuppliedCountryCode, select,\n' +
+ 'AT {Austrian}\n' +
+ 'BE {Belgian}\n' +
+ 'CZ {Czech}\n' +
+ 'DE {German}\n' +
+ 'ES {Spanish}\n' +
+ 'FR {French}\n' +
+ 'HU {Hungarian}\n' +
+ 'IT {Italian}\n' +
+ 'NL {Dutch}\n' +
+ 'PL {Polish}\n' +
+ 'RO {Romanian}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} {fieldName} is not allowed.',
},
};
diff --git a/packages/input-iban/translations/es.js b/packages/input-iban/translations/es.js
index d1b48c57d..cfd2fef8c 100644
--- a/packages/input-iban/translations/es.js
+++ b/packages/input-iban/translations/es.js
@@ -16,5 +16,20 @@ export default {
'RO {Rumano}\n' +
'other {{params}}\n' +
'}.',
+ IsNotCountryIBAN:
+ '{fieldName} {userSuppliedCountryCode, select,\n' +
+ 'AT {Austriaco}\n' +
+ 'BE {Belga}\n' +
+ 'CZ {Checo}\n' +
+ 'DE {Alemán}\n' +
+ 'ES {Español}\n' +
+ 'FR {Francés}\n' +
+ 'HU {Húngaro}\n' +
+ 'IT {Italiano}\n' +
+ 'NL {Neerlandés}\n' +
+ 'PL {Polaco}\n' +
+ 'RO {Rumano}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} no se permite.',
},
};
diff --git a/packages/input-iban/translations/fr.js b/packages/input-iban/translations/fr.js
index 9447c4044..87bc00c4d 100644
--- a/packages/input-iban/translations/fr.js
+++ b/packages/input-iban/translations/fr.js
@@ -16,5 +16,20 @@ export default {
'RO {roumain}\n' +
'other {{params}}\n' +
'} valide.',
+ IsNotCountryIBAN:
+ '{fieldName} {userSuppliedCountryCode, select,\n' +
+ 'AT {autrichien}\n' +
+ 'BE {belge}\n' +
+ 'CZ {tchèque}\n' +
+ 'DE {allemand}\n' +
+ 'ES {espagnol}\n' +
+ 'FR {français}\n' +
+ 'HU {hongrois}\n' +
+ 'IT {italien}\n' +
+ 'NL {néerlandais}\n' +
+ 'PL {polonais}\n' +
+ 'RO {roumain}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ "} n'est pas autorisé.",
},
};
diff --git a/packages/input-iban/translations/hu.js b/packages/input-iban/translations/hu.js
index d8b1bf34c..1fd205995 100644
--- a/packages/input-iban/translations/hu.js
+++ b/packages/input-iban/translations/hu.js
@@ -16,5 +16,20 @@ export default {
'RO {Román}\n' +
'other {{params}}\n' +
'} {fieldName} értéket.',
+ IsNotCountryIBAN:
+ '{userSuppliedCountryCode, select,\n' +
+ 'AT {Osztrák}\n' +
+ 'BE {Belga}\n' +
+ 'CZ {Cseh}\n' +
+ 'DE {Német}\n' +
+ 'ES {Spanyol}\n' +
+ 'FR {Francia}\n' +
+ 'HU {Magyar}\n' +
+ 'IT {Olasz}\n' +
+ 'NL {Holland}\n' +
+ 'PL {Lengyel}\n' +
+ 'RO {Román}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} {fieldName} nem engedélyezett.',
},
};
diff --git a/packages/input-iban/translations/it.js b/packages/input-iban/translations/it.js
index 3eac1ab3e..b87a32711 100644
--- a/packages/input-iban/translations/it.js
+++ b/packages/input-iban/translations/it.js
@@ -16,5 +16,20 @@ export default {
'RO {Rumeno}\n' +
'other {{params}}\n' +
'}.',
+ IsNotCountryIBAN:
+ '{fieldName} {userSuppliedCountryCode, select,\n' +
+ 'AT {Austriaco}\n' +
+ 'BE {Belga}\n' +
+ 'CZ {Ceco}\n' +
+ 'DE {Tedesco}\n' +
+ 'ES {Spagnolo}\n' +
+ 'FR {Francese}\n' +
+ 'HU {Ungherese}\n' +
+ 'IT {Italiano}\n' +
+ 'NL {Olandese}\n' +
+ 'PL {Polacco}\n' +
+ 'RO {Rumeno}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} non è permesso.',
},
};
diff --git a/packages/input-iban/translations/nl.js b/packages/input-iban/translations/nl.js
index c2974e41c..edd102eba 100644
--- a/packages/input-iban/translations/nl.js
+++ b/packages/input-iban/translations/nl.js
@@ -16,5 +16,20 @@ export default {
'RO {Roemeense}\n' +
'other {{params}}\n' +
'} {fieldName} in.',
+ IsNotCountryIBAN:
+ '{userSuppliedCountryCode, select,\n' +
+ 'AT {Oostenrijkse}\n' +
+ 'BE {Belgische}\n' +
+ 'CZ {Tsjechische}\n' +
+ 'DE {Duitse}\n' +
+ 'ES {Spaanse}\n' +
+ 'FR {Franse}\n' +
+ 'HU {Hongaarse}\n' +
+ 'IT {Italiaanse}\n' +
+ 'NL {Nederlandse}\n' +
+ 'PL {Poolse}\n' +
+ 'RO {Roemeense}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} {fieldName} is niet toegestaan.',
},
};
diff --git a/packages/input-iban/translations/pl.js b/packages/input-iban/translations/pl.js
index 22b2d6b29..303269a59 100644
--- a/packages/input-iban/translations/pl.js
+++ b/packages/input-iban/translations/pl.js
@@ -16,5 +16,20 @@ export default {
'RO {Rumuński}\n' +
'other {{params}}\n' +
'} {fieldName}.',
+ IsNotCountryIBAN:
+ '{userSuppliedCountryCode, select,\n' +
+ 'AT {Austriacki}\n' +
+ 'BE {Belgijski}\n' +
+ 'CZ {Czeski}\n' +
+ 'DE {Niemiecki}\n' +
+ 'ES {Hiszpański}\n' +
+ 'FR {Francuski}\n' +
+ 'HU {Węgierski}\n' +
+ 'IT {Włoski}\n' +
+ 'NL {Holenderski}\n' +
+ 'PL {Polski}\n' +
+ 'RO {Rumuński}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} {fieldName} nie jest dozwolone.',
},
};
diff --git a/packages/input-iban/translations/ro.js b/packages/input-iban/translations/ro.js
index c2be4d085..bec11d061 100644
--- a/packages/input-iban/translations/ro.js
+++ b/packages/input-iban/translations/ro.js
@@ -16,5 +16,20 @@ export default {
'RO {românesc}\n' +
'other {{params}}\n' +
'} valid(ă).',
+ IsNotCountryIBAN:
+ '{fieldName} {userSuppliedCountryCode, select,\n' +
+ 'AT {austriac}\n' +
+ 'BE {belgian}\n' +
+ 'CZ {ceh}\n' +
+ 'DE {german}\n' +
+ 'ES {spaniol}\n' +
+ 'FR {francez}\n' +
+ 'HU {maghiar}\n' +
+ 'IT {italian}\n' +
+ 'NL {olandez}\n' +
+ 'PL {polonez}\n' +
+ 'RO {românesc}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} nu este permis.',
},
};
diff --git a/packages/input-iban/translations/ru.js b/packages/input-iban/translations/ru.js
index f6e3d2863..5986d9f57 100644
--- a/packages/input-iban/translations/ru.js
+++ b/packages/input-iban/translations/ru.js
@@ -16,5 +16,20 @@ export default {
'RO {Румынский}\n' +
'other {{params}}\n' +
'} {fieldName}.',
+ IsNotCountryIBAN:
+ '{userSuppliedCountryCode, select,\n' +
+ 'AT {Австрийский}\n' +
+ 'BE {Бельгийский}\n' +
+ 'CZ {Чешский}\n' +
+ 'DE {Немецкий}\n' +
+ 'ES {Испанский}\n' +
+ 'FR {Французский}\n' +
+ 'HU {Венгерский}\n' +
+ 'IT {Итальянский}\n' +
+ 'NL {Нидерландский}\n' +
+ 'PL {Польский}\n' +
+ 'RO {Румынский}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} {fieldName} не допускается.',
},
};
diff --git a/packages/input-iban/translations/sk.js b/packages/input-iban/translations/sk.js
index 5a9666020..f568fecbe 100644
--- a/packages/input-iban/translations/sk.js
+++ b/packages/input-iban/translations/sk.js
@@ -16,5 +16,20 @@ export default {
'RO {rumunský}\n' +
'other {{params}}\n' +
'} kód {fieldName}.',
+ IsNotCountryIBAN:
+ '{userSuppliedCountryCode, select,\n' +
+ 'AT {Rakúsky}\n' +
+ 'BE {Belgický}\n' +
+ 'CZ {Český}\n' +
+ 'DE {Nemecký}\n' +
+ 'ES {Španielsky}\n' +
+ 'FR {Francúzsky}\n' +
+ 'HU {Maďarský}\n' +
+ 'IT {Taliansky}\n' +
+ 'NL {Holandský}\n' +
+ 'PL {Poľský}\n' +
+ 'RO {Rumunský}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} {fieldName} nie je povolené.',
},
};
diff --git a/packages/input-iban/translations/uk.js b/packages/input-iban/translations/uk.js
index 407b98375..2842bc3a7 100644
--- a/packages/input-iban/translations/uk.js
+++ b/packages/input-iban/translations/uk.js
@@ -16,5 +16,20 @@ export default {
'RO {румунська}\n' +
'other {{params}}\n' +
'} {fieldName}.',
+ IsNotCountryIBAN:
+ '{userSuppliedCountryCode, select,\n' +
+ 'AT {Австрійський}\n' +
+ 'BE {Бельгійський}\n' +
+ 'CZ {Чеський}\n' +
+ 'DE {Німецький}\n' +
+ 'ES {Iспанський}\n' +
+ 'FR {Французький}\n' +
+ 'HU {Угорський}\n' +
+ 'IT {Iталійський}\n' +
+ 'NL {Голландський}\n' +
+ 'PL {Польський}\n' +
+ 'RO {Румунська}\n' +
+ 'other {{userSuppliedCountryCode}}\n' +
+ '} {fieldName} не дозволено.',
},
};
diff --git a/packages/input-iban/translations/zh.js b/packages/input-iban/translations/zh.js
index a33889edc..1d6a1e76e 100644
--- a/packages/input-iban/translations/zh.js
+++ b/packages/input-iban/translations/zh.js
@@ -16,5 +16,20 @@ export default {
'RO {罗马尼亚}\n' +
'另一个 {{params}}\n' +
'} {fieldName}。',
+ IsNotCountryIBAN:
+ '{userSuppliedCountryCode, select,\n' +
+ 'AT {奥}\n' +
+ 'BE {比利时的}\n' +
+ 'CZ {捷克}\n' +
+ 'DE {德语}\n' +
+ 'ES {西班牙语}\n' +
+ 'FR {法国}\n' +
+ 'HU {匈牙利}\n' +
+ 'IT {意大利}\n' +
+ 'NL {荷兰人}\n' +
+ 'PL {抛光}\n' +
+ 'RO {罗马尼亚}\n' +
+ '另一个 {{userSuppliedCountryCode}}\n' +
+ '} {fieldName} 不允許。',
},
};