@bigcommerce/stencil-cli 8.2.0 → 8.4.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 (71) hide show
  1. package/bin/stencil-bundle.js +7 -18
  2. package/bin/stencil-debug.js +5 -9
  3. package/bin/stencil-download.js +7 -19
  4. package/bin/stencil-init.js +4 -8
  5. package/bin/stencil-pull.js +5 -11
  6. package/bin/stencil-push.js +5 -8
  7. package/bin/stencil-release.js +5 -10
  8. package/bin/stencil-scss-autofix.js +6 -11
  9. package/bin/stencil-start.js +6 -9
  10. package/bin/stencil.js +2 -3
  11. package/constants.js +9 -9
  12. package/lib/BuildConfigManager.js +25 -23
  13. package/lib/Cycles.js +3 -12
  14. package/lib/ScssValidator.js +5 -9
  15. package/lib/StencilCLISettings.js +1 -3
  16. package/lib/StencilConfigManager.js +6 -22
  17. package/lib/StencilDebug.js +7 -10
  18. package/lib/archiveManager.js +7 -23
  19. package/lib/bundle-validator.js +28 -64
  20. package/lib/cliCommon.js +11 -21
  21. package/lib/commander.js +2 -3
  22. package/lib/content-api-client.js +5 -13
  23. package/lib/css/compile.js +5 -11
  24. package/lib/graphql/query.js +5 -8
  25. package/lib/lang/validator.js +5 -11
  26. package/lib/lang-assembler.js +4 -10
  27. package/lib/lang-helper.js +3 -6
  28. package/lib/nodeSass/AutoFixer.js +10 -19
  29. package/lib/nodeSass/BaseFixer.js +5 -7
  30. package/lib/nodeSass/BaseRulesFixer.js +3 -8
  31. package/lib/nodeSass/CommaRemovalFixer.js +3 -8
  32. package/lib/nodeSass/ConditionalImportFixer.js +3 -9
  33. package/lib/nodeSass/UndefinedVariableFixer.js +3 -6
  34. package/lib/parse-json.js +10 -9
  35. package/lib/regions.js +3 -23
  36. package/lib/release/questions.js +3 -13
  37. package/lib/release/release.js +16 -55
  38. package/lib/spinner.js +1 -2
  39. package/lib/stencil-bundle.js +19 -78
  40. package/lib/stencil-download.js +5 -6
  41. package/lib/stencil-download.utils.js +5 -18
  42. package/lib/stencil-init.js +8 -24
  43. package/lib/stencil-pull.js +4 -5
  44. package/lib/stencil-pull.utils.js +5 -28
  45. package/lib/stencil-push.js +3 -4
  46. package/lib/stencil-push.utils.js +12 -102
  47. package/lib/stencil-start.js +19 -48
  48. package/lib/store-settings-api-client.js +4 -7
  49. package/lib/template-assembler.js +6 -45
  50. package/lib/theme-api-client.js +7 -30
  51. package/lib/theme-config.js +16 -59
  52. package/lib/utils/NetworkUtils.js +6 -16
  53. package/lib/utils/asyncUtils.js +2 -3
  54. package/lib/utils/frontmatter.js +4 -5
  55. package/lib/utils/fsUtils.js +6 -10
  56. package/lib/validator/schema-translations.js +5 -7
  57. package/package.json +12 -9
  58. package/server/config.js +3 -7
  59. package/server/index.js +29 -29
  60. package/server/lib/page-type-util.js +2 -5
  61. package/server/lib/show-logo.js +3 -3
  62. package/server/lib/utils.js +6 -11
  63. package/server/manifest.js +7 -11
  64. package/server/plugins/renderer/renderer.module.js +38 -100
  65. package/server/plugins/renderer/responses/index.js +7 -4
  66. package/server/plugins/renderer/responses/pencil-response.js +4 -32
  67. package/server/plugins/renderer/responses/raw-response.js +6 -14
  68. package/server/plugins/renderer/responses/redirect-response.js +1 -4
  69. package/server/plugins/router/router.module.js +9 -14
  70. package/server/plugins/theme-assets/theme-assets.module.js +15 -27
  71. package/lib/css-assembler.js +0 -99
@@ -1,15 +1,13 @@
1
- require('colors');
2
- const NetworkUtils = require('./utils/NetworkUtils');
1
+ import 'colors';
2
+ import NetworkUtils from './utils/NetworkUtils.js';
3
3
 
4
4
  const networkUtils = new NetworkUtils();
