@nuskin/contentstack-lib 1.0.0-pur-1208.2
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/.eslintrc.json +30 -0
- package/.gitlab-ci.yml +10 -0
- package/.releaserc +27 -0
- package/.vscode/launch.json +50 -0
- package/CHANGELOG.md +0 -0
- package/README.md +77 -0
- package/__tests__/api.spec.js +155 -0
- package/__tests__/resources/checkoutAdrStrings.json +57 -0
- package/__tests__/resources/checkoutCartStrings.json +40 -0
- package/__tests__/resources/getStringsMergedResult.json +60 -0
- package/__tests__/resources/getStringsResult.json +75 -0
- package/__tests__/resources/singleCheckoutAdrStrings.json +55 -0
- package/__tests__/resources/singleCheckoutAdrStringsCamel.json +55 -0
- package/__tests__/resources/singleCheckoutAdrStringsCommon.json +55 -0
- package/__tests__/resources/singleCheckoutCartStrings.json +36 -0
- package/__tests__/resources/singleCheckoutCartStringsCamel.json +36 -0
- package/config/dev.json +6 -0
- package/config/prod.json +6 -0
- package/config/stage.json +6 -0
- package/config/test.json +6 -0
- package/docs/CHANGELOG.md +1 -0
- package/gl-sbom-npm-yarn.cdx.json +10278 -0
- package/jest.config.js +16 -0
- package/package.json +35 -0
- package/src/api.js +181 -0
- package/src/index.js +13 -0
package/jest.config.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
transform: {
|
|
3
|
+
"^.+\\.(js|jsx)?$": "babel-jest"
|
|
4
|
+
},
|
|
5
|
+
testURL: "http://localhost/",
|
|
6
|
+
collectCoverage: true,
|
|
7
|
+
collectCoverageFrom: ["src/*.js"],
|
|
8
|
+
coveragePathIgnorePatterns: [
|
|
9
|
+
"/node_modules/",
|
|
10
|
+
"package.json",
|
|
11
|
+
"package-lock.json",
|
|
12
|
+
"index.js"
|
|
13
|
+
],
|
|
14
|
+
testResultsProcessor: "jest-sonar-reporter",
|
|
15
|
+
coverageReporters: ["html", "lcov", "text-summary"]
|
|
16
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nuskin/contentstack-lib",
|
|
3
|
+
"version": "1.0.0-pur-1208.2",
|
|
4
|
+
"description": "This project contains configuration and api code to access Contentstack, to be shared between the backend (AWS Lambda) and frontend (Vue, etc).",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "jest --coverage",
|
|
8
|
+
"lint": "eslint src __tests__"
|
|
9
|
+
},
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git@code.tls.nuskin.io:ns-am/utility/npm/contentstack-lib.git"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [],
|
|
18
|
+
"author": "Treg Anderson <tsanderson@nuskin.com>",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"homepage": "https://code.tls.nuskin.io/ns-am/utility/npm/contentstack-lib/blob/master/README.md",
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"eslint": "5.16.0",
|
|
23
|
+
"eslint-config-google": "0.14.0",
|
|
24
|
+
"eslint-config-prettier": "4.1.0",
|
|
25
|
+
"eslint-plugin-json": "2.1.1",
|
|
26
|
+
"eslint-plugin-prettier": "3.1.2",
|
|
27
|
+
"jest": "25.1.0",
|
|
28
|
+
"jest-sonar-reporter": "2.0.0",
|
|
29
|
+
"prettier": "1.19.1"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"axios": "1.7.7",
|
|
33
|
+
"contentstack": "^3.16.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/api.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const Contentstack = require('contentstack');
|
|
4
|
+
let env = null;
|
|
5
|
+
let Stack = null;
|
|
6
|
+
|
|
7
|
+
let api_key;
|
|
8
|
+
let delivery_token;
|
|
9
|
+
let environment;
|
|
10
|
+
|
|
11
|
+
const COMMON_LANGUAGES = {
|
|
12
|
+
'da': 'da-dk',
|
|
13
|
+
'id': 'id-id',
|
|
14
|
+
'hu': 'hu-hu',
|
|
15
|
+
'ro': 'ro-ro',
|
|
16
|
+
'tk': 'tk-tk',
|
|
17
|
+
'pl': 'pl-pl',
|
|
18
|
+
'sk': 'sk-sk',
|
|
19
|
+
'th': 'th-th',
|
|
20
|
+
'uk': 'uk-ua',
|
|
21
|
+
'tr': 'tr-tr'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Convert string from snake case to camel case
|
|
26
|
+
* @param {string} snakeCasedString
|
|
27
|
+
* @returns {string} camelCaseString
|
|
28
|
+
* @private
|
|
29
|
+
*/
|
|
30
|
+
function _snakeToCamel(s) {
|
|
31
|
+
return s.replace(/(_\w)/g, k => k[1].toUpperCase());
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Convert object with snake case properties to camel case
|
|
36
|
+
* @param {*} obj - object to convert
|
|
37
|
+
* @returns {*} camelCasedObject
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
function _snakeObjectToCamel(obj) {
|
|
41
|
+
// If obj is falsy or not an object, return it unchanged
|
|
42
|
+
if (!obj || typeof obj !== 'object') return obj;
|
|
43
|
+
|
|
44
|
+
if (Array.isArray(obj)) {
|
|
45
|
+
// obj is array; recurse into its children
|
|
46
|
+
return obj.map(_snakeObjectToCamel);
|
|
47
|
+
} else {
|
|
48
|
+
// obj is object; convert its keys and recurse into its values
|
|
49
|
+
const camelKeyedFields = Object.entries(obj).map(([k, v]) => [
|
|
50
|
+
_snakeToCamel(k),
|
|
51
|
+
_snakeObjectToCamel(v)
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
return Object.fromEntries(camelKeyedFields);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get the environment from the url if we are running in a browser
|
|
60
|
+
* @return {string} environment
|
|
61
|
+
* @private
|
|
62
|
+
*/
|
|
63
|
+
function _getEnv() {
|
|
64
|
+
return (window.location.hostname.includes('dev') || window.location.hostname.includes('localhost')) ? 'dev' :
|
|
65
|
+
window.location.hostname.includes('test') ? 'test' :
|
|
66
|
+
window.location.hostname.includes('stage') ? 'stage' : 'prod';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Get entries for a list of content types.
|
|
71
|
+
* @param {string[]} contentTypeUIDs
|
|
72
|
+
* @param {string} locale
|
|
73
|
+
* @param {boolean=} camelcase
|
|
74
|
+
* @returns {Promise<*>}
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
async function _getSingletonEntries(contentTypeUIDs, locale, camelcase) {
|
|
78
|
+
const promises = contentTypeUIDs.map(uid => {
|
|
79
|
+
return Stack
|
|
80
|
+
.ContentType(uid)
|
|
81
|
+
.Query()
|
|
82
|
+
.language(locale)
|
|
83
|
+
.includeFallback()
|
|
84
|
+
.toJSON()
|
|
85
|
+
.findOne();
|
|
86
|
+
});
|
|
87
|
+
// Make calls simultaneously but if any fail allow the other calls to finish
|
|
88
|
+
const result = await Promise.allSettled(promises);
|
|
89
|
+
// If there is an error getting the strings from CS value will be null, then return an empty {}
|
|
90
|
+
return result.map(r => {
|
|
91
|
+
const val = r.value || {};
|
|
92
|
+
return camelcase ? _snakeObjectToCamel(val) : val;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Merges the strings for the locale US-en with the fallback strings en
|
|
98
|
+
* @param {Object[]} fallbackStrings
|
|
99
|
+
* @param {Object[]} localeStrings
|
|
100
|
+
* @return {Promise<Object[]>}
|
|
101
|
+
* @private
|
|
102
|
+
*/
|
|
103
|
+
async function _mergeFallbackStrings(fallbackStrings, localeStrings) {
|
|
104
|
+
// loop through all the results and merge strings
|
|
105
|
+
return fallbackStrings.map((strings, index) => {
|
|
106
|
+
return {...strings, ...localeStrings[index]};
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get entries for a list of content types. The content types must be of type single.
|
|
112
|
+
* Entries are returned in the order they were requested
|
|
113
|
+
* This function is useful for getting a list of strings from multiple content types at once.
|
|
114
|
+
*
|
|
115
|
+
* @param {string[]} options.contentTypeUIDs - list of content types that contains the strings for your application
|
|
116
|
+
* @param {string} options.language - language you want to get the translations for
|
|
117
|
+
* @param {string=} options.country
|
|
118
|
+
* @param {boolean=} options.mergeWithFallback - merges string results of Ex: US-en with en
|
|
119
|
+
* @param {boolean=} options.camelcase
|
|
120
|
+
* @returns {Promise<Object[]>} The entries are returned in the order they were requested
|
|
121
|
+
*/
|
|
122
|
+
async function getSingletonEntries(options) {
|
|
123
|
+
const {contentTypeUIDs, language, country, camelcase, mergeWithFallback} = options;
|
|
124
|
+
if (!contentTypeUIDs || !contentTypeUIDs.length || !language) {
|
|
125
|
+
throw new Error('Call to getSingletonEntries: options.contentTypeUIDs and language are required');
|
|
126
|
+
}
|
|
127
|
+
const mappedLanguage = language === 'in' ? 'id' : language;
|
|
128
|
+
const commonLocale = COMMON_LANGUAGES[mappedLanguage] || mappedLanguage;
|
|
129
|
+
const locale = country ? `${country}-${mappedLanguage}` : commonLocale;
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
// If we don't have a country or we aren't merging with fallback then there is nothing to merge
|
|
133
|
+
return (!mergeWithFallback || !country) ?
|
|
134
|
+
await _getSingletonEntries(contentTypeUIDs, locale, camelcase) :
|
|
135
|
+
_mergeFallbackStrings(
|
|
136
|
+
await _getSingletonEntries(contentTypeUIDs, commonLocale, camelcase), // get fallback strings Ex: en
|
|
137
|
+
await _getSingletonEntries(contentTypeUIDs, locale, camelcase) // get locale strings for Ex: US-en
|
|
138
|
+
);
|
|
139
|
+
} catch (e) {
|
|
140
|
+
console.error(e);
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Returns contentstack Stack object initialized with the api key, deliveryToken, and extended with custom functionality
|
|
147
|
+
* @param {'dev' | 'test' | 'stage' | 'prod'} environment
|
|
148
|
+
* @return {Object} Stack - contentstack Stack sdk object with additional getStrings function
|
|
149
|
+
*/
|
|
150
|
+
function getStack() {
|
|
151
|
+
if (!environment) {
|
|
152
|
+
if (!window || !window.location) {
|
|
153
|
+
throw new Error('Environment must be passed into getStack');
|
|
154
|
+
}
|
|
155
|
+
environment = _getEnv();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// If the environment requested hasn't changed return the stack we already have
|
|
159
|
+
if (environment === env && Stack) {
|
|
160
|
+
return Stack;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
env = environment;
|
|
164
|
+
Stack = Contentstack.Stack({api_key, delivery_token, environment})
|
|
165
|
+
|
|
166
|
+
// extend the Stack with a custom function to get translations
|
|
167
|
+
Stack.getSingletonEntries = getSingletonEntries;
|
|
168
|
+
|
|
169
|
+
return Stack;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function init({env, apiKey, deliveryToken}) {
|
|
173
|
+
environment = env;
|
|
174
|
+
api_key = apiKey;
|
|
175
|
+
delivery_token = deliveryToken;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
module.exports = {
|
|
179
|
+
init,
|
|
180
|
+
getStack
|
|
181
|
+
};
|
package/src/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WARNING: The use of `require` and `module.exports` is because this package has to remain
|
|
3
|
+
* in CommonJS format. Do not change ANY files here to ES6 standards or it will break usages.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
const {getStack, init} = require("./api.js");
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
init,
|
|
12
|
+
getStack
|
|
13
|
+
};
|