cht-conf 4.4.1 → 4.5.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.
Files changed (63) hide show
  1. package/.editorconfig +15 -0
  2. package/CHANGELOG.md +7 -0
  3. package/README.md +9 -1
  4. package/package.json +27 -26
  5. package/src/bin/shell-completion.js +5 -5
  6. package/src/cli/supported-actions.js +2 -2
  7. package/src/cli/usage.js +2 -0
  8. package/src/fn/backup-all-forms.js +1 -1
  9. package/src/fn/compile-app-settings.js +41 -14
  10. package/src/fn/compress-pngs.js +10 -8
  11. package/src/fn/compress-svgs.js +5 -2
  12. package/src/fn/create-users.js +6 -3
  13. package/src/fn/csv-to-docs.js +73 -52
  14. package/src/fn/delete-contacts.js +2 -0
  15. package/src/fn/edit-contacts.js +14 -11
  16. package/src/fn/fetch-csvs-from-google-drive.js +3 -3
  17. package/src/fn/fetch-forms-from-google-drive.js +3 -3
  18. package/src/fn/initialise-project-layout.js +14 -8
  19. package/src/fn/merge-contacts.js +10 -2
  20. package/src/fn/move-contacts.js +2 -0
  21. package/src/fn/upload-custom-translations.js +29 -22
  22. package/src/fn/upload-docs.js +30 -13
  23. package/src/fn/upload-privacy-policies.js +4 -1
  24. package/src/fn/upload-sms-from-csv.js +11 -11
  25. package/src/fn/watch-project.js +212 -204
  26. package/src/lib/api.js +22 -22
  27. package/src/lib/args-form-filter.js +1 -1
  28. package/src/lib/attachments-from-dir.js +3 -1
  29. package/src/lib/check-cht-conf-dependency-version.js +4 -2
  30. package/src/lib/check-for-updates.js +4 -3
  31. package/src/lib/compilation/compile-contact-summary.js +12 -2
  32. package/src/lib/compilation/compile-tasks-and-targets.js +5 -2
  33. package/src/lib/compilation/package-lib.js +5 -2
  34. package/src/lib/compilation/validate-declarative-schema.js +49 -32
  35. package/src/lib/convert-forms.js +27 -9
  36. package/src/lib/exec-promise.js +27 -19
  37. package/src/lib/fetch-document-list.js +2 -2
  38. package/src/lib/generate-users-csv.js +1 -1
  39. package/src/lib/get-api-url.js +4 -1
  40. package/src/lib/google-auth.js +15 -5
  41. package/src/lib/hierarchy-operations/delete-hierarchy.js +4 -1
  42. package/src/lib/hierarchy-operations/hierarchy-data-source.js +7 -2
  43. package/src/lib/hierarchy-operations/index.js +16 -4
  44. package/src/lib/hierarchy-operations/jsdocFolder.js +4 -1
  45. package/src/lib/hierarchy-operations/lineage-constraints.js +12 -6
  46. package/src/lib/hierarchy-operations/replace-lineage.js +20 -18
  47. package/src/lib/insert-or-replace.js +6 -2
  48. package/src/lib/log.js +6 -2
  49. package/src/lib/main.js +4 -3
  50. package/src/lib/nools-utils.js +5 -3
  51. package/src/lib/parse-purge.js +4 -1
  52. package/src/lib/parse-targets.js +3 -1
  53. package/src/lib/polyfill.js +3 -1
  54. package/src/lib/progress-bar.js +26 -13
  55. package/src/lib/skip-fn.js +5 -3
  56. package/src/lib/sync-fs.js +24 -12
  57. package/src/lib/upload-forms.js +17 -7
  58. package/src/lib/validation/form/can-generate-xform.js +3 -1
  59. package/src/lib/validation/form/check-xpaths-exist.js +8 -3
  60. package/src/lib/validation/form/deprecated-appearance.js +4 -2
  61. package/src/lib/validation/form/has-instance-id.js +4 -1
  62. package/src/lib/validation/form/no-required-notes.js +4 -1
  63. package/src/lib/warn-upload-overwrite.js +6 -3
