@@ -5530,12 +5530,11 @@ O.Get.any = (...getters) => o => k => {
55305530███████████████████████████████████████████████████████████████████████████████*/
55315531
55325532
5533- /* This isn't yet another parser implementation but a type that is meant to
5534- replace ture/false validations suffering from boolean blindness. A parser takes
5535- unstructured data and tries to add structre to it. It returns structured data
5536- on success or the original data on error (or throws the error). Besides the
5537- valid/invalid dichotomy the type also can represent a maybe valid value where
5538- confidence quantifies the amount of indeterminism. */
5533+ /* The parser type is meant to replace ture/false validations suffering from
5534+ boolean blindness. A parser takes a value of a general type like string or
5535+ number and adds meta information on success or provides reason on failure. The
5536+ type can model a third state that represents a maybe successfully parsed value,
5537+ where confidence is quantified as a number between 0 and 1. */
55395538
55405539
55415540export const Parser = { } ;
@@ -6593,7 +6592,7 @@ Parser.acronym = specialChars => s => {
65936592 if ( rx . length < 2 ) {
65946593 return Parser . Invalid ( {
65956594 value : s ,
6596- reason : "less than 2 upper-case letters" ,
6595+ reason : "contains less than 2 upper-case letters" ,
65976596 kind : "acronym" ,
65986597 } ) ;
65996598 }
@@ -6610,6 +6609,107 @@ Parser.acronym = specialChars => s => {
66106609Parser . acronym_ = Parser . acronym ( "&/" ) ;
66116610
66126611
6612+ // parse a proper name like Foo, Foo-Bar, O'Foo, McFoo
6613+
6614+ Parser . properName = prefixes => s => {
6615+ if ( / [ ^ \p{ L} ' \- ] / v. test ( s ) ) {
6616+ return Parser . Invalid ( {
6617+ value : s ,
6618+ kind : "proper name" ,
6619+ reason : "contains invalid characters" ,
6620+ } ) ;
6621+ }
6622+
6623+ else if ( ! / \p{ Lu} / v. test ( s [ 0 ] ) ) {
6624+ return Parser . Invalid ( {
6625+ value : s ,
6626+ kind : "proper name" ,
6627+ reason : "first letter must be upper-case" ,
6628+ } ) ;
6629+ }
6630+
6631+ else if ( S . countChar ( "-" ) ( s ) > 1 ) {
6632+ return Parser . Invalid ( {
6633+ value : s ,
6634+ kind : "proper name" ,
6635+ reason : "contains more than one hyphen" ,
6636+ } ) ;
6637+ }
6638+
6639+ else if ( S . countChar ( "'" ) ( s ) > 1 ) {
6640+ return Parser . Invalid ( {
6641+ value : s ,
6642+ kind : "proper name" ,
6643+ reason : "contains more than one apostrophe" ,
6644+ } ) ;
6645+ }
6646+
6647+ else if ( s . startsWith ( "-" ) || s . startsWith ( "'" ) ) {
6648+ return Parser . Invalid ( {
6649+ value : s ,
6650+ kind : "proper name" ,
6651+ reason : "special characters at the beginning" ,
6652+ } ) ;
6653+ }
6654+
6655+ else if ( s . endsWith ( "-" ) || s . endsWith ( "'" ) ) {
6656+ return Parser . Invalid ( {
6657+ value : s ,
6658+ kind : "proper name" ,
6659+ reason : "special characters at the end" ,
6660+ } ) ;
6661+ }
6662+
6663+ for ( let i = 1 ; i < s . length ; i ++ ) {
6664+ const c = s [ i ] , prev = s [ i - 1 ] ;
6665+
6666+ if ( c === "-" || c === "'" ) continue ;
6667+
6668+ else if ( prev === "-" || prev === "'" ) {
6669+ if ( / \p{ Ll} / v. test ( c ) ) {
6670+ return Parser . Invalid ( {
6671+ value : s ,
6672+ kind : "proper name" ,
6673+ reason : "unexpected lower-case letter after special character" ,
6674+ } ) ;
6675+ }
6676+ }
6677+
6678+ else if ( / \p{ Lu} / v. test ( c ) ) {
6679+ const sub = s . substring ( 0 , i ) ;
6680+ let match = false ;
6681+
6682+ for ( const prefix of prefixes ) {
6683+ if ( sub . endsWith ( prefix ) ) {
6684+ match = true ;
6685+ break ;
6686+ }
6687+ }
6688+
6689+ if ( match === false ) return Parser . Invalid ( {
6690+ value : s ,
6691+ kind : "proper name" ,
6692+ reason : "unexpected upper-case letter" ,
6693+ } ) ;
6694+
6695+ }
6696+
6697+ else if ( ! / \p{ Ll} / v. test ( c ) ) {
6698+ return Parser . Invalid ( {
6699+ value : s ,
6700+ kind : "proper name" ,
6701+ reason : `letter expected at ${ i + 1 } ` ,
6702+ } ) ;
6703+ }
6704+ }
6705+
6706+ return Parser . Valid ( {
6707+ value : s ,
6708+ kind : "proper name" ,
6709+ } ) ;
6710+ } ;
6711+
6712+
66136713Parser . sentence = s => {
66146714 const last = s [ s . length - 1 ] ;
66156715 let type = "" ;
0 commit comments