5
-
6
5
  async function getStoreSettingsLocale({ apiHost, storeHash, accessToken }) {
7
6
  try {
8
7
  const response = await networkUtils.sendApiRequest({
9
8
  url: `${apiHost}/stores/${storeHash}/v3/settings/store/locale`,
10
9
  accessToken,
11
10
  });
12
-
13
11
  if (!response.data.data) {
14
12
  throw new Error('Received empty store locale in the server response'.red);
15
13
  } else if (!response.data.data.default_shopper_language) {
@@ -21,14 +19,13 @@ async function getStoreSettingsLocale({ apiHost, storeHash, accessToken }) {
21
19
  'Received empty shopper_language_selection_method field in the server response'.red,
22
20
  );
23
21
  }
24
-
25
22
  return response.data.data;
26
23
  } catch (err) {
27
24
  err.name = 'StoreSettingsLocaleError';
28
25
  throw err;
29
26
  }
30
27
  }
31
-
32
- module.exports = {
28
+ export { getStoreSettingsLocale };
29
+ export default {
33
30
  getStoreSettingsLocale,
34
31
  };
@@ -1,8 +1,8 @@
1
- const _ = require('lodash');
2
- const async = require('async');
3
- const fs = require('graceful-fs');
4
- const path = require('path');
5
- const upath = require('upath');
1
+ import * as _ from 'lodash-es';
2
+ import async from 'async';
3
+ import fs from 'graceful-fs';
4
+ import path from 'path';
5
+ import upath from 'upath';
6
6
 
7
7
  const partialRegex = /\{\{>\s*([_|\-|a-zA-Z0-9@'"/]+)[^{]*?}}/g;
8
8
  const partialWithoutBracketsRegex = /[^>{{}}\s*]+/g;
@@ -11,7 +11,6 @@ const includeRegex = /{{2}>\s*([_|\-|a-zA-Z0-9/]+)[^{]*?}{2}/g;
11
11
  const pathStringRegex = /^["'].+["']$/;
12
12
  const packageMarker = 'external/';
13
13
  const partialBlock = '@partial-block';
14
-
15
14
  /**
16
15
  * indicates if a template source is a node modules dependency
17
16
  *
@@ -27,14 +26,11 @@ const applyExternalPath = (templateName, templates) => {
27
26
  };
28
27
  const modifyNestedPartial = (partial) => {
29
28
  const partialFragments = partial.match(partialWithoutBracketsRegex);
30
-
31
29
  if (partialFragments) {
32
30
  return [`${partialFragments.shift()}'`, ...partialFragments].join(' ');
33
31
  }
34
-
35
32
  return partialFragments;
36
33
  };
37
-
38
34
  const replacePartialNames = (content, partialRoute) => {
39
35
  return content.replace(
40
36
  includeRegex,
@@ -42,14 +38,12 @@ const replacePartialNames = (content, partialRoute) => {
42
38
  `{{> '${defineBaseRoute(partialRoute)}/${modifyNestedPartial(partialName)} }}`,
43
39
  );
44
40
  };
45
-
46
41
  const trimPartial = (partial) => {
47
42
  if (pathStringRegex.test(partial)) {
48
43
  return partial.slice(1, -1);
49
44
  }
50
45
  return partial;
51
46
  };
52
-
53
47
  /**
54
48
  * Takes a templates folder and template name. It returns simple path for custom template if it's available
55
49
  * or use default folder instead
@@ -60,7 +54,6 @@ const trimPartial = (partial) => {
60
54
  function getCustomPath(templatesFolder, templateName) {
61
55
  let customTemplatesDir;
62
56
  let customTemplateName;
63
-
64
57
  if (templateName.startsWith(packageMarker)) {
65
58
  customTemplatesDir = templatesFolder.replace('templates', 'node_modules');
66
59
  customTemplateName = templateName.slice(packageMarker.length);
@@ -68,10 +61,8 @@ function getCustomPath(templatesFolder, templateName) {
68
61
  customTemplatesDir = templatesFolder;
69
62
  customTemplateName = templateName;
70
63
  }
71
-
72
64
  return path.join(customTemplatesDir, `${customTemplateName}.html`);
73
65
  }
74
-
75
66
  /**
76
67
  * Takes a list of templates and grabs their content. It returns simple key/val pair
77
68
  * of filename => content
@@ -86,24 +77,20 @@ function getContent(templatesFolder, templatePaths, callback) {
86
77
  {},
87
78
  (acc, templatePath, reduceCallback) => {
88
79
  const file = getCustomPath(templatesFolder, templatePath);
89
-
90
80
  fs.readFile(file, { encoding: 'utf-8' }, (err, content) => {
91
81
  if (err) {
92
82
  reduceCallback(err);
93
83
  return;
94
84
  }
95
-
96
85
  acc[templatePath] = templatePath.startsWith(packageMarker)
97
86
  ? replacePartialNames(content, templatePath)
98
87
  : content;
99
-
100
88
  reduceCallback(null, acc);
101
89
  });
102
90
  },
103
91
  callback,
104
92
  );
105
93
  }
106
-
107
94
  /**
108
95
  * Parses the passed in templates and returns all of the partials for each one
109
96
  *
@@ -117,23 +104,18 @@ function getTemplatePaths(templatesFolder, templates, options, callback) {
117
104
  // eslint-disable-next-line no-param-reassign
118
105
  callback = options;
119
106
  }
120
-
121
107
  let templatePaths = [];
122
108
  const missingTemplates = [];
123
-
124
109
  if (!templates) {
125
110
  callback(null);
126
111
  return;
127
112
  }
128
-
129
113
  const normalizedTemplates = Array.isArray(templates) ? templates : [templates];
130
-
131
114
  // eslint-disable-next-line no-use-before-define
132
115
  async.each(normalizedTemplates, resolvePartials, (err) => {
133
116
  if (err) {
134
117
  return callback(err);
135
118
  }
136
-
137
119
  if (missingTemplates.length > 0) {
138
120
  return callback(
139
121
  new Error(
@@ -144,29 +126,22 @@ function getTemplatePaths(templatesFolder, templates, options, callback) {
144
126
  if (options.bundle) {
145
127
  templatePaths = templatePaths.map((ele) => upath.toUnix(ele));
146
128
  }
147
-
148
129
  return callback(null, templatePaths);
149
130
  });
150
-
151
131
  function resolvePartials(t, cb2) {
152
132
  const templateName = trimPartial(t);
153
133
  const templatePath = getCustomPath(templatesFolder, templateName);
154
-
155
134
  fs.readFile(templatePath, { encoding: 'utf-8' }, (err, content) => {
156
135
  const componentPaths = [];
157
136
  let matches = [];
158
-
159
137
  if (err) {
160
138
  missingTemplates.push(templateName);
161
139
  cb2();
162
140
  return;
163
141
  }
164
-
165
142
  templatePaths.push(templateName);
166
-
167
143
  let match = partialRegex.exec(content);
168
144
  let partialPath;
169
-
170
145
  while (match !== null) {
171
146
  [, partialPath] = match;
172
147
  if (!templatePaths.includes(partialPath)) {
@@ -176,16 +151,13 @@ function getTemplatePaths(templatesFolder, templates, options, callback) {
176
151
  }
177
152
  match = partialRegex.exec(content);
178
153
  }
179
-
180
154
  match = dynamicComponentRegex.exec(content);
181
-
182
155
  while (match !== null) {
183
156
  if (componentPaths.indexOf(match[1]) === -1) {
184
157
  componentPaths.push(match[1]);
185
158
  }
186
159
  match = dynamicComponentRegex.exec(content);
187
160
  }
188
-
189
161
  async.each(
190
162
  componentPaths,
191
163
  (componentPath, cb3) => {
@@ -194,7 +166,6 @@ function getTemplatePaths(templatesFolder, templates, options, callback) {
194
166
  cb3(err3);
195
167
  return;
196
168
  }
197
-
198
169
  matches = _.reduce(
199
170
  files,
200
171
  (acc, file) => {
@@ -203,12 +174,10 @@ function getTemplatePaths(templatesFolder, templates, options, callback) {
203
174
  if (templatePaths.indexOf(partialPath) === -1) {
204
175
  acc.push(partialPath);
205
176
  }
206
-
207
177
  return acc;
208
178
  },
209
179
  matches,
210
180
  );
211
-
212
181
  cb3();
213
182
  });
214
183
  },
@@ -217,18 +186,15 @@ function getTemplatePaths(templatesFolder, templates, options, callback) {
217
186
  cb2(err2);
218
187
  return;
219
188
  }
220
-
221
189
  if (isExternalTemplate(templateName)) {
222
190
  matches = applyExternalPath(templateName, matches);
223
191
  }
224
-
225
192
  async.each(matches, resolvePartials, cb2);
226
193
  },
227
194
  );
228
195
  });
229
196
  }
230
197
  }
231
-
232
198
  /**
233
199
  * Parses the passed in templates and resolves all of their partials.
234
200
  *
@@ -242,11 +208,9 @@ function assemble(templatesFolder, templates, callback) {
242
208
  callback(err);
243
209
  return;
244
210
  }
245
-
246
211
  getContent(templatesFolder, templatePaths, callback);
247
212
  });
248
213
  }
249
-
250
214
  /**
251
215
  * Parses the passed in template and resolves all of their partials for bundling
252
216
  * @param templatesFolder
@@ -255,17 +219,14 @@ function assemble(templatesFolder, templates, callback) {
255
219
  */
256
220
  function assembleAndBundle(templatesFolder, templates, callback) {
257
221
  const options = { bundle: true };
258
-
259
222
  getTemplatePaths(templatesFolder, templates, options, (err, templatePaths) => {
260
223
  if (err) {
261
224
  callback(err);
262
225
  return;
263
226
  }
264
-
265
227
  getContent(templatesFolder, templatePaths, callback);
266
228
  });
267
229
  }
268
-
269
230
  /**
270
231
  * Get template content
271
232
  * @param templatesFolder
@@ -276,7 +237,7 @@ function getTemplateContentSync(templatesFolder, templateFile) {
276
237
  return fs.readFileSync(templatePath).toString();
277
238
  }
278
239
 
279
- module.exports = {
240
+ export default {
280
241
  packageMarker,
281
242
  partialRegex,
282
243
  dynamicComponentRegex,
@@ -1,12 +1,11 @@
1
- require('colors');
2
- const fs = require('fs');
3
- const path = require('path');
4
- const FormData = require('form-data');
5
- const NetworkUtils = require('./utils/NetworkUtils');
6
- const { PACKAGE_INFO } = require('../constants');
1
+ import 'colors';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import FormData from 'form-data';
5
+ import NetworkUtils from './utils/NetworkUtils.js';
6
+ import { PACKAGE_INFO } from '../constants.js';
7
7
 
8
8
  const networkUtils = new NetworkUtils();
9
-
10
9
  /**
11
10
  * @param {object} options
12
11
  * @param {string} options.storeUrl
@@ -25,7 +24,6 @@ async function getStoreHash({ storeUrl }) {
25
24
  throw err;
26
25
  }
27
26
  }
28
-
29
27
  /**
30
28
  * @param {object} options
31
29
  * @param {string} options.storeUrl
@@ -35,7 +33,6 @@ async function getStoreHash({ storeUrl }) {
35
33
  async function checkCliVersion({ storeUrl, currentCliVersion = PACKAGE_INFO.version }) {
36
34
  const url = new URL(`/stencil-version-check?v=${currentCliVersion}`, storeUrl).toString();
37
35
  let payload;
38
-
39
36
  try {
40
37
  const response = await networkUtils.sendApiRequest({ url });
41
38
  payload = response.data;
@@ -61,7 +58,6 @@ async function checkCliVersion({ storeUrl, currentCliVersion = PACKAGE_INFO.vers
61
58
  }
62
59
  return payload;
63
60
  }
64
-
65
61
  /**
66
62
  * @param {object} options
67
63
  * @param {string} options.variationId
@@ -103,7 +99,6 @@ async function activateThemeByVariationId({
103
99
  throw err;
104
100
  }
105
101
  }
106
-
107
102
  /**
108
103
  * @param {object} options
109
104
  * @param {string} options.themeId
@@ -119,7 +114,6 @@ async function deleteThemeById({ themeId, accessToken, apiHost, storeHash }) {
119
114
  method: 'DELETE',
120
115
  });
121
116
  }
122
-
123
117
  /**
124
118
  * @param {object} options
125
119
  * @param {string} options.accessToken
@@ -146,7 +140,6 @@ async function getJob({ accessToken, apiHost, storeHash, jobId, resultFilter })
146
140
  err.name = 'JobCompletionStatusCheckError';
147
141
  throw err;
148
142
  }
149
-
150
143
  if (response.status !== 200 || (payload.data && payload.data.status === 'FAILED')) {
151
144
  const error = new Error('Job Failed');
152
145
  error.name = 'JobCompletionStatusCheckError';
@@ -158,10 +151,8 @@ async function getJob({ accessToken, apiHost, storeHash, jobId, resultFilter })
158
151
  error.name = 'JobCompletionStatusCheckPendingError';
159
152
  throw error;
160
153
  }
161
-
162
154
  return resultFilter ? resultFilter(payload.data.result) : payload.data.result;
163
155
  }
164
-
165
156
  /**
166
157
  * @param {object} options
167
158
  * @param {string} options.accessToken
@@ -176,7 +167,6 @@ async function getThemes({ accessToken, apiHost, storeHash }) {
176
167
  });
177
168
  return response.data.data;
178
169
  }
179
-
180
170
  /**
181
171
  * @param {object} options
182
172
  * @param {string} options.accessToken
@@ -198,7 +188,6 @@ async function getChannelActiveTheme({ accessToken, apiHost, storeHash, channelI
198
188
  );
199
189
  }
200
190
  }
201
-
202
191
  /**
203
192
  * @param {object} options
204
193
  * @param {string} options.accessToken
@@ -224,7 +213,6 @@ async function getStoreChannels({ accessToken, apiHost, storeHash }) {
224
213
  );
225
214
  }
226
215
  });
227
-
228
216
  if (channelsResponse) {
229
217
  return sitesResponse.data.data.filter(
230
218
  (site) =>
@@ -232,13 +220,11 @@ async function getStoreChannels({ accessToken, apiHost, storeHash }) {
232
220
  .length > 0,
233
221
  );
234
222
  }
235
-
236
223
  return sitesResponse.data.data;
237
224
  } catch (err) {
238
225
  throw new Error(`Could not fetch a list of the store channels: ${err.message}`);
239
226
  }
240
227
  }
241
-
242
228
  /**
243
229
  * @param {object} options
244
230
  * @param {string} options.accessToken
@@ -271,7 +257,6 @@ async function getThemeConfiguration({
271
257
  throw new Error(`Could not fetch theme configuration: ${err.message}`);
272
258
  }
273
259
  }
274
-
275
260
  /**
276
261
  * @param {object} options
277
262
  * @param {string} options.themeId
@@ -292,7 +277,6 @@ async function getVariationsByThemeId({ accessToken, apiHost, storeHash, themeId
292
277
  throw err;
293
278
  }
294
279
  }
295
-
296
280
  /**
297
281
  * @param {object} options
298
282
  * @param {string} options.bundleZipPath
@@ -307,7 +291,6 @@ async function postTheme({ bundleZipPath, accessToken, apiHost, storeHash, uploa
307
291
  formData.append('file', fs.createReadStream(bundleZipPath), {
308
292
  filename: path.basename(bundleZipPath),
309
293
  });
310
-
311
294
  const response = await networkUtils.sendApiRequest({
312
295
  url: `${apiHost}/stores/${storeHash}/v3/themes`,
313
296
  method: 'POST',
@@ -320,7 +303,6 @@ async function postTheme({ bundleZipPath, accessToken, apiHost, storeHash, uploa
320
303
  validateStatus: () => true, // Wanna handle the statuses manually later
321
304
  });
322
305
  const payload = response.data;
323
-
324
306
  if (response.status === 409) {
325
307
  // This status code is overloaded, so we need to check the message to determine
326
308
  // if we want to trigger the theme deletion flow.
@@ -333,25 +315,20 @@ async function postTheme({ bundleZipPath, accessToken, apiHost, storeHash, uploa
333
315
  ) {
334
316
  return { themeLimitReached: true };
335
317
  }
336
-
337
318
  const message =
338
319
  'You already have a theme upload in progress. You will need to wait for it to finish processing before uploading a new one.';
339
320
  throw new Error((payload && payload.title) || message);
340
321
  }
341
-
342
322
  if (response.status === 413) {
343
323
  const message =
344
324
  'Your theme bundle is too large. Please reduce the size of your assets to bring the zip file size under 50MB.';
345
325
  throw new Error((payload && payload.title) || message);
346
326
  }
347
-
348
327
  if (response.status !== 201) {
349
328
  throw new Error((payload && payload.title) || 'Server Error');
350
329
  }
351
-
352
330
  return { jobId: payload.job_id };
353
331
  }
354
-
355
332
  /**
356
333
  * @param {object} options
357
334
  * @param {string} options.accessToken
@@ -383,7 +360,7 @@ async function downloadTheme({ accessToken, apiHost, storeHash, themeId }) {
383
360
  }
384
361
  }
385
362
 
386
- module.exports = {
363
+ export default {
387
364
  getStoreHash,
388
365
  checkCliVersion,
389
366
  activateThemeByVariationId,