forceios 9.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # Salesforce Mobile SDK for iOS Package
2
+
3
+ The **forceios** npm package allows users to create iOS mobile applications to interface with the [Salesforce Platform](http://www.salesforce.com/platform/overview/), leveraging [Salesforce Mobile SDK for iOS](https://github.com/forcedotcom/SalesforceMobileSDK-iOS).
4
+
5
+ ## Getting Started
6
+
7
+ If you're new to mobile development or the force.com platform, you may want to start at the [Mobile SDK landing page](http://wiki.developerforce.com/page/Mobile_SDK). This page offers a variety of resources to help you determine the best technology path for creating your app, as well as many guides and blog posts detailing how to work with the Mobile SDK.
8
+
9
+ But assuming you're all read up, here's how to get started with the **forceios** package to create the starting point for your mobile application.
10
+
11
+ ## Install the forceios Package
12
+
13
+ Because forceios is a command-line utility, we recommend installing it globally, so that it's easily accessible on your path:
14
+
15
+ sudo npm install forceios -g
16
+
17
+ You're of course welcome to install it locally as well:
18
+
19
+ npm install forceios
20
+
21
+ In local installations, you can access the forceios app at `[Install Directory]/node_modules/.bin/forceios`.
22
+
23
+ ## Using forceios
24
+
25
+ For the rest of this document, we'll assume that `forceios` is on your path.
26
+
27
+ Typing `forceios` with no arguments gives you a breakdown of the usage:
28
+
29
+ ```
30
+ -> forceios
31
+ forceios: Tool for building an iOS native mobile application using Salesforce Mobile SDK
32
+
33
+ Usage:
34
+
35
+ # create an iOS native mobile application
36
+ forceios create
37
+ [--apptype=application type (native_swift or native, leave empty for native_swift)]
38
+ --appname=application name
39
+ --packagename=app package identifier (e.g. com.mycompany.myapp)
40
+ --organization=organization name (your company's/organization's name)
41
+ [--outputdir=output directory (leave empty for current directory)]
42
+
43
+ OR
44
+
45
+ # create an iOS native mobile application from a template
46
+ forceios createwithtemplate
47
+ --templaterepouri=template repo URI or Mobile SDK template name
48
+ --appname=application name
49
+ --packagename=app package identifier (e.g. com.mycompany.myapp)
50
+ --organization=organization name (your company's/organization's name)
51
+ [--outputdir=output directory (leave empty for current directory)]
52
+
53
+ OR
54
+
55
+ # list available Mobile SDK templates
56
+ forceios listtemplates
57
+
58
+ OR
59
+
60
+ # validate store or syncs configuration
61
+ forceios checkconfig
62
+ --configpath=path to store or syncs config to validate
63
+ --configtype=type of config to validate (store or syncs)
64
+
65
+ OR
66
+
67
+ # show version of Mobile SDK
68
+ forceios version
69
+
70
+ OR
71
+
72
+ forceios
73
+ ```
74
+
75
+ **Note:** You can specify any or all of the arguments as command line options as specified in the usage. If you run `forceios create` with missing arguments, it prompts you for each missing option interactively.
76
+
77
+ Once the creation script completes, you'll have a fully functioning basic application of the type you specified. The new application has an Xcode workspace that you can peruse, run, and debug.
78
+
79
+ ### forceios create options
80
+
81
+ **App Type:** \( *Optional* \) The type of application you wish to develop:
82
+
83
+ - **native\_swift** (default) — A fully native iOS application written in Swift
84
+ - **native** — A fully native iOS application written in Objective C
85
+
86
+ **App Name:** The name of your application
87
+
88
+ **App Package Identifier:** An identifier for your company, similar to a Java package (e.g. `com.acme.MobileApps`). This concatenates with the app name to form the unique identifier for your app in the App Store.
89
+
90
+ **Organization:** The name of your company or organization. For example, `Acme Widgets, Inc.`
91
+
92
+ **Output Directory:** \( *Optional* \) The folder where you want your app to be created.
93
+
94
+ ## More information
95
+
96
+ - After your app has been created, you will see some on-screen instructions for next steps, such as building and running your app, importing the project into XCode, and changing the default Connected App (sample) configuration values to match your own Connected App.
97
+
98
+ - You can find the `forcedroid` npm package [here](https://npmjs.org/package/forcedroid) to develop Mobile SDK apps for Android.
99
+
100
+ - You can find the `forcehybrid` npm package [here](https://npmjs.org/package/forcehybrid) to develop Mobile SDK hybrid apps for iOS and Android.
101
+
102
+ - You can find the `forcereact` npm package [here](https://npmjs.org/package/forcereact) to develop Mobile SDK react native apps for iOS and Android.
103
+
104
+ - The Salesforce Mobile SDK for iOS source repository lives [here](https://github.com/forcedotcom/SalesforceMobileSDK-iOS).
105
+
106
+ - The Salesforce Mobile SDK for Android source repository lives [here](https://github.com/forcedotcom/SalesforceMobileSDK-Android).
107
+
108
+ - See [our developerforce site](http://wiki.developerforce.com/page/Mobile_SDK) for more information about how you can leverage Salesforce Mobile SDK with the force.com platform.
109
+
110
+ - If you would like to make suggestions, have questions, or encounter any issues, we'd love to hear from you. Post any feedback you have on [Salesforce StackExchange](https://salesforce.stackexchange.com/questions/tagged/mobilesdk).
package/forceios.js ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+
3
+ /*
4
+ * Copyright (c) 2016-present, salesforce.com, inc.
5
+ * All rights reserved.
6
+ * Redistribution and use of this software in source and binary forms, with or
7
+ * without modification, are permitted provided that the following conditions
8
+ * are met:
9
+ * - Redistributions of source code must retain the above copyright notice, this
10
+ * list of conditions and the following disclaimer.
11
+ * - Redistributions in binary form must reproduce the above copyright notice,
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ * - Neither the name of salesforce.com, inc. nor the names of its contributors
15
+ * may be used to endorse or promote products derived from this software without
16
+ * specific prior written permission of salesforce.com, inc.
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ * POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+ // Dependencies
31
+ var SDK = require('./shared/constants'),
32
+ createHelper = require('./shared/createHelper');
33
+
34
+
35
+ // Do everything
36
+ createHelper.createApp(SDK.forceclis.forceios);
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "forceios",
3
+ "version": "9.2.0",
4
+ "description": "Utilities for creating mobile apps based on the Salesforce Mobile SDK for iOS",
5
+ "keywords": [ "mobilesdk", "ios", "salesforce", "mobile", "sdk" ],
6
+ "homepage": "https://github.com/forcedotcom/SalesforceMobileSDK-iOS",
7
+ "bugs": "https://github.com/forcedotcom/SalesforceMobileSDK-iOS/issues",
8
+ "licenses" : [
9
+ { "type": "Salesforce.com Mobile SDK License", "url": "https://github.com/forcedotcom/SalesforceMobileSDK-iOS/blob/master/LICENSE.md" }
10
+ ],
11
+ "os" : [ "darwin" ],
12
+ "engines": {
13
+ "node": ">=7.0.0"
14
+ },
15
+ "bin" : { "forceios" : "forceios.js" },
16
+ "dependencies": {
17
+ "shelljs": "0.8.4",
18
+ "ajv": "^6.10.2",
19
+ "jsonlint": "^1.6.3"
20
+ },
21
+ "repository": {
22
+ "type" : "git",
23
+ "url" : "https://github.com/forcedotcom/SalesforceMobileSDK-Package.git"
24
+ },
25
+ "author": { "name": "Kevin Hawkins", "email": "khawkins@salesforce.com" },
26
+ "contributors": [
27
+ { "name": "Wolfgang Mathurin", "email": "wmathurin@salesforce.com" },
28
+ { "name": "Bharath Hariharan", "email": "bhariharan@salesforce.com" }
29
+ ]
30
+ }
@@ -0,0 +1,245 @@
1
+ /*
2
+ * Copyright (c) 2013-present, salesforce.com, inc.
3
+ * All rights reserved.
4
+ * Redistribution and use of this software in source and binary forms, with or
5
+ * without modification, are permitted provided that the following conditions
6
+ * are met:
7
+ * - Redistributions of source code must retain the above copyright notice, this
8
+ * list of conditions and the following disclaimer.
9
+ * - Redistributions in binary form must reproduce the above copyright notice,
10
+ * this list of conditions and the following disclaimer in the documentation
11
+ * and/or other materials provided with the distribution.
12
+ * - Neither the name of salesforce.com, inc. nor the names of its contributors
13
+ * may be used to endorse or promote products derived from this software without
14
+ * specific prior written permission of salesforce.com, inc.
15
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25
+ * POSSIBILITY OF SUCH DAMAGE.
26
+ */
27
+
28
+ // Helper module for parsing the command line arguments to our package front-end.
29
+
30
+ var readline = require('readline');
31
+ var outputColors = require('./outputColors');
32
+
33
+ /**
34
+ * Parses an array of command line arguments, each of the form '--argName=argValue', or
35
+ * optionally, '--argName'. Treats '--argName=' as '--argName'.
36
+ *
37
+ * @param {Array} argsArray The array of String arguments of the specified format.
38
+ * @return A map in the form of { 'argName': 'argValue' [, ...] }
39
+ */
40
+ var parseArgs = function(argsArray) {
41
+ var argMap = {};
42
+ for (var i = 0; i < argsArray.length; i++) {
43
+ var fullArg = argsArray[i];
44
+ var argSplitRegExp = /^--([^=]+)(=(.*))?$/;
45
+ if (!argSplitRegExp.test(fullArg)) {
46
+ throw new Error('Illegal argument: ' + fullArg);
47
+ }
48
+ var argName = fullArg.replace(argSplitRegExp, "$1");
49
+ argName = argName.toLocaleLowerCase();
50
+ var argVal = fullArg.replace(argSplitRegExp, "$3");
51
+ argMap[argName] = argVal;
52
+ }
53
+
54
+ return argMap;
55
+ };
56
+
57
+ /**
58
+ * A method to process command line arguments interactively. Any arguments that were not specified
59
+ * on the command line will be prompted for on stdin, for the user to configure.
60
+ *
61
+ * @param {Array} argsArray The array of command line arguments (if any), of the form --argName=argValue, or --argName.
62
+ * @param {ArgProcessorList} argProcessorList A list of arguments and their various processing characteristics.
63
+ * @param {Function} callback The callback method to invoke once all arguments have been processed.
64
+ */
65
+ var processArgsInteractive = function(argsArray, argProcessorList, callback) {
66
+ // Get any initial arguments from the command line.
67
+ var argsMap = parseArgs(argsArray);
68
+
69
+ processArgsInteractiveHelper(argsMap, argProcessorList, callback, 0);
70
+ };
71
+
72
+ /**
73
+ * (Recursive) helper function for processArgsInteractive.
74
+ * @param argsMap A map of arguments in the form of { 'argName': 'argValue' [, ...] }.
75
+ * @param {ArgProcessorList} argProcessorList A list of arguments and their various processing characteristics.
76
+ * @param {Function} callback The callback method to invoke once all arguments have been processed.
77
+ * @param {Number} currentIndex The index of the current argument being processed.
78
+ */
79
+ var processArgsInteractiveHelper = function(argsMap, argProcessorList, callback, currentIndex) {
80
+ if (currentIndex === argProcessorList.processorList.length)
81
+ return callback(argsMap);
82
+
83
+ var argProcessor = argProcessorList.processorList[currentIndex];
84
+ var initialArgValue = argsMap[argProcessor.argName];
85
+
86
+ // Arg preprocessors determine whether an arg should even be presented as an option.
87
+ if (typeof argProcessor.preprocessorFunction === 'undefined') {
88
+ // By default, process each argument.
89
+ processArgument(initialArgValue, argsMap, argProcessor, function(resultArgValue) {
90
+ argsMap[argProcessor.argName] = resultArgValue;
91
+ processArgsInteractiveHelper(argsMap, argProcessorList, callback, currentIndex + 1);
92
+ });
93
+ } else {
94
+ var shouldProcessArgument = argProcessor.preprocessorFunction(argsMap);
95
+ if (shouldProcessArgument) {
96
+ processArgument(initialArgValue, argsMap, argProcessor, function(resultArgValue) {
97
+ argsMap[argProcessor.argName] = resultArgValue;
98
+ processArgsInteractiveHelper(argsMap, argProcessorList, callback, currentIndex + 1);
99
+ });
100
+ } else {
101
+ // If the user specified a value already, warn them that it won't be used.
102
+ if (typeof initialArgValue !== 'undefined') {
103
+ console.log(outputColors.yellow + 'WARNING: ' + outputColors.reset
104
+ + '\'' + argProcessor.argName + '\' is not a valid argument in this scenario, and its value will be ignored.');
105
+ argsMap[argProcessor.argName] = undefined;
106
+ }
107
+ processArgsInteractiveHelper(argsMap, argProcessorList, callback, currentIndex + 1);
108
+ }
109
+ }
110
+ };
111
+
112
+ /**
113
+ * Evaluates an argument value against its argument processor
114
+ * @param {String} argValue The specified value of the argument.
115
+ * @param argsMap A map of arguments in the form of { 'argName': 'argValue' [, ...] }.
116
+ * @param {ArgProcessor} argProcessor The argument processor, used to evaluate the arg value.
117
+ * @param {Function} postProcessingCallback The callback to invoke once a valid arg value has been determined.
118
+ */
119
+ var processArgument = function(argValue, argsMap, argProcessor, postProcessingCallback) {
120
+ // NB: If argValue is undefined (i.e. no initial command line input), even for optional arguments the user must
121
+ // be prompted at least once.
122
+ var processingResult = null;
123
+ if (typeof argValue !== 'undefined') {
124
+ processingResult = argProcessor.processorFunction(argValue, argsMap);
125
+ if (!(processingResult instanceof ArgProcessorOutput)) {
126
+ throw new Error ('Expecting processing result of type ArgProcessorOutput. Got \'' + (typeof processingResult) + '\'.');
127
+ }
128
+ if (processingResult.isValid) {
129
+ if (typeof processingResult.replacementValue !== 'undefined') {
130
+ return postProcessingCallback(processingResult.replacementValue);
131
+ } else {
132
+ return postProcessingCallback(argValue);
133
+ }
134
+ }
135
+ }
136
+
137
+ // Otherwise, arg value was either not present, or not valid. If the user actually entered an invalid value, show the error prompt.
138
+ if (processingResult && !processingResult.isValid) {
139
+ if (typeof processingResult.message !== 'undefined') {
140
+ console.log(outputColors.red + processingResult.message + outputColors.reset);
141
+ } else {
142
+ console.log(outputColors.red + 'Invalid value for \'' + argProcessor.argName + '\'.' + outputColors.reset);
143
+ }
144
+ }
145
+ // If we have an inputPrompt, prompt the user
146
+ if (argProcessor.inputPrompt) {
147
+ var rl = readline.createInterface({
148
+ input: process.stdin,
149
+ output: process.stdout
150
+ });
151
+ rl.question(argProcessor.inputPrompt + ' ', function(answer) {
152
+ rl.close();
153
+ processArgument(answer, argsMap, argProcessor, postProcessingCallback);
154
+ });
155
+ }
156
+ else {
157
+ processArgument('', argsMap, argProcessor, postProcessingCallback);
158
+ }
159
+ };
160
+
161
+ /**
162
+ * Creates an instance of an ArgProcessorList.
163
+ *
164
+ * @constructor
165
+ */
166
+ var ArgProcessorList = function() {
167
+ this.processorList = [];
168
+ };
169
+
170
+ /**
171
+ * Adds an ArgProcessor to the list of processors.
172
+ *
173
+ * @param {String} argName The name of the argument.
174
+ * @param {String} inputPrompt The prompt to show the user, when interactively configuring the arg value. If null, the user will not be prompted interactively.
175
+ * @param {Function} processorFunction The function used to validate the arg value.
176
+ * @param {Function} preprocessorFunction An optional function that can be used to determine whether the argument should be configured.
177
+ * @return {ArgProcessorList} The updated ArgProcessorList, for chaining calls.
178
+ */
179
+ ArgProcessorList.prototype.addArgProcessor = function(argName, inputPrompt, processorFunction, preprocessorFunction) {
180
+ var argProcessor = new ArgProcessor(argName, inputPrompt, processorFunction, preprocessorFunction);
181
+ this.processorList.push(argProcessor);
182
+ return this;
183
+ };
184
+
185
+ /**
186
+ * Creates an instance of the ArgProcessor object.
187
+ *
188
+ * @constructor
189
+ * @param {String} argName The name of the argument.
190
+ * @param {String} inputPrompt The prompt to show the user, when interactively configuring the arg value. If null, the user will not be prompted interactively.
191
+ * @param {Function} processorFunction The function used to validate the arg value.
192
+ * @param {Function} preprocessorFunction An optional function that can be used to determine whether the argument should be configured.
193
+ */
194
+ var ArgProcessor = function(argName, inputPrompt, processorFunction, preprocessorFunction) {
195
+ if ((typeof argName !== 'string') || argName.trim() === '') {
196
+ throw new Error('Invalid value for argName: \'' + argName + '\'.');
197
+ }
198
+ if (typeof processorFunction !== 'function') {
199
+ throw new Error('processorFunction should be a function.');
200
+ }
201
+ if ((typeof preprocessorFunction !== 'undefined') && (typeof preprocessorFunction !== 'function')) {
202
+ throw new Error('If defined, preprocessorFunction should be a function.');
203
+ }
204
+
205
+ this.argName = argName;
206
+ this.inputPrompt = inputPrompt;
207
+ this.processorFunction = processorFunction;
208
+ this.preprocessorFunction = preprocessorFunction;
209
+ };
210
+
211
+ /**
212
+ * Creates an instance of the ArgProcessorOutput object, used to return the result of processing an arg value.
213
+ *
214
+ * @constructor
215
+ * @param {Boolean} isValid Whether or not the arg value was a valid value.
216
+ * @param {String} messageOrReplacementValue Optional value. If arg is not valid, a message explaining the failure. If valid, an optional replacment value for the argument.
217
+ */
218
+ var ArgProcessorOutput = function(isValid, messageOrReplacementValue) {
219
+
220
+ // If an argument is valid (isValid == true), there won't need to be a message
221
+ // assocated with it. And if it's not valid, you wouldn't provide a replacement
222
+ // value for it (at least in the workflow as defined—replacement values imply a
223
+ // "valid" alternative argument value). Hence the single second argument serving
224
+ // two masters. But we'll normalize the value for consumption. NB: In either
225
+ // use case, this argument can be optional.
226
+
227
+ if (typeof isValid !== 'boolean') {
228
+ throw new Error('isValid should be a boolean value.');
229
+ }
230
+ this.isValid = isValid;
231
+
232
+ if (typeof messageOrReplacementValue !== 'undefined') {
233
+ if (this.isValid)
234
+ this.replacementValue = messageOrReplacementValue;
235
+ else
236
+ this.message = messageOrReplacementValue;
237
+ }
238
+ };
239
+
240
+ // Exports
241
+
242
+ module.exports.parseArgs = parseArgs;
243
+ module.exports.ArgProcessorList = ArgProcessorList;
244
+ module.exports.processArgsInteractive = processArgsInteractive;
245
+ module.exports.ArgProcessorOutput = ArgProcessorOutput;
@@ -0,0 +1,206 @@
1
+ /*
2
+ * Copyright (c) 2016-present, salesforce.com, inc.
3
+ * All rights reserved.
4
+ * Redistribution and use of this software in source and binary forms, with or
5
+ * without modification, are permitted provided that the following conditions
6
+ * are met:
7
+ * - Redistributions of source code must retain the above copyright notice, this
8
+ * list of conditions and the following disclaimer.
9
+ * - Redistributions in binary form must reproduce the above copyright notice,
10
+ * this list of conditions and the following disclaimer in the documentation
11
+ * and/or other materials provided with the distribution.
12
+ * - Neither the name of salesforce.com, inc. nor the names of its contributors
13
+ * may be used to endorse or promote products derived from this software without
14
+ * specific prior written permission of salesforce.com, inc.
15
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25
+ * POSSIBILITY OF SUCH DAMAGE.
26
+ */
27
+
28
+ // Dependencies
29
+ var path = require('path'),
30
+ shelljs = require('shelljs'),
31
+ SDK = require('./constants'),
32
+ COLOR = require('./outputColors'),
33
+ commandLineUtils = require('./commandLineUtils'),
34
+ logInfo = require('./utils').logInfo,
35
+ getTemplates = require('./templateHelper').getTemplates,
36
+ validateJson = require('./jsonChecker').validateJson;
37
+
38
+ function applyCli(f, cli) {
39
+ return typeof f === 'function' ? f(cli): f;
40
+ }
41
+
42
+ function getArgsExpanded(cli, commandName) {
43
+ var argNames = applyCli(SDK.commands[commandName].args, cli);
44
+ return argNames
45
+ .map(argName => SDK.args[argName])
46
+ .map(arg =>
47
+ ({
48
+ name: arg.name,
49
+ 'char': arg.char,
50
+ description: applyCli(arg.description, cli),
51
+ longDescription: applyCli(arg.longDescription, cli),
52
+ prompt: applyCli(arg.prompt, cli),
53
+ error: applyCli(arg.error, cli),
54
+ validate: applyCli(arg.validate, cli),
55
+ promptIf: arg.promptIf,
56
+ required: arg.required === undefined ? true : arg.required,
57
+ hasValue: arg.hasValue === undefined ? true : arg.hasValue,
58
+ hidden: applyCli(arg.hidden, cli),
59
+ type: arg.type
60
+ })
61
+ );
62
+
63
+ }
64
+
65
+ function getCommandExpanded(cli, commandName) {
66
+ var command = SDK.commands[commandName];
67
+ return {
68
+ name: command.name,
69
+ args: getArgsExpanded(cli, commandName),
70
+ description: applyCli(command.description, cli),
71
+ longDescription: applyCli(command.longDescription, cli),
72
+ help: applyCli(command.help, cli)
73
+ };
74
+ }
75
+
76
+ function readConfig(args, cli, handler) {
77
+ var commandLineArgs = args.slice(2, args.length);
78
+ var commandName = commandLineArgs.shift();
79
+ commandName = commandName ? commandName.toLowerCase() : commandName;
80
+
81
+ var processorList = null;
82
+
83
+ switch (commandName || '') {
84
+ case SDK.commands.version.name:
85
+ printVersion(cli);
86
+ process.exit(0);
87
+ break;
88
+ case SDK.commands.create.name:
89
+ case SDK.commands.createwithtemplate.name:
90
+ processorList = buildArgsProcessorList(cli, commandName);
91
+ commandLineUtils.processArgsInteractive(commandLineArgs, processorList, handler);
92
+ break;
93
+ case SDK.commands.checkconfig.name:
94
+ processorList = buildArgsProcessorList(cli, commandName);
95
+ commandLineUtils.processArgsInteractive(commandLineArgs, processorList, function (config) {
96
+ validateJson(config.configpath, config.configtype);
97
+ });
98
+ break;
99
+ case SDK.commands.listtemplates.name:
100
+ listTemplates(cli);
101
+ process.exit(0);
102
+ break;
103
+ default:
104
+ usage(cli);
105
+ process.exit(1);
106
+ };
107
+
108
+
109
+ }
110
+
111
+ function printVersion(cli) {
112
+ logInfo(cli.name + ' version ' + SDK.version);
113
+ }
114
+
115
+ function printArgs(cli, commandName) {
116
+ getArgsExpanded(cli, commandName)
117
+ .filter(arg => !arg.hidden)
118
+ .forEach(arg => logInfo(' ' + (!arg.required ? '[' : '') + '--' + arg.name + '=' + arg.description + (!arg.required ? ']' : ''), COLOR.magenta));
119
+ }
120
+
121
+ function listTemplates(cli) {
122
+ var cliName = cli.name;
123
+ var applicableTemplates = getTemplates(cli);
124
+
125
+ logInfo('\nAvailable templates:\n', COLOR.cyan);
126
+ for (var i=0; i<applicableTemplates.length; i++) {
127
+ var template = applicableTemplates[i];
128
+ logInfo((i+1) + ') ' + template.description, COLOR.cyan);
129
+ logInfo(cliName + ' ' + SDK.commands.createwithtemplate.name + ' --' + SDK.args.templateRepoUri.name + '=' + template.path, COLOR.magenta);
130
+ }
131
+ logInfo('');
132
+ }
133
+
134
+ function usage(cli) {
135
+ var cliName = cli.name;
136
+ var cliVersion = SDK.version;
137
+ var appTypes = cli.appTypes;
138
+ var platforms = cli.platforms;
139
+
140
+ logInfo('\n' + cliName + ': Tool for building ' + cli.purpose + ' using Salesforce Mobile SDK', COLOR.cyan);
141
+ logInfo('\nUsage:\n', COLOR.cyan);
142
+ for (var i=0; i<cli.commands.length; i++) {
143
+ if (i>0) {
144
+ logInfo('\n OR \n', COLOR.cyan);
145
+ }
146
+ var commandName = cli.commands[i];
147
+ var command = getCommandExpanded(cli, commandName);
148
+ logInfo('# ' + command.description, COLOR.magenta);
149
+ logInfo(cliName + ' ' + commandName, COLOR.magenta);
150
+ printArgs(cli, commandName);
151
+ }
152
+ logInfo('\n OR \n', COLOR.cyan);
153
+ logInfo(cliName, COLOR.magenta);
154
+ logInfo('\nWe also offer:', COLOR.cyan);
155
+ for (var otherCliName in SDK.forceclis) {
156
+ var otherCli = SDK.forceclis[otherCliName];
157
+ if (otherCli.name != cli.name) {
158
+ logInfo('- ' + otherCli.name + ': Tool for building ' + otherCli.purpose + ' using Salesforce Mobile SDK', COLOR.cyan);
159
+ }
160
+ }
161
+ logInfo('\n');
162
+ }
163
+
164
+ //
165
+ // Processor list
166
+ //
167
+ function buildArgsProcessorList(cli, commandName) {
168
+ var argProcessorList = new commandLineUtils.ArgProcessorList();
169
+
170
+ for (var arg of getArgsExpanded(cli, commandName)) {
171
+ addProcessorFor(argProcessorList, arg.name, arg.prompt, arg.error, arg.validate, arg.promptIf);
172
+ }
173
+
174
+ return argProcessorList;
175
+ }
176
+
177
+ //
178
+ // Helper function to add arg processor
179
+ // * argProcessorList: ArgProcessorList
180
+ // * argName: string, name of argument
181
+ // * prompt: string for prompt
182
+ // * error: function
183
+ // * validation: function or null (no validation)
184
+ // * preprocessor: function or null
185
+ //
186
+ function addProcessorFor(argProcessorList, argName, prompt, error, validation, preprocessor) {
187
+ argProcessorList.addArgProcessor(argName, prompt, function(val) {
188
+ val = val.trim();
189
+
190
+ // validation is either a function or null
191
+ if (validation == null || validation(val)) {
192
+ return new commandLineUtils.ArgProcessorOutput(true, val);
193
+ }
194
+ else {
195
+ return new commandLineUtils.ArgProcessorOutput(false, error(val));
196
+ }
197
+
198
+ }, preprocessor);
199
+ }
200
+
201
+ module.exports = {
202
+ readConfig: readConfig,
203
+ printVersion: printVersion,
204
+ getArgsExpanded: getArgsExpanded,
205
+ getCommandExpanded: getCommandExpanded
206
+ };