@@ -26,269 +26,277 @@ const { execute: uploadCustomTranslations, TRANSLATIONS_DIR_PATH } = require('./
26
26
  const { execute: uploadResources, RESOURCES_DIR_PATH, RESOURCE_CONFIG_PATH } = require('./upload-resources');
27
27
 
28
28
  const watcherEvents = {
29
- CreateEvent: 'create',
30
- DeleteEvent: 'delete',
31
- UpdateEvent: 'update'
29
+ CreateEvent: 'create',
30
+ DeleteEvent: 'delete',
31
+ UpdateEvent: 'update'
32
32
  };
33
33
 
34
34
  const runValidation = (validation, forms) => {
35
- if(environment.skipValidate) {
36
- return;
37
- }
38
- return validation(forms);
35
+ if(environment.skipValidate) {
36
+ return;
37
+ }
38
+ return validation(forms);
39
39
  };
40
40
 
41
41
  const uploadInitialState = async (api) => {
42
- await uploadResources();
43
- await runValidation(validateAppForms, environment.extraArgs);
44
- await runValidation(validateContactForms, environment.extraArgs);
45
- await runValidation(validateTrainingForms, environment.extraArgs);
46
- await uploadAppForms(environment.extraArgs);
47
- await uploadContactForms(environment.extraArgs);
48
- await uploadTrainingForms(environment.extraArgs);
49
- await uploadCustomTranslations();
50
- await uploadAppSettings(api);
42
+ await uploadResources();
43
+ await runValidation(validateAppForms, environment.extraArgs);
44
+ await runValidation(validateContactForms, environment.extraArgs);
45
+ await runValidation(validateTrainingForms, environment.extraArgs);
46
+ await uploadAppForms(environment.extraArgs);
47
+ await uploadContactForms(environment.extraArgs);
48
+ await uploadTrainingForms(environment.extraArgs);
49
+ await uploadCustomTranslations();
50
+ await uploadAppSettings(api);
51
51
  };
52
52
 
53
53
  let fsEventsSubscription;
54
54
  let eventQueue;
55
55
 
56
56
  const cleanUp = async () => {
57
- if (fsEventsSubscription) {
58
- await fsEventsSubscription.unsubscribe();
59
- fsEventsSubscription = undefined;
60
- }
61
- if (eventQueue) {
62
- await eventQueue.clear();
63
- eventQueue = undefined;
64
- }
57
+ if (fsEventsSubscription) {
58
+ await fsEventsSubscription.unsubscribe();
59
+ fsEventsSubscription = undefined;
60
+ }
61
+ if (eventQueue) {
62
+ await eventQueue.clear();
63
+ eventQueue = undefined;
64
+ }
65
65
  };
66
66
 
67
67
  const waitForKillSignal = () => {
68
- return new Promise((resolve) => {
69
- process.on('SIGINT', async () => {
70
- await cleanUp();
71
- resolve();
72
- });
68
+ return new Promise((resolve) => {
69
+ process.on('SIGINT', async () => {
70
+ await cleanUp();
71
+ resolve();
73
72
  });
73
+ });
74
74
  };
75
75
 
76
76
  const deleteForm = (fileName, formDir) => {
77
- const form = uploadForms.formFileMatcher(fileName) || convertForms.formFileMatcher(fileName);
78
- if (!form) {
79
- return false;
80
- }
81
- const absFormDirPath = path.join(environment.pathToProject, formDir);
82
- const formFiles = fs.readdirSync(absFormDirPath).map(file => (uploadForms.formFileMatcher(file) || convertForms.formFileMatcher(file))).filter(_form => _form === form);
83
- const canDelete = formFiles.length <= 0;
84
- if (canDelete) {
85
- eventQueue.enqueue(async () => {
86
- await deleteForms([form]);
87
- return fileName;
88
- });
89
- return true;
90
- }
91
- warn(`You have to delete all form files (.xlsx, .properties.json, .xml) associated with the ${form} form to delete it from ${environment.apiUrl}`);
77
+ const form = uploadForms.formFileMatcher(fileName) || convertForms.formFileMatcher(fileName);
78
+ if (!form) {
92
79
  return false;
80
+ }
81
+ const absFormDirPath = path.join(environment.pathToProject, formDir);
82
+ const formFiles = fs
83
+ .readdirSync(absFormDirPath)
84
+ .map(file => (uploadForms.formFileMatcher(file) || convertForms.formFileMatcher(file)))
85
+ .filter(_form => _form === form);
86
+ const canDelete = formFiles.length <= 0;
87
+ if (canDelete) {
88
+ eventQueue.enqueue(async () => {
89
+ await deleteForms([form]);
90
+ return fileName;
91
+ });
92
+ return true;
93
+ }
94
+ warn(
95
+ `You have to delete all form files (.xlsx, .properties.json, .xml) associated with the ${form} form `
96
+ + `to delete it from ${environment.apiUrl}`
97
+ );
98
+ return false;
93
99
  };
94
100
 
95
101
  const getFormCommandContext = (parsedPath) => {
96
- if (parsedPath.dir === path.join(environment.pathToProject, APP_FORMS_PATH)) {
97
- return {
98
- path: APP_FORMS_PATH,
99
- validateForms: validateAppForms,
100
- uploadForms: uploadAppForms,
101
- convertForms: convertAppForms,
102
- };
103
- }
102
+ if (parsedPath.dir === path.join(environment.pathToProject, APP_FORMS_PATH)) {
103
+ return {
104
+ path: APP_FORMS_PATH,
105
+ validateForms: validateAppForms,
106
+ uploadForms: uploadAppForms,
107
+ convertForms: convertAppForms,
108
+ };
109
+ }
104
110
 
105
- if (parsedPath.dir === path.join(environment.pathToProject, TRAINING_FORMS_PATH)) {
106
- return {
107
- path: TRAINING_FORMS_PATH,
108
- validateForms: validateTrainingForms,
109
- uploadForms: uploadTrainingForms,
110
- convertForms: convertTrainingForms,
111
- };
112
- }
111
+ if (parsedPath.dir === path.join(environment.pathToProject, TRAINING_FORMS_PATH)) {
112
+ return {
113
+ path: TRAINING_FORMS_PATH,
114
+ validateForms: validateTrainingForms,
115
+ uploadForms: uploadTrainingForms,
116
+ convertForms: convertTrainingForms,
117
+ };
118
+ }
113
119
 
114
- if (parsedPath.dir === path.join(environment.pathToProject, CONTACT_FORMS_PATH)) {
115
- return {
116
- path: CONTACT_FORMS_PATH,
117
- validateForms: validateContactForms,
118
- uploadForms: uploadContactForms,
119
- convertForms: convertContactForm,
120
- };
121
- }
120
+ if (parsedPath.dir === path.join(environment.pathToProject, CONTACT_FORMS_PATH)) {
121
+ return {
122
+ path: CONTACT_FORMS_PATH,
123
+ validateForms: validateContactForms,
124
+ uploadForms: uploadContactForms,
125
+ convertForms: convertContactForm,
126
+ };
127
+ }
122
128
 
123
- if (parsedPath.dir === path.join(environment.pathToProject, COLLECT_FORMS_PATH)) {
124
- return {
125
- path: COLLECT_FORMS_PATH,
126
- validateForms: validateCollectForms,
127
- uploadForms: uploadCollectForms,
128
- convertForms: convertCollectForms,
129
- };
130
- }
129
+ if (parsedPath.dir === path.join(environment.pathToProject, COLLECT_FORMS_PATH)) {
130
+ return {
131
+ path: COLLECT_FORMS_PATH,
132
+ validateForms: validateCollectForms,
133
+ uploadForms: uploadCollectForms,
134
+ convertForms: convertCollectForms,
135
+ };
136
+ }
131
137
 
132
- return;
138
+ return;
133
139
  };
134
140
 
135
141
  const processForm = (eventType, fileName, commandContext) => {
136
- if (eventType === watcherEvents.DeleteEvent && deleteForm(fileName, commandContext.path)) {
137
- return true;
138
- }
139
- let form = uploadForms.formFileMatcher(fileName);
140
- if (form) {
141
- eventQueue.enqueue(async () => {
142
- await runValidation(commandContext.validateForms, [form]);
143
- await commandContext.uploadForms([form]);
144
- return fileName;
145
- });
146
- return true;
147
- }
142
+ if (eventType === watcherEvents.DeleteEvent && deleteForm(fileName, commandContext.path)) {
143
+ return true;
144
+ }
145
+ let form = uploadForms.formFileMatcher(fileName);
146
+ if (form) {
147
+ eventQueue.enqueue(async () => {
148
+ await runValidation(commandContext.validateForms, [form]);
149
+ await commandContext.uploadForms([form]);
150
+ return fileName;
151
+ });
152
+ return true;
153
+ }
148
154
 
149
- form = convertForms.formFileMatcher(fileName);
150
- if (form) {
151
- eventQueue.enqueue(async () => {
152
- await commandContext.convertForms([form]);
153
- return fileName;
154
- });
155
- return true;
156
- }
157
- return false;
155
+ form = convertForms.formFileMatcher(fileName);
156
+ if (form) {
157
+ eventQueue.enqueue(async () => {
158
+ await commandContext.convertForms([form]);
159
+ return fileName;
160
+ });
161
+ return true;
162
+ }
163
+ return false;
158
164
  };
159
165
 
160
166
  const getFormMediaCommandContext = (parsedPath) => {
161
- if (parsedPath.dir.startsWith(path.join(environment.pathToProject, APP_FORMS_PATH))
167
+ if (parsedPath.dir.startsWith(path.join(environment.pathToProject, APP_FORMS_PATH))
162
168
  && path.parse(parsedPath.dir).dir.endsWith(APP_FORMS_PATH)) {
163
- // Check if the directory's immediate parent is forms/app
164
- return {
165
- validateForms: validateAppForms,
166
- uploadForms: uploadAppForms,
167
- };
168
- }
169
+ // Check if the directory's immediate parent is forms/app
170
+ return {
171
+ validateForms: validateAppForms,
172
+ uploadForms: uploadAppForms,
173
+ };
174
+ }
169
175
 
170
- if (parsedPath.dir.startsWith(path.join(environment.pathToProject, TRAINING_FORMS_PATH))
176
+ if (parsedPath.dir.startsWith(path.join(environment.pathToProject, TRAINING_FORMS_PATH))
171
177
  && path.parse(parsedPath.dir).dir.endsWith(TRAINING_FORMS_PATH)) {
172
- // Check if the directory's immediate parent is forms/training
173
- return {
174
- validateForms: validateTrainingForms,
175
- uploadForms: uploadTrainingForms,
176
- };
177
- }
178
+ // Check if the directory's immediate parent is forms/training
179
+ return {
180
+ validateForms: validateTrainingForms,
181
+ uploadForms: uploadTrainingForms,
182
+ };
183
+ }
178
184
 
179
- return;
185
+ return;
180
186
  };
181
187
 
182
188
  const processFormMedia = (formMediaDir, fileName, commandContext) => {
183
- const form = uploadForms.formMediaMatcher(formMediaDir);
184
- if (form) {
185
- eventQueue.enqueue(async () => {
186
- await runValidation(commandContext.validateForms,[form]);
187
- await commandContext.uploadForms([form]);
188
- return fileName;
189
- });
190
- return true;
191
- }
192
- return false;
189
+ const form = uploadForms.formMediaMatcher(formMediaDir);
190
+ if (form) {
191
+ eventQueue.enqueue(async () => {
192
+ await runValidation(commandContext.validateForms,[form]);
193
+ await commandContext.uploadForms([form]);
194
+ return fileName;
195
+ });
196
+ return true;
197
+ }
198
+ return false;
193
199
  };
194
200
 
195
201
  const processConfigFiles = (api, fileName) => {
196
- if (fileName === APP_SETTINGS_JSON_PATH) {
197
- eventQueue.enqueue(async () => {
198
- await uploadAppSettings(api);
199
- return fileName;
200
- });
201
- return true;
202
- }
203
- if (configFileMatcher(fileName)) {
204
- eventQueue.enqueue(async () => {
205
- await compileAppSettings();
206
- return fileName;
207
- });
208
- return true;
209
- }
210
- return false;
202
+ if (fileName === APP_SETTINGS_JSON_PATH) {
203
+ eventQueue.enqueue(async () => {
204
+ await uploadAppSettings(api);
205
+ return fileName;
206
+ });
207
+ return true;
208
+ }
209
+ if (configFileMatcher(fileName)) {
210
+ eventQueue.enqueue(async () => {
211
+ await compileAppSettings();
212
+ return fileName;
213
+ });
214
+ return true;
215
+ }
216
+ return false;
211
217
  };
212
218
 
213
219
  const watchProject = {
214
- watch: async (api, blockFn, callback = {}, uploadStateOnStart = false) => {
215
- if (uploadStateOnStart) {
216
- await uploadInitialState(api);
217
- info('Initial State Uploaded');
218
- }
220
+ watch: async (api, blockFn, callback = {}, uploadStateOnStart = false) => {
221
+ if (uploadStateOnStart) {
222
+ await uploadInitialState(api);
223
+ info('Initial State Uploaded');
224
+ }
219
225
 
220
- eventQueue = new Queue({ concurrent: 1, start: true });
226
+ eventQueue = new Queue({ concurrent: 1, start: true });
221
227
 
222
- fsEventsSubscription = await watcher.subscribe(environment.pathToProject, async (err, events) => {
223
- if (err) {
224
- error(err);
225
- return;
226
- }
227
- for (const event of events) {
228
- const changePath = event.path;
229
- const parsedPath = path.parse(changePath);
230
- const fileName = parsedPath.base;
228
+ fsEventsSubscription = await watcher.subscribe(environment.pathToProject, async (err, events) => {
229
+ if (err) {
230
+ error(err);
231
+ return;
232
+ }
233
+ for (const event of events) {
234
+ const changePath = event.path;
235
+ const parsedPath = path.parse(changePath);
236
+ const fileName = parsedPath.base;
231
237
 
232
- const formContext = getFormCommandContext(parsedPath);
233
- if (formContext) {
234
- processForm(event.type, fileName, formContext);
235
- continue;
236
- }
238
+ const formContext = getFormCommandContext(parsedPath);
239
+ if (formContext) {
240
+ processForm(event.type, fileName, formContext);
241
+ continue;
242
+ }
237
243
 
238
- const formMediaContext = getFormMediaCommandContext(parsedPath);
239
- if (formMediaContext) {
240
- const dirName = path.parse(parsedPath.dir).base;
241
- processFormMedia(dirName, fileName, formMediaContext);
242
- continue;
243
- }
244
+ const formMediaContext = getFormMediaCommandContext(parsedPath);
245
+ if (formMediaContext) {
246
+ const dirName = path.parse(parsedPath.dir).base;
247
+ processFormMedia(dirName, fileName, formMediaContext);
248
+ continue;
249
+ }
244
250
 
245
- if (parsedPath.dir === path.join(environment.pathToProject, TRANSLATIONS_DIR_PATH)) {
246
- eventQueue.enqueue(async () => {
247
- await uploadCustomTranslations();
248
- return fileName;
249
- });
250
- continue;
251
- }
251
+ if (parsedPath.dir === path.join(environment.pathToProject, TRANSLATIONS_DIR_PATH)) {
252
+ eventQueue.enqueue(async () => {
253
+ await uploadCustomTranslations();
254
+ return fileName;
255
+ });
256
+ continue;
257
+ }
252
258
 
253
- if (parsedPath.dir === path.join(environment.pathToProject, APP_SETTINGS_DIR_PATH)) {
254
- processConfigFiles(api, fileName);
255
- continue;
256
- }
259
+ if (parsedPath.dir === path.join(environment.pathToProject, APP_SETTINGS_DIR_PATH)) {
260
+ processConfigFiles(api, fileName);
261
+ continue;
262
+ }
257
263
 
258
- if (parsedPath.dir === environment.pathToProject && parsedPath.base !== RESOURCE_CONFIG_PATH) {
259
- processConfigFiles(api, fileName);
260
- continue;
261
- }
264
+ if (parsedPath.dir === environment.pathToProject && parsedPath.base !== RESOURCE_CONFIG_PATH) {
265
+ processConfigFiles(api, fileName);
266
+ continue;
267
+ }
262
268
 
263
- if (parsedPath.base === RESOURCE_CONFIG_PATH || parsedPath.dir === path.join(environment.pathToProject, RESOURCES_DIR_PATH)) {
264
- eventQueue.enqueue(async () => {
265
- await uploadResources();
266
- return fileName;
267
- });
268
- continue;
269
- }
270
- }
271
- });
269
+ if (parsedPath.base === RESOURCE_CONFIG_PATH
270
+ || parsedPath.dir === path.join(environment.pathToProject, RESOURCES_DIR_PATH)
271
+ ) {
272
+ eventQueue.enqueue(async () => {
273
+ await uploadResources();
274
+ return fileName;
275
+ });
276
+ continue;
277
+ }
278
+ }
279
+ });
272
280
 
273
- eventQueue.on('resolve', file => {
274
- if (callback) {
275
- callback(file);
276
- }
277
- });
278
- eventQueue.on('reject', err => error('watch-mode: Error while processing change,', err));
281
+ eventQueue.on('resolve', file => {
282
+ if (callback) {
283
+ callback(file);
284
+ }
285
+ });
286
+ eventQueue.on('reject', err => error('watch-mode: Error while processing change,', err));
279
287
 
280
- info('watching', environment.pathToProject, 'for changes');
281
- await blockFn();
282
- },
283
- close: async () => {
284
- info('stopping watchers');
285
- await cleanUp();
286
- }
288
+ info('watching', environment.pathToProject, 'for changes');
289
+ await blockFn();
290
+ },
291
+ close: async () => {
292
+ info('stopping watchers');
293
+ await cleanUp();
294
+ }
287
295
  };
288
296
 
289
297
  const api = require('../lib/api');
290
298
  module.exports = {
291
- watchProject,
292
- requiresInstance: true,
293
- execute: () => watchProject.watch(api(), waitForKillSignal, false, true)
299
+ watchProject,
300
+ requiresInstance: true,
301
+ execute: () => watchProject.watch(api(), waitForKillSignal, false, true)
294
302
  };
package/src/lib/api.js CHANGED
@@ -210,28 +210,28 @@ const api = {
210
210
  headers: { 'Content-Type': 'application/xml' },
211
211
  body: formXml,
212
212
  })
213
- .then(resp => {
214
- try {
215
- return JSON.parse(resp);
216
- } catch (e) {
217
- throw new Error('Invalid JSON response validating XForm against the API: ' + resp);
218
- }
219
- })
220
- .catch(err => {
221
- if (err.statusCode === 404) {
222
- // The endpoint doesn't exist in the API (old CHT version), so
223
- // we assume the form is valid but return special JSON
224
- // highlighting the situation, and remembering the lack
225
- // of the endpoint so next call there is no need
226
- // to call the missed endpoint again
227
- this._formsValidateEndpointFound = false;
228
- return {ok: true, formsValidateEndpointFound: false};
229
- }
230
- if (err.statusCode === 400 && err.error) {
231
- throw new Error(JSON.parse(err.error).error);
232
- }
233
- throw err;
234
- });
213
+ .then(resp => {
214
+ try {
215
+ return JSON.parse(resp);
216
+ } catch (e) {
217
+ throw new Error('Invalid JSON response validating XForm against the API: ' + resp);
218
+ }
219
+ })
220
+ .catch(err => {
221
+ if (err.statusCode === 404) {
222
+ // The endpoint doesn't exist in the API (old CHT version), so
223
+ // we assume the form is valid but return special JSON
224
+ // highlighting the situation, and remembering the lack
225
+ // of the endpoint so next call there is no need
226
+ // to call the missed endpoint again
227
+ this._formsValidateEndpointFound = false;
228
+ return {ok: true, formsValidateEndpointFound: false};
229
+ }
230
+ if (err.statusCode === 400 && err.error) {
231
+ throw new Error(JSON.parse(err.error).error);
232
+ }
233
+ throw err;
234
+ });
235
235
  },
236
236
 
237
237
  async getCompressibleTypes () {
@@ -16,4 +16,4 @@ module.exports = (formsDir, extension, options) => {
16
16
  }
17
17
 
18
18
  return filteredFiles;
19
- };
19
+ };
@@ -3,7 +3,9 @@ const fs = require('./sync-fs');
3
3
  const warn = require('./log').warn;
