From abc90f2e6acb5cb6ebefb62ccb07e3c74fa9cdab Mon Sep 17 00:00:00 2001
From: Ibrahim Hadeed <ihadeed@users.noreply.github.com>
Date: Sun, 4 Dec 2016 11:42:30 -0500
Subject: [PATCH] chore(): optimize CordovaProperty and InstanceProperty
 decorators (#635)

* chore(): optimize InstanceProperty wrapper

* chore(): optimize CordovaProperty wrapper

* tslint'

* fix decorators
---
 src/plugins/apprate.ts            |  2 +-
 src/plugins/contacts.ts           | 80 +++++++++++++++----------------
 src/plugins/device.ts             | 11 +++--
 src/plugins/media-capture.ts      | 12 ++---
 src/plugins/mixpanel.ts           |  2 +
 src/plugins/network.ts            |  2 +-
 src/plugins/plugin.ts             | 50 +++++++++++--------
 src/plugins/screen-orientation.ts |  6 +--
 src/plugins/statusbar.ts          |  2 +-
 src/plugins/webintent.ts          |  8 +---
 10 files changed, 87 insertions(+), 88 deletions(-)

diff --git a/src/plugins/apprate.ts b/src/plugins/apprate.ts
index da0b5622..b3dfa2b6 100644
--- a/src/plugins/apprate.ts
+++ b/src/plugins/apprate.ts
@@ -57,7 +57,7 @@ export class AppRate {
    * See table below for options
    */
   @CordovaProperty
-  static get preferences() { return window.AppRate.preferences; }
+  static preferences;
 
   /**
    * Prompts the user for rating
diff --git a/src/plugins/contacts.ts b/src/plugins/contacts.ts
index c0c28d73..cc71c3d4 100644
--- a/src/plugins/contacts.ts
+++ b/src/plugins/contacts.ts
@@ -42,20 +42,20 @@ export interface IContactProperties {
  */
 export class Contact implements IContactProperties {
   private _objectInstance: any;
-  @InstanceProperty get id(): string { return; }
-  @InstanceProperty get displayName(): string { return; }
-  @InstanceProperty get name(): IContactName {return; }
-  @InstanceProperty get nickname(): string { return; }
-  @InstanceProperty get phoneNumbers(): IContactField[] { return; }
-  @InstanceProperty get emails(): IContactField[] { return; }
-  @InstanceProperty get addresses(): IContactAddress[] { return; }
-  @InstanceProperty get ims(): IContactField[] { return; }
-  @InstanceProperty get organizations(): IContactOrganization[] { return; }
-  @InstanceProperty get birthday(): Date { return; }
-  @InstanceProperty get note(): string { return; }
-  @InstanceProperty get photos(): IContactField[] { return; }
-  @InstanceProperty get categories(): IContactField[] { return; }
-  @InstanceProperty get urls(): IContactField[] { return; }
+  @InstanceProperty id: string;
+  @InstanceProperty displayName: string;
+  @InstanceProperty name: IContactName;
+  @InstanceProperty nickname: string;
+  @InstanceProperty phoneNumbers: IContactField[];
+  @InstanceProperty emails: IContactField[];
+  @InstanceProperty addresses: IContactAddress[];
+  @InstanceProperty ims: IContactField[];
+  @InstanceProperty organizations: IContactOrganization[];
+  @InstanceProperty birthday: Date;
+  @InstanceProperty note: string;
+  @InstanceProperty photos: IContactField[];
+  @InstanceProperty categories: IContactField[];
+  @InstanceProperty urls: IContactField[];
 
   constructor() {
     this._objectInstance = navigator.contacts.create();
@@ -126,12 +126,12 @@ export class ContactName implements IContactName {
     this._objectInstance = new window.ContactName(formatted, familyName, givenName, middleName, honorificPrefix, honorificSuffix);
   }
 
-  @InstanceProperty get formatted(): string { return; }
-  @InstanceProperty get familyName(): string { return; }
-  @InstanceProperty get givenName(): string { return; }
-  @InstanceProperty get middleName(): string { return; }
-  @InstanceProperty get honorificPrefix(): string { return; }
-  @InstanceProperty get honorificSuffix(): string { return; }
+  @InstanceProperty formatted: string;
+  @InstanceProperty familyName: string;
+  @InstanceProperty givenName: string;
+  @InstanceProperty middleName: string;
+  @InstanceProperty honorificPrefix: string;
+  @InstanceProperty honorificSuffix: string;
 }
 
 export interface IContactField {
@@ -153,9 +153,9 @@ export class ContactField implements IContactField {
     this._objectInstance = new window.ContactField(type, value, pref);
   }
 
-  @InstanceProperty get type(): string { return; }
-  @InstanceProperty get value(): string { return; }
-  @InstanceProperty get pref(): boolean { return; }
+  @InstanceProperty type: string;
+  @InstanceProperty value: string;
+  @InstanceProperty pref: boolean;
 }
 
 export interface IContactAddress {
@@ -195,21 +195,21 @@ export class ContactAddress implements IContactAddress {
   }
 
   /** Set to true if this ContactAddress contains the user's preferred value. */
-  @InstanceProperty get pref(): boolean { return; }
+  @InstanceProperty pref: boolean;
   /** A string indicating what type of field this is, home for example. */
-  @InstanceProperty get type(): string { return; }
+  @InstanceProperty type: string;
   /** The full address formatted for display. */
-  @InstanceProperty get formatted(): string { return; }
+  @InstanceProperty formatted: string;
   /** The full street address. */
-  @InstanceProperty get streetAddress(): string { return; }
+  @InstanceProperty streetAddress: string;
   /** The city or locality. */
-  @InstanceProperty get locality(): string { return; }
+  @InstanceProperty locality: string;
   /** The state or region. */
-  @InstanceProperty get region(): string { return; }
+  @InstanceProperty region: string;
   /** The zip code or postal code. */
-  @InstanceProperty get postalCode(): string { return; }
+  @InstanceProperty postalCode: string;
   /** The country name. */
-  @InstanceProperty get country(): string { return; }
+  @InstanceProperty country: string;
 }
 
 export interface IContactOrganization {
@@ -234,15 +234,15 @@ export class ContactOrganization implements IContactOrganization {
     this._objectInstance = new window.ContactOrganization();
   }
   /** Set to true if this ContactOrganization contains the user's preferred value. */
-  @InstanceProperty get pref(): boolean { return; }
+  @InstanceProperty pref: boolean;
   /** A string that indicates what type of field this is, home for example. */
-  @InstanceProperty get type(): string { return; }
+  @InstanceProperty type: string;
   /** The name of the organization. */
-  @InstanceProperty get name(): string { return; }
+  @InstanceProperty name: string;
   /** The department the contract works for. */
-  @InstanceProperty get department(): string { return; }
+  @InstanceProperty department: string;
   /** The contact's title at the organization. */
-  @InstanceProperty get title(): string { return; }
+  @InstanceProperty title: string;
 }
 
 /** Search options to filter navigator.contacts.  */
@@ -272,22 +272,22 @@ export class ContactFindOptions implements IContactFindOptions {
   /**
    * The search string used to find navigator.contacts. (Default: "")
    */
-  @InstanceProperty get filter(): string { return; }
+  @InstanceProperty filter: string;
 
   /**
    * Determines if the find operation returns multiple navigator.contacts. (Default: false)
    */
-  @InstanceProperty get multiple(): boolean { return; }
+  @InstanceProperty multiple: boolean;
 
   /**
    * Contact fields to be returned back. If specified, the resulting Contact object only features values for these fields.
    */
-  @InstanceProperty get desiredFields(): any { return; }
+  @InstanceProperty desiredFields: any;
 
   /**
    * (Android only): Filters the search to only return contacts with a phone number informed.
    */
-  @InstanceProperty get hasPhoneNumber(): boolean { return; }
+  @InstanceProperty hasPhoneNumber: boolean;
 }
 
 /**
diff --git a/src/plugins/device.ts b/src/plugins/device.ts
index d3b90817..a97149d0 100644
--- a/src/plugins/device.ts
+++ b/src/plugins/device.ts
@@ -1,11 +1,12 @@
 import { CordovaProperty, Plugin } from './plugin';
 
 
-declare var window: {
-  device: Device
-};
+declare var window: any;
 
-export interface Device {
+/**
+ * @private
+ */
+export interface IDevice {
   /** Get the version of Cordova running on the device. */
   cordova: string;
   /**
@@ -54,6 +55,6 @@ export class Device {
    * @returns {Device} The device object.
    */
   @CordovaProperty
-  static get device(): Device { return window.device; }
+  static device: IDevice;
 
 }
diff --git a/src/plugins/media-capture.ts b/src/plugins/media-capture.ts
index b7dcafc4..2adc95c8 100644
--- a/src/plugins/media-capture.ts
+++ b/src/plugins/media-capture.ts
@@ -33,27 +33,21 @@ export class MediaCapture {
    * @returns {ConfigurationData[]}
    */
   @CordovaProperty
-  static get supportedImageModes(): ConfigurationData[] {
-    return <ConfigurationData[]>navigator.device.capture.supportedImageModes;
-  }
+  static supportedImageModes: ConfigurationData[];
 
   /**
    * The audio recording formats supported by the device.
    * @returns {ConfigurationData[]}
    */
   @CordovaProperty
-  static get supportedAudioModes(): ConfigurationData[] {
-    return <ConfigurationData[]>navigator.device.capture.supportedAudioModes;
-  }
+  static supportedAudioModes: ConfigurationData[];
 
   /**
    * The recording video resolutions and formats supported by the device.
    * @returns {ConfigurationData[]}
    */
   @CordovaProperty
-  static get supportedVideoModes(): ConfigurationData[] {
-    return <ConfigurationData[]>navigator.device.capture.supportedVideoModes;
-  }
+  static supportedVideoModes: ConfigurationData[];
 
   /**
    * Start the audio recorder application and return information about captured audio clip files.
diff --git a/src/plugins/mixpanel.ts b/src/plugins/mixpanel.ts
index 44e623a4..b5a9fd72 100644
--- a/src/plugins/mixpanel.ts
+++ b/src/plugins/mixpanel.ts
@@ -16,6 +16,8 @@ declare var mixpanel: any;
  *   .catch(onError);
  *
  * ```
+ * @classes
+ * MixpanelPeople
  */
 @Plugin({
   pluginName: 'Mixpanel',
diff --git a/src/plugins/network.ts b/src/plugins/network.ts
index cf0ad673..5493dde7 100644
--- a/src/plugins/network.ts
+++ b/src/plugins/network.ts
@@ -55,7 +55,7 @@ export class Network {
    * Return the network connection type
    */
   @CordovaProperty
-  static get connection(): string { return navigator.connection.type; }
+  static connection: string;
 
   /**
    * Get notified when the device goes offline
diff --git a/src/plugins/plugin.ts b/src/plugins/plugin.ts
index 090afe71..23e90bf5 100644
--- a/src/plugins/plugin.ts
+++ b/src/plugins/plugin.ts
@@ -404,43 +404,51 @@ export function CordovaInstance(opts: any = {}) {
  *
  * Before calling the original method, ensure Cordova and the plugin are installed.
  */
-export function CordovaProperty(target: Function, key: string, descriptor: TypedPropertyDescriptor<any>) {
-  let originalMethod = descriptor.get;
-
-  descriptor.get = function(...args: any[]) {
+export function CordovaProperty(target: Function, key: string) {
+  let exists: Function = function(): boolean {
     if (!window.cordova) {
       cordovaWarn(this.name, null);
-      return {};
+      return false;
     }
-    let pluginObj: any = this;
-    let pluginInstance = getPlugin(pluginObj.pluginRef);
+    let pluginInstance = getPlugin(this.pluginRef);
     if (!pluginInstance) {
       pluginWarn(this, key);
-      return {};
+      return false;
     }
-    return originalMethod.apply(this, args);
+    return true;
   };
 
-  return descriptor;
+  Object.defineProperty(target, key, {
+    get: function() {
+      if (exists) {
+        return this.pluginRef[key];
+      } else {
+        return {};
+      }
+    },
+    set: function(value) {
+      if (exists) {
+        this.pluginRef[key] = value;
+      }
+    }
+  });
 }
 
 /**
  * @private
  * @param target
  * @param key
- * @param descriptor
  * @constructor
  */
-export function InstanceProperty(target: any, key: string, descriptor: TypedPropertyDescriptor<any>) {
-  descriptor.get = function() {
-    return this._objectInstance[key];
-  };
-
-  descriptor.set = function(...args: any[]) {
-    this._objectInstance[key] = args[0];
-  };
-
-  return descriptor;
+export function InstanceProperty(target: any, key: string) {
+  Object.defineProperty(target, key, {
+    get: function(){
+      return this._objectInstance[key];
+    },
+    set: function(value){
+      this._objectInstance[key] = value;
+    }
+  });
 }
 
 /**
diff --git a/src/plugins/screen-orientation.ts b/src/plugins/screen-orientation.ts
index 80aa46ce..15e0b42c 100644
--- a/src/plugins/screen-orientation.ts
+++ b/src/plugins/screen-orientation.ts
@@ -59,11 +59,9 @@ export class ScreenOrientation {
   @Cordova({ sync: true })
   static unlockOrientation(): void { }
 
-  /*
+  /**
    * Get the current orientation of the device.
    */
   @CordovaProperty
-  static get orientation() {
-    return window.screen.orientation;
-  }
+  static orientation: string;
 }
diff --git a/src/plugins/statusbar.ts b/src/plugins/statusbar.ts
index 16f81be1..42c37abb 100644
--- a/src/plugins/statusbar.ts
+++ b/src/plugins/statusbar.ts
@@ -117,6 +117,6 @@ export class StatusBar {
    * Whether the StatusBar is currently visible or not.
    */
   @CordovaProperty
-  static get isVisible() { return window.StatusBar.isVisible; }
+  static isVisible: boolean;
 
 }
diff --git a/src/plugins/webintent.ts b/src/plugins/webintent.ts
index 3d1cc7d4..3ffd4fe9 100644
--- a/src/plugins/webintent.ts
+++ b/src/plugins/webintent.ts
@@ -26,14 +26,10 @@ declare var window;
 export class WebIntent {
 
   @CordovaProperty
-  static get ACTION_VIEW() {
-    return window.plugins.webintent.ACTION_VIEW;
-  }
+  static ACTION_VIEW;
 
   @CordovaProperty
-  static get EXTRA_TEXT() {
-    return window.plugins.webintent.EXTRA_TEXT;
-  }
+  static EXTRA_TEXT;
 
   /**
    * @param options {Object} { action: any, url: string, type?: string }