/**
 * Created by eddyspreeuwers on 4/24/21.
 */ import { log } from "./xml-utils" ; import max = require ( "lodash/fp/max" ) ; import last = require ( "lodash/fp/last" ) ; export const digits = '0123456789' ; export const a2z = 'abcdefghijklmnopqrstuvwxyz' ; export const A2Z = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ; export const leestekens = '~§±!@#$%^&*()-_=+[]{}|;:.,\'"' . split ( '' ) . sort ( ) . join ( '' ) ; export const allW = digits + A2Z + a2z ; export const allC = digits + A2Z + a2z + leestekens ; const CHAR_TYPE = 'char' ; const MAX_OPTIONS_LENGTH = 1000 ; const MAX_LENGTH = 100 ; const SPECIALS = { '\\d' : digits , '\\w' : allW , '\\.' : '.' , '\\-' : '-' , '\\[' : '[' , '\\]' : ']' , '\\{' : '{' , '\\}' : '}' , '\\*' : '*' , '\\+' : '+' , '\\^' : '^' , '\\?' : '?' , '.' : allC , '\\\\' : '\\\\' , } ; export function buildVariants ( optionVariants , series , maxLength ) { const newOptionVariants = { } ; ( optionVariants || [ ] ) . forEach ( ( ov ) => { ( series || [ ] ) . forEach ( s => { if ( ( maxLength || 10000 ) >= ( ov + s ) . length ) { newOptionVariants [ ov + s ] = 1 ; } else { newOptionVariants [ ov ] = 1 ; } } ) ; } ) ; return Object . keys ( newOptionVariants ) . sort ( ) ; } export function makeVariants ( optionVariants , series , maxLength ) { return buildVariants ( optionVariants , series . split ( '' ) , maxLength ) ; } function invertSeries ( res ) { return allC . split ( '' ) . filter ( e => res . indexOf ( e ) < 0 ) . join ( '' ) ; } function expandRange ( start , end ) { return start + allW . split ( start ) . reverse ( ) . shift ( ) . split ( end ) . shift ( ) + end ; } export function range ( index , pattern ) { let result = '' ; const part = pattern . substring ( index ) ; let matches = part . match ( /\^?(\w-\w)/ ) ; if ( matches && matches . index === 0 ) { const [ start , end ] = matches [ 1 ] . split ( '-' ) ; let res = expandRange ( start , end ) ; if ( part . indexOf ( '^' ) === 0 ) { res = invertSeries ( res ) ; } result += res ; index += matches [ 0 ] . length ; } return [ result , index ] ; } export function char ( index , pattern ) { let result = '' ; const part = pattern . substring ( index ) ; const matches = part . match ( /\^?(\w|<|>|!|#"%|&|=|_)/ ) ; if ( matches && matches . index === 0 ) { result += ( pattern [ index ] === '^' ) ? invertSeries ( matches [ 1 ] ) : matches [ 1 ] ; index += matches [ 0 ] . length ; } return [ result , index ] ; } export function repeat ( index , pattern ) { let result = '' ; const part = pattern . substring ( index ) ; const matches = part . match ( /\{(\d+)(,\d+)?\}/ ) ; if ( matches && matches . index === 0 ) { let min = matches [ 1 ] ; let max = matches [ 2 ] || ( ',' + matches [ 1 ] ) ; result = [ min , max ] . join ( '' ) ; index += matches [ 0 ] . length ; } return [ result , index ] ; } export function specials ( index , pattern ) { let result = '' ; let part = pattern . substring ( index ) ; for ( let t in SPECIALS ) { if ( part . indexOf ( t ) === 0 ) { result = SPECIALS [ t ] ; index += t . length ; break ; } } return [ result , index ] ; } export function series ( index , pattern ) { if ( pattern [ index ] !== '[' ) { return [ '' , index ] ; } const offset = index ; let [ r , i ] = [ '' , 0 ] ; let result = '' ; index ++ ; while ( pattern [ index ] !== ']' ) { [ r , i ] = specials ( index , pattern ) ; if ( r ) { result += r ; index = i ; continue ; } [ r , i ] = range ( index , pattern ) ; if ( r ) { result += r ; index = i ; continue ; } [ r , i ] = char ( index , pattern ) ; if ( r ) { result += r ; index = i ; continue ; } if ( index >= pattern . length ) { return [ '' , offset ] ; } break ; } if ( pattern [ index ] === ']' ) { index ++ ; } return [ result , index ] ; } export function variants ( pattern , index = 0 , maxLength = MAX_LENGTH ) { const offset = index ; let [ r , i ] = [ '' , 0 ] ; let result = null ; let options = [ '' ] ; let startOptionIndex = 0 ; let lastOptionType = null ; while ( pattern [ index ] !== '|' && pattern [ index ] !== ')' && index < pattern . length ) { [ r , i ] = specials ( index , pattern ) ; if ( r ) { startOptionIndex = options . length ; options = makeVariants ( options , r , maxLength ) ; index = i ; result = r ; lastOptionType = 'special' ; continue ; } [ r , i ] = series ( index , pattern ) ; if ( r ) { startOptionIndex = options . length ; options = makeVariants ( options , r , maxLength ) ; index = i ; result = r ; lastOptionType = 'series' ; continue ; } [ r , i ] = char ( index , pattern ) ; if ( r ) { startOptionIndex = options . length ; options = makeVariants ( options , r , maxLength ) ; index = i ; result = r ; lastOptionType = CHAR_TYPE ; continue ; } [ r , i ] = repeat ( index , pattern ) ; if ( r ) { const [ min , max ] = r . split ( ',' ) . map ( s => + s ) ; options = options . map ( o => o . substring ( 0 , o . length - 1 ) ) ; const orgLength = options [ options . length - 1 ] . length ; const chars = result . split ( '' ) ; chars . unshift ( '' ) ; while ( options [ options . length - 1 ] . length < Math . min ( maxLength , ( 1 + max ) ) && options . length < MAX_OPTIONS_LENGTH ) { options = buildVariants ( options , chars , maxLength ) ; } options = options . filter ( o => o . length >= orgLength + min ) ; index = i ; continue ; } let c = pattern [ index ] ; if ( ( c === '*' || c === '+' || c === '?' ) && result !== null ) { if ( c === '*' || c === '?' ) { options = options . map ( o => o . substring ( 0 , o . length - 1 ) ) ; } const chars = result . split ( '' ) ; chars . unshift ( '' ) ; while ( options [ options . length - 1 ] . length < maxLength && options . length < MAX_OPTIONS_LENGTH ) { options = buildVariants ( options , chars , maxLength ) ; if ( c === '?' ) { break ; } } index ++ ; continue ; } break ; } result = ( offset === index ) ? null : options ; return [ result , index ] ; } export function option ( pattern , index = 0 , maxLength = MAX_LENGTH ) { const offset = index ; let [ r , i ] = [ null , 0 ] ; let result = null ; while ( index < pattern . length ) { [ r , i ] = variants ( pattern , index ) ; if ( r ) { if ( ! result ) result = [ ] ; result = result . concat ( r ) ; index = i ; continue ; } if ( pattern [ index ] === '|' ) { break ; } break ; } return [ result , index ] ; } export function group ( pattern , index = 0 , maxLength = 10 ) { if ( pattern [ index ] !== '(' ) { return [ null , index ] ; } const offset = index ; let [ r , i ] = [ null , 0 ] ; let result = null ; let options = [ ] ; index ++ ; while ( index < pattern . length ) { [ r , i ] = option ( pattern , index ) ; if ( r ) { options = options . concat ( r ) ; index = i ; result = r ; continue ; } if ( pattern [ index ] == '|' ) { index ++ ; continue ; } if ( pattern [ index ] !== ')' ) { return [ null , offset ] ; } break ; } if ( pattern [ index ] !== ')' ) { return [ null , offset ] ; } result = ( options . length > 0 ) ? options : null ; index ++ ; return [ result , index ] ; } export function expression ( pattern , index = 0 , maxLength = 10 ) { let [ r , i ] = [ null , 0 ] ; let result = null ; let options = [ ] ; let startIndex = 0 ; while ( index < pattern . length ) { if ( pattern [ index ] === '|' ) { startIndex = options . length ; index ++ ; } [ r , i ] = group ( pattern , index ) ; if ( r ) { const lastOptions = options . filter ( ( e , i , a ) => i >= startIndex ) ; if ( lastOptions . length === 0 ) { options = options . concat ( r ) ; } else { options = buildVariants ( lastOptions , r , maxLength ) ; } index = i ; result = r ; continue ; } [ r , i ] = option ( pattern , index ) ; if ( r ) { const lastOptions = options . filter ( ( e , i , a ) => i >= startIndex ) ; if ( lastOptions . length === 0 ) { options = options . concat ( r ) ; } else { options = buildVariants ( lastOptions , [ r [ 0 ] ] , maxLength ) ; } index = i ; result = r ; continue ; } let c = pattern [ index ] ; ; if ( ( c === '*' || c === '+' || c === '?' ) && result !== null ) { let lastOptions = options . filter ( ( e , i , a ) => i >= startIndex ) ; const firstOptions = options . filter ( ( e , i , a ) => i < startIndex ) ; if ( c === '*' || c === '?' ) { lastOptions = lastOptions . map ( o => o . substring ( 0 , o . length - 1 ) ) ; } const chars = result ; chars . unshift ( '' ) ; while ( lastOptions [ lastOptions . length - 1 ] . length < maxLength && lastOptions . length < MAX_OPTIONS_LENGTH ) { lastOptions = buildVariants ( lastOptions , chars , maxLength ) ; if ( c === '?' ) { break ; } } options = firstOptions . concat ( lastOptions ) ; index ++ ; continue ; } break ; } result = options ; index ++ ; return [ result , index ] ; } export function regexpPattern2typeAlias ( pattern , base , attr ? ) { let result = '' ; let maxInt = ( attr && /\d+/ . test ( attr [ 'maxInclusive' ] ) ) ? parseInt ( attr [ 'maxInclusive' ] ) : undefined ; let minInt = ( attr && /\d+/ . test ( attr [ 'minInclusive' ] ) ) ? parseInt ( attr [ 'minInclusive' ] ) : undefined ; let maxLength = ( attr && /\d+/ . test ( attr [ 'maxLength' ] ) ) ? parseInt ( attr [ 'maxLength' ] ) : undefined ; const [ v , i ] = expression ( pattern , 0 , maxLength ) ; if ( ! v ) { return base ; } let options = v || [ ] ; if ( base === 'string' ) { result = options . filter ( n => ! maxLength || ( '' + n ) . length <= maxLength ) . map ( o => `"${ o . replace ( '"' , '\\"' ) }"` ) . join ( '|' ) ; } else if ( base === 'number' ) { result = options . filter ( o => /\d\.?\d*/ . test ( o ) ) . map ( s => + s ) . filter ( n => ! maxLength || ( '' + n ) . length <= maxLength ) . filter ( n => ( ! maxInt || n <= maxInt ) ) . filter ( n => ( ! minInt || n >= minInt ) ) . filter ( ( n , i , a ) => a . indexOf ( n ) === i ) . join ( '|' ) . replace ( /\|+/g , '|' ) ; } else { result = base ; } if ( result . length > 500 ) { result = base ; } log ( 'alias result :' , result ) ; return result || base ; }