4
4
 
5
5
  module.exports = dir => {
6
- if(!fs.exists(dir)) return warn('Cannot build list of attachments from non-existent dir:', dir);
6
+ if(!fs.exists(dir)) {
7
+ return warn('Cannot build list of attachments from non-existent dir:', dir);
8
+ }
7
9
 
8
10
  const attachments = {};
9
11
  fs.recurseFiles(dir)
@@ -19,8 +19,8 @@ module.exports = projectDir => {
19
19
  const majorRunningVersion = semver.major(runningVersion);
20
20
  let upgradeDowngradeLocalMsg = '';
21
21
  let upgradeDowngradeProjectMsg = '';
22
- let satisfiesLessThanMajorRunningVersion = semver.satisfies(projectVersion, `<${majorRunningVersion}.x`);
23
- let satisifiesGreaterThanRunningVersion = semver.satisfies(projectVersion, `>${runningVersion}`);
22
+ const satisfiesLessThanMajorRunningVersion = semver.satisfies(projectVersion, `<${majorRunningVersion}.x`);
23
+ const satisifiesGreaterThanRunningVersion = semver.satisfies(projectVersion, `>${runningVersion}`);
24
24
 
25
25
  if(satisfiesLessThanMajorRunningVersion || satisifiesGreaterThanRunningVersion) {
26
26
 
@@ -34,6 +34,7 @@ module.exports = projectDir => {
34
34
  upgradeDowngradeProjectMsg = 'downgrade';
35
35
  }
36
36
 
37
+ /* eslint-disable max-len */
37
38
  throw new Error(`Your cht-conf version is incompatible with the project's cht-conf version:
38
39
  Your local cht-conf version: ${runningVersion}
39
40
  The project cht-conf version: ${projectVersion}
@@ -44,6 +45,7 @@ module.exports = projectDir => {
44
45
  npm i -g cht-conf@${projectVersion}
45
46
  and try again, or ${upgradeDowngradeProjectMsg} the project cht-conf version to ${runningVersion}, or ignore this warning with --skip-dependency-check
46
47
  `);
48
+ /* eslint-enable max-len */
47
49
 
48
50
  }
49
51
  };
@@ -6,7 +6,9 @@ module.exports = (options) => {
6
6
  const current = require('../../package').version;
7
7
  info(`Current version: ${current}. Checking NPM for updates…`);
8
8
 
9
- if (!options) options = {};
9
+ if (!options) {
10
+ options = {};
11
+ }
10
12
 
11
13
  return request
12
14
  .get('https://registry.npmjs.org/cht-conf')
@@ -33,6 +35,5 @@ module.exports = (options) => {
33
35
  } else {
34
36
  warn(`Could not check NPM for updates. Error: ${err.message}`);
35
37
  }
36
- })
37
- ;
38
+ });
38
39
  };
