@bigcommerce/stencil-cli 8.3.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 (70) 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 +3 -6
  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 +15 -75
  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 +11 -8
  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
@@ -1,9 +1,8 @@
1
- require('colors');
2
- const fsModule = require('fs');
3
- const path = require('path');
4
-
5
- const fsUtilsModule = require('./utils/fsUtils');
6
- const { THEME_PATH, API_HOST } = require('../constants');
1
+ import 'colors';
2
+ import fsModule from 'fs';
3
+ import path from 'path';
4
+ import fsUtilsModule from './utils/fsUtils.js';
5
+ import { THEME_PATH, API_HOST } from '../constants.js';
7
6
 
8
7
  class StencilConfigManager {
9
8
  constructor({
@@ -15,13 +14,11 @@ class StencilConfigManager {
15
14
  this.oldConfigFileName = '.stencil';
16
15
  this.configFileName = 'config.stencil.json';
17
16
  this.secretsFileName = 'secrets.stencil.json';
18
-
19
17
  this.themePath = themePath;
20
18
  this.oldConfigPath = path.join(themePath, this.oldConfigFileName);
21
19
  this.configPath = path.join(themePath, this.configFileName);
22
20
  this.secretsPath = path.join(themePath, this.secretsFileName);
23
21
  this.secretFieldsSet = new Set(['accessToken', 'githubToken']);
24
-
25
22
  this._fs = fs;
26
23
  this._fsUtils = fsUtils;
27
24
  this._logger = logger;
@@ -46,21 +43,17 @@ class StencilConfigManager {
46
43
  await this._migrateOldConfig(parsedConfig);
47
44
  return this._validateStencilConfig(parsedConfig, ignoreMissingFields);
48
45
  }
49
-
50
46
  const generalConfig = this._fs.existsSync(this.configPath)
51
47
  ? await this._fsUtils.parseJsonFile(this.configPath)
52
48
  : null;
53
49
  const secretsConfig = await this._getSecretsConfig(generalConfig);
54
-
55
50
  if (generalConfig || secretsConfig) {
56
51
  const parsedConfig = { ...generalConfig, ...secretsConfig };
57
52
  return this._validateStencilConfig(parsedConfig, ignoreMissingFields);
58
53
  }
59
-
60
54
  if (ignoreFileNotExists) {
61
55
  return null;
62
56
  }
63
-
64
57
  throw new Error('Please run'.red + ' $ stencil init'.cyan + ' first.'.red);
65
58
  }
66
59
 
@@ -69,7 +62,6 @@ class StencilConfigManager {
69
62
  */
70
63
  async save(config) {
71
64
  const { generalConfig, secretsConfig } = this._splitStencilConfig(config);
72
-
73
65
  await this._fs.promises.writeFile(this.configPath, JSON.stringify(generalConfig, null, 2));
74
66
  await this._fs.promises.writeFile(this.secretsPath, JSON.stringify(secretsConfig, null, 2));
75
67
  }
@@ -100,12 +92,10 @@ class StencilConfigManager {
100
92
  async _getSecretsConfig(generalConfig) {
101
93
  if (generalConfig && generalConfig.secretsFileName) {
102
94
  const secretsPath = path.join(this.themePath, generalConfig.secretsFileName);
103
-
104
95
  if (this._fs.existsSync(secretsPath)) {
105
96
  return this._fsUtils.parseJsonFile(secretsPath);
106
97
  }
107
98
  }
108
-
109
99
  return this._fs.existsSync(this.secretsPath)
110
100
  ? this._fsUtils.parseJsonFile(this.secretsPath)
111
101
  : null;
@@ -119,7 +109,6 @@ class StencilConfigManager {
119
109
  */
120
110
  _validateStencilConfig(configFile, ignoreMissingFields) {
121
111
  const config = configFile;
122
-
123
112
  if (!ignoreMissingFields && (!config.normalStoreUrl || !config.customLayouts)) {
124
113
  throw new Error(
125
114
  'Error: Your stencil config is outdated. Please run'.red +
@@ -127,13 +116,11 @@ class StencilConfigManager {
127
116
  ' again.'.red,
128
117
  );
129
118
  }
130
-
131
119
  if (!config.apiHost) {
132
120
  config.apiHost = API_HOST;
133
121
  } else {
134
122
  this._logger.log(`API host set in config file: ${config.apiHost}`);
135
123
  }
136
-
137
124
  return config;
138
125
  }
139
126
 
@@ -146,10 +133,8 @@ class StencilConfigManager {
146
133
  `Detected a deprecated ${this.oldConfigFileName.cyan} file.\n` +
147
134
  `It will be replaced with ${this.configFileName.cyan} and ${this.secretsFileName.cyan}\n`,
148
135
  );
149
-
150
136
  await this.save(config);
151
137
  await this._fs.promises.unlink(this.oldConfigPath);
152
-
153
138
  this._logger.log(
154
139
  `The deprecated ${this.oldConfigFileName.cyan} file was successfully replaced.\n` +
155
140
  `Make sure to add ${this.secretsFileName.cyan} to .gitignore.\n` +
@@ -157,5 +142,4 @@ class StencilConfigManager {
157
142
  );
158
143
  }
159
144
  }
160
-
161
- module.exports = StencilConfigManager;
145
+ export default StencilConfigManager;
@@ -1,10 +1,9 @@
1
- const fsModule = require('fs');
2
- const path = require('path');
3
- const osModule = require('os');
4
-
5
- const { PACKAGE_INFO, THEME_PATH } = require('../constants');
6
- const ThemeConfig = require('./theme-config');
7
- const StencilConfigManager = require('./StencilConfigManager');
1
+ import fsModule from 'fs';
2
+ import path from 'path';
3
+ import osModule from 'os';
4
+ import { PACKAGE_INFO, THEME_PATH } from '../constants.js';
5
+ import ThemeConfig from './theme-config.js';
6
+ import StencilConfigManager from './StencilConfigManager.js';
8
7
 
9
8
  class StencilDebug {
10
9
  constructor({
@@ -55,7 +54,6 @@ class StencilDebug {
55
54
 
56
55
  async getThemeInfo() {
57
56
  this.checkExecutableLocation(this._themeConfig);
58
-
59
57
  const rawConfig = await this._themeConfig.getRawConfig();
60
58
  const {
61
59
  name,
@@ -109,5 +107,4 @@ class StencilDebug {
109
107
  }
110
108
  }
111
109
  }
112
-
113
- module.exports = StencilDebug;
110
+ export default StencilDebug;
@@ -1,15 +1,10 @@
1
- /**
2
- * @module Contains functions for working with archives
3
- */
4
-
5
- const yauzl = require('yauzl');
6
- const fs = require('fs');
7
- const path = require('path');
8
- const { promisify } = require('util');
9
- const stream = require('stream');
1
+ import yauzl from 'yauzl';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { promisify } from 'util';
5
+ import stream from 'stream';
10
6
 
11
7
  const pipeline = promisify(stream.pipeline);
12
-
13
8
  /**
14
9
  * @param {object} options
15
10
  * @param {string} options.zipPath
@@ -20,9 +15,7 @@ const pipeline = promisify(stream.pipeline);
20
15
  */
21
16
  async function extractZipFiles({ zipPath, fileToExtract, exclude = [], outputNames = {} }) {
22
17
  let foundMatch = false;
23
-
24
18
  const zipFile = await promisify(yauzl.open)(zipPath, { lazyEntries: true });
25
-
26
19
  await new Promise((resolve, reject) => {
27
20
  zipFile.on('entry', async (entry) => {
28
21
  try {
@@ -33,50 +26,41 @@ async function extractZipFiles({ zipPath, fileToExtract, exclude = [], outputNam
33
26
  exclude.length &&
34
27
  // startsWith used to exclude files from the specified directories
35
28
  exclude.some((excludeItem) => entry.fileName.startsWith(excludeItem));
36
-
37
29
  if (isDirectory || isNotTheSearchedFile || isExcluded) {
38
30
  zipFile.readEntry();
39
31
  return;
40
32
  }
41
-
42
33
  const outputFilePath = outputNames[entry.fileName] || entry.fileName;
43
34
  const outputDir = path.parse(outputFilePath).dir;
44
35
  // Create a directory if the parent directory does not exists
45
36
  if (outputDir && !fs.existsSync(outputDir)) {
46
37
  await fs.promises.mkdir(outputDir, { recursive: true });
47
38
  }
48
-
49
39
  const readableStream = await promisify(zipFile.openReadStream.bind(zipFile))(entry);
50
40
  const writeStream = fs.createWriteStream(outputFilePath, { flag: 'w+' });
51
41
  await pipeline(readableStream, writeStream);
52
-
53
42
  if (foundMatch) {
54
43
  zipFile.close();
55
44
  resolve();
56
45
  return;
57
46
  }
58
-
59
47
  zipFile.readEntry();
60
48
  } catch (err) {
61
49
  reject(err);
62
50
  }
63
51
  });
64
-
65
52
  zipFile.readEntry();
66
-
67
53
  zipFile.once('end', () => {
68
54
  zipFile.close();
69
-
70
55
  if (!foundMatch && fileToExtract) {
71
56
  reject(new Error(`${fileToExtract} not found`));
72
57
  return;
73
58
  }
74
-
75
59
  resolve();
76
60
  });
77
61
  });
78
62
  }
79
-
80
- module.exports = {
63
+ export { extractZipFiles };
64
+ export default {
81
65
  extractZipFiles,
82
66
  };
@@ -1,21 +1,17 @@
1
- require('colors');
2
- const os = require('os');
3
- const _ = require('lodash');
4
- const async = require('async');
5
- const fs = require('fs');
6
- const sizeOf = require('image-size');
7
- const path = require('path');
8
- const Validator = require('ajv');
9
- const yamlValidator = require('js-yaml');
10
-
11
- const { recursiveReadDir } = require('./utils/fsUtils');
12
- const { getFrontmatterContent, interpolateThemeSettings } = require('./utils/frontmatter');
13
- const ValidatorSchemaTranslations = require('./validator/schema-translations');
14
- const privateThemeConfigValidationSchema = require('./schemas/privateThemeConfig.json');
15
- const themeConfigValidationSchema = require('./schemas/themeConfig.json');
16
- const themeValidationSchema = require('./schemas/themeSchema.json');
17
- const ScssValidator = require('./ScssValidator');
18
- const LangHelpersValidator = require('./lang/validator');
1
+ import 'colors';
2
+ import os from 'os';
3
+ import { isObject, isArray, difference, uniq, flatten, every } from 'lodash-es';
4
+ import async from 'async';
5
+ import fs from 'fs';
6
+ import sizeOf from 'image-size';
7
+ import path from 'path';
8
+ import Validator from 'ajv';
9
+ import yamlValidator from 'js-yaml';
10
+ import { recursiveReadDir } from './utils/fsUtils.js';
11
+ import { getFrontmatterContent, interpolateThemeSettings } from './utils/frontmatter.js';
12
+ import ValidatorSchemaTranslations from './validator/schema-translations.js';
13
+ import ScssValidator from './ScssValidator.js';
14
+ import LangHelpersValidator from './lang/validator.js';
19
15
 
20
16
  const VALID_IMAGE_TYPES = ['.jpg', '.jpeg', '.png', '.gif'];
21
17
  const WIDTH_COMPOSED = 600;
@@ -28,6 +24,15 @@ const MAX_SIZE_COMPOSED = 1024 * 1024 * 2; // 2MB
28
24
  const MAX_SIZE_MOBILE = 1024 * 1024; // 1MB
29
25
  const MAX_SIZE_DESKTOP = 1024 * 1024 * 5; // 5MB
30
26
 
27
+ const privateThemeConfigUrl = new URL('./schemas/privateThemeConfig.json', import.meta.url);
28
+ const privateThemeConfigValidationSchema = JSON.parse(fs.readFileSync(privateThemeConfigUrl));
29
+
30
+ const themeConfigValidationSchemaUrl = new URL('./schemas/themeConfig.json', import.meta.url);
31
+ const themeConfigValidationSchema = JSON.parse(fs.readFileSync(themeConfigValidationSchemaUrl));
32
+
33
+ const themeValidationSchemaUrl = new URL('./schemas/themeSchema.json', import.meta.url);
34
+ const themeValidationSchema = JSON.parse(fs.readFileSync(themeValidationSchemaUrl));
35
+
31
36
  class BundleValidator {
32
37
  /**
33
38
  * Run some validations to ensure that the platform will accept the theme
@@ -44,7 +49,6 @@ class BundleValidator {
44
49
  this.jsonSchemaValidatorOptions = { schemaId: 'auto', allErrors: true };
45
50
  this.scssValidator = new ScssValidator(themePath, themeConfig);
46
51
  this.langHelpersValidator = new LangHelpersValidator(themePath, themeConfig);
47
-
48
52
  // Array of tasks used in async.series
49
53
  this.validationTasks = [
50
54
  this._validateThemeConfiguration.bind(this),
@@ -54,7 +58,6 @@ class BundleValidator {
54
58
  this._validateCssFiles.bind(this),
55
59
  this._validateLangFiles.bind(this),
56
60
  ];
57
-
58
61
  if (!this.isPrivate) {
59
62
  this.validationTasks.push(this._validateMetaImages.bind(this));
60
63
  }
@@ -87,10 +90,8 @@ class BundleValidator {
87
90
  new RegExp(`{+\\s*${element}\\s*}+`),
88
91
  ) !== -1,
89
92
  );
90
-
91
93
  validated.push(...matches);
92
94
  }
93
-
94
95
  cb(null, validated);
95
96
  },
96
97
  (err, validationRes) => {
@@ -98,18 +99,13 @@ class BundleValidator {
98
99
  callback(err);
99
100
  return;
100
101
  }
101
-
102
- const results = _.difference(
103
- this.objectsToValidate,
104
- _.uniq(_.flatten(validationRes)),
105
- );
102
+ const results = difference(this.objectsToValidate, uniq(flatten(validationRes)));
106
103
  if (results.length !== 0) {
107
104
  callback(
108
105
  new Error(`Missing required objects/properties: ${results.join('\n')}`),
109
106
  );
110
107
  return;
111
108
  }
112
-
113
109
  callback(null, !!results);
114
110
  },
115
111
  );
@@ -134,7 +130,6 @@ class BundleValidator {
134
130
  const rawSchema = await this.themeConfig.getRawSchema();
135
131
  this._validateJsonSchema('schema', themeValidationSchema, rawSchema);
136
132
  }
137
-
138
133
  return true;
139
134
  }
140
135
 
@@ -151,17 +146,14 @@ class BundleValidator {
151
146
  ' file in your top level theme directory.';
152
147
  throw new Error(errMsg);
153
148
  }
154
-
155
149
  if (!this.isPrivate && !this.themeConfig.schemaExists()) {
156
150
  console.log("Warning: Your theme is missing a 'schema.json' file.".orange);
157
151
  }
158
-
159
152
  // Validate against the theme registry config schema
160
153
  const validationSchema = this.isPrivate
161
154
  ? privateThemeConfigValidationSchema
162
155
  : themeConfigValidationSchema;
163
156
  const rawConfig = await this.themeConfig.getRawConfig();
164
-
165
157
  return this._validateJsonSchema('config', validationSchema, rawConfig);
166
158
  }
167
159
 
@@ -175,7 +167,6 @@ class BundleValidator {
175
167
  _validateJsonSchema(type, schema, data) {
176
168
  const validator = new Validator(this.jsonSchemaValidatorOptions);
177
169
  validator.validate(schema, data);
178
-
179
170
  if (validator.errors && validator.errors.length > 0) {
180
171
  let errorMessage = `Your theme's ${type}.json has errors:`;
181
172
  for (const error of validator.errors) {
@@ -183,7 +174,6 @@ class BundleValidator {
183
174
  }
184
175
  throw new Error(errorMessage.red);
185
176
  }
186
-
187
177
  return true;
188
178
  }
189
179
 
@@ -195,11 +185,9 @@ class BundleValidator {
195
185
  async _validateSchemaTranslations() {
196
186
  const validatorSchemaTranslations = new ValidatorSchemaTranslations();
197
187
  const validator = new Validator(this.jsonSchemaValidatorOptions);
198
-
199
188
  if (this.themeConfig.schemaExists()) {
200
189
  validatorSchemaTranslations.setSchema(await this.themeConfig.getRawSchema());
201
190
  }
202
-
203
191
  if (this.themeConfig.schemaTranslationsExists()) {
204
192
  try {
205
193
  const rawSchemaTranslations = await this.themeConfig.getRawSchemaTranslations();
@@ -210,38 +198,31 @@ class BundleValidator {
210
198
  } else if (validatorSchemaTranslations.getSchemaKeys().length) {
211
199
  throw new Error('Missed schemaTranslations.json file'.red);
212
200
  }
213
-
214
201
  const missedKeys = validatorSchemaTranslations.findMissedKeys();
215
202
  const unusedKeys = validatorSchemaTranslations.findUnusedKeys();
216
203
  validator.validate(
217
204
  validatorSchemaTranslations.getValidationSchema(),
218
205
  validatorSchemaTranslations.getTranslations(),
219
206
  );
220
-
221
207
  if (
222
208
  (validator.errors && validator.errors.length) ||
223
209
  missedKeys.length ||
224
210
  unusedKeys.length
225
211
  ) {
226
212
  let errorMessage = "Your theme's schemaTranslations.json has errors:";
227
-
228
213
  missedKeys.forEach((key) => {
229
214
  errorMessage += `\r\nmissing translation key "${key}"`;
230
215
  });
231
-
232
216
  unusedKeys.forEach((key) => {
233
217
  errorMessage += `\r\nunused translation key "${key}"`;
234
218
  });
235
-
236
219
  if (validator.errors && validator.errors.length) {
237
220
  validator.errors.forEach((error) => {
238
221
  errorMessage += `\r\nschemaTranslations${error.message}`;
239
222
  });
240
223
  }
241
-
242
224
  throw new Error(errorMessage.red);
243
225
  }
244
-
245
226
  return true;
246
227
  }
247
228
 
@@ -254,7 +235,6 @@ class BundleValidator {
254
235
  const { meta, variations } = await this.themeConfig.getConfig();
255
236
  const composedImagePath = path.resolve(this.themePath, 'meta', meta.composed_image);
256
237
  const imageTasks = [];
257
-
258
238
  if (!this._isValidImageType(composedImagePath)) {
259
239
  throw new Error(
260
240
  'Invalid file type for "meta.composed_image".'.red +
@@ -269,16 +249,13 @@ class BundleValidator {
269
249
  imageTasks.push((cb) =>
270
250
  this._validateImage(composedImagePath, WIDTH_COMPOSED, HEIGHT_COMPOSED, cb),
271
251
  );
272
-
273
252
  for (const variation of variations) {
274
253
  const id = variation.id.blue;
275
-
276
254
  const desktopScreenshotPath = path.resolve(
277
255
  this.themePath,
278
256
  'meta',
279
257
  variation.meta.desktop_screenshot,
280
258
  );
281
-
282
259
  if (!this._isValidImageType(desktopScreenshotPath)) {
283
260
  throw new Error(
284
261
  `Invalid file type for ${id} variation's "desktop_screenshot".`.red +
@@ -293,13 +270,11 @@ class BundleValidator {
293
270
  imageTasks.push((cb) =>
294
271
  this._validateImage(desktopScreenshotPath, WIDTH_DESKTOP, HEIGHT_DESKTOP, cb),
295
272
  );
296
-
297
273
  const mobileScreenshotPath = path.resolve(
298
274
  this.themePath,
299
275
  'meta',
300
276
  variation.meta.mobile_screenshot,
301
277
  );
302
-
303
278
  if (!this._isValidImageType(mobileScreenshotPath)) {
304
279
  throw new Error(
305
280
  `Invalid file type for ${id} variation's "mobile_screenshot".`.red +
@@ -315,7 +290,6 @@ class BundleValidator {
315
290
  this._validateImage(mobileScreenshotPath, WIDTH_MOBILE, HEIGHT_MOBILE, cb),
316
291
  );
317
292
  }
318
-
319
293
  return async.parallel(imageTasks);
320
294
  }
321
295
 
@@ -342,12 +316,10 @@ class BundleValidator {
342
316
  cb(err);
343
317
  return;
344
318
  }
345
-
346
319
  let failureMessage = '';
347
320
  const imageHeight = dimensions.height;
348
321
  const imageWidth = dimensions.width;
349
322
  const { size } = fs.statSync(imagePath);
350
-
351
323
  if (width === WIDTH_DESKTOP && height === HEIGHT_DESKTOP && size > MAX_SIZE_DESKTOP) {
352
324
  failureMessage =
353
325
  `Image of size ${size} bytes at path (${imagePath}) ` +
@@ -369,7 +341,6 @@ class BundleValidator {
369
341
  `Image of size ${size} bytes at path (${imagePath}) ` +
370
342
  `is greater than allowed size ${MAX_SIZE_MOBILE}\n`;
371
343
  }
372
-
373
344
  if (imageWidth !== width || imageHeight !== height) {
374
345
  failureMessage +=
375
346
  `Image at (${imagePath}) has incorrect dimensions (${imageWidth}x${imageHeight}) should be` +
@@ -377,7 +348,6 @@ class BundleValidator {
377
348
  cb(new Error(failureMessage));
378
349
  return;
379
350
  }
380
-
381
351
  cb(null, true);
382
352
  });
383
353
  }
@@ -387,13 +357,11 @@ class BundleValidator {
387
357
  const filePaths = await recursiveReadDir(path.join(this.themePath, 'templates'), [
388
358
  '!*.html',
389
359
  ]);
390
-
391
360
  for await (const filePath of filePaths) {
392
361
  const fileContent = await fs.promises.readFile(filePath, { encoding: 'utf-8' });
393
362
  const frontmatter = getFrontmatterContent(fileContent);
394
363
  if (frontmatter) {
395
364
  const yaml = interpolateThemeSettings(frontmatter, config.settings);
396
-
397
365
  try {
398
366
  const result = yamlValidator.loadAll(yaml);
399
367
  this.validateTrailingSymbols(result[0]);
@@ -404,7 +372,6 @@ class BundleValidator {
404
372
  }
405
373
  }
406
374
  }
407
-
408
375
  return true;
409
376
  }
410
377
 
@@ -417,13 +384,12 @@ class BundleValidator {
417
384
  }
418
385
 
419
386
  validateTrailingSymbols(data) {
420
- if (_.isObject(data)) {
421
- return _.every(data, (value) => this.validateTrailingSymbols(value));
387
+ if (isObject(data)) {
388
+ return every(data, (value) => this.validateTrailingSymbols(value));
422
389
  }
423
- if (_.isArray(data)) {
390
+ if (isArray(data)) {
424
391
  return data.every((row) => this.validateTrailingSymbols(row));
425
392
  }
426
-
427
393
  return data ? this.hasFrontmatterValidValue(data) : true;
428
394
  }
429
395
 
@@ -431,7 +397,6 @@ class BundleValidator {
431
397
  if (this.hasUnallowedTrailingSymbol(value)) {
432
398
  throw new Error(`Found unallowed trailing symbol in: "${value}"`);
433
399
  }
434
-
435
400
  return true;
436
401
  }
437
402
 
@@ -445,5 +410,4 @@ class BundleValidator {
445
410
  return symbols.includes(trailingSymbol);
446
411
  }
447
412
  }
448
-
449
- module.exports = BundleValidator;
413
+ export default BundleValidator;
package/lib/cliCommon.js CHANGED
@@ -1,6 +1,6 @@
1
- const semver = require('semver');
2
- const { PACKAGE_INFO } = require('../constants');
3
- const stencilCLISettings = require('./StencilCLISettings');
1
+ import semver from 'semver';
2
+ import { PACKAGE_INFO } from '../constants.js';
3
+ import stencilCLISettings from './StencilCLISettings.js';
4
4
 
5
5
  const messages = {
6
6
  visitTroubleshootingPage:
@@ -8,7 +8,6 @@ const messages = {
8
8
  submitGithubIssue:
9
9
  'If this error persists, please visit https://github.com/bigcommerce/stencil-cli/issues and submit an issue.',
10
10
  };
11
-
12
11
  /**
13
12
  * @param {Object} object
14
13
 
@@ -19,13 +18,13 @@ function printObject(object) {
19
18
  console.log(`${property}: ${object[property]}`);
20
19
  }
21
20
  }
22
-
23
21
  /**
24
22
  * @param {Error} error
25
23
 
26
24
  * @returns {void}
27
25
  */
28
26
  function printNetworkError(config) {
27
+ console.log(config);
29
28
  console.log(`URL: `.yellow + config.url);
30
29
  console.log(`Method: `.yellow + config.method.toUpperCase());
31
30
  if (config.data) {
@@ -33,7 +32,6 @@ function printNetworkError(config) {
33
32
  printObject(config.data);
34
33
  }
35
34
  }
36
-
37
35
  /**
38
36
  * @param {Error} error
39
37
  * @param {Array<{message: string}>} [error.messages]
@@ -41,7 +39,6 @@ function printNetworkError(config) {
41
39
  */
42
40
  function printCliResultError(error) {
43
41
  console.error(`\n\n${'not ok'.red} -- ${error || 'Unknown error'}\n`);
44
-
45
42
  if (error && Array.isArray(error.messages)) {
46
43
  for (const item of error.messages) {
47
44
  if (item && item.message) {
@@ -49,41 +46,34 @@ function printCliResultError(error) {
49
46
  }
50
47
  }
51
48
  }
52
-
53
49
  if (error && (error.config || error.response)) {
54
50
  // In case if request didn't receive any response, response object is not available
55
51
  const networkReq = error.config || error.response;
56
52
  printNetworkError(networkReq);
57
53
  }
58
-
59
54
  console.log(messages.visitTroubleshootingPage);
60
-
61
55
  console.log(messages.submitGithubIssue);
62
56
  }
63
-
64
57
  /**
65
58
  * @param {Error} error
66
59
  * @returns {void}
67
60
  */
68
61
  function printCliResultErrorAndExit(error) {
62
+ console.log(error);
69
63
  printCliResultError(error);
70
64
  // Exit with error code so automated systems recognize it as a failure
71
65
  // eslint-disable-next-line no-process-exit
72
66
  process.exit(1);
73
67
  }
74
-
75
68
  function checkNodeVersion() {
76
69
  const satisfies = semver.satisfies(process.versions.node, PACKAGE_INFO.engines.node);
77
-
78
70
  if (!satisfies) {
79
71
  throw new Error(
80
72
  `You are running an unsupported version of node. Please upgrade to ${PACKAGE_INFO.engines.node}`,
81
73
  );
82
74
  }
83
-
84
75
  return satisfies;
85
76
  }
86
-
87
77
  function applyCommonOptions(program) {
88
78
  program
89
79
  .option('-h, --host [hostname]', 'specify the api host')
@@ -95,22 +85,22 @@ function applyCommonOptions(program) {
95
85
  )
96
86
  .parse(process.argv);
97
87
  }
98
-
99
88
  function setupCLI(options) {
100
89
  stencilCLISettings.setVerbose(options.verbose);
101
90
  }
102
-
103
91
  function prepareCommand(program) {
104
92
  applyCommonOptions(program);
105
93
  checkNodeVersion();
106
-
107
94
  const options = program.opts();
108
95
  setupCLI(options);
109
-
110
96
  return options;
111
97
  }
112
-
113
- module.exports = {
98
+ export { messages };
99
+ export { printCliResultError };
100
+ export { printCliResultErrorAndExit };
101
+ export { checkNodeVersion };
102
+ export { prepareCommand };
103
+ export default {
114
104
  messages,
115
105
  printCliResultError,
116
106
  printCliResultErrorAndExit,
package/lib/commander.js CHANGED
@@ -1,8 +1,7 @@
1
- const program = require('commander');
1
+ import program from 'commander';
2
2
 
3
3
  program
4
4
  // Avoid option name clashes https://www.npmjs.com/package/commander#avoiding-option-name-clashes
5
5
  .storeOptionsAsProperties(false)
6
6
  .passCommandToAction(false);
7
-
8
- module.exports = program;
7
+ export default program;