refactor(misc): cleanup & simplify (#131)

* refactor: PlatformJson

* refactor: CordovaCheck

* refactor(plist-helpers): rename underscore variable

* refactor(plist-helpers): rename pruneOBJECT function

* refactor(plist-helpers): formatting

* refactor(CordovaCheck): simplify isCordova w/ pwd

* refactor(plist-helpers): simplify array merge

* refactor(plist-helpers): simplify dict merge

* refactor(PlatformJson): use readJsonSync

Co-authored-by: エリス <erisu@users.noreply.github.com>
diff --git a/src/CordovaCheck.js b/src/CordovaCheck.js
index d434f33..bec4916 100644
--- a/src/CordovaCheck.js
+++ b/src/CordovaCheck.js
@@ -24,17 +24,14 @@
     if (fs.existsSync(path.join(dir, 'www'))) {
         if (fs.existsSync(path.join(dir, 'config.xml'))) {
             // For sure is.
-            if (fs.existsSync(path.join(dir, 'platforms'))) {
-                return 2;
-            } else {
-                return 1;
-            }
+            return fs.existsSync(path.join(dir, 'platforms')) ? 2 : 1;
         }
         // Might be (or may be under platforms/).
         if (fs.existsSync(path.join(dir, 'www', 'config.xml'))) {
             return 1;
         }
     }
+
     return 0;
 }
 
@@ -46,27 +43,33 @@
         // Prefer PWD over cwd so that symlinked dirs within your PWD work correctly (CB-5687).
         const pwd = process.env.PWD;
         const cwd = process.cwd();
-        if (pwd && pwd !== cwd && pwd !== 'undefined') {
-            return isCordova(pwd) || isCordova(cwd);
-        }
-        return isCordova(cwd);
+        const hasPwd = pwd && pwd !== cwd && pwd !== 'undefined';
+
+        return (hasPwd && isCordova(pwd)) || isCordova(cwd);
     }
+
     let bestReturnValueSoFar = false;
+
     for (let i = 0; i < 1000; ++i) {
         const result = isRootDir(dir);
+
         if (result === 2) {
             return dir;
         }
+
         if (result === 1) {
             bestReturnValueSoFar = dir;
         }
+
         const parentDir = path.normalize(path.join(dir, '..'));
         // Detect fs root.
         if (parentDir === dir) {
             return bestReturnValueSoFar;
         }
+
         dir = parentDir;
     }
+
     console.error('Hit an unhandled case in CordovaCheck.isCordova');
     return false;
 }
diff --git a/src/PlatformJson.js b/src/PlatformJson.js
index 5e82809..0cceae1 100644
--- a/src/PlatformJson.js
+++ b/src/PlatformJson.js
@@ -28,10 +28,10 @@
 
     static load (plugins_dir, platform) {
         const filePath = path.join(plugins_dir, `${platform}.json`);
-        let root = null;
-        if (fs.existsSync(filePath)) {
-            root = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
-        }
+        const root = fs.existsSync(filePath)
+            ? fs.readJsonSync(filePath)
+            : null;
+
         return new PlatformJson(filePath, platform, root);
     }
 
