Simplify main function behind legacy adapter
authorRaphael von der Grün <raphinesse@gmail.com>
Thu, 5 Jul 2018 10:48:38 +0000 (12:48 +0200)
committerRaphael von der Grün <raphinesse@gmail.com>
Thu, 5 Jul 2018 10:48:38 +0000 (12:48 +0200)
Including:
- Unwrap deeply nested options object
- Rename options object to `opts`
- Shallow copy `opts` to avoid mutating caller's object
- Make Q-wrapping explicit

Co-authored-by: Christopher J. Brody <chris.brody@gmail.com>
index.js

index 22cc582..9895879 100644 (file)
--- a/index.js
+++ b/index.js
@@ -22,7 +22,7 @@ const fs = require('fs-extra');
 var os = require('os');
 var path = require('path');
 
-var Promise = require('q');
+var Q = require('q');
 var isUrl = require('is-url');
 var isObject = require('isobject');
 var requireFresh = require('import-fresh');
@@ -58,31 +58,47 @@ function setupEvents (externalEventEmitter) {
     return events;
 }
 
+module.exports = cordovaCreateLegacyAdapter;
+
 /**
- * Usage:
- * @dir - directory where the project will be created. Required.
- * @optionalId - app id. Required (but be "undefined")
- * @optionalName - app name. Required (but can be "undefined").
- * @cfg - extra config to be saved in .cordova/config.json Required (but can be "{}").
- * @extEvents - An EventEmitter instance that will be used for logging purposes. Required (but can be "undefined").
- **/
-// Returns a promise.
-module.exports = function (dir, optionalId, optionalName, cfg, extEvents) {
-    return Promise.resolve().then(function () {
-        events = setupEvents(extEvents);
-        events.emit('verbose', 'Using detached cordova-create');
+* Legacy interface. See README for documentation
+*/
+function cordovaCreateLegacyAdapter (dir, id, name, cfg, extEvents) {
+    // Unwrap and shallow-clone that nasty nested config object
+    const opts = Object.assign({}, ((cfg || {}).lib || {}).www);
+
+    if (id) opts.id = id;
+    if (name) opts.name = name;
+    if (extEvents) opts.extEvents = extEvents;
+
+    return Q(cordovaCreate(dir, opts));
+}
 
+/**
+ * Creates a new cordova project in the given directory.
+ *
+ * @param {string} dest         directory where the project will be created.
+ * @param {Object} [opts={}]    options to be used for creating the project.
+ * @returns {Promise}           Resolves when project creation has finished.
+ */
+function cordovaCreate (dest, opts = {}) {
+    // TODO this is to avoid having a huge diff. Remove later.
+    let dir = dest;
+
+    return Promise.resolve().then(function () {
         if (!dir) {
             throw new CordovaError('Directory not specified. See `cordova help`.');
         }
 
-        cfg = cfg || {};
-        if (!isObject(cfg)) {
-            throw new CordovaError('If given, cfg must be an object');
+        if (!isObject(opts)) {
+            throw new CordovaError('Given options must be an object');
         }
 
-        if (optionalId) cfg.id = optionalId;
-        if (optionalName) cfg.name = optionalName;
+        // Shallow copy opts
+        opts = Object.assign({}, opts);
+
+        events = setupEvents(opts.extEvents);
+        events.emit('verbose', 'Using detached cordova-create');
 
         // Make absolute.
         dir = path.resolve(dir);
@@ -91,18 +107,16 @@ module.exports = function (dir, optionalId, optionalName, cfg, extEvents) {
             throw new CordovaError('Path already exists and is not empty: ' + dir);
         }
 
-        if (cfg.id && !validateIdentifier(cfg.id)) {
+        if (opts.id && !validateIdentifier(opts.id)) {
             throw new CordovaError('App id contains a reserved word, or is not a valid identifier.');
         }
 
         // This was changed from "uri" to "url", but checking uri for backwards compatibility.
-        cfg.lib = cfg.lib || {};
-        cfg.lib.www = cfg.lib.www || {};
-        cfg.lib.www.url = cfg.lib.www.url || cfg.lib.www.uri;
+        opts.url = opts.url || opts.uri;
 
-        if (!cfg.lib.www.url) {
-            cfg.lib.www.url = require.resolve('cordova-app-hello-world');
-            cfg.lib.www.template = true;
+        if (!opts.url) {
+            opts.url = require.resolve('cordova-app-hello-world');
+            opts.template = true;
         }
 
         // Make sure that the source www/ is not a direct ancestor of the
@@ -110,14 +124,14 @@ module.exports = function (dir, optionalId, optionalName, cfg, extEvents) {
         // we make sure that the shortest relative path from source-to-target
         // must start by going up at least one directory or with a drive
         // letter for Windows.
-        var rel_path = path.relative(cfg.lib.www.url, dir);
+        var rel_path = path.relative(opts.url, dir);
         var goes_up = rel_path.split(path.sep)[0] === '..';
 
         if (!(goes_up || rel_path[1] === ':')) {
             throw new CordovaError(
                 'Project dir "' + dir +
                 '" must not be created at/inside the template used to create the project "' +
-                cfg.lib.www.url + '".'
+                opts.url + '".'
             );
         }
     })
@@ -126,21 +140,21 @@ module.exports = function (dir, optionalId, optionalName, cfg, extEvents) {
             events.emit('log', 'Creating a new cordova project.');
 
             // If symlink, don't fetch
-            if (cfg.lib.www.link) {
-                return cfg.lib.www.url;
+            if (opts.link) {
+                return opts.url;
             }
 
-            var isGit = cfg.lib.www.template && isUrl(cfg.lib.www.url);
-            var isNPM = cfg.lib.www.template && (cfg.lib.www.url.indexOf('@') > -1 || !fs.existsSync(path.resolve(cfg.lib.www.url))) && !isGit;
+            var isGit = opts.template && isUrl(opts.url);
+            var isNPM = opts.template && (opts.url.indexOf('@') > -1 || !fs.existsSync(path.resolve(opts.url))) && !isGit;
             // Always use cordova fetch to obtain the npm or git template
             if (isGit || isNPM) {
                 // Saved to .Cordova folder (ToDo: Delete installed template after using)
                 var tempDest = global_config_path;
-                var target = cfg.lib.www.url;
+                var target = opts.url;
                 // add latest to npm module if no version is specified
                 // this prevents create using an older cached version of the template
                 if (isNPM && target.indexOf('@') === -1) {
-                    target = cfg.lib.www.url + '@latest';
+                    target = opts.url + '@latest';
                 }
                 events.emit('verbose', 'Using cordova-fetch for ' + target);
                 return fetch(target, tempDest, {})
@@ -153,7 +167,7 @@ module.exports = function (dir, optionalId, optionalName, cfg, extEvents) {
                     });
             // If assets are not online, resolve as a relative path on local computer
             } else {
-                return path.resolve(cfg.lib.www.url);
+                return path.resolve(opts.url);
             }
         })
         .then(function (input_directory) {
@@ -184,13 +198,13 @@ module.exports = function (dir, optionalId, optionalName, cfg, extEvents) {
 
             try {
                 // Copy files from template to project
-                if (cfg.lib.www.template) {
+                if (opts.template) {
                     events.emit('verbose', 'Copying assets.');
                     copyTemplateFiles(import_from_path, dir, isSubDir);
                 }
 
                 // If --link, link merges, hooks, www, and config.xml (and/or copy to root)
-                if (cfg.lib.www.link) {
+                if (opts.link) {
                     events.emit('verbose', 'Symlinking assets.');
                     linkFromTemplate(import_from_path, dir);
                 }
@@ -219,12 +233,12 @@ module.exports = function (dir, optionalId, optionalName, cfg, extEvents) {
                 var pkgjson = requireFresh(pkgjsonPath);
 
                 // Pkjson.displayName should equal config's name.
-                if (cfg.name) {
-                    pkgjson.displayName = cfg.name;
+                if (opts.name) {
+                    pkgjson.displayName = opts.name;
                 }
                 // Pkjson.name should equal config's id.
-                if (cfg.id) {
-                    pkgjson.name = cfg.id.toLowerCase();
+                if (opts.id) {
+                    pkgjson.name = opts.id.toLowerCase();
                 } else {
                     // Use default name.
                     pkgjson.name = 'helloworld';
@@ -243,13 +257,13 @@ module.exports = function (dir, optionalId, optionalName, cfg, extEvents) {
             if (!fs.lstatSync(configPath).isSymbolicLink()) {
                 // Write out id, name and default version to config.xml
                 var conf = new ConfigParser(configPath);
-                if (cfg.id) conf.setPackageName(cfg.id);
-                if (cfg.name) conf.setName(cfg.name);
+                if (opts.id) conf.setPackageName(opts.id);
+                if (opts.name) conf.setName(opts.name);
                 conf.setVersion(DEFAULT_VERSION);
                 conf.write();
             }
         });
-};
+}
 
 /**
  * Recursively copies folder to destination if folder is not found in destination (including symlinks).