@@ -9,8 +9,18 @@ module.exports = async (projectDir, options) => {
9
9
  const freeformPathExists = fs.exists(freeformPath);
10
10
  const structuredPathExists = fs.exists(structuredPath);
11
11
 
12
- if (!freeformPathExists && !structuredPathExists) throw new Error(`Could not find contact-summary javascript at either of ${freeformPath} or ${structuredPath}. Please create one xor other of these files.`);
13
- if (freeformPathExists && structuredPathExists) throw new Error(`Found contact-summary javascript at both ${freeformPath} and ${structuredPath}. Only one of these files should exist.`);
12
+ if (!freeformPathExists && !structuredPathExists) {
13
+ throw new Error(
14
+ `Could not find contact-summary javascript at either of ${freeformPath} or ${structuredPath}. `
15
+ + 'Please create one xor other of these files.'
16
+ );
17
+ }
18
+ if (freeformPathExists && structuredPathExists) {
19
+ throw new Error(
20
+ `Found contact-summary javascript at both ${freeformPath} and ${structuredPath}. `
21
+ + 'Only one of these files should exist.'
22
+ );
23
+ }
14
24
 
15
25
  const baseEslintPath = path.join(__dirname, '../../contact-summary/.eslintrc');
16
26
  const pathToDeclarativeLib = path.join(__dirname, '../../contact-summary/lib.js');
@@ -22,7 +22,10 @@ const compileTasksAndTargets = async (projectDir, options = {}) => {
22
22
 
23
23
  if (legacyRules !== undefined) {
24
24
  if (findMissingDeclarativeFiles(projectDir).length !== DECLARATIVE_NOOLS_FILES.length) {
25
- throw new Error(`Both legacy and declarative files found. You should either have rules.nools.js xor ${DECLARATIVE_NOOLS_FILES} files.`);
25
+ throw new Error(
26
+ 'Both legacy and declarative files found. '
27
+ + `You should either have rules.nools.js xor ${DECLARATIVE_NOOLS_FILES} files.`
28
+ );
26
29
  }
27
30
 
28
31
  const rules = options.minifyScripts ? nools.minify(legacyRules) : legacyRules;
@@ -54,4 +57,4 @@ const compileDeclarativeFiles = async (projectDir, options) => {
54
57
  return pack(projectDir, pathToDeclarativeLib, baseEslintPath, options);
55
58
  };
56
59
 
57
- module.exports = compileTasksAndTargets;
60
+ module.exports = compileTasksAndTargets;
@@ -67,7 +67,8 @@ module.exports = (pathToProject, entry, baseEslintPath, options = {}) => {
67
67
  failOnError: false,
68
68
  failOnWarning: false,
69
69
  }),
70
- new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ }), // Ignore all optional deps of moment.js
70
+ // Ignore all optional deps of moment.js
71
+ new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ }),
71
72
  ],
72
73
  });
73
74
 
@@ -89,7 +90,9 @@ module.exports = (pathToProject, entry, baseEslintPath, options = {}) => {
89
90
  }
90
91
 
91
92
  if (stats.hasWarnings()) {
92
- const hasWarningsRelatedToLinting = stats.toJson().warnings.some(warning => warning.message.includes('warnings potentially fixable'));
93
+ const hasWarningsRelatedToLinting = stats
94
+ .toJson().warnings
95
+ .some(warning => warning.message.includes('warnings potentially fixable'));
93
96
  const shouldHalt = options.haltOnWebpackWarning ||
94
97
  options.haltOnLintMessage && hasWarningsRelatedToLinting;
95
98