@@ -91,16 +91,13 @@
      */
     addPluginMetadata (pluginInfo) {
         const installedModules = this.root.modules || [];
-
         const installedPaths = installedModules.map(m => m.file);
-
         const modulesToInstall = pluginInfo.getJsModules(this.platform)
             .map(module => new ModuleMetadata(pluginInfo.id, module))
             // Filter out modules which are already added to metadata
             .filter(metadata => !installedPaths.includes(metadata.file));
 
         this.root.modules = installedModules.concat(modulesToInstall);
-
         this.root.plugin_metadata = this.root.plugin_metadata || {};
         this.root.plugin_metadata[pluginInfo.id] = pluginInfo.version;
 
@@ -127,12 +124,12 @@
      * @returns {this} Current PlatformJson instance to allow calls chaining
      */
     removePluginMetadata (pluginInfo) {
+        const installedModules = this.root.modules || [];
         const modulesToRemove = pluginInfo.getJsModules(this.platform)
             .map(jsModule => ['plugins', pluginInfo.id, jsModule.src].join('/'));
 
-        const installedModules = this.root.modules || [];
+        // Leave only those metadatas which 'file' is not in removed modules
         this.root.modules = installedModules
-            // Leave only those metadatas which 'file' is not in removed modules
             .filter(m => !modulesToRemove.includes(m.file));
 
         if (this.root.plugin_metadata) {
@@ -159,10 +156,12 @@
      */
     makeTopLevel (pluginId) {
         const plugin = this.root.dependent_plugins[pluginId];
+
         if (plugin) {
             delete this.root.dependent_plugins[pluginId];
             this.root.installed_plugins[pluginId] = plugin;
         }
+
         return this;
     }
 
@@ -206,6 +205,7 @@
     const munge = root.config_munge;
     if (!munge.files) {
         const new_munge = { files: {} };
+
         for (const file in munge) {
             for (const selector in munge[file]) {
                 for (const xml_child in munge[file][selector]) {
@@ -216,17 +216,18 @@
                 }
             }
         }
+
         root.config_munge = new_munge;
     }
 
     return root;
 }
 
-/**
- * Run-time representation of a module entry in 'cordova_plugins.js'
- */
 class ModuleMetadata {
     /**
+     * Creates a ModuleMetadata object that represents module entry in 'cordova_plugins.js'
+     * file at run time
+     *
      * @param {String}  pluginId  Plugin id where this module installed from
      * @param (JsModule|Object)  jsModule  A js-module entry from PluginInfo class to generate metadata for
      */
@@ -241,9 +242,11 @@
         if (jsModule.clobbers && jsModule.clobbers.length > 0) {
             this.clobbers = jsModule.clobbers.map(o => o.target);
         }
+
         if (jsModule.merges && jsModule.merges.length > 0) {
             this.merges = jsModule.merges.map(o => o.target);
         }
+
         if (jsModule.runs) {
             this.runs = true;
         }
diff --git a/src/util/plist-helpers.js b/src/util/plist-helpers.js
index 7d08459..901d39e 100644
--- a/src/util/plist-helpers.js
+++ b/src/util/plist-helpers.js
@@ -18,29 +18,24 @@
 */
 
 // contains PLIST utility functions
-const __ = require('underscore');
+const _ = require('underscore');
 const plist = require('plist');
 
 // adds node to doc at selector
 module.exports.graftPLIST = graftPLIST;
 function graftPLIST (doc, xml, selector) {
     const obj = plist.parse(`<plist>${xml}</plist>`);
+    const node = doc[selector];
 
-    let node = doc[selector];
     if (node && Array.isArray(node) && Array.isArray(obj)) {
-        node = node.concat(obj);
-        for (let i = 0; i < node.length; i++) {
-            for (let j = i + 1; j < node.length; ++j) {
-                if (nodeEqual(node[i], node[j])) { node.splice(j--, 1); }
-            }
-        }
-        doc[selector] = node;
+        const isNew = item => !node.some(nodeChild => nodeEqual(item, nodeChild));
+        doc[selector] = node.concat(obj.filter(isNew));
     } else {
         // plist uses objects for <dict>. If we have two dicts we merge them instead of
         // overriding the old one. See CB-6472
-        if (node && __.isObject(node) && __.isObject(obj) && !__.isDate(node) && !__.isDate(obj)) { // arrays checked above
-            __.extend(obj, node);
-        }
+        const isDict = o => _.isObject(o) && !_.isDate(o); // arrays checked above
+        if (isDict(node) && isDict(obj)) _.extend(obj, node);
+
         doc[selector] = obj;
     }
 
@@ -52,19 +47,21 @@
 function prunePLIST (doc, xml, selector) {
     const obj = plist.parse(`<plist>${xml}</plist>`);
 
-    pruneOBJECT(doc, selector, obj);
+    pruneObject(doc, selector, obj);
 
     return true;
 }
 
-function pruneOBJECT (doc, selector, fragment) {
+function pruneObject (doc, selector, fragment) {
     if (Array.isArray(fragment) && Array.isArray(doc[selector])) {
         let empty = true;
+
         for (const i in fragment) {
             for (const j in doc[selector]) {
-                empty = pruneOBJECT(doc[selector], j, fragment[i]) && empty;
+                empty = pruneObject(doc[selector], j, fragment[i]) && empty;
             }
         }
+
         if (empty) {
             delete doc[selector];
             return true;
@@ -78,13 +75,16 @@
 }
 
 function nodeEqual (node1, node2) {
-    if (typeof node1 !== typeof node2) { return false; } else if (typeof node1 === 'string') {
+    if (typeof node1 !== typeof node2) {
+        return false;
+    } else if (typeof node1 === 'string') {
         node2 = escapeRE(node2).replace(/\\\$\(\S+\)/gm, '(.*?)');
         return new RegExp(`^${node2}$`).test(node1);
     } else {
         for (const key in node2) {
             if (!nodeEqual(node1[key], node2[key])) return false;
         }
+
         return true;
     }
 }