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.
@@ -0,0 +1,368 @@
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
+ SDK = require('./constants'),
31
+ utils = require('./utils'),
32
+ configHelper = require('./configHelper'),
33
+ prepareTemplate = require('./templateHelper').prepareTemplate,
34
+ getSDKTemplateURI = require('./templateHelper').getSDKTemplateURI,
35
+ fs = require('fs');
36
+
37
+ // Constant
38
+ var SERVER_PROJECT_DIR = 'server';
39
+
40
+ //
41
+ // Helper for native application creation
42
+ //
43
+ function createNativeApp(config) {
44
+
45
+ // Copying template to projectDir
46
+ utils.copyFile(config.templateLocalPath, config.projectDir);
47
+
48
+ // Run prepare function of template
49
+ var prepareResult = prepareTemplate(config, config.projectDir);
50
+
51
+ if (config.platform === 'ios' && config.apptype === 'react_native') {
52
+ // Use legacy build
53
+ useLegacyBuild(config, 'ios');
54
+ }
55
+
56
+ // Cleanup
57
+ utils.removeFile(path.join(config.projectDir, 'template.js'));
58
+
59
+ // Done
60
+ return prepareResult;
61
+ }
62
+
63
+ //
64
+ // Helper for hybrid application creation
65
+ //
66
+ function createHybridApp(config) {
67
+
68
+ // Create app with cordova
69
+ utils.runProcessThrowError('cordova create "' + config.projectDir + '" ' + config.packagename + ' ' + config.appname);
70
+ utils.runProcessThrowError('npm install shelljs@0.7.0', config.projectDir);
71
+
72
+ for (var platform of config.platform.split(',')) {
73
+ utils.runProcessThrowError('cordova platform add ' + platform + '@' + SDK.tools.cordova.platformVersion[platform], config.projectDir);
74
+ }
75
+ utils.runProcessThrowError('cordova plugin add ' + config.cordovaPluginRepoUri + ' --force', config.projectDir);
76
+
77
+ // Web directory - the home for the template
78
+ var webDir = path.join(config.projectDir, 'www');
79
+
80
+ // Remove the default Cordova app.
81
+ utils.removeFile(webDir);
82
+
83
+ // Copying template to www
84
+ utils.copyFile(config.templateLocalPath, webDir);
85
+
86
+ // Run prepare function of template
87
+ var prepareResult = prepareTemplate(config, webDir);
88
+
89
+ // Cleanup
90
+ utils.removeFile(path.join(webDir, 'template.js'));
91
+
92
+ // If template includes server side files
93
+ // Create a fresh sfdx project
94
+ // Add cordova js and plugins at static resources
95
+ // Merge files from template into it
96
+ if (utils.dirExists(path.join(webDir, SERVER_PROJECT_DIR))) {
97
+ config.serverDir = path.join(config.projectDir, SERVER_PROJECT_DIR)
98
+ utils.runProcessThrowError('sfdx force:project:create -n ' + SERVER_PROJECT_DIR, config.projectDir);
99
+
100
+ // Copy cordova js to static resources
101
+ for (var platform of config.platform.split(',')) {
102
+ var cordovaStaticResourcesDir = path.join(config.serverDir, 'force-app', 'main', 'default', 'staticresources', 'cordova' + platform);
103
+ utils.mkDirIfNeeded(cordovaStaticResourcesDir);
104
+ utils.copyFile(path.join(config.projectDir, 'platforms', platform, 'platform_www', '*'), cordovaStaticResourcesDir);
105
+ }
106
+
107
+ // Merge server files from templates
108
+ utils.mergeFile(path.join(webDir, SERVER_PROJECT_DIR), config.serverDir);
109
+
110
+ // Remove server files from www
111
+ utils.removeFile(path.join(webDir, SERVER_PROJECT_DIR));
112
+ }
113
+
114
+ // Run cordova prepare
115
+ utils.runProcessThrowError('cordova prepare', config.projectDir);
116
+
117
+ if (config.platform === 'ios') {
118
+ // Use legacy build
119
+ useLegacyBuild(config, path.join('platforms', 'ios'));
120
+
121
+ // Removing libCordova.a from build (it causes issues e.g. CDVWKWebViewEngine won't register as plugin because it won't be recognized as a kind of CDVPlugin)
122
+ utils.logInfo('Updating xcode project file');
123
+ var xcodeProjectFile = path.join(config.projectDir,'platforms', 'ios', config.appname + '.xcodeproj', 'project.pbxproj')
124
+ var xcodeProjectFileContent = fs.readFileSync(xcodeProjectFile, 'utf8');
125
+ var newXcodeProjectFileContent = xcodeProjectFileContent.split('\n').filter(line => line.indexOf('libCordova.a in Frameworks') == -1).join('\n');
126
+ fs.writeFileSync(xcodeProjectFile, newXcodeProjectFileContent);
127
+ utils.logInfo('Updated xcode project file');
128
+ }
129
+
130
+ // Done
131
+ return prepareResult;
132
+
133
+ }
134
+
135
+ //
136
+ // Use legacy build system in XCode
137
+ //
138
+ function useLegacyBuild(config, iosSubDir) {
139
+ var xcSettingsDir = path.join(config.projectDir, iosSubDir, config.appname + '.xcworkspace', 'xcshareddata')
140
+ var xcSettingsFile = path.join(xcSettingsDir, 'WorkspaceSettings.xcsettings');
141
+ var plistFileContent = '<?xml version="1.0" encoding="UTF-8"?>\n' +
142
+ '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n' +
143
+ '<plist version="1.0">\n' +
144
+ '<dict>\n' +
145
+ '<key>BuildSystemType</key>\n' +
146
+ '<string>Original</string>\n' +
147
+ '<key>DisableBuildSystemDeprecationDiagnostic</key>\n' +
148
+ '<true/>\n' +
149
+ '</dict>\n' +
150
+ '</plist>\n';
151
+ utils.logInfo('Creating WorkspaceSettings.xcsettings for project. Setting the BuildSystemType to original in ' + xcSettingsFile);
152
+ utils.mkDirIfNeeded(xcSettingsDir)
153
+ fs.writeFileSync(xcSettingsFile,plistFileContent,'utf8');
154
+ utils.logInfo('Created WorkspaceSettings.xcsettings for project ' + config.appname);
155
+ }
156
+
157
+ //
158
+ // Print details
159
+ //
160
+ function printDetails(config) {
161
+ // Printing out details
162
+ var details = ['Creating ' + config.platform.replace(',', ' and ') + ' ' + config.apptype + ' application using Salesforce Mobile SDK',
163
+ ' with app name: ' + config.appname,
164
+ ' package name: ' + config.packagename,
165
+ ' organization: ' + config.organization,
166
+ '',
167
+ ' in: ' + config.projectPath,
168
+ '',
169
+ ' from template repo: ' + config.templaterepouri
170
+ ];
171
+
172
+ if (config.templatepath) {
173
+ details = details.concat([' template path: ' + config.templatepath]);
174
+ }
175
+
176
+
177
+ // Hybrid extra details
178
+ if (config.apptype.indexOf('hybrid') >= 0) {
179
+ if (config.apptype === 'hybrid_remote') {
180
+ details = details.concat([' start page: ' + config.startpage]);
181
+ }
182
+
183
+ details = details.concat([' plugin repo: ' + config.cordovaPluginRepoUri]);
184
+ }
185
+
186
+ utils.logParagraph(details);
187
+ }
188
+
189
+ //
190
+ // Print next steps
191
+ //
192
+ function printNextSteps(ide, projectPath, result) {
193
+ var workspacePath = path.join(projectPath, result.workspacePath);
194
+ var bootconfigFile = path.join(projectPath, result.bootconfigFile);
195
+
196
+ // Printing out next steps
197
+ utils.logParagraph(['Next steps' + (result.platform ? ' for ' + result.platform : '') + ':',
198
+ '',
199
+ 'Your application project is ready in ' + projectPath + '.',
200
+ 'To use your new application in ' + ide + ', do the following:',
201
+ ' - open ' + workspacePath + ' in ' + ide,
202
+ ' - build and run',
203
+ 'Before you ship, make sure to plug your OAuth Client ID and Callback URI,',
204
+ 'and OAuth Scopes into ' + bootconfigFile,
205
+ ]);
206
+
207
+ };
208
+
209
+ //
210
+ // Print next steps for server project if present
211
+ //
212
+ function printNextStepsForServerProjectIfNeeded(projectPath) {
213
+ var serverProjectPath = path.join(projectPath, SERVER_PROJECT_DIR);
214
+ var hasServerProject = utils.dirExists(serverProjectPath);
215
+ // Extra steps if there is a server project
216
+ if (hasServerProject) {
217
+ utils.logParagraph(['Your application also has a server project in ' + serverProjectPath + '.',
218
+ 'Make sure to deploy it to your org before running your application.',
219
+ '',
220
+ 'From ' + projectPath + ' do the following to setup a scratch org, push the server code:',
221
+ ' - sfdx force:org:create -f server/config/project-scratch-def.json -a MyOrg',
222
+ ' - cd server',
223
+ ' - sfdx force:source:push -u MyOrg',
224
+ 'You also need a password to login to the scratch org from the mobile app:',
225
+ ' - sfdx force:user:password:generate -u MyOrg'
226
+ ]);
227
+ }
228
+
229
+
230
+ }
231
+
232
+ //
233
+ // Check tools
234
+ //
235
+ function checkTools(toolNames) {
236
+ try {
237
+ utils.log("Checking tools");
238
+ for (var toolName of toolNames) {
239
+ utils.checkToolVersion(SDK.tools[toolName].checkCmd, SDK.tools[toolName].minVersion, SDK.tools[toolName].maxVersion);
240
+ }
241
+ }
242
+ catch (error) {
243
+ utils.logError('Missing tools\n', error);
244
+ process.exit(1);
245
+ }
246
+ }
247
+
248
+ //
249
+ // Create app - check tools, read config then actually create app
250
+ //
251
+ function createApp(forcecli, config) {
252
+
253
+ // Can't target ios or run pod if not on a mac
254
+ if (process.platform != 'darwin') {
255
+ forcecli.platforms = forcecli.platforms.filter(p=>p!='ios');
256
+ forcecli.toolNames = forcecli.toolNames.filter(t=>t!='pod');
257
+
258
+ if (forcecli.platforms.length == 0) {
259
+ utils.logError('You can only run ' + forcecli.name + ' on a Mac');
260
+ process.exit(1);
261
+ }
262
+ }
263
+
264
+ // Check tools
265
+ checkTools(forcecli.toolNames);
266
+
267
+ if (config === undefined) {
268
+ // Read parameters from command line
269
+ configHelper.readConfig(process.argv, forcecli, function(config) { actuallyCreateApp(forcecli, config); });
270
+ }
271
+ else {
272
+ // Use parameters passed through
273
+ actuallyCreateApp(forcecli, config);
274
+ }
275
+ }
276
+
277
+ //
278
+ // Actually create app
279
+ //
280
+ function actuallyCreateApp(forcecli, config) {
281
+ try {
282
+ // Adding platform
283
+ if (forcecli.platforms.length == 1) {
284
+ config.platform = forcecli.platforms[0];
285
+ }
286
+
287
+ // Adding app type
288
+ if (forcecli.appTypes.length == 1 || config.apptype === undefined || config.apptype === '') {
289
+ config.apptype = forcecli.appTypes[0];
290
+ }
291
+
292
+ // Setting log level
293
+ if (config.verbose) {
294
+ utils.setLogLevel(utils.LOG_LEVELS.DEBUG);
295
+ }
296
+ else {
297
+ utils.setLogLevel(utils.LOG_LEVELS.INFO);
298
+ }
299
+
300
+ // Computing projectDir
301
+ config.projectDir = config.outputdir ? path.resolve(config.outputdir) : path.join(process.cwd(),config.appname)
302
+ config.projectPath = path.relative(process.cwd(), config.projectDir);
303
+
304
+ // Adding version
305
+ config.version = SDK.version;
306
+
307
+ // Figuring out template repo uri and path
308
+ if (config.templaterepouri) {
309
+ if (!config.templaterepouri.startsWith("https://")) {
310
+ // Given a Mobile SDK template name
311
+ config.templatepath = config.templaterepouri;
312
+ config.templaterepouri = SDK.templatesRepoUri;
313
+ } else {
314
+ // Given a full URI
315
+ var templateUriParsed = utils.separateRepoUrlPathBranch(config.templaterepouri);
316
+ config.templaterepouri = templateUriParsed.repo + '#' + templateUriParsed.branch;
317
+ config.templatepath = templateUriParsed.path;
318
+ }
319
+ }
320
+ else {
321
+ config.templaterepouri = SDK.templatesRepoUri;
322
+ config.templatepath = forcecli.appTypesToPath[config.apptype];
323
+ }
324
+
325
+ // Creating tmp dir for template clone
326
+ var tmpDir = utils.mkTmpDir();
327
+
328
+ // Cloning template repo
329
+ var repoDir = utils.cloneRepo(tmpDir, config.templaterepouri);
330
+ config.templateLocalPath = path.join(repoDir, config.templatepath);
331
+
332
+ // Getting apptype from template
333
+ config.apptype = require(path.join(config.templateLocalPath, 'template.js')).appType;
334
+
335
+ var isNative = config.apptype.indexOf('native') >= 0;
336
+
337
+ // Adding hybrid only config
338
+ if (!isNative) {
339
+ config.cordovaPluginRepoUri = config.pluginrepouri || SDK.tools.cordova.pluginRepoUri;
340
+ }
341
+
342
+ // Print details
343
+ printDetails(config);
344
+
345
+ // Creating application
346
+ var results = isNative ? createNativeApp(config) : createHybridApp(config);
347
+
348
+ // Cleanup
349
+ utils.removeFile(tmpDir);
350
+
351
+ // Printing next steps
352
+ if (!(results instanceof Array)) { results = [results] };
353
+ for (var result of results) {
354
+ var ide = SDK.ides[result.platform || config.platform.split(',')[0]];
355
+ printNextSteps(ide, config.projectPath, result);
356
+ }
357
+ printNextStepsForServerProjectIfNeeded(config.projectPath);
358
+
359
+ }
360
+ catch (error) {
361
+ utils.logError(forcecli.name + ' failed\n', error);
362
+ process.exit(1);
363
+ }
364
+ }
365
+
366
+ module.exports = {
367
+ createApp
368
+ };
@@ -0,0 +1,24 @@
1
+ {
2
+ "soups": [
3
+ {
4
+ "soupName": "userSoup1",
5
+ "indexes": [
6
+ { "path": "stringField1", "type": "string"},
7
+ { "path": "integerField1", "type": "integer"},
8
+ { "path": "floatingField1", "type": "floating"},
9
+ { "path": "json1Field1", "type": "json1"},
10
+ { "path": "ftsField1", "type": "full_text"}
11
+ ]
12
+ },
13
+ {
14
+ "soupName": "userSoup2",
15
+ "indexes": [
16
+ { "path": "stringField2", "type": "string"},
17
+ { "path": "integerField2", "type": "integer"},
18
+ { "path": "floatingField2", "type": "floating"},
19
+ { "path": "json1Field2", "type": "json1"},
20
+ { "path": "ftsField2", "type": "full_text"}
21
+ ]
22
+ }
23
+ ]
24
+ }
@@ -0,0 +1,190 @@
1
+ {
2
+ "syncs": [
3
+ {
4
+ "syncName": "soqlSyncDown",
5
+ "syncType": "syncDown",
6
+ "soupName": "accounts",
7
+ "target": {
8
+ "type":"soql",
9
+ "query":"SELECT Id, Name, LastModifiedDate FROM Account"
10
+ },
11
+ "options": {
12
+ "mergeMode":"OVERWRITE"
13
+ }
14
+ },
15
+ {
16
+ "syncName": "soqlSyncDownWithBatchSize",
17
+ "syncType": "syncDown",
18
+ "soupName": "accounts",
19
+ "target": {
20
+ "type":"soql",
21
+ "query":"SELECT Id, Name, LastModifiedDate FROM Account",
22
+ "maxBatchSize": 200
23
+ },
24
+ "options": {
25
+ "mergeMode":"OVERWRITE"
26
+ }
27
+ },
28
+ {
29
+ "syncName": "soslSyncDown",
30
+ "syncType": "syncDown",
31
+ "soupName": "accounts",
32
+ "target": {
33
+ "type":"sosl",
34
+ "query":"FIND {Joe} IN NAME FIELDS RETURNING Account"
35
+ },
36
+ "options": {
37
+ "mergeMode":"LEAVE_IF_CHANGED"
38
+ }
39
+ },
40
+ {
41
+ "syncName": "mruSyncDown",
42
+ "syncType": "syncDown",
43
+ "soupName": "accounts",
44
+ "target": {
45
+ "type":"mru",
46
+ "sobjectType": "Account",
47
+ "fieldlist": ["Name", "Description"]
48
+ },
49
+ "options": {
50
+ "mergeMode":"OVERWRITE"
51
+ }
52
+ },
53
+ {
54
+ "syncName": "refreshSyncDown",
55
+ "syncType": "syncDown",
56
+ "soupName": "accounts",
57
+ "target": {
58
+ "type":"refresh",
59
+ "sobjectType": "Account",
60
+ "fieldlist": ["Name", "Description"],
61
+ "soupName": "accounts"
62
+ },
63
+ "options": {
64
+ "mergeMode":"LEAVE_IF_CHANGED"
65
+ }
66
+ },
67
+ {
68
+ "syncName": "layoutSyncDown",
69
+ "syncType": "syncDown",
70
+ "soupName": "accounts",
71
+ "target": {
72
+ "type":"layout",
73
+ "sobjectType": "Account",
74
+ "formFactor": "Medium",
75
+ "layoutType": "Compact",
76
+ "mode": "Edit"
77
+ },
78
+ "options": {
79
+ "mergeMode":"OVERWRITE"
80
+ }
81
+ },
82
+ {
83
+ "syncName": "metadataSyncDown",
84
+ "syncType": "syncDown",
85
+ "soupName": "accounts",
86
+ "target": {
87
+ "type":"metadata",
88
+ "sobjectType": "Account"
89
+ },
90
+ "options": {
91
+ "mergeMode":"LEAVE_IF_CHANGED"
92
+ }
93
+ },
94
+ {
95
+ "syncName": "parentChildrenSyncDown",
96
+ "syncType": "syncDown",
97
+ "soupName": "accounts",
98
+ "target": {
99
+ "parent" : {
100
+ "idFieldName" : "IdX",
101
+ "sobjectType" : "Account",
102
+ "modificationDateFieldName" : "LastModifiedDateX",
103
+ "soupName" : "accounts"
104
+ },
105
+ "parentFieldlist" : ["IdX", "Name", "Description"],
106
+ "children" : {
107
+ "parentIdFieldName" : "AccountId",
108
+ "idFieldName" : "IdY",
109
+ "sobjectType" : "Contact",
110
+ "modificationDateFieldName" : "LastModifiedDateY",
111
+ "soupName" : "contacts",
112
+ "sobjectTypePlural" : "Contacts"
113
+ },
114
+ "childrenFieldlist" : [
115
+ "LastName",
116
+ "AccountId"
117
+ ],
118
+ "relationshipType" : "MASTER_DETAIL",
119
+ "parentSoqlFilter" : "NameX like 'James%'",
120
+ "type" : "parent_children"
121
+ },
122
+ "options": {
123
+ "mergeMode": "OVERWRITE"
124
+ }
125
+ },
126
+ {
127
+ "syncName": "noBatchSyncUp",
128
+ "syncType": "syncUp",
129
+ "soupName": "accounts",
130
+ "target": {
131
+ "iOSImpl": "SFSyncUpTarget",
132
+ "androidImpl": "com.salesforce.androidsdk.mobilesync.target.SyncUpTarget",
133
+ "createFieldlist": ["Name"],
134
+ "updateFieldlist": ["Description"]
135
+ },
136
+ "options": {
137
+ "fieldlist": [],
138
+ "mergeMode":"LEAVE_IF_CHANGED"
139
+ }
140
+ },
141
+ {
142
+ "syncName": "batchSyncUp",
143
+ "syncType": "syncUp",
144
+ "soupName": "accounts",
145
+ "target": {
146
+ "idFieldName": "IdX",
147
+ "modificationDateFieldName": "LastModifiedDateX",
148
+ "externalIdFieldName": "ExternalIdX"
149
+ },
150
+ "options": {
151
+ "fieldlist": ["Name", "Description"],
152
+ "mergeMode":"OVERWRITE"
153
+ }
154
+ },
155
+ {
156
+ "syncName": "parentChildrenSyncUp",
157
+ "syncType": "syncUp",
158
+ "soupName": "accounts",
159
+ "target": {
160
+ "iOSImpl" : "SFParentChildrenSyncUpTarget",
161
+ "androidImpl": "com.salesforce.androidsdk.mobilesync.target.ParentChildrenSyncUpTarget",
162
+ "parent" : {
163
+ "idFieldName" : "IdX",
164
+ "externalIdFieldName": "ExternalIdX",
165
+ "sobjectType" : "Account",
166
+ "modificationDateFieldName" : "LastModifiedDateX",
167
+ "soupName" : "accounts"
168
+ },
169
+ "createFieldlist" : ["IdX", "Name", "Description"],
170
+ "updateFieldlist" : ["Name", "Description"],
171
+ "children" : {
172
+ "parentIdFieldName" : "AccountId",
173
+ "idFieldName" : "IdY",
174
+ "externalIdFieldName": "ExternalIdY",
175
+ "sobjectType" : "Contact",
176
+ "modificationDateFieldName" : "LastModifiedDateY",
177
+ "soupName" : "contacts",
178
+ "sobjectTypePlural" : "Contacts"
179
+ },
180
+ "childrenCreateFieldlist" : ["LastName", "AccountId"],
181
+ "childrenUpdateFieldlist" : ["FirstName", "AccountId"],
182
+ "relationshipType" : "MASTER_DETAIL"
183
+ },
184
+ "options": {
185
+ "fieldlist":[],
186
+ "mergeMode":"LEAVE_IF_CHANGED"
187
+ }
188
+ }
189
+ ]
190
+ }
@@ -0,0 +1,75 @@
1
+ /*
2
+ * Copyright (c) 2019-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 fs = require('fs'),
30
+ path = require('path'),
31
+ COLOR = require('./outputColors'),
32
+ utils = require('./utils'),
33
+ Ajv = require('ajv'),
34
+ jsonlint = require('jsonlint')
35
+ ;
36
+
37
+ // Config type to schema map
38
+ var SCHEMA = {
39
+ store: path.resolve(__dirname, 'store.schema.json'),
40
+ syncs: path.resolve(__dirname, 'syncs.schema.json')
41
+ };
42
+
43
+
44
+ //
45
+ // Validate config against schema
46
+ //
47
+ function validateJson(configPath, configType) {
48
+ var config = readJsonFile(configPath)
49
+ var schema = readJsonFile(SCHEMA[configType])
50
+ var ajv = new Ajv({allErrors: true});
51
+ var valid = ajv.validate(schema, config);
52
+ if (!valid) {
53
+ utils.logError(JSON.stringify(ajv.errors, null, " "))
54
+ } else {
55
+ utils.logInfo(`${configPath} conforms to ${configType} schema\n`, COLOR.green)
56
+ }
57
+ }
58
+
59
+ //
60
+ // Read json from file and validates that is valid json
61
+ //
62
+ function readJsonFile(filePath) {
63
+ try {
64
+ var content = fs.readFileSync(filePath, "UTF-8");
65
+ var json = jsonlint.parse(content);
66
+ return json;
67
+ } catch (error) {
68
+ utils.logError(`Error parsing ${filePath}: ${error}\n`);
69
+ process.exit(1);
70
+ }
71
+ }
72
+
73
+ module.exports = {
74
+ validateJson
75
+ };