@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/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
+ };