@bigcommerce/stencil-cli 3.6.4 → 3.7.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.
- package/CHANGELOG.md +13 -0
- package/lib/bundle-validator.js +59 -0
- package/lib/lang-helper.js +59 -0
- package/lib/stencil-start.js +61 -2
- package/lib/store-settings-api-client.js +34 -0
- package/lib/utils/frontmatter.js +33 -0
- package/package-lock.json +83 -20
- package/package.json +3 -2
- package/server/index.js +2 -0
- package/server/plugins/renderer/renderer.module.js +22 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
### 3.7.0 (2021-12-08)
|
|
2
|
+
|
|
3
|
+
- fix: strf-9535 Add fallback for shopper language default ([804](https://github.com/bigcommerce/stencil-cli/pull/804))
|
|
4
|
+
- feat: strf-9245 Warn user if shopper default language file is missing or has missing keys ([802](https://github.com/bigcommerce/stencil-cli/pull/802))
|
|
5
|
+
- Bump paper to rc52
|
|
6
|
+
|
|
7
|
+
Note: BREAKING CHANGE!
|
|
8
|
+
In order to get stencil cli working with this version, new Stencil CLI token should be created
|
|
9
|
+
|
|
10
|
+
### 3.6.5 (2021-11-22)
|
|
11
|
+
|
|
12
|
+
- fix: strf-4307 Frontmatter/yaml validation and trailing symbols checks ([798](https://github.com/bigcommerce/stencil-cli/pull/798))
|
|
13
|
+
|
|
1
14
|
### 3.6.4 (2021-11-5)
|
|
2
15
|
|
|
3
16
|
- fix: strf-9474 Removed "git+" prefix from package-lock ([794](https://github.com/bigcommerce/stencil-cli/pull/794))
|
package/lib/bundle-validator.js
CHANGED
|
@@ -6,7 +6,10 @@ const fs = require('fs');
|
|
|
6
6
|
const sizeOf = require('image-size');
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const Validator = require('ajv');
|
|
9
|
+
const yamlValidator = require('js-yaml');
|
|
9
10
|
|
|
11
|
+
const { recursiveReadDir } = require('./utils/fsUtils');
|
|
12
|
+
const { getFrontmatterContent, interpolateThemeSettings } = require('./utils/frontmatter');
|
|
10
13
|
const ValidatorSchemaTranslations = require('./validator/schema-translations');
|
|
11
14
|
const privateThemeConfigValidationSchema = require('./schemas/privateThemeConfig.json');
|
|
12
15
|
const themeConfigValidationSchema = require('./schemas/themeConfig.json');
|
|
@@ -43,6 +46,7 @@ class BundleValidator {
|
|
|
43
46
|
this._validateThemeConfiguration.bind(this),
|
|
44
47
|
this._validateThemeSchema.bind(this),
|
|
45
48
|
this._validateSchemaTranslations.bind(this),
|
|
49
|
+
this._validateTemplatesFrontmatter.bind(this),
|
|
46
50
|
];
|
|
47
51
|
|
|
48
52
|
if (!this.isPrivate) {
|
|
@@ -371,6 +375,61 @@ class BundleValidator {
|
|
|
371
375
|
cb(null, true);
|
|
372
376
|
});
|
|
373
377
|
}
|
|
378
|
+
|
|
379
|
+
async _validateTemplatesFrontmatter() {
|
|
380
|
+
const config = await this.themeConfig.getRawConfig();
|
|
381
|
+
const filePaths = await recursiveReadDir(path.join(this.themePath, 'templates'), [
|
|
382
|
+
'!*.html',
|
|
383
|
+
]);
|
|
384
|
+
|
|
385
|
+
for await (const filePath of filePaths) {
|
|
386
|
+
const fileContent = await fs.promises.readFile(filePath, { encoding: 'utf-8' });
|
|
387
|
+
const frontmatter = getFrontmatterContent(fileContent);
|
|
388
|
+
if (frontmatter) {
|
|
389
|
+
const yaml = interpolateThemeSettings(frontmatter, config.settings);
|
|
390
|
+
|
|
391
|
+
try {
|
|
392
|
+
const result = yamlValidator.loadAll(yaml);
|
|
393
|
+
this.validateTrailingSymbols(result[0]);
|
|
394
|
+
} catch (e) {
|
|
395
|
+
throw new Error(
|
|
396
|
+
`Error: ${e.message}, while parsing frontmatter at "${filePath}".`.red,
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
validateTrailingSymbols(data) {
|
|
406
|
+
if (_.isObject(data)) {
|
|
407
|
+
return _.every(data, (value) => this.validateTrailingSymbols(value));
|
|
408
|
+
}
|
|
409
|
+
if (_.isArray(data)) {
|
|
410
|
+
return data.every((row) => this.validateTrailingSymbols(row));
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return data ? this.hasFrontmatterValidValue(data) : true;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
hasFrontmatterValidValue(value) {
|
|
417
|
+
if (this.hasUnallowedTrailingSymbol(value)) {
|
|
418
|
+
throw new Error(`Found unallowed trailing symbol in: "${value}"`);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
getUnallowedTrailingSymbols() {
|
|
425
|
+
return [',', ';'];
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
hasUnallowedTrailingSymbol(value) {
|
|
429
|
+
const symbols = this.getUnallowedTrailingSymbols();
|
|
430
|
+
const trailingSymbol = value.toString().trim().slice(-1);
|
|
431
|
+
return symbols.includes(trailingSymbol);
|
|
432
|
+
}
|
|
374
433
|
}
|
|
375
434
|
|
|
376
435
|
module.exports = BundleValidator;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require('colors');
|
|
2
|
+
const fsUtilsModule = require('./utils/fsUtils');
|
|
3
|
+
|
|
4
|
+
function flattenObject(object, result = {}, parentKey = '') {
|
|
5
|
+
return Object.entries(object).reduce((currentLayer, [key, innerValue]) => {
|
|
6
|
+
const resultKey = parentKey !== '' ? `${parentKey}.${key}` : key;
|
|
7
|
+
if (typeof innerValue === 'object') {
|
|
8
|
+
return flattenObject(innerValue, currentLayer, resultKey);
|
|
9
|
+
}
|
|
10
|
+
// eslint-disable-next-line no-param-reassign
|
|
11
|
+
currentLayer[resultKey] = innerValue;
|
|
12
|
+
return currentLayer;
|
|
13
|
+
}, result);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class LangHelper {
|
|
17
|
+
constructor({ fsUtils = fsUtilsModule, logger = console } = {}) {
|
|
18
|
+
this._fsUtils = fsUtils;
|
|
19
|
+
this._logger = logger;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async checkLangKeysPresence(filesPaths, themeLang) {
|
|
23
|
+
const themeLangFilename = `${themeLang}.json`;
|
|
24
|
+
const defaultLangFilePath = filesPaths.find((filePath) =>
|
|
25
|
+
filePath.includes(themeLangFilename),
|
|
26
|
+
);
|
|
27
|
+
const defaultLangFile = await this._fsUtils.parseJsonFile(defaultLangFilePath);
|
|
28
|
+
const flattenedDefaultLang = flattenObject(defaultLangFile);
|
|
29
|
+
const alreadyWarnedKey = [];
|
|
30
|
+
|
|
31
|
+
for await (const filePath of filesPaths) {
|
|
32
|
+
if (!filePath.includes(themeLangFilename)) {
|
|
33
|
+
const langFile = await this._fsUtils.parseJsonFile(filePath);
|
|
34
|
+
const flattenedLang = flattenObject(langFile);
|
|
35
|
+
const langKeys = Object.keys(flattenedLang);
|
|
36
|
+
for (const langKey of langKeys) {
|
|
37
|
+
if (!alreadyWarnedKey.includes(langKey)) {
|
|
38
|
+
if (!flattenedDefaultLang[langKey]) {
|
|
39
|
+
this._logger.log(
|
|
40
|
+
`${
|
|
41
|
+
'Warning'.yellow
|
|
42
|
+
}: file: ${defaultLangFilePath} doesn't have ${langKey}, which is present in ${filePath}`,
|
|
43
|
+
);
|
|
44
|
+
} else if (flattenedDefaultLang[langKey].trim().length === 0) {
|
|
45
|
+
this._logger.log(
|
|
46
|
+
`${
|
|
47
|
+
'Warning'.yellow
|
|
48
|
+
}: file: ${defaultLangFilePath} has ${langKey}, but it's empty`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
alreadyWarnedKey.push(langKey);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = LangHelper;
|
package/lib/stencil-start.js
CHANGED
|
@@ -14,11 +14,15 @@ const fsUtilsModule = require('./utils/fsUtils');
|
|
|
14
14
|
const stencilPushUtilsModule = require('./stencil-push.utils');
|
|
15
15
|
const cliCommonModule = require('./cliCommon');
|
|
16
16
|
const themeApiClientModule = require('./theme-api-client');
|
|
17
|
+
const storeSettingsApiClientModule = require('./store-settings-api-client');
|
|
18
|
+
const LangHelper = require('./lang-helper');
|
|
17
19
|
|
|
18
20
|
class StencilStart {
|
|
19
21
|
constructor({
|
|
20
22
|
browserSync = BrowserSync.create(),
|
|
21
23
|
themeApiClient = themeApiClientModule,
|
|
24
|
+
storeSettingsApiClient = storeSettingsApiClientModule,
|
|
25
|
+
langHelper = new LangHelper(),
|
|
22
26
|
fsUtils = fsUtilsModule,
|
|
23
27
|
cliCommon = cliCommonModule,
|
|
24
28
|
stencilConfigManager = new StencilConfigManager(),
|
|
@@ -31,6 +35,8 @@ class StencilStart {
|
|
|
31
35
|
} = {}) {
|
|
32
36
|
this._browserSync = browserSync;
|
|
33
37
|
this._themeApiClient = themeApiClient;
|
|
38
|
+
this._storeSettingsApiClient = storeSettingsApiClient;
|
|
39
|
+
this._langHelper = langHelper;
|
|
34
40
|
this._fsUtils = fsUtils;
|
|
35
41
|
this._cliCommon = cliCommon;
|
|
36
42
|
this._stencilConfigManager = stencilConfigManager;
|
|
@@ -62,6 +68,11 @@ class StencilStart {
|
|
|
62
68
|
storeInfoFromAPI,
|
|
63
69
|
);
|
|
64
70
|
|
|
71
|
+
this._storeSettingsLocale = await this.getStoreSettingsLocale(
|
|
72
|
+
cliOptions,
|
|
73
|
+
updatedStencilConfig,
|
|
74
|
+
);
|
|
75
|
+
|
|
65
76
|
await this.startLocalServer(cliOptions, updatedStencilConfig);
|
|
66
77
|
|
|
67
78
|
this._logger.log(this.getStartUpInfo(updatedStencilConfig));
|
|
@@ -69,14 +80,24 @@ class StencilStart {
|
|
|
69
80
|
await this.startBrowserSync(cliOptions, updatedStencilConfig, browserSyncPort);
|
|
70
81
|
}
|
|
71
82
|
|
|
83
|
+
async getStoreSettingsLocale(cliOptions, stencilConfig) {
|
|
84
|
+
const { accessToken } = stencilConfig;
|
|
85
|
+
const apiHost = cliOptions.apiHost || stencilConfig.apiHost;
|
|
86
|
+
return this._storeSettingsApiClient.getStoreSettingsLocale({
|
|
87
|
+
storeHash: this.storeHash,
|
|
88
|
+
accessToken,
|
|
89
|
+
apiHost,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
72
93
|
async getChannelUrl(stencilConfig, cliOptions) {
|
|
73
94
|
const { accessToken } = stencilConfig;
|
|
74
95
|
const apiHost = cliOptions.apiHost || stencilConfig.apiHost;
|
|
75
|
-
|
|
96
|
+
this.storeHash = await this._themeApiClient.getStoreHash({
|
|
76
97
|
storeUrl: stencilConfig.normalStoreUrl,
|
|
77
98
|
});
|
|
78
99
|
const channels = await this._themeApiClient.getStoreChannels({
|
|
79
|
-
storeHash,
|
|
100
|
+
storeHash: this.storeHash,
|
|
80
101
|
accessToken,
|
|
81
102
|
apiHost,
|
|
82
103
|
});
|
|
@@ -132,6 +153,7 @@ class StencilStart {
|
|
|
132
153
|
useCache: cliOptions.cache,
|
|
133
154
|
themePath: this._themeConfigManager.themePath,
|
|
134
155
|
stencilCliVersion: PACKAGE_INFO.version,
|
|
156
|
+
storeSettingsLocale: this._storeSettingsLocale,
|
|
135
157
|
});
|
|
136
158
|
}
|
|
137
159
|
|
|
@@ -179,6 +201,20 @@ class StencilStart {
|
|
|
179
201
|
}
|
|
180
202
|
});
|
|
181
203
|
|
|
204
|
+
const langsPath = path.join(themePath, 'lang');
|
|
205
|
+
this._browserSync.watch(langsPath, async (event) => {
|
|
206
|
+
try {
|
|
207
|
+
if (event === 'change') {
|
|
208
|
+
await this.checkLangFiles(
|
|
209
|
+
langsPath,
|
|
210
|
+
this._storeSettingsLocale.default_shopper_language,
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
} catch (e) {
|
|
214
|
+
this._logger.error(e);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
182
218
|
// tunnel value should be true/false or a string with name
|
|
183
219
|
// https://browsersync.io/docs/options#option-tunnel
|
|
184
220
|
// convert undefined/true -> false/true
|
|
@@ -215,6 +251,8 @@ class StencilStart {
|
|
|
215
251
|
if (this._buildConfigManager.development) {
|
|
216
252
|
this._buildConfigManager.initWorker().development(this._browserSync);
|
|
217
253
|
}
|
|
254
|
+
|
|
255
|
+
await this.checkLangFiles(langsPath, this._storeSettingsLocale.default_shopper_language);
|
|
218
256
|
}
|
|
219
257
|
|
|
220
258
|
/**
|
|
@@ -236,6 +274,27 @@ class StencilStart {
|
|
|
236
274
|
);
|
|
237
275
|
}
|
|
238
276
|
|
|
277
|
+
async checkLangFiles(langsPath, defaultShopperLanguage) {
|
|
278
|
+
const filesPaths = await this._fsUtils.recursiveReadDir(langsPath);
|
|
279
|
+
const isDefaultLanguagePresent = filesPaths.some((file) =>
|
|
280
|
+
file.includes(defaultShopperLanguage),
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
if (!isDefaultLanguagePresent) {
|
|
284
|
+
this._logger.log(
|
|
285
|
+
`${
|
|
286
|
+
'Warning'.yellow
|
|
287
|
+
}: "missing language file for default shopper language: ${defaultShopperLanguage}"`,
|
|
288
|
+
);
|
|
289
|
+
} else {
|
|
290
|
+
try {
|
|
291
|
+
await this._langHelper.checkLangKeysPresence(filesPaths, defaultShopperLanguage);
|
|
292
|
+
} catch (e) {
|
|
293
|
+
this._logger.error(e);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
239
298
|
/**
|
|
240
299
|
* Displays information about your environment and configuration.
|
|
241
300
|
* @param {Object} stencilConfig
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require('colors');
|
|
2
|
+
const NetworkUtils = require('./utils/NetworkUtils');
|
|
3
|
+
|
|
4
|
+
const networkUtils = new NetworkUtils();
|
|
5
|
+
|
|
6
|
+
async function getStoreSettingsLocale({ apiHost, storeHash, accessToken }) {
|
|
7
|
+
try {
|
|
8
|
+
const response = await networkUtils.sendApiRequest({
|
|
9
|
+
url: `${apiHost}/stores/${storeHash}/v3/settings/store/locale`,
|
|
10
|
+
accessToken,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
if (!response.data.data) {
|
|
14
|
+
throw new Error('Received empty store locale in the server response'.red);
|
|
15
|
+
} else if (!response.data.data.default_shopper_language) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
'Received empty default_shopper_language field in the server response'.red,
|
|
18
|
+
);
|
|
19
|
+
} else if (!response.data.data.shopper_language_selection_method) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
'Received empty shopper_language_selection_method field in the server response'.red,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return response.data.data;
|
|
26
|
+
} catch (err) {
|
|
27
|
+
err.name = 'StoreSettingsLocaleError';
|
|
28
|
+
throw err;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = {
|
|
33
|
+
getStoreSettingsLocale,
|
|
34
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const frontmatterRegex = /---\r?\n(?:.|\s)*?\r?\n---\r?\n/g;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {String} file
|
|
6
|
+
* @returns {String|null}
|
|
7
|
+
*/
|
|
8
|
+
function getFrontmatterContent(file) {
|
|
9
|
+
const frontmatterMatch = file.match(frontmatterRegex);
|
|
10
|
+
return frontmatterMatch !== null ? frontmatterMatch[0] : null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* @param {String} frontmatter
|
|
16
|
+
* @param {Object} settings
|
|
17
|
+
* @returns {String}
|
|
18
|
+
*/
|
|
19
|
+
function interpolateThemeSettings(frontmatter, settings) {
|
|
20
|
+
for (const [key, val] of Object.entries(settings)) {
|
|
21
|
+
const regex = `{{\\s*?theme_settings\\.${key}\\s*?}}`;
|
|
22
|
+
// eslint-disable-next-line no-param-reassign
|
|
23
|
+
frontmatter = frontmatter.replace(new RegExp(regex, 'g'), val);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return frontmatter;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = {
|
|
30
|
+
frontmatterRegex,
|
|
31
|
+
getFrontmatterContent,
|
|
32
|
+
interpolateThemeSettings,
|
|
33
|
+
};
|
package/package-lock.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bigcommerce/stencil-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0",
|
|
4
4
|
"lockfileVersion": 1,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"dependencies": {
|
|
@@ -570,19 +570,19 @@
|
|
|
570
570
|
}
|
|
571
571
|
},
|
|
572
572
|
"@bigcommerce/stencil-paper": {
|
|
573
|
-
"version": "3.0.0-rc.
|
|
574
|
-
"resolved": "https://registry.npmjs.org/@bigcommerce/stencil-paper/-/stencil-paper-3.0.0-rc.
|
|
575
|
-
"integrity": "sha512-
|
|
573
|
+
"version": "3.0.0-rc.52",
|
|
574
|
+
"resolved": "https://registry.npmjs.org/@bigcommerce/stencil-paper/-/stencil-paper-3.0.0-rc.52.tgz",
|
|
575
|
+
"integrity": "sha512-hANH4m0dh9YJuXIlirXj2F9HeWv8k2kJXH1lZkDWx7Ukl0Mn+caibBFprb4Ds+maAc9mHjg9ECUZ5WFT2wBSgA==",
|
|
576
576
|
"requires": {
|
|
577
|
-
"@bigcommerce/stencil-paper-handlebars": "4.5.
|
|
577
|
+
"@bigcommerce/stencil-paper-handlebars": "4.5.1",
|
|
578
578
|
"accept-language-parser": "~1.4.1",
|
|
579
579
|
"messageformat": "~0.2.2"
|
|
580
580
|
}
|
|
581
581
|
},
|
|
582
582
|
"@bigcommerce/stencil-paper-handlebars": {
|
|
583
|
-
"version": "4.5.
|
|
584
|
-
"resolved": "https://registry.npmjs.org/@bigcommerce/stencil-paper-handlebars/-/stencil-paper-handlebars-4.5.
|
|
585
|
-
"integrity": "sha512-
|
|
583
|
+
"version": "4.5.1",
|
|
584
|
+
"resolved": "https://registry.npmjs.org/@bigcommerce/stencil-paper-handlebars/-/stencil-paper-handlebars-4.5.1.tgz",
|
|
585
|
+
"integrity": "sha512-drdYQDXFI8BI/H4/ACmYJUA1QfCbpYVp8MxG/B+JNZypg6UzTnWRJOvCKqohfr9obnLbSdL+nMjVol2cq/RmgQ==",
|
|
586
586
|
"requires": {
|
|
587
587
|
"@bigcommerce/handlebars-v4": "4.7.6",
|
|
588
588
|
"handlebars": "3.0.8",
|
|
@@ -962,6 +962,22 @@
|
|
|
962
962
|
"ms": "2.1.2"
|
|
963
963
|
}
|
|
964
964
|
},
|
|
965
|
+
"esprima": {
|
|
966
|
+
"version": "4.0.1",
|
|
967
|
+
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
|
968
|
+
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
|
969
|
+
"dev": true
|
|
970
|
+
},
|
|
971
|
+
"js-yaml": {
|
|
972
|
+
"version": "3.14.1",
|
|
973
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
|
974
|
+
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
|
975
|
+
"dev": true,
|
|
976
|
+
"requires": {
|
|
977
|
+
"argparse": "^1.0.7",
|
|
978
|
+
"esprima": "^4.0.0"
|
|
979
|
+
}
|
|
980
|
+
},
|
|
965
981
|
"ms": {
|
|
966
982
|
"version": "2.1.2",
|
|
967
983
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
|
@@ -1520,6 +1536,12 @@
|
|
|
1520
1536
|
"resolve-from": "^5.0.0"
|
|
1521
1537
|
},
|
|
1522
1538
|
"dependencies": {
|
|
1539
|
+
"esprima": {
|
|
1540
|
+
"version": "4.0.1",
|
|
1541
|
+
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
|
1542
|
+
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
|
1543
|
+
"dev": true
|
|
1544
|
+
},
|
|
1523
1545
|
"find-up": {
|
|
1524
1546
|
"version": "4.1.0",
|
|
1525
1547
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
|
@@ -1530,6 +1552,16 @@
|
|
|
1530
1552
|
"path-exists": "^4.0.0"
|
|
1531
1553
|
}
|
|
1532
1554
|
},
|
|
1555
|
+
"js-yaml": {
|
|
1556
|
+
"version": "3.14.1",
|
|
1557
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
|
1558
|
+
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
|
1559
|
+
"dev": true,
|
|
1560
|
+
"requires": {
|
|
1561
|
+
"argparse": "^1.0.7",
|
|
1562
|
+
"esprima": "^4.0.0"
|
|
1563
|
+
}
|
|
1564
|
+
},
|
|
1533
1565
|
"locate-path": {
|
|
1534
1566
|
"version": "5.0.0",
|
|
1535
1567
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
|
@@ -6110,6 +6142,22 @@
|
|
|
6110
6142
|
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
|
6111
6143
|
"dev": true
|
|
6112
6144
|
},
|
|
6145
|
+
"esprima": {
|
|
6146
|
+
"version": "4.0.1",
|
|
6147
|
+
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
|
6148
|
+
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
|
6149
|
+
"dev": true
|
|
6150
|
+
},
|
|
6151
|
+
"js-yaml": {
|
|
6152
|
+
"version": "3.14.1",
|
|
6153
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
|
6154
|
+
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
|
6155
|
+
"dev": true,
|
|
6156
|
+
"requires": {
|
|
6157
|
+
"argparse": "^1.0.7",
|
|
6158
|
+
"esprima": "^4.0.0"
|
|
6159
|
+
}
|
|
6160
|
+
},
|
|
6113
6161
|
"ms": {
|
|
6114
6162
|
"version": "2.1.2",
|
|
6115
6163
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
|
@@ -7327,6 +7375,22 @@
|
|
|
7327
7375
|
"integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==",
|
|
7328
7376
|
"requires": {
|
|
7329
7377
|
"js-yaml": "^3.13.1"
|
|
7378
|
+
},
|
|
7379
|
+
"dependencies": {
|
|
7380
|
+
"esprima": {
|
|
7381
|
+
"version": "4.0.1",
|
|
7382
|
+
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
|
7383
|
+
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
|
7384
|
+
},
|
|
7385
|
+
"js-yaml": {
|
|
7386
|
+
"version": "3.14.1",
|
|
7387
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
|
7388
|
+
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
|
7389
|
+
"requires": {
|
|
7390
|
+
"argparse": "^1.0.7",
|
|
7391
|
+
"esprima": "^4.0.0"
|
|
7392
|
+
}
|
|
7393
|
+
}
|
|
7330
7394
|
}
|
|
7331
7395
|
},
|
|
7332
7396
|
"fs-constants": {
|
|
@@ -12174,18 +12238,17 @@
|
|
|
12174
12238
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
|
12175
12239
|
},
|
|
12176
12240
|
"js-yaml": {
|
|
12177
|
-
"version": "
|
|
12178
|
-
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-
|
|
12179
|
-
"integrity": "sha512-
|
|
12241
|
+
"version": "4.1.0",
|
|
12242
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
|
12243
|
+
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
|
12180
12244
|
"requires": {
|
|
12181
|
-
"argparse": "^
|
|
12182
|
-
"esprima": "^4.0.0"
|
|
12245
|
+
"argparse": "^2.0.1"
|
|
12183
12246
|
},
|
|
12184
12247
|
"dependencies": {
|
|
12185
|
-
"
|
|
12186
|
-
"version": "
|
|
12187
|
-
"resolved": "https://registry.npmjs.org/
|
|
12188
|
-
"integrity": "sha512-
|
|
12248
|
+
"argparse": {
|
|
12249
|
+
"version": "2.0.1",
|
|
12250
|
+
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
|
12251
|
+
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
|
12189
12252
|
}
|
|
12190
12253
|
}
|
|
12191
12254
|
},
|
|
@@ -18062,9 +18125,9 @@
|
|
|
18062
18125
|
"integrity": "sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g=="
|
|
18063
18126
|
},
|
|
18064
18127
|
"uglify-js": {
|
|
18065
|
-
"version": "3.14.
|
|
18066
|
-
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.
|
|
18067
|
-
"integrity": "sha512-
|
|
18128
|
+
"version": "3.14.4",
|
|
18129
|
+
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.4.tgz",
|
|
18130
|
+
"integrity": "sha512-AbiSR44J0GoCeV81+oxcy/jDOElO2Bx3d0MfQCUShq7JRXaM4KtQopZsq2vFv8bCq2yMaGrw1FgygUd03RyRDA==",
|
|
18068
18131
|
"optional": true
|
|
18069
18132
|
},
|
|
18070
18133
|
"uglify-to-browserify": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bigcommerce/stencil-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0",
|
|
4
4
|
"description": "CLI tool to run BigCommerce Stores locally for theme development.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"engines": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"package-lock.json"
|
|
45
45
|
],
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@bigcommerce/stencil-paper": "^3.0.0-rc.
|
|
47
|
+
"@bigcommerce/stencil-paper": "^3.0.0-rc.52",
|
|
48
48
|
"@bigcommerce/stencil-styles": "2.1.0",
|
|
49
49
|
"@hapi/boom": "^8.0.1",
|
|
50
50
|
"@hapi/glue": "^6.2.0",
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"graceful-fs": "^4.2.4",
|
|
68
68
|
"image-size": "^0.9.1",
|
|
69
69
|
"inquirer": "^8.1.5",
|
|
70
|
+
"js-yaml": "^4.1.0",
|
|
70
71
|
"lodash": "^4.17.20",
|
|
71
72
|
"memory-cache": "^0.2.0",
|
|
72
73
|
"npm-which": "^3.0.1",
|
package/server/index.js
CHANGED
|
@@ -29,6 +29,8 @@ function buildManifest(srcManifest, options) {
|
|
|
29
29
|
options.dotStencilFile.customLayouts;
|
|
30
30
|
pluginsByName['./plugins/renderer/renderer.module'].themePath = options.themePath;
|
|
31
31
|
pluginsByName['./plugins/renderer/renderer.module'].storeUrl = storeUrl;
|
|
32
|
+
pluginsByName['./plugins/renderer/renderer.module'].storeSettingsLocale =
|
|
33
|
+
options.storeSettingsLocale;
|
|
32
34
|
pluginsByName['./plugins/theme-assets/theme-assets.module'].themePath = options.themePath;
|
|
33
35
|
|
|
34
36
|
resManifest.register.plugins = _.reduce(
|
|
@@ -14,6 +14,11 @@ const { readFromStream } = require('../../../lib/utils/asyncUtils');
|
|
|
14
14
|
const NetworkUtils = require('../../../lib/utils/NetworkUtils');
|
|
15
15
|
const contentApiClient = require('../../../lib/content-api-client');
|
|
16
16
|
const { getPageType } = require('../../lib/page-type-util');
|
|
17
|
+
const {
|
|
18
|
+
frontmatterRegex,
|
|
19
|
+
getFrontmatterContent,
|
|
20
|
+
interpolateThemeSettings,
|
|
21
|
+
} = require('../../../lib/utils/frontmatter');
|
|
17
22
|
|
|
18
23
|
const networkUtils = new NetworkUtils();
|
|
19
24
|
|
|
@@ -262,7 +267,6 @@ internals.parseResponse = async (bcAppData, request, response, responseArgs) =>
|
|
|
262
267
|
* @returns {Object}
|
|
263
268
|
*/
|
|
264
269
|
internals.getResourceConfig = (data, request, configuration) => {
|
|
265
|
-
const frontmatterRegex = /---\r?\n(?:.|\s)*?\r?\n---\r?\n/g;
|
|
266
270
|
const missingThemeSettingsRegex = /{{\\s*?theme_settings\\..+?\\s*?}}/g;
|
|
267
271
|
let resourcesConfig = {};
|
|
268
272
|
const templatePath = data.template_file;
|
|
@@ -276,16 +280,12 @@ internals.getResourceConfig = (data, request, configuration) => {
|
|
|
276
280
|
templatePath,
|
|
277
281
|
);
|
|
278
282
|
|
|
279
|
-
|
|
280
|
-
if (
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
frontmatterContent = frontmatterContent.replace(new RegExp(regex, 'g'), val);
|
|
287
|
-
}
|
|
288
|
-
|
|
283
|
+
let frontmatterContent = getFrontmatterContent(rawTemplate);
|
|
284
|
+
if (frontmatterContent !== null) {
|
|
285
|
+
frontmatterContent = interpolateThemeSettings(
|
|
286
|
+
frontmatterContent,
|
|
287
|
+
configuration.settings,
|
|
288
|
+
);
|
|
289
289
|
// Remove any handlebars tags that weren't interpolated because there was no setting for it
|
|
290
290
|
frontmatterContent = frontmatterContent.replace(missingThemeSettingsRegex, '');
|
|
291
291
|
// Replace the frontmatter with the newly interpolated version
|
|
@@ -364,6 +364,16 @@ internals.getTemplatePath = (requestPath, data) => {
|
|
|
364
364
|
return templatePath || data.template_file;
|
|
365
365
|
};
|
|
366
366
|
|
|
367
|
+
function getAcceptLanguageHeader(request) {
|
|
368
|
+
if (
|
|
369
|
+
internals.options.storeSettingsLocale.shopper_language_selection_method ===
|
|
370
|
+
'default_shopper_language'
|
|
371
|
+
) {
|
|
372
|
+
return internals.options.storeSettingsLocale.default_shopper_language;
|
|
373
|
+
}
|
|
374
|
+
return request.headers['accept-language'];
|
|
375
|
+
}
|
|
376
|
+
|
|
367
377
|
/**
|
|
368
378
|
* Creates a new Pencil Response object and returns it.
|
|
369
379
|
*
|
|
@@ -400,7 +410,7 @@ internals.getPencilResponse = (data, request, response, configuration, renderedR
|
|
|
400
410
|
context,
|
|
401
411
|
translations: data.translations,
|
|
402
412
|
method: request.method,
|
|
403
|
-
acceptLanguage: request
|
|
413
|
+
acceptLanguage: getAcceptLanguageHeader(request),
|
|
404
414
|
headers: response.headers,
|
|
405
415
|
statusCode: response.status,
|
|
406
416
|
},
|