@@ -1513,6 +1513,20 @@ A.interpolate = ({sep, trailing = false}) => xs => {
15131513} ;
15141514
15151515
1516+ // retrieve duplicate values
1517+
1518+ A . retrieveDupes = xs => {
1519+ const uniqs = new Set ( ) , dupes = new Set ( ) ;
1520+
1521+ for ( const x of xs ) {
1522+ if ( uniqs . has ( x ) ) dupes . add ( x ) ;
1523+ else uniqs . add ( x ) ;
1524+ }
1525+
1526+ return Array . from ( dupes ) :
1527+ } ;
1528+
1529+
15161530// set a focus on an array without altering the underlying array
15171531
15181532A . focus = ( { from, to} ) => xs => {
@@ -5920,40 +5934,54 @@ Parser.time = ({date = new Date("0000-01-01"), _throw = false}) => s => {
59205934} ;
59215935
59225936
5923- Parser . iban = ( { _throw = false } ) => s => {
5924- const codeLen = 22 ;
5937+ Parser . iban = ( { locale, _throw = false } ) => s => {
5938+ switch ( locale ) {
5939+ case "deDE" : {
5940+ const codeLen = 22 ;
59255941
5926- const iban = s . toUpperCase ( ) ,
5927- code = iban . match ( / ^ ( [ A - Z ] { 2 } ) ( \d { 2 } ) ( [ A - Z \d ] + ) $ / ) ;
5942+ const iban = s . toUpperCase ( ) ,
5943+ code = iban . match ( / ^ ( [ A - Z ] { 2 } ) ( \d { 2 } ) ( [ A - Z \d ] + ) $ / ) ;
59285944
5929- let digits ;
5945+ let digits ;
59305946
5931- if ( ! code || iban . length !== codeLen ) return false ;
5947+ if ( ! code || iban . length !== codeLen ) {
5948+ if ( _throw ) throw new Err ( `malformed iban "${ s } "` ) ;
59325949
5933- digits = ( code [ 3 ] + code [ 1 ] + code [ 2 ] ) . replace ( / [ A - Z ] / g, letter => {
5934- return letter . charCodeAt ( 0 ) - 55 ;
5935- } ) ;
5950+ else return Parser . Invalid ( {
5951+ value : s ,
5952+ kind : "iban" ,
5953+ reason : "malformed iban" ,
5954+ } ) ;
5955+ }
59365956
5937- let checksum = digits . slice ( 0 , 2 ) ,
5938- fragment ;
5957+ digits = ( code [ 3 ] + code [ 1 ] + code [ 2 ] ) . replace ( / [ A - Z ] / g, letter => {
5958+ return letter . charCodeAt ( 0 ) - 55 ;
5959+ } ) ;
59395960
5940- for ( let offset = 2 ; offset < digits . length ; offset += 7 ) {
5941- fragment = String ( checksum ) + digits . substring ( offset , offset + 7 ) ;
5942- checksum = parseInt ( fragment , 10 ) % 97 ;
5943- }
5961+ let checksum = digits . slice ( 0 , 2 ) ,
5962+ fragment ;
59445963
5945- if ( checksum === 1 ) return Parser . Valid ( {
5946- value : s ,
5947- kind : "iban" ,
5948- } ) ;
5964+ for ( let offset = 2 ; offset < digits . length ; offset += 7 ) {
5965+ fragment = String ( checksum ) + digits . substring ( offset , offset + 7 ) ;
5966+ checksum = parseInt ( fragment , 10 ) % 97 ;
5967+ }
59495968
5950- else if ( _throw ) throw new Err ( `malformed iban "${ s } "` ) ;
5969+ if ( checksum === 1 ) return Parser . Valid ( {
5970+ value : s ,
5971+ kind : "iban" ,
5972+ } ) ;
59515973
5952- else return Parser . Invalid ( {
5953- value : s ,
5954- kind : "iban" ,
5955- reason : "malformed iban" ,
5956- } ) ;
5974+ else if ( _throw ) throw new Err ( `malformed iban "${ s } "` ) ;
5975+
5976+ else return Parser . Invalid ( {
5977+ value : s ,
5978+ kind : "iban" ,
5979+ reason : "malformed iban" ,
5980+ } ) ;
5981+ }
5982+
5983+ default : throw new Err ( `not supported locale "${ locale } "` ) ;
5984+ }
59575985} ;
59585986
59595987
@@ -9101,6 +9129,12 @@ S.stripAllButNum = s => s.replaceAll(/[^\p{N}]/gv, "");
91019129S . catWith = s => ( ...xs ) => xs . join ( s ) ;
91029130
91039131
9132+ S . cat = S . catWith ( "" ) ;
9133+
9134+
9135+ S . cat_ = S . catWith ( " " ) ;
9136+
9137+
91049138// try to truncate a string without breaking its tokens
91059139
91069140S . trunc = maxLen => s => {
@@ -9144,12 +9178,6 @@ S.trunc2 = maxLen => s => {
91449178} ;
91459179
91469180
9147- S . cat = S . catWith ( "" ) ;
9148-
9149-
9150- S . cat_ = S . catWith ( " " ) ;
9151-
9152-
91539181/* Plain applicator but with a telling name. Intended use:
91549182
91559183 S.template(o => `Happy ${o.foo}, ${o.bar}!`)
@@ -9337,7 +9365,7 @@ S.splitName = s => {
93379365 const compos2 = compos . slice ( 0 , - 1 ) . reduce ( ( acc , compo ) =>
93389366 A . pushn ( compo . split ( / - | (?< = \. ) (? = \p{ L} ) / v) ) ( acc ) , [ ] ) ;
93399367
9340- const firstName = compos2 [ 0 ] ,
9368+ const firstName = compos2 . length ? compos2 [ 0 ] : "" ,
93419369 middleNames = compos2 . slice ( 1 ) ,
93429370 lastNames = compos [ compos . length - 1 ] . split ( / - / ) ;
93439371
@@ -9346,6 +9374,9 @@ S.splitName = s => {
93469374} ;
93479375
93489376
9377+ S . splitMergedWords = s => s => s . split ( / (?< = \p{ Ll} ) (? = \p{ Lu} ) / v) . join ( " " ) ;
9378+
9379+
93499380//█████ Retrieval █████████████████████████████████████████████████████████████
93509381
93519382
0 commit comments