import { isStr } from './utils' ; /**
 * An array that is derived from a path string
 * For example, if your template has a path that looks like `'person.name'`, its corresponding Ref
 * looks like `['person', 'name']`
 */ export type Ref = string [ ] ; internal const cacheSize = 1000 ; internal export class Cache < T > { private map : { [ path ] : T ; } ; private cachedKeys : string [ ] ; private oldestIndex : number ; constructor ( private size ) { this . reset ( ) ; } public reset ( ) { this . oldestIndex = 0 ; this . map = { } ; this . cachedKeys = new Array < string > ( this . size ) ; } public get ( key ) { return this . map [ key ] ; } public set ( key , value ) { this . map [ key ] = value ; const oldestKey = this . cachedKeys [ this . oldestIndex ] ; if ( oldestKey !== undefined ) { delete this . map [ oldestKey ] ; } this . cachedKeys [ this . oldestIndex ] = key ; this . oldestIndex ++ ; this . oldestIndex %= this . size ; } } internal const cache = new Cache < string [ ] > ( cacheSize ) ; internal interface RegExpWithNameGroup extends RegExpExecArray { groups : { name : string ; } ; } internal const pathPatterns = [ /\s*\.\s*(?<name>[$_\w]+)\s*/y , /\s*\[\s*(?<quote>['"`])(?<name>.*?)\k<quote>\s*\]\s*/y , /\s*\[\s*\+?\s*0*(?<name>\d{1,16}?)\s*\]\s*/y , /^\s*(?<name>[$_\w]+)\s*/y , ] ; param path throws throws returns export function parsePath ( path ) { if ( ! isStr ( path ) ) { throw new TypeError ( `Cannot parse ref. Expected string. Got a ${ typeof path }` ) ; } const ref = [ ] ; if ( path . trim ( ) === '' ) { return ref ; } let currIndex = 0 ; let patternMatched ; do { patternMatched = false ; for ( const pattern of pathPatterns ) { pattern . lastIndex = currIndex ; const parsedResult = pattern . exec ( path ) ; if ( parsedResult ) { patternMatched = true ; currIndex = pattern . lastIndex ; ref . push ( ( parsedResult as RegExpWithNameGroup ) . groups . name ) ; break ; } } } while ( patternMatched ) ; if ( currIndex !== path . length ) { throw new SyntaxError ( `Could not parse path: "${ path }"` ) ; } return ref ; } internal function parseRefCached ( path ) { let result = cache . get ( path ) ; if ( result === undefined ) { result = parsePath ( path ) ; cache . set ( path , result ) ; } return result ; } parsePath . cached = parseRefCached ;