import { Parser , AccessMember , AccessScope } from 'aurelia-binding' ; import { isString , isNumber } from './util' ; export type PropertyAccessor < TObject , TValue > = ( object : TObject ) => TValue ; export class PropertyAccessorParser { public static inject = [ Parser ] ; constructor ( private parser ) { } public parse < TObject , TValue > ( property ) { if ( isString ( property ) || isNumber ( property ) ) { return property as string | number ; } const accessorText = getAccessorExpression ( property . toString ( ) ) ; const accessor = this . parser . parse ( accessorText ) ; if ( accessor instanceof AccessScope || accessor instanceof AccessMember && accessor . object instanceof AccessScope ) { return accessor . name ; } throw new Error ( `Invalid property expression: "${ accessor }"` ) ; } } export function getAccessorExpression ( fn ) { const classic = /^function\s*\([$_\w\d]+\)\s*\{(?:\s*"use strict";)?(?:[$_\s\w\d\/\*.['"\]+;]+)?\s*return\s+[$_\w\d]+\.([$_\w\d]+)\s*;?\s*\}$/ ; const arrow = /^\(?[$_\w\d]+\)?\s*=>\s*[$_\w\d]+\.([$_\w\d]+)$/ ; const match = classic . exec ( fn ) || arrow . exec ( fn ) ; if ( match === null ) { throw new Error ( `Unable to parse accessor function:\n${ fn }` ) ; } return match [ 1 ] ; }