@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,6 +1,5 @@
1
- const _ = require('lodash');
2
- const Paper = require('@bigcommerce/stencil-paper');
3
-
1
+ import { each } from 'lodash-es';
2
+ import Paper from '@bigcommerce/stencil-paper';
4
3
  /**
5
4
  * Escapes html entities
6
5
  *
@@ -13,17 +12,14 @@ const escapeHtml = (html) => {
13
12
  '>': '>',
14
13
  '"': '"',
15
14
  };
16
-
17
15
  return html.replace(/[&<>"]/g, (tag) => charsToReplace[tag] || tag);
18
16
  };
19
-
20
17
  /**
21
18
  * Scape special characters for regular expression
22
19
  *
23
20
  * @param {string} string
24
21
  */
25
22
  const escapeRegex = (string) => string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
26
-
27
23
  /**
28
24
  * Returns template path
29
25
  *
@@ -33,24 +29,18 @@ const escapeRegex = (string) => string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
33
29
  */
34
30
  const getTemplatePath = (request, data) => {
35
31
  let paths = data.template_file;
36
-
37
32
  if (request.headers['stencil-options']) {
38
33
  const options = JSON.parse(request.headers['stencil-options']);
39
-
40
34
  if (options.render_with && typeof options.render_with === 'string') {
41
35
  const componentsToRender = options.render_with.split(',');
42
-
43
36
  paths = componentsToRender.map((component) => `components/${component}`);
44
-
45
37
  if (paths.length === 1) {
46
38
  [paths] = paths;
47
39
  }
48
40
  }
49
41
  }
50
-
51
42
  return paths;
52
43
  };
53
-
54
44
  /**
55
45
  * Returns boolean if this handlebars version is supported
56
46
  *
@@ -58,7 +48,6 @@ const getTemplatePath = (request, data) => {
58
48
  */
59
49
  const isSupportedHandlebarsVersion = (version) =>
60
50
  ['handlebars-v3', 'handlebars-v4'].includes(version);
61
-
62
51
  /**
63
52
  * Node.js projects are using variables in format: handlebars-v3, handlebars-v4;
64
53
  * Storefront and db are using format: handlebars_v3, handlebars_v4;
@@ -67,7 +56,6 @@ const isSupportedHandlebarsVersion = (version) =>
67
56
  * @param {string} version
68
57
  */
69
58
  const compatibilizeTemplateEngine = (version) => version.replace('_', '-');
70
-
71
59
  /**
72
60
  * Output post-processing
73
61
  *
@@ -76,25 +64,20 @@ const compatibilizeTemplateEngine = (version) => version.replace('_', '-');
76
64
  */
77
65
  const makeDecorator = (request, context) => (content) => {
78
66
  let updatedContent = content;
79
-
80
67
  if (context.settings) {
81
68
  const baseUrlregex = new RegExp(escapeRegex(context.settings.base_url), 'g');
82
69
  updatedContent = content.replace(baseUrlregex, '');
83
-
84
70
  const secureBaseUrlRegex = new RegExp(escapeRegex(context.settings.secure_base_url), 'g');
85
71
  updatedContent = content.replace(secureBaseUrlRegex, '');
86
72
  }
87
-
88
73
  if (request.query.debug === 'bar') {
89
74
  const contextStr = escapeHtml(JSON.stringify(context, null, 2));
90
75
  const debugBar = `<pre style="background-color:#EEE; word-wrap:break-word;"> ${contextStr} </pre>`;
91
76
  const bodyRegex = new RegExp('</body>');
92
77
  updatedContent = content.replace(bodyRegex, `${debugBar}\n</body>`);
93
78
  }
94
-
95
79
  return updatedContent;
96
80
  };
