UNPKG

datum-focus

Version:

Data shape, model, metadata, JSON, JSON Schema, GraphQL, MongoDB query and aggregations, iterator generators

116 lines (97 loc) 3.44 kB
export function cleanseAssertionOperators<T extends number | string | symbol = string>( parsedName: string ): T { return <T>parsedName.replace(/[?!]/g, ""); } export interface NameofOptions { /** * Take only the last property of nested properties. */ lastProp?: boolean; } export function nameof<T extends Object>( nameFunction: ((obj: T) => any) | { new (...params: any[]): T }, options?: NameofOptions ): string { const fnStr = nameFunction.toString(); // ES6 class name: // "class ClassName { ..." if ( fnStr.startsWith("class ") && // Theoretically could, for some ill-advised reason, be "class => class.prop". !fnStr.startsWith("class =>") ) { return cleanseAssertionOperators( fnStr.substring("class ".length, fnStr.indexOf(" {")) ); } // ES6 prop selector: // "x => x.prop" if (fnStr.includes("=>")) { return cleanseAssertionOperators(fnStr.substring(fnStr.indexOf(".") + 1)); } // ES5 prop selector: // "function (x) { return x.prop; }" // webpack production build excludes the spaces and optional trailing semicolon: // "function(x){return x.prop}" // FYI - during local dev testing i observed carriage returns after the curly brackets as well // Note by maintainer: See https://github.com/IRCraziestTaxi/ts-simple-nameof/pull/13#issuecomment-567171802 for explanation of this regex. const matchRegex = /function\s*\(\w+\)\s*\{[\r\n\s]*return\s+\w+\.((\w+\.)*(\w+))/i; const es5Match = fnStr.match(matchRegex); if (es5Match) { return options && options.lastProp ? es5Match[3] : es5Match[1]; } // ES5 class name: // "function ClassName() { ..." if (fnStr.startsWith("function ")) { return cleanseAssertionOperators( fnStr.substring("function ".length, fnStr.indexOf("(")) ); } // Invalid function. throw new Error("nameof: Invalid function."); } export function nameOf<T extends Object>( nameFunction: (obj: T) => unknown ): keyof T { const fnStr = nameFunction.toString(); // ES6 class name: // "class ClassName { ..." if ( fnStr.startsWith("class ") && // Theoretically could, for some ill-advised reason, be "class => class.prop". !fnStr.startsWith("class =>") ) { return cleanseAssertionOperators<keyof T>( fnStr.substring("class ".length, fnStr.indexOf(" {")) ); } // ES6 prop selector: // "x => x.prop" if (fnStr.includes("=>")) { return cleanseAssertionOperators<keyof T>( fnStr.substring(fnStr.indexOf(".") + 1) ); } // ES5 prop selector: // "function (x) { return x.prop; }" // webpack production build excludes the spaces and optional trailing semicolon: // "function(x){return x.prop}" // FYI - during local dev testing i observed carriage returns after the curly brackets as well // Note by maintainer: See https://github.com/IRCraziestTaxi/ts-simple-nameof/pull/13#issuecomment-567171802 for explanation of this regex. const matchRegex = /function\s*\(\w+\)\s*\{[\r\n\s]*return\s+\w+\.((\w+\.)*(\w+))/i; const es5Match = fnStr.match(matchRegex); if (es5Match) { return <keyof T>es5Match[1]; } // ES5 class name: // "function ClassName() { ..." if (fnStr.startsWith("function ")) { return cleanseAssertionOperators( fnStr.substring("function ".length, fnStr.indexOf("(")) ); } // Invalid function. throw new Error("nameof: Invalid function."); } export default nameof;