27 October, 2015
2 Comments
1 category
Let’s assume we have the class [GuidGenerator] in a TypeScript module [research.my.long.namespace] and at runtime you have an instance of the GuidGenerator, how do you get the full class name including module name, in this case: “research.my.long.namespace.GuidGenerator”.
Well you walk the object graph starting with the root / global object, in the browser this will be the window object.
NOTE: all code is in “strict” modus.
TypeScript Class [GuidGenerator]:
module research.my.long.namespace {
"use strict";
export interface IGuidGenerator {
generate(): string;
}
export class GuidGenerator implements IGuidGenerator {
generate() {
var randomNumberToGuid = function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : r & 0x3 | 0x8;
return v.toString(16);
}
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, randomNumberToGuid);
}
}
}
We use the resolver object to get the full class name:
var resolver = new NameResolver();
var generator = new research.my.long.namespace.GuidGenerator();
var name = resolver.getFullClassNameFromInstance(generator, window)
console.log(name);
Result
The resolver class
module research.metadata {
"use strict";
interface IProcessResult {
fnFound: boolean;
path: Array<string>;
}
export interface INameResolver {
getFullClassNameFromInstance(instance: any, global: any): string;
}
export class NameResolver implements INameResolver {
private _fn: any;
private _global: any;
private _processed: Array<any>;
/**
To handle recursiveness in the object graph, collect all handled nodes in the object graph,
so an object is only traversed once.
*/
isProcessed(obj: any): boolean {
var result = false;
for (var i, length; i < length; i += 1) {
if (this._processed[i] === obj) {
return true;
}
}
return result;
}
processProperty(obj: any, key: string, path: Array<string>): IProcessResult {
var result: IProcessResult = {
fnFound: false,
path: path
}
if (obj.hasOwnProperty(key)) {
try {
var prop = obj[key];
if (prop === this._fn) {
// Function found, stop traversing the object graph.
result.fnFound = true;
return result;
}
// Continue traversing the object graph.
result = this.processObject(prop, path);
if (result.fnFound) {
// Function found, stop traversing the object graph.
return result;
}
} catch (error) {
// Access to some properties result in exceptions.
}
}
return result;
}
processObject(obj: any, path: Array<string>): IProcessResult {
var result: IProcessResult = {
fnFound: false,
path: path
}
if (this.isProcessed(obj)) {
return result;
}
this._processed.push(obj);
for (var key in obj) {
var pathCopy = path.slice();
pathCopy.push(key);
var processResult = this.processProperty(obj, key, pathCopy);
if (processResult.fnFound) {
return processResult;
}
}
return processResult;
}
getFullClassNameFromInstance(instance: any, global: any): string {
this._fn = instance["constructor"];
this._global = global;
this._processed = [];
var processResult = this.processObject(this._global, []);
var fullFnName = "";
if (processResult.fnFound) {
fullFnName = processResult.path.join(".");
}
return fullFnName;
}
}
}
Tags: TypeScript
Category: Uncategorized
I tried your code in a typescript playground and got “resolver._fn” as result … did I miss something ?
To tell the thruth, your code copied and pasted in typescript playground works fine. The result “resolver._fn” is coming out when I try to apply the code to my test module:
module app.model {
export interface IDataModel {
}
export interface IBehaviorModel {
fromDataModel(dataModel: TDataModel): TBehaviorModel ;
}
export class SampleDataModel implements IDataModel {}
export class SampleBehaviorModel implements IBehaviorModel{
public fromDataModel(dataModel: SampleDataModel){
return new SampleBehaviorModel();
};
}
export class Utils {
public static __getClass(object) {
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
}
}
}
module research.metadata {
“use strict”;
interface IProcessResult {
fnFound: boolean;
path: Array;
}
export interface INameResolver {
getFullClassNameFromInstance(instance: any, global: any): string;
}
export class NameResolver implements INameResolver {
private _fn: any;
private _global: any;
private _processed: Array;
/**
To handle recursiveness in the object graph, collect all handled nodes in the object graph,
so an object is only traversed once.
*/
isProcessed(obj: any): boolean {
var result = false;
for (var i, length; i < length; i += 1) {
if (this._processed[i] === obj) {
return true;
}
}
return result;
}
processProperty(obj: any, key: string, path: Array): IProcessResult {
var result: IProcessResult = {
fnFound: false,
path: path
}
if (obj.hasOwnProperty(key)) {
try {
var prop = obj[key];
if (prop === this._fn) {
// Function found, stop traversing the object graph.
result.fnFound = true;
return result;
}
// Continue traversing the object graph.
result = this.processObject(prop, path);
if (result.fnFound) {
// Function found, stop traversing the object graph.
return result;
}
} catch (error) {
// Access to some properties result in exceptions.
}
}
return result;
}
processObject(obj: any, path: Array): IProcessResult {
var result: IProcessResult = {
fnFound: false,
path: path
}
if (this.isProcessed(obj)) {
return result;
}
this._processed.push(obj);
for (var key in obj) {
var pathCopy = path.slice();
pathCopy.push(key);
var processResult = this.processProperty(obj, key, pathCopy);
if (processResult.fnFound) {
return processResult;
}
}
return processResult;
}
getFullClassNameFromInstance(instance: any, global: any): string {
this._fn = instance[“constructor”];
this._global = global;
this._processed = [];
var processResult = this.processObject(this._global, []);
var fullFnName = “”;
if (processResult.fnFound) {
fullFnName = processResult.path.join(“.”);
}
return fullFnName;
}
}
}
var myModel = new app.model.SampleBehaviorModel();
var resolver = new research.metadata.NameResolver();
alert( resolver.getFullClassNameFromInstance(myModel, window) );
the alert shows “resolver._fn”