97
-
98
81
  class PencilResponse {
99
82
  /**
100
83
  * @param {Object} data
@@ -120,13 +103,11 @@ class PencilResponse {
120
103
  const templateEngine = compatibilizeTemplateEngine(
121
104
  this.data.context.template_engine || 'handlebars-v3',
122
105
  );
123
-
124
106
  if (!isSupportedHandlebarsVersion(templateEngine)) {
125
107
  throw new Error(
126
108
  'Provided Handlebars version is not supported! Please use:handlebars-v3, handlebars-v4',
127
109
  );
128
110
  }
129
-
130
111
  const paper = new Paper(
131
112
  this.data.context.settings,
132
113
  this.data.context.theme_settings,
@@ -136,31 +117,23 @@ class PencilResponse {
136
117
  // Set the environment to dev
137
118
  this.data.context.in_development = true;
138
119
  this.data.context.in_production = false;
139
-
140
120
  paper.addDecorator(makeDecorator(request, this.data.context));
141
121
  paper.setContent(this.data.renderedRegions);
142
-
143
122
  // Plugins have the opportunity to add/modify the response by using decorators
144
- _.each(request.app.decorators, (decorator) => {
123
+ each(request.app.decorators, (decorator) => {
145
124
  paper.addDecorator(decorator);
146
125
  });
147
-
148
126
  const templatePath = getTemplatePath(request, this.data);
149
-
150
127
  if (request.query.debug === 'context') {
151
128
  return this.data.context;
152
129
  }
153
-
154
130
  try {
155
131
  await paper.loadTheme(templatePath, this.data.acceptLanguage);
156
132
  const output = await paper.renderTheme(templatePath, this.data);
157
-
158
133
  const response = h.response(output).code(this.data.statusCode);
159
-
160
134
  if (this.data.headers['set-cookie']) {
161
135
  response.header('set-cookie', this.data.headers['set-cookie']);
162
136
  }
163
-
164
137
  return response;
165
138
  } catch (err) {
166
139
  console.error(err.message.red);
@@ -168,5 +141,4 @@ class PencilResponse {
168
141
  }
169
142
  }
170
143
  }
171
-
172
- module.exports = PencilResponse;
144
+ export default PencilResponse;
@@ -1,11 +1,10 @@
1
- const cheerio = require('cheerio');
2
- const utils = require('../../../lib/utils');
1
+ import * as cheerio from 'cheerio';
2
+ import { int2uuid } from '../../../lib/utils.js';
3
3
 
4
4
  const internals = {
5
- stubActiveVersion: utils.int2uuid(1),
6
- stubActiveConfig: utils.int2uuid(1),
5
+ stubActiveVersion: int2uuid(1),
6
+ stubActiveConfig: int2uuid(1),
7
7
  };
8
-
9
8
  class RawResponse {
10
9
  /**
11
10
  * @param {buffer} data
@@ -21,15 +20,13 @@ class RawResponse {
21
20
 
22
21
  respond(request, h) {
23
22
  let payload = this.data;
24
- internals.stubActiveConfig = utils.int2uuid(request.app.themeConfig.variationIndex + 1);
25
-
23
+ internals.stubActiveConfig = int2uuid(request.app.themeConfig.variationIndex + 1);
26
24
  if (
27
25
  request.path.startsWith('/checkout.php') ||
28
26
  request.path.startsWith('/finishorder.php')
29
27
  ) {
30
28
  payload = this._appendCss(payload.toString('utf8'));
31
29
  }
32
-
33
30
  // To be removed when we go to Phase 3
34
31
  if (request.path.startsWith('/checkout')) {
35
32
  payload = payload
@@ -39,9 +36,7 @@ class RawResponse {
39
36
  `/stencil/${internals.stubActiveVersion}/${internals.stubActiveConfig}/css/optimized-checkout.css`,
40
37
  );
41
38
  }
42
-
43
39
  const response = h.response(payload).code(this.statusCode);
44
-
45
40
  for (const [name, values] of Object.entries(this.headers)) {
46
41
  switch (name) {
47
42
  case 'transfer-encoding':
@@ -56,7 +51,6 @@ class RawResponse {
56
51
  response.header(name, values.toString());
57
52
  }
58
53
  }
59
-
60
54
  return response;
61
55
  }
62
56
 
@@ -69,10 +63,8 @@ class RawResponse {
69
63
  _appendCss(payload) {
70
64
  const dom = cheerio.load(payload);
71
65
  const url = `/stencil/${internals.stubActiveVersion}/${internals.stubActiveConfig}/css/checkout.css`;
72
-
73
66
  dom('head').append(`<link href="${url}" type="text/css" rel="stylesheet">`);
74
67
  return dom.html();
75
68
  }
76
69
  }
77
-
78
- module.exports = RawResponse;
70
+ export default RawResponse;
@@ -12,7 +12,6 @@ class RedirectResponse {
12
12
 
13
13
  respond(request, h) {
14
14
  const response = h.redirect(this.location).code(this.statusCode);
15
-
16
15
  for (const [name, values] of Object.entries(this.headers)) {
17
16
  switch (name) {
18
17
  case 'transfer-encoding':
@@ -34,9 +33,7 @@ class RedirectResponse {
34
33
  response.header(name, values.toString());
35
34
  }
36
35
  }
37
-
38
36
  return response;
39
37
  }
40
38
  }
41
-
42
- module.exports = RedirectResponse;
39
+ export default RedirectResponse;
@@ -1,5 +1,5 @@
1
- const _ = require('lodash');
2
- const ThemeConfig = require('../../../lib/theme-config');
1
+ import { defaultsDeep } from 'lodash-es';
2
+ import ThemeConfig from '../../../lib/theme-config.js';
3
3
 
4
4
  const internals = {
5
5
  options: {
@@ -19,7 +19,6 @@ const internals = {
19
19
  graphQL: '/graphql',
20
20
  },
21
21
  };
22
-
23
22
  function mapUri(req) {
24
23
  const host = `https://${internals.options.storeUrl.replace(/http[s]?:\/\//, '')}`;
25
24
  const urlParams = req.url.search || '';
@@ -28,28 +27,22 @@ function mapUri(req) {
28
27
  'stencil-cli': internals.options.stencilCliVersion,
29
28
  'x-auth-token': internals.options.accessToken,
30
29
  };
31
-
32
30
  return { uri, headers };
33
31
  }
34
-
35
32
  function register(server, options) {
36
- internals.options = _.defaultsDeep(options, internals.options);
37
-
33
+ internals.options = defaultsDeep(options, internals.options);
38
34
  server.ext('onRequest', (request, h) => {
39
35
  request.app.storeUrl = internals.options.storeUrl;
40
36
  request.app.normalStoreUrl = internals.options.normalStoreUrl;
41
37
  request.app.apiKey = internals.options.apiKey;
42
38
  request.app.themeConfig = ThemeConfig.getInstance();
43
-
44
39
  return h.continue;
45
40
  });
46
-
47
41
  server.dependency(
48
42
  ['@hapi/inert', '@hapi/h2o2', 'Renderer', 'ThemeAssets'],
49
43
  internals.registerRoutes,
50
44
  );
51
45
  }
52
-
53
46
  internals.registerRoutes = (server) => {
54
47
  server.route([
55
48
  {
@@ -188,9 +181,11 @@ internals.registerRoutes = (server) => {
188
181
  },
189
182
  ]);
190
183
  };
191
-
192
- module.exports = {
184
+ export const name = 'Router';
185
+ export const version = '0.0.1';
186
+ export { register };
187
+ export default {
193
188
  register,
194
- name: 'Router',
195
- version: '0.0.1',
189
+ name,
190
+ version,
196
191
  };
@@ -1,42 +1,35 @@
1
- const _ = require('lodash');
2
- const Boom = require('@hapi/boom');
3
- const path = require('path');
4
- const utils = require('../../lib/utils');
5
- const cssCompiler = require('../../../lib/css/compile');
1
+ import { defaultsDeep } from 'lodash-es';
2
+ import * as Boom from '@hapi/boom';
3
+ import path from 'path';
4
+ import { uuidRegExp, uuid2int } from '../../lib/utils.js';
5
+ import cssCompiler from '../../../lib/css/compile.js';
6
6
 
7
7
  const internals = {
8
8
  options: {},
9
9
  };
10
-
11
10
  function register(server, options) {
12
- internals.options = _.defaultsDeep(options, internals.options);
13
-
11
+ internals.options = defaultsDeep(options, internals.options);
14
12
  server.expose('cssHandler', internals.cssHandler);
15
13
  server.expose('assetHandler', internals.assetHandler);
16
14
  }
17
-
18
15
  /**
19
16
  * Get the variation index from the "ConfigId" in the css filename
20
17
  * @param {string} fileName
21
18
  * @returns {number}
22
19
  */
23
20
  internals.getVariationIndex = (fileName) => {
24
- const match = fileName.match(new RegExp(`.+-(${utils.uuidRegExp})$`));
25
-
26
- return match ? utils.uuid2int(match[1]) - 1 : 0;
21
+ const match = fileName.match(new RegExp(`.+-(${uuidRegExp})$`));
22
+ return match ? uuid2int(match[1]) - 1 : 0;
27
23
  };
28
-
29
24
  /**
30
25
  * Get the original css file name
31
26
  * @param {string} fileName
32
27
  * @returns {string}
33
28
  */
34
29
  internals.getOriginalFileName = (fileName) => {
35
- const match = fileName.match(new RegExp(`(.+)-${utils.uuidRegExp}$`));
36
-
30
+ const match = fileName.match(new RegExp(`(.+)-${uuidRegExp}$`));
37
31
  return match ? match[1] : fileName;
38
32
  };
39
-
40
33
  /**
41
34
  * CSS Compiler Handler. This utilises the CSS Assembler to gather all of the CSS files and then the
42
35
  * StencilStyles plugin to compile them all.
@@ -46,19 +39,15 @@ internals.getOriginalFileName = (fileName) => {
46
39
  internals.cssHandler = async (request, h) => {
47
40
  const variationIndex = internals.getVariationIndex(request.params.fileName);
48
41
  const variationExists = await request.app.themeConfig.variationExists(variationIndex);
49
-
50
42
  if (!variationExists) {
51
43
  throw Boom.notFound(`Variation ${variationIndex + 1} does not exist.`);
52
44
  }
53
-
54
45
  // Set the variation to get the right theme configuration
55
46
  request.app.themeConfig.setVariation(variationIndex);
56
-
57
47
  // Get the theme configuration
58
48
  const configuration = await request.app.themeConfig.getConfig();
59
49
  const fileName = internals.getOriginalFileName(request.params.fileName);
60
50
  const themeAssetsPath = internals.getThemeAssetsPath();
61
-
62
51
  try {
63
52
  const css = await cssCompiler.compile(configuration, themeAssetsPath, fileName);
64
53
  return h.response(css).type('text/css');
@@ -67,7 +56,6 @@ internals.cssHandler = async (request, h) => {
67
56
  throw Boom.badData(err);
68
57
  }
69
58
  };
70
-
71
59
  /**
72
60
  * Assets handler
73
61
  *
@@ -76,16 +64,16 @@ internals.cssHandler = async (request, h) => {
76
64
  */
77
65
  internals.assetHandler = (request, h) => {
78
66
  const filePath = path.join(internals.getThemeAssetsPath(), request.params.fileName);
79
-
80
67
  return h.file(filePath);
81
68
  };
82
-
83
69
  internals.getThemeAssetsPath = () => {
84
70
  return path.join(internals.options.themePath, 'assets');
85
71
  };
86
-
87
- module.exports = {
72
+ export const name = 'ThemeAssets';
73
+ export const version = '0.0.1';
74
+ export { register };
75
+ export default {
88
76
  register,
89
- name: 'ThemeAssets',
90
- version: '0.0.1',
77
+ name,
78
+ version,
91
79
  };
@@ -1,99 +0,0 @@
1
- const async = require('async');
2
- const fs = require('fs');
3
- const path = require('path');
4
- const upath = require('upath');
5
-
6
- const importRegex = /@import\s+?["'](.+?)["'];/g;
7
-
8
- /**
9
- * Parses all of the imports for SCSS files and returns a flat object with the file path as the key and
10
- * file content as the value.
11
- *
12
- * @param cssFiles
13
- * @param absolutePath
14
- * @param type - scss
15
- * @param options - options object
16
- * @param callback
17
- */
18
- function assemble(cssFiles, absolutePath, type, options, callback) {
19
- const ret = {};
20
- const ext = `.${type}`;
21
-
22
- const cssFilesArr = Array.isArray(cssFiles) ? cssFiles : [cssFiles];
23
-
24
- const parseImports = (cssFileAlias, parseImportsCallback) => {
25
- const normalizedCssFileAlias = cssFileAlias.replace(/(\.scss)$/g, '');
26
- const typedCssFilePath = path.join(absolutePath, normalizedCssFileAlias + ext);
27
- const rawCssFilePath = path.join(absolutePath, normalizedCssFileAlias + '.css');
28
- const cssFileAliasDir = path.parse(normalizedCssFileAlias).dir;
29
-
30
- const fileParts = path.parse(typedCssFilePath);
31
- const underscoredFilePath = path.join(fileParts.dir, `_${fileParts.base}`);
32
- let filePath;
33
-
34
- if (fs.existsSync(typedCssFilePath)) {
35
- filePath = typedCssFilePath;
36
- } else if (fs.existsSync(underscoredFilePath)) {
37
- filePath = underscoredFilePath;
38
- } else if (ext === '.scss' && fs.existsSync(rawCssFilePath)) {
39
- filePath = rawCssFilePath;
40
- } else {
41
- // File doesn't exist, just return to skip it
42
- parseImportsCallback();
43
- return;
44
- }
45
-
46
- fs.readFile(filePath, { encoding: 'utf-8' }, (err, content) => {
47
- const matches = [];
48
- let match;
49
- let importCssFileAlias;
50
-
51
- if (!err) {
52
- // Ensure all import paths are Unix paths for prod compat.
53
- const cssFile = options.bundle
54
- ? upath.toUnix(normalizedCssFileAlias + ext)
55
- : normalizedCssFileAlias + ext;
56
-
57
- ret[cssFile] = content;
58
- match = importRegex.exec(content);
59
-
60
- while (match !== null) {
61
- [, importCssFileAlias] = match;
62
- if (cssFileAliasDir) {
63
- importCssFileAlias = path.join(cssFileAliasDir, importCssFileAlias);
64
- }
65
-
66
- if (!ret[importCssFileAlias + ext]) {
67
- matches.push(importCssFileAlias);
68
- }
69
-
70
- match = importRegex.exec(content);
71
- }
72
- }
73
-
74
- async.each(matches, parseImports, parseImportsCallback);
75
- });
76
- };
77
-
78
- async.map(
79
- cssFilesArr,
80
- (cssFile, mapCallback) => {
81
- const cssFileParts = path.parse(cssFile);
82
- const cssFileAlias = path.join(cssFileParts.dir, cssFileParts.name);
83
-
84
- parseImports(cssFileAlias, mapCallback);
85
- },
86
- (err) => {
87
- if (err) {
88
- callback(err);
89
- return;
90
- }
91
-
92
- callback(null, ret);
93
- },
94
- );
95
- }
96
-
97
- module.exports = {
98
- assemble,
99
- };