@splitsoftware/splitio-commons 1.5.1-rc.1 → 1.6.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/CHANGES.txt +5 -2
- package/cjs/integrations/ga/GaToSplit.js +12 -11
- package/esm/integrations/ga/GaToSplit.js +12 -11
- package/package.json +1 -5
- package/src/integrations/ga/GaToSplit.ts +14 -8
- package/src/integrations/ga/autoRequire.js +33 -0
- package/src/integrations/ga/types.ts +13 -2
- package/types/integrations/ga/types.d.ts +13 -2
- package/cjs/sync/offline/LocalhostFromFile.js +0 -13
- package/cjs/sync/offline/splitsParser/splitsParserFromFile.js +0 -151
- package/esm/sync/offline/LocalhostFromFile.js +0 -9
- package/esm/sync/offline/splitsParser/splitsParserFromFile.js +0 -146
- package/src/sync/offline/LocalhostFromFile.ts +0 -12
- package/src/sync/offline/splitsParser/splitsParserFromFile.ts +0 -182
package/CHANGES.txt
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
1.
|
|
2
|
-
-
|
|
1
|
+
1.6.0 (July 21, 2022)
|
|
2
|
+
- Added `autoRequire` configuration option to the Google Analytics to Split integration, which takes care of requiring the splitTracker plugin on trackers dynamically created by Google tag managers (See https://help.split.io/hc/en-us/articles/360040838752#set-up-with-gtm-and-gtag.js).
|
|
3
|
+
- Updated browser listener to push remaining impressions and events on 'visibilitychange' and 'pagehide' DOM events, instead of 'unload', which is not reliable in modern mobile and desktop Web browsers.
|
|
4
|
+
- Updated the synchronization flow to be more reliable in the event of an edge case generating delay in cache purge propagation, keeping the SDK cache properly synced.
|
|
5
|
+
- Bugfixing - Removed js-yaml dependency to avoid resolution to an incompatible version on certain npm versions when installing third-party dependencies that also define js-yaml as transitive dependency (Related to issue https://github.com/splitio/javascript-client/issues/662).
|
|
3
6
|
|
|
4
7
|
1.5.0 (June 29, 2022)
|
|
5
8
|
- Added a new config option to control the tasks that listen or poll for updates on feature flags and segments, via the new config sync.enabled . Running online Split will always pull the most recent updates upon initialization, this only affects updates fetching on a running instance. Useful when a consistent session experience is a must or to save resources when updates are not being used.
|
|
@@ -10,23 +10,24 @@ var logNameMapper = 'ga-to-split:mapper';
|
|
|
10
10
|
/**
|
|
11
11
|
* Provides a plugin to use with analytics.js, accounting for the possibility
|
|
12
12
|
* that the global command queue has been renamed or not yet defined.
|
|
13
|
-
* @param
|
|
14
|
-
* @param
|
|
13
|
+
* @param window Reference to global object.
|
|
14
|
+
* @param pluginName The plugin name identifier.
|
|
15
|
+
* @param pluginConstructor The plugin constructor function.
|
|
16
|
+
* @param log Logger instance.
|
|
17
|
+
* @param autoRequire If true, log error when auto-require script is not detected
|
|
15
18
|
*/
|
|
16
|
-
function providePlugin(pluginName, pluginConstructor) {
|
|
19
|
+
function providePlugin(window, pluginName, pluginConstructor, log, autoRequire) {
|
|
17
20
|
// get reference to global command queue. Init it if not defined yet.
|
|
18
|
-
// @ts-expect-error
|
|
19
21
|
var gaAlias = window.GoogleAnalyticsObject || 'ga';
|
|
20
22
|
window[gaAlias] = window[gaAlias] || function () {
|
|
21
|
-
|
|
22
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
23
|
-
args[_i] = arguments[_i];
|
|
24
|
-
}
|
|
25
|
-
(window[gaAlias].q = window[gaAlias].q || []).push(args);
|
|
23
|
+
(window[gaAlias].q = window[gaAlias].q || []).push(arguments);
|
|
26
24
|
};
|
|
27
25
|
// provides the plugin for use with analytics.js.
|
|
28
|
-
// @ts-expect-error
|
|
29
26
|
window[gaAlias]('provide', pluginName, pluginConstructor);
|
|
27
|
+
if (autoRequire && (!window[gaAlias].q || window[gaAlias].q.push === [].push)) {
|
|
28
|
+
// Expecting spy on ga.q push method but not found
|
|
29
|
+
log.error(logPrefix + 'integration is configured to autorequire the splitTracker plugin, but the necessary script does not seem to have run. Please check the docs.');
|
|
30
|
+
}
|
|
30
31
|
}
|
|
31
32
|
// Default mapping: object used for building the default mapper from hits to Split events
|
|
32
33
|
var defaultMapping = {
|
|
@@ -246,6 +247,6 @@ function GaToSplit(sdkOptions, params) {
|
|
|
246
247
|
return SplitTracker;
|
|
247
248
|
}());
|
|
248
249
|
// Register the plugin, even if config is invalid, since, if not provided, it will block `ga` command queue.
|
|
249
|
-
providePlugin('splitTracker', SplitTracker);
|
|
250
|
+
providePlugin(window, 'splitTracker', SplitTracker, log, sdkOptions.autoRequire);
|
|
250
251
|
}
|
|
251
252
|
exports.GaToSplit = GaToSplit;
|
|
@@ -7,23 +7,24 @@ var logNameMapper = 'ga-to-split:mapper';
|
|
|
7
7
|
/**
|
|
8
8
|
* Provides a plugin to use with analytics.js, accounting for the possibility
|
|
9
9
|
* that the global command queue has been renamed or not yet defined.
|
|
10
|
-
* @param
|
|
11
|
-
* @param
|
|
10
|
+
* @param window Reference to global object.
|
|
11
|
+
* @param pluginName The plugin name identifier.
|
|
12
|
+
* @param pluginConstructor The plugin constructor function.
|
|
13
|
+
* @param log Logger instance.
|
|
14
|
+
* @param autoRequire If true, log error when auto-require script is not detected
|
|
12
15
|
*/
|
|
13
|
-
function providePlugin(pluginName, pluginConstructor) {
|
|
16
|
+
function providePlugin(window, pluginName, pluginConstructor, log, autoRequire) {
|
|
14
17
|
// get reference to global command queue. Init it if not defined yet.
|
|
15
|
-
// @ts-expect-error
|
|
16
18
|
var gaAlias = window.GoogleAnalyticsObject || 'ga';
|
|
17
19
|
window[gaAlias] = window[gaAlias] || function () {
|
|
18
|
-
|
|
19
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
20
|
-
args[_i] = arguments[_i];
|
|
21
|
-
}
|
|
22
|
-
(window[gaAlias].q = window[gaAlias].q || []).push(args);
|
|
20
|
+
(window[gaAlias].q = window[gaAlias].q || []).push(arguments);
|
|
23
21
|
};
|
|
24
22
|
// provides the plugin for use with analytics.js.
|
|
25
|
-
// @ts-expect-error
|
|
26
23
|
window[gaAlias]('provide', pluginName, pluginConstructor);
|
|
24
|
+
if (autoRequire && (!window[gaAlias].q || window[gaAlias].q.push === [].push)) {
|
|
25
|
+
// Expecting spy on ga.q push method but not found
|
|
26
|
+
log.error(logPrefix + 'integration is configured to autorequire the splitTracker plugin, but the necessary script does not seem to have run. Please check the docs.');
|
|
27
|
+
}
|
|
27
28
|
}
|
|
28
29
|
// Default mapping: object used for building the default mapper from hits to Split events
|
|
29
30
|
var defaultMapping = {
|
|
@@ -240,5 +241,5 @@ export function GaToSplit(sdkOptions, params) {
|
|
|
240
241
|
return SplitTracker;
|
|
241
242
|
}());
|
|
242
243
|
// Register the plugin, even if config is invalid, since, if not provided, it will block `ga` command queue.
|
|
243
|
-
providePlugin('splitTracker', SplitTracker);
|
|
244
|
+
providePlugin(window, 'splitTracker', SplitTracker, log, sdkOptions.autoRequire);
|
|
244
245
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@splitsoftware/splitio-commons",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Split Javascript SDK common components",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "esm/index.js",
|
|
@@ -47,13 +47,9 @@
|
|
|
47
47
|
"tslib": "^2.3.1"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"js-yaml": "^3.13.1",
|
|
51
50
|
"ioredis": "^4.28.0"
|
|
52
51
|
},
|
|
53
52
|
"peerDependenciesMeta": {
|
|
54
|
-
"js-yaml": {
|
|
55
|
-
"optional": true
|
|
56
|
-
},
|
|
57
53
|
"ioredis": {
|
|
58
54
|
"optional": true
|
|
59
55
|
}
|
|
@@ -19,20 +19,26 @@ const logNameMapper = 'ga-to-split:mapper';
|
|
|
19
19
|
/**
|
|
20
20
|
* Provides a plugin to use with analytics.js, accounting for the possibility
|
|
21
21
|
* that the global command queue has been renamed or not yet defined.
|
|
22
|
-
* @param
|
|
23
|
-
* @param
|
|
22
|
+
* @param window Reference to global object.
|
|
23
|
+
* @param pluginName The plugin name identifier.
|
|
24
|
+
* @param pluginConstructor The plugin constructor function.
|
|
25
|
+
* @param log Logger instance.
|
|
26
|
+
* @param autoRequire If true, log error when auto-require script is not detected
|
|
24
27
|
*/
|
|
25
|
-
function providePlugin(pluginName: string, pluginConstructor: Function) {
|
|
28
|
+
function providePlugin(window: any, pluginName: string, pluginConstructor: Function, log: ILogger, autoRequire?: boolean) {
|
|
26
29
|
// get reference to global command queue. Init it if not defined yet.
|
|
27
|
-
// @ts-expect-error
|
|
28
30
|
const gaAlias = window.GoogleAnalyticsObject || 'ga';
|
|
29
|
-
window[gaAlias] = window[gaAlias] || function (
|
|
30
|
-
(window[gaAlias].q = window[gaAlias].q || []).push(
|
|
31
|
+
window[gaAlias] = window[gaAlias] || function () {
|
|
32
|
+
(window[gaAlias].q = window[gaAlias].q || []).push(arguments);
|
|
31
33
|
};
|
|
32
34
|
|
|
33
35
|
// provides the plugin for use with analytics.js.
|
|
34
|
-
// @ts-expect-error
|
|
35
36
|
window[gaAlias]('provide', pluginName, pluginConstructor);
|
|
37
|
+
|
|
38
|
+
if (autoRequire && (!window[gaAlias].q || window[gaAlias].q.push === [].push)) {
|
|
39
|
+
// Expecting spy on ga.q push method but not found
|
|
40
|
+
log.error(logPrefix + 'integration is configured to autorequire the splitTracker plugin, but the necessary script does not seem to have run. Please check the docs.');
|
|
41
|
+
}
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
// Default mapping: object used for building the default mapper from hits to Split events
|
|
@@ -284,5 +290,5 @@ export function GaToSplit(sdkOptions: GoogleAnalyticsToSplitOptions, params: IIn
|
|
|
284
290
|
}
|
|
285
291
|
|
|
286
292
|
// Register the plugin, even if config is invalid, since, if not provided, it will block `ga` command queue.
|
|
287
|
-
providePlugin('splitTracker', SplitTracker);
|
|
293
|
+
providePlugin(window, 'splitTracker', SplitTracker, log, sdkOptions.autoRequire);
|
|
288
294
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
2
|
+
/**
|
|
3
|
+
* Auto-require script to use with GoogleAnalyticsToSplit integration
|
|
4
|
+
*/
|
|
5
|
+
(function (w, g, o) {
|
|
6
|
+
w[o] = w[o] || g;
|
|
7
|
+
w[g] = w[g] || function () { w[g].q.push(arguments); };
|
|
8
|
+
w[g].q = w[g].q || [];
|
|
9
|
+
|
|
10
|
+
var trackerNames = {};
|
|
11
|
+
function name(arg) { return typeof arg === 'object' && typeof arg.name === 'string' && arg.name; }
|
|
12
|
+
|
|
13
|
+
function processCommand(command) { // Queue a `require` command if v is a `create` command
|
|
14
|
+
if (command && command[0] === 'create') {
|
|
15
|
+
var trackerName = name(command[1]) || name(command[2]) || name(command[3]) || (typeof command[3] === 'string' ? command[3] : undefined); // Get tracker name
|
|
16
|
+
|
|
17
|
+
if (!trackerNames[trackerName]) {
|
|
18
|
+
trackerNames[trackerName] = true;
|
|
19
|
+
w[g]((trackerName ? trackerName + '.' : '') + 'require', 'splitTracker'); // Auto-require
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
w[g].q.forEach(processCommand); // Process already queued commands
|
|
25
|
+
|
|
26
|
+
var originalPush = w[g].q.push;
|
|
27
|
+
w[g].q.push = function (command) { // Spy new queued commands
|
|
28
|
+
var result = originalPush.apply(this, arguments);
|
|
29
|
+
processCommand(command);
|
|
30
|
+
return result;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
})(window, 'ga', 'GoogleAnalyticsObject');
|
|
@@ -53,13 +53,24 @@ export interface GoogleAnalyticsToSplitOptions {
|
|
|
53
53
|
* If not provided, events are sent using the key and traffic type provided at SDK config
|
|
54
54
|
*/
|
|
55
55
|
identities?: Identity[],
|
|
56
|
+
/**
|
|
57
|
+
* Optional flag to log an error if the `auto-require` script is not detected.
|
|
58
|
+
* The auto-require script automatically requires the `splitTracker` plugin for created trackers,
|
|
59
|
+
* and should be placed right after your Google Analytics, Google Tag Manager or gtag.js script tag.
|
|
60
|
+
*
|
|
61
|
+
* @see {@link https://help.split.io/hc/en-us/articles/360040838752#set-up-with-gtm-and-gtag.js}
|
|
62
|
+
*
|
|
63
|
+
* @property {boolean} autoRequire
|
|
64
|
+
* @default false
|
|
65
|
+
*/
|
|
66
|
+
autoRequire?: boolean,
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
/**
|
|
59
70
|
* Enable 'Google Analytics to Split' integration, to track Google Analytics hits as Split events.
|
|
60
71
|
* Used by the browser variant of the isomorphic JS SDK.
|
|
61
72
|
*
|
|
62
|
-
* @see {@link https://help.split.io/hc/en-us/articles/
|
|
73
|
+
* @see {@link https://help.split.io/hc/en-us/articles/360040838752#google-analytics-to-split}
|
|
63
74
|
*/
|
|
64
75
|
export interface IGoogleAnalyticsToSplitConfig extends GoogleAnalyticsToSplitOptions {
|
|
65
76
|
type: 'GOOGLE_ANALYTICS_TO_SPLIT'
|
|
@@ -129,7 +140,7 @@ export interface SplitToGoogleAnalyticsOptions {
|
|
|
129
140
|
* Enable 'Split to Google Analytics' integration, to track Split impressions and events as Google Analytics hits.
|
|
130
141
|
* Used by the browser variant of the isomorphic JS SDK.
|
|
131
142
|
*
|
|
132
|
-
* @see {@link https://help.split.io/hc/en-us/articles/
|
|
143
|
+
* @see {@link https://help.split.io/hc/en-us/articles/360040838752#split-to-google-analytics}
|
|
133
144
|
*/
|
|
134
145
|
export interface ISplitToGoogleAnalyticsConfig extends SplitToGoogleAnalyticsOptions {
|
|
135
146
|
type: 'SPLIT_TO_GOOGLE_ANALYTICS'
|
|
@@ -52,12 +52,23 @@ export interface GoogleAnalyticsToSplitOptions {
|
|
|
52
52
|
* If not provided, events are sent using the key and traffic type provided at SDK config
|
|
53
53
|
*/
|
|
54
54
|
identities?: Identity[];
|
|
55
|
+
/**
|
|
56
|
+
* Optional flag to log an error if the `auto-require` script is not detected.
|
|
57
|
+
* The auto-require script automatically requires the `splitTracker` plugin for created trackers,
|
|
58
|
+
* and should be placed right after your Google Analytics, Google Tag Manager or gtag.js script tag.
|
|
59
|
+
*
|
|
60
|
+
* @see {@link https://help.split.io/hc/en-us/articles/360040838752#set-up-with-gtm-and-gtag.js}
|
|
61
|
+
*
|
|
62
|
+
* @property {boolean} autoRequire
|
|
63
|
+
* @default false
|
|
64
|
+
*/
|
|
65
|
+
autoRequire?: boolean;
|
|
55
66
|
}
|
|
56
67
|
/**
|
|
57
68
|
* Enable 'Google Analytics to Split' integration, to track Google Analytics hits as Split events.
|
|
58
69
|
* Used by the browser variant of the isomorphic JS SDK.
|
|
59
70
|
*
|
|
60
|
-
* @see {@link https://help.split.io/hc/en-us/articles/
|
|
71
|
+
* @see {@link https://help.split.io/hc/en-us/articles/360040838752#google-analytics-to-split}
|
|
61
72
|
*/
|
|
62
73
|
export interface IGoogleAnalyticsToSplitConfig extends GoogleAnalyticsToSplitOptions {
|
|
63
74
|
type: 'GOOGLE_ANALYTICS_TO_SPLIT';
|
|
@@ -125,7 +136,7 @@ export interface SplitToGoogleAnalyticsOptions {
|
|
|
125
136
|
* Enable 'Split to Google Analytics' integration, to track Split impressions and events as Google Analytics hits.
|
|
126
137
|
* Used by the browser variant of the isomorphic JS SDK.
|
|
127
138
|
*
|
|
128
|
-
* @see {@link https://help.split.io/hc/en-us/articles/
|
|
139
|
+
* @see {@link https://help.split.io/hc/en-us/articles/360040838752#split-to-google-analytics}
|
|
129
140
|
*/
|
|
130
141
|
export interface ISplitToGoogleAnalyticsConfig extends SplitToGoogleAnalyticsOptions {
|
|
131
142
|
type: 'SPLIT_TO_GOOGLE_ANALYTICS';
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LocalhostFromFile = void 0;
|
|
4
|
-
var splitsParserFromFile_1 = require("./splitsParser/splitsParserFromFile");
|
|
5
|
-
var syncManagerOffline_1 = require("./syncManagerOffline");
|
|
6
|
-
// Singleton instance of the factory function for offline SyncManager from YAML file (a.k.a. localhostFromFile)
|
|
7
|
-
// Requires Node 'fs' and 'path' APIs.
|
|
8
|
-
var localhostFromFile = (0, syncManagerOffline_1.syncManagerOfflineFactory)(splitsParserFromFile_1.splitsParserFromFileFactory);
|
|
9
|
-
localhostFromFile.type = 'LocalhostFromFile';
|
|
10
|
-
function LocalhostFromFile() {
|
|
11
|
-
return localhostFromFile;
|
|
12
|
-
}
|
|
13
|
-
exports.LocalhostFromFile = LocalhostFromFile;
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.splitsParserFromFileFactory = void 0;
|
|
4
|
-
var tslib_1 = require("tslib");
|
|
5
|
-
/* eslint-disable no-undef */
|
|
6
|
-
// @TODO consider moving it to Node-SDK and remove js-yaml dependency from Js-commons
|
|
7
|
-
var fs_1 = (0, tslib_1.__importDefault)(require("fs"));
|
|
8
|
-
var path_1 = (0, tslib_1.__importDefault)(require("path"));
|
|
9
|
-
// @ts-ignore
|
|
10
|
-
var js_yaml_1 = (0, tslib_1.__importDefault)(require("js-yaml"));
|
|
11
|
-
var lang_1 = require("../../../utils/lang");
|
|
12
|
-
var parseCondition_1 = require("./parseCondition");
|
|
13
|
-
var logPrefix = 'sync:offline:splits-fetcher: ';
|
|
14
|
-
var DEFAULT_FILENAME = '.split';
|
|
15
|
-
function configFilesPath(configFilePath) {
|
|
16
|
-
if (configFilePath === DEFAULT_FILENAME || !(0, lang_1.isString)(configFilePath)) {
|
|
17
|
-
var root = process.env.HOME;
|
|
18
|
-
if (process.env.SPLIT_CONFIG_ROOT)
|
|
19
|
-
root = process.env.SPLIT_CONFIG_ROOT;
|
|
20
|
-
if (!root)
|
|
21
|
-
throw new Error('Missing split mock configuration root.');
|
|
22
|
-
configFilePath = path_1.default.join(root, DEFAULT_FILENAME);
|
|
23
|
-
}
|
|
24
|
-
// Validate the extensions
|
|
25
|
-
if (!((0, lang_1.endsWith)(configFilePath, '.yaml', true) || (0, lang_1.endsWith)(configFilePath, '.yml', true) || (0, lang_1.endsWith)(configFilePath, '.split', true)))
|
|
26
|
-
throw new Error("Invalid extension specified for Splits mock file. Accepted extensions are \".yml\" and \".yaml\". Your specified file is " + configFilePath);
|
|
27
|
-
if (!fs_1.default.existsSync(configFilePath))
|
|
28
|
-
throw new Error("Split configuration not found in " + configFilePath + " - Please review your Split file location.");
|
|
29
|
-
return configFilePath;
|
|
30
|
-
}
|
|
31
|
-
// This function is not pure nor meant to be. Here we apply modifications to cover
|
|
32
|
-
// for behaviour that's ensured by the BE.
|
|
33
|
-
function arrangeConditions(mocksData) {
|
|
34
|
-
// Iterate through each Split data
|
|
35
|
-
(0, lang_1.forOwn)(mocksData, function (data) {
|
|
36
|
-
var conditions = data.conditions;
|
|
37
|
-
// On the manager, as the split jsons come with all treatments on the partitions prop,
|
|
38
|
-
// we'll add all the treatments to the first condition.
|
|
39
|
-
var firstRolloutCondition = (0, lang_1.find)(conditions, function (cond) { return cond.conditionType === 'ROLLOUT'; });
|
|
40
|
-
// Malformed mocks may have
|
|
41
|
-
var treatments = (0, lang_1.uniq)(data.treatments);
|
|
42
|
-
// If they're only specifying a whitelist we add the treatments there.
|
|
43
|
-
var allTreatmentsCondition = firstRolloutCondition ? firstRolloutCondition : conditions[0];
|
|
44
|
-
var fullyAllocatedTreatment = allTreatmentsCondition.partitions[0].treatment;
|
|
45
|
-
treatments.forEach(function (treatment) {
|
|
46
|
-
if (treatment !== fullyAllocatedTreatment) {
|
|
47
|
-
allTreatmentsCondition.partitions.push({
|
|
48
|
-
treatment: treatment,
|
|
49
|
-
size: 0
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
// Don't need these anymore
|
|
54
|
-
// @ts-expect-error
|
|
55
|
-
delete data.treatments;
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
function splitsParserFromFileFactory() {
|
|
59
|
-
var previousMock = 'NO_MOCK_LOADED';
|
|
60
|
-
// Parse `.split` configuration file and return a map of "Split Objects"
|
|
61
|
-
function readSplitConfigFile(log, filePath) {
|
|
62
|
-
var SPLIT_POSITION = 0;
|
|
63
|
-
var TREATMENT_POSITION = 1;
|
|
64
|
-
var data;
|
|
65
|
-
try {
|
|
66
|
-
data = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
67
|
-
}
|
|
68
|
-
catch (e) {
|
|
69
|
-
log.error(e && e.message);
|
|
70
|
-
return {};
|
|
71
|
-
}
|
|
72
|
-
if (data === previousMock)
|
|
73
|
-
return false;
|
|
74
|
-
previousMock = data;
|
|
75
|
-
var splitObjects = data.split(/\r?\n/).reduce(function (accum, line, index) {
|
|
76
|
-
var tuple = line.trim();
|
|
77
|
-
if (tuple === '' || tuple.charAt(0) === '#') {
|
|
78
|
-
log.debug(logPrefix + ("Ignoring empty line or comment at #" + index));
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
tuple = tuple.split(/\s+/);
|
|
82
|
-
if (tuple.length !== 2) {
|
|
83
|
-
log.debug(logPrefix + ("Ignoring line since it does not have exactly two columns #" + index));
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
var splitName = tuple[SPLIT_POSITION];
|
|
87
|
-
var condition = (0, parseCondition_1.parseCondition)({ treatment: tuple[TREATMENT_POSITION] });
|
|
88
|
-
accum[splitName] = { conditions: [condition], configurations: {}, trafficTypeName: 'localhost' };
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return accum;
|
|
92
|
-
}, {});
|
|
93
|
-
return splitObjects;
|
|
94
|
-
}
|
|
95
|
-
// Parse `.yml` or `.yaml` configuration files and return a map of "Split Objects"
|
|
96
|
-
function readYAMLConfigFile(log, filePath) {
|
|
97
|
-
var data = '';
|
|
98
|
-
var yamldoc = null;
|
|
99
|
-
try {
|
|
100
|
-
data = fs_1.default.readFileSync(filePath, 'utf8');
|
|
101
|
-
if (data === previousMock)
|
|
102
|
-
return false;
|
|
103
|
-
previousMock = data;
|
|
104
|
-
yamldoc = js_yaml_1.default.safeLoad(data);
|
|
105
|
-
}
|
|
106
|
-
catch (e) {
|
|
107
|
-
log.error(e);
|
|
108
|
-
return {};
|
|
109
|
-
}
|
|
110
|
-
// Each entry will be mapped to a condition, but we'll also keep the configurations map.
|
|
111
|
-
var mocksData = yamldoc.reduce(function (accum, splitEntry) {
|
|
112
|
-
var splitName = Object.keys(splitEntry)[0];
|
|
113
|
-
if (!splitName || !(0, lang_1.isString)(splitEntry[splitName].treatment))
|
|
114
|
-
log.error(logPrefix + 'Ignoring entry on YAML since the format is incorrect.');
|
|
115
|
-
var mockData = splitEntry[splitName];
|
|
116
|
-
// "Template" for each split accumulated data
|
|
117
|
-
if (!accum[splitName]) {
|
|
118
|
-
accum[splitName] = {
|
|
119
|
-
configurations: {}, conditions: [], treatments: [], trafficTypeName: 'localhost'
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
// Assign the config if there is one on the mock
|
|
123
|
-
if (mockData.config)
|
|
124
|
-
accum[splitName].configurations[mockData.treatment] = mockData.config;
|
|
125
|
-
// Parse the condition from the entry.
|
|
126
|
-
var condition = (0, parseCondition_1.parseCondition)(mockData);
|
|
127
|
-
accum[splitName].conditions[condition.conditionType === 'ROLLOUT' ? 'push' : 'unshift'](condition);
|
|
128
|
-
// Also keep track of the treatments, will be useful for manager functionality.
|
|
129
|
-
accum[splitName].treatments.push(mockData.treatment);
|
|
130
|
-
return accum;
|
|
131
|
-
}, {});
|
|
132
|
-
arrangeConditions(mocksData);
|
|
133
|
-
return mocksData;
|
|
134
|
-
}
|
|
135
|
-
// Load the content of a configuration file into an Object
|
|
136
|
-
return function splitsParserFromFile(_a) {
|
|
137
|
-
var features = _a.features, log = _a.log;
|
|
138
|
-
var filePath = configFilesPath(features);
|
|
139
|
-
var mockData;
|
|
140
|
-
// If we have a filePath, it means the extension is correct, choose the parser.
|
|
141
|
-
if ((0, lang_1.endsWith)(filePath, '.split')) {
|
|
142
|
-
log.warn(logPrefix + '.split mocks will be deprecated soon in favor of YAML files, which provide more targeting power. Take a look in our documentation.');
|
|
143
|
-
mockData = readSplitConfigFile(log, filePath);
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
mockData = readYAMLConfigFile(log, filePath);
|
|
147
|
-
}
|
|
148
|
-
return mockData;
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
exports.splitsParserFromFileFactory = splitsParserFromFileFactory;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { splitsParserFromFileFactory } from './splitsParser/splitsParserFromFile';
|
|
2
|
-
import { syncManagerOfflineFactory } from './syncManagerOffline';
|
|
3
|
-
// Singleton instance of the factory function for offline SyncManager from YAML file (a.k.a. localhostFromFile)
|
|
4
|
-
// Requires Node 'fs' and 'path' APIs.
|
|
5
|
-
var localhostFromFile = syncManagerOfflineFactory(splitsParserFromFileFactory);
|
|
6
|
-
localhostFromFile.type = 'LocalhostFromFile';
|
|
7
|
-
export function LocalhostFromFile() {
|
|
8
|
-
return localhostFromFile;
|
|
9
|
-
}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-undef */
|
|
2
|
-
// @TODO consider moving it to Node-SDK and remove js-yaml dependency from Js-commons
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
// @ts-ignore
|
|
6
|
-
import yaml from 'js-yaml';
|
|
7
|
-
import { isString, endsWith, find, forOwn, uniq, } from '../../../utils/lang';
|
|
8
|
-
import { parseCondition } from './parseCondition';
|
|
9
|
-
var logPrefix = 'sync:offline:splits-fetcher: ';
|
|
10
|
-
var DEFAULT_FILENAME = '.split';
|
|
11
|
-
function configFilesPath(configFilePath) {
|
|
12
|
-
if (configFilePath === DEFAULT_FILENAME || !isString(configFilePath)) {
|
|
13
|
-
var root = process.env.HOME;
|
|
14
|
-
if (process.env.SPLIT_CONFIG_ROOT)
|
|
15
|
-
root = process.env.SPLIT_CONFIG_ROOT;
|
|
16
|
-
if (!root)
|
|
17
|
-
throw new Error('Missing split mock configuration root.');
|
|
18
|
-
configFilePath = path.join(root, DEFAULT_FILENAME);
|
|
19
|
-
}
|
|
20
|
-
// Validate the extensions
|
|
21
|
-
if (!(endsWith(configFilePath, '.yaml', true) || endsWith(configFilePath, '.yml', true) || endsWith(configFilePath, '.split', true)))
|
|
22
|
-
throw new Error("Invalid extension specified for Splits mock file. Accepted extensions are \".yml\" and \".yaml\". Your specified file is " + configFilePath);
|
|
23
|
-
if (!fs.existsSync(configFilePath))
|
|
24
|
-
throw new Error("Split configuration not found in " + configFilePath + " - Please review your Split file location.");
|
|
25
|
-
return configFilePath;
|
|
26
|
-
}
|
|
27
|
-
// This function is not pure nor meant to be. Here we apply modifications to cover
|
|
28
|
-
// for behaviour that's ensured by the BE.
|
|
29
|
-
function arrangeConditions(mocksData) {
|
|
30
|
-
// Iterate through each Split data
|
|
31
|
-
forOwn(mocksData, function (data) {
|
|
32
|
-
var conditions = data.conditions;
|
|
33
|
-
// On the manager, as the split jsons come with all treatments on the partitions prop,
|
|
34
|
-
// we'll add all the treatments to the first condition.
|
|
35
|
-
var firstRolloutCondition = find(conditions, function (cond) { return cond.conditionType === 'ROLLOUT'; });
|
|
36
|
-
// Malformed mocks may have
|
|
37
|
-
var treatments = uniq(data.treatments);
|
|
38
|
-
// If they're only specifying a whitelist we add the treatments there.
|
|
39
|
-
var allTreatmentsCondition = firstRolloutCondition ? firstRolloutCondition : conditions[0];
|
|
40
|
-
var fullyAllocatedTreatment = allTreatmentsCondition.partitions[0].treatment;
|
|
41
|
-
treatments.forEach(function (treatment) {
|
|
42
|
-
if (treatment !== fullyAllocatedTreatment) {
|
|
43
|
-
allTreatmentsCondition.partitions.push({
|
|
44
|
-
treatment: treatment,
|
|
45
|
-
size: 0
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
// Don't need these anymore
|
|
50
|
-
// @ts-expect-error
|
|
51
|
-
delete data.treatments;
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
export function splitsParserFromFileFactory() {
|
|
55
|
-
var previousMock = 'NO_MOCK_LOADED';
|
|
56
|
-
// Parse `.split` configuration file and return a map of "Split Objects"
|
|
57
|
-
function readSplitConfigFile(log, filePath) {
|
|
58
|
-
var SPLIT_POSITION = 0;
|
|
59
|
-
var TREATMENT_POSITION = 1;
|
|
60
|
-
var data;
|
|
61
|
-
try {
|
|
62
|
-
data = fs.readFileSync(filePath, 'utf-8');
|
|
63
|
-
}
|
|
64
|
-
catch (e) {
|
|
65
|
-
log.error(e && e.message);
|
|
66
|
-
return {};
|
|
67
|
-
}
|
|
68
|
-
if (data === previousMock)
|
|
69
|
-
return false;
|
|
70
|
-
previousMock = data;
|
|
71
|
-
var splitObjects = data.split(/\r?\n/).reduce(function (accum, line, index) {
|
|
72
|
-
var tuple = line.trim();
|
|
73
|
-
if (tuple === '' || tuple.charAt(0) === '#') {
|
|
74
|
-
log.debug(logPrefix + ("Ignoring empty line or comment at #" + index));
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
tuple = tuple.split(/\s+/);
|
|
78
|
-
if (tuple.length !== 2) {
|
|
79
|
-
log.debug(logPrefix + ("Ignoring line since it does not have exactly two columns #" + index));
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
var splitName = tuple[SPLIT_POSITION];
|
|
83
|
-
var condition = parseCondition({ treatment: tuple[TREATMENT_POSITION] });
|
|
84
|
-
accum[splitName] = { conditions: [condition], configurations: {}, trafficTypeName: 'localhost' };
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return accum;
|
|
88
|
-
}, {});
|
|
89
|
-
return splitObjects;
|
|
90
|
-
}
|
|
91
|
-
// Parse `.yml` or `.yaml` configuration files and return a map of "Split Objects"
|
|
92
|
-
function readYAMLConfigFile(log, filePath) {
|
|
93
|
-
var data = '';
|
|
94
|
-
var yamldoc = null;
|
|
95
|
-
try {
|
|
96
|
-
data = fs.readFileSync(filePath, 'utf8');
|
|
97
|
-
if (data === previousMock)
|
|
98
|
-
return false;
|
|
99
|
-
previousMock = data;
|
|
100
|
-
yamldoc = yaml.safeLoad(data);
|
|
101
|
-
}
|
|
102
|
-
catch (e) {
|
|
103
|
-
log.error(e);
|
|
104
|
-
return {};
|
|
105
|
-
}
|
|
106
|
-
// Each entry will be mapped to a condition, but we'll also keep the configurations map.
|
|
107
|
-
var mocksData = yamldoc.reduce(function (accum, splitEntry) {
|
|
108
|
-
var splitName = Object.keys(splitEntry)[0];
|
|
109
|
-
if (!splitName || !isString(splitEntry[splitName].treatment))
|
|
110
|
-
log.error(logPrefix + 'Ignoring entry on YAML since the format is incorrect.');
|
|
111
|
-
var mockData = splitEntry[splitName];
|
|
112
|
-
// "Template" for each split accumulated data
|
|
113
|
-
if (!accum[splitName]) {
|
|
114
|
-
accum[splitName] = {
|
|
115
|
-
configurations: {}, conditions: [], treatments: [], trafficTypeName: 'localhost'
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
// Assign the config if there is one on the mock
|
|
119
|
-
if (mockData.config)
|
|
120
|
-
accum[splitName].configurations[mockData.treatment] = mockData.config;
|
|
121
|
-
// Parse the condition from the entry.
|
|
122
|
-
var condition = parseCondition(mockData);
|
|
123
|
-
accum[splitName].conditions[condition.conditionType === 'ROLLOUT' ? 'push' : 'unshift'](condition);
|
|
124
|
-
// Also keep track of the treatments, will be useful for manager functionality.
|
|
125
|
-
accum[splitName].treatments.push(mockData.treatment);
|
|
126
|
-
return accum;
|
|
127
|
-
}, {});
|
|
128
|
-
arrangeConditions(mocksData);
|
|
129
|
-
return mocksData;
|
|
130
|
-
}
|
|
131
|
-
// Load the content of a configuration file into an Object
|
|
132
|
-
return function splitsParserFromFile(_a) {
|
|
133
|
-
var features = _a.features, log = _a.log;
|
|
134
|
-
var filePath = configFilesPath(features);
|
|
135
|
-
var mockData;
|
|
136
|
-
// If we have a filePath, it means the extension is correct, choose the parser.
|
|
137
|
-
if (endsWith(filePath, '.split')) {
|
|
138
|
-
log.warn(logPrefix + '.split mocks will be deprecated soon in favor of YAML files, which provide more targeting power. Take a look in our documentation.');
|
|
139
|
-
mockData = readSplitConfigFile(log, filePath);
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
mockData = readYAMLConfigFile(log, filePath);
|
|
143
|
-
}
|
|
144
|
-
return mockData;
|
|
145
|
-
};
|
|
146
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { splitsParserFromFileFactory } from './splitsParser/splitsParserFromFile';
|
|
2
|
-
import { syncManagerOfflineFactory } from './syncManagerOffline';
|
|
3
|
-
import { SplitIO } from '../../types';
|
|
4
|
-
|
|
5
|
-
// Singleton instance of the factory function for offline SyncManager from YAML file (a.k.a. localhostFromFile)
|
|
6
|
-
// Requires Node 'fs' and 'path' APIs.
|
|
7
|
-
const localhostFromFile = syncManagerOfflineFactory(splitsParserFromFileFactory) as SplitIO.LocalhostFactory;
|
|
8
|
-
localhostFromFile.type = 'LocalhostFromFile';
|
|
9
|
-
|
|
10
|
-
export function LocalhostFromFile(): SplitIO.LocalhostFactory {
|
|
11
|
-
return localhostFromFile;
|
|
12
|
-
}
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-undef */
|
|
2
|
-
// @TODO consider moving it to Node-SDK and remove js-yaml dependency from Js-commons
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
// @ts-ignore
|
|
6
|
-
import yaml from 'js-yaml';
|
|
7
|
-
import { isString, endsWith, find, forOwn, uniq, } from '../../../utils/lang';
|
|
8
|
-
import { parseCondition, IMockSplitEntry } from './parseCondition';
|
|
9
|
-
import { ISplitPartial } from '../../../dtos/types';
|
|
10
|
-
import { ISettings, SplitIO } from '../../../types';
|
|
11
|
-
import { ILogger } from '../../../logger/types';
|
|
12
|
-
import { ISplitsParser } from './types';
|
|
13
|
-
|
|
14
|
-
const logPrefix = 'sync:offline:splits-fetcher: ';
|
|
15
|
-
|
|
16
|
-
type IYamlSplitEntry = Record<string, IMockSplitEntry>
|
|
17
|
-
|
|
18
|
-
const DEFAULT_FILENAME = '.split';
|
|
19
|
-
|
|
20
|
-
function configFilesPath(configFilePath?: SplitIO.MockedFeaturesFilePath): SplitIO.MockedFeaturesFilePath {
|
|
21
|
-
if (configFilePath === DEFAULT_FILENAME || !isString(configFilePath)) {
|
|
22
|
-
let root = process.env.HOME;
|
|
23
|
-
|
|
24
|
-
if (process.env.SPLIT_CONFIG_ROOT) root = process.env.SPLIT_CONFIG_ROOT;
|
|
25
|
-
|
|
26
|
-
if (!root) throw new Error('Missing split mock configuration root.');
|
|
27
|
-
|
|
28
|
-
configFilePath = path.join(root, DEFAULT_FILENAME);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Validate the extensions
|
|
32
|
-
if (!(endsWith(configFilePath, '.yaml', true) || endsWith(configFilePath, '.yml', true) || endsWith(configFilePath, '.split', true)))
|
|
33
|
-
throw new Error(`Invalid extension specified for Splits mock file. Accepted extensions are ".yml" and ".yaml". Your specified file is ${configFilePath}`);
|
|
34
|
-
|
|
35
|
-
if (!fs.existsSync(configFilePath as SplitIO.MockedFeaturesFilePath))
|
|
36
|
-
throw new Error(`Split configuration not found in ${configFilePath} - Please review your Split file location.`);
|
|
37
|
-
|
|
38
|
-
return configFilePath as SplitIO.MockedFeaturesFilePath;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// This function is not pure nor meant to be. Here we apply modifications to cover
|
|
42
|
-
// for behaviour that's ensured by the BE.
|
|
43
|
-
function arrangeConditions(mocksData: Record<string, Required<ISplitPartial> & { treatments: string[] }>) {
|
|
44
|
-
// Iterate through each Split data
|
|
45
|
-
forOwn(mocksData, data => {
|
|
46
|
-
const conditions = data.conditions;
|
|
47
|
-
|
|
48
|
-
// On the manager, as the split jsons come with all treatments on the partitions prop,
|
|
49
|
-
// we'll add all the treatments to the first condition.
|
|
50
|
-
const firstRolloutCondition = find(conditions, cond => cond.conditionType === 'ROLLOUT');
|
|
51
|
-
// Malformed mocks may have
|
|
52
|
-
const treatments = uniq(data.treatments);
|
|
53
|
-
// If they're only specifying a whitelist we add the treatments there.
|
|
54
|
-
const allTreatmentsCondition = firstRolloutCondition ? firstRolloutCondition : conditions[0];
|
|
55
|
-
|
|
56
|
-
const fullyAllocatedTreatment = allTreatmentsCondition.partitions[0].treatment;
|
|
57
|
-
|
|
58
|
-
treatments.forEach(treatment => {
|
|
59
|
-
if (treatment !== fullyAllocatedTreatment) {
|
|
60
|
-
allTreatmentsCondition.partitions.push({
|
|
61
|
-
treatment, size: 0
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Don't need these anymore
|
|
67
|
-
// @ts-expect-error
|
|
68
|
-
delete data.treatments;
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function splitsParserFromFileFactory(): ISplitsParser {
|
|
73
|
-
|
|
74
|
-
let previousMock = 'NO_MOCK_LOADED';
|
|
75
|
-
|
|
76
|
-
// Parse `.split` configuration file and return a map of "Split Objects"
|
|
77
|
-
function readSplitConfigFile(log: ILogger, filePath: SplitIO.MockedFeaturesFilePath): false | Record<string, ISplitPartial> {
|
|
78
|
-
const SPLIT_POSITION = 0;
|
|
79
|
-
const TREATMENT_POSITION = 1;
|
|
80
|
-
let data;
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
data = fs.readFileSync(filePath, 'utf-8');
|
|
84
|
-
} catch (e) {
|
|
85
|
-
log.error(e && (e as Error).message);
|
|
86
|
-
|
|
87
|
-
return {};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (data === previousMock) return false;
|
|
91
|
-
previousMock = data;
|
|
92
|
-
|
|
93
|
-
const splitObjects = data.split(/\r?\n/).reduce((accum, line, index) => {
|
|
94
|
-
let tuple: string | string[] = line.trim();
|
|
95
|
-
|
|
96
|
-
if (tuple === '' || tuple.charAt(0) === '#') {
|
|
97
|
-
log.debug(logPrefix + `Ignoring empty line or comment at #${index}`);
|
|
98
|
-
} else {
|
|
99
|
-
tuple = tuple.split(/\s+/);
|
|
100
|
-
|
|
101
|
-
if (tuple.length !== 2) {
|
|
102
|
-
log.debug(logPrefix + `Ignoring line since it does not have exactly two columns #${index}`);
|
|
103
|
-
} else {
|
|
104
|
-
const splitName = tuple[SPLIT_POSITION];
|
|
105
|
-
const condition = parseCondition({ treatment: tuple[TREATMENT_POSITION] });
|
|
106
|
-
accum[splitName] = { conditions: [condition], configurations: {}, trafficTypeName: 'localhost' };
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return accum;
|
|
111
|
-
}, {} as Record<string, ISplitPartial>);
|
|
112
|
-
|
|
113
|
-
return splitObjects;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Parse `.yml` or `.yaml` configuration files and return a map of "Split Objects"
|
|
117
|
-
function readYAMLConfigFile(log: ILogger, filePath: SplitIO.MockedFeaturesFilePath): false | Record<string, ISplitPartial> {
|
|
118
|
-
let data = '';
|
|
119
|
-
let yamldoc = null;
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
data = fs.readFileSync(filePath, 'utf8');
|
|
123
|
-
|
|
124
|
-
if (data === previousMock) return false;
|
|
125
|
-
previousMock = data;
|
|
126
|
-
|
|
127
|
-
yamldoc = yaml.safeLoad(data);
|
|
128
|
-
} catch (e) {
|
|
129
|
-
log.error(e);
|
|
130
|
-
|
|
131
|
-
return {};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Each entry will be mapped to a condition, but we'll also keep the configurations map.
|
|
135
|
-
const mocksData = (yamldoc as IYamlSplitEntry[]).reduce((accum, splitEntry) => {
|
|
136
|
-
const splitName = Object.keys(splitEntry)[0];
|
|
137
|
-
|
|
138
|
-
if (!splitName || !isString(splitEntry[splitName].treatment))
|
|
139
|
-
log.error(logPrefix + 'Ignoring entry on YAML since the format is incorrect.');
|
|
140
|
-
|
|
141
|
-
const mockData = splitEntry[splitName];
|
|
142
|
-
|
|
143
|
-
// "Template" for each split accumulated data
|
|
144
|
-
if (!accum[splitName]) {
|
|
145
|
-
accum[splitName] = {
|
|
146
|
-
configurations: {}, conditions: [], treatments: [], trafficTypeName: 'localhost'
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Assign the config if there is one on the mock
|
|
151
|
-
if (mockData.config) accum[splitName].configurations[mockData.treatment] = mockData.config;
|
|
152
|
-
// Parse the condition from the entry.
|
|
153
|
-
const condition = parseCondition(mockData);
|
|
154
|
-
accum[splitName].conditions[condition.conditionType === 'ROLLOUT' ? 'push' : 'unshift'](condition);
|
|
155
|
-
// Also keep track of the treatments, will be useful for manager functionality.
|
|
156
|
-
accum[splitName].treatments.push(mockData.treatment);
|
|
157
|
-
|
|
158
|
-
return accum;
|
|
159
|
-
}, {} as Record<string, Required<ISplitPartial> & { treatments: string[] }>);
|
|
160
|
-
|
|
161
|
-
arrangeConditions(mocksData);
|
|
162
|
-
|
|
163
|
-
return mocksData;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Load the content of a configuration file into an Object
|
|
167
|
-
return function splitsParserFromFile({ features, log }: ISettings): false | Record<string, ISplitPartial> {
|
|
168
|
-
const filePath = configFilesPath(features as string);
|
|
169
|
-
let mockData: false | Record<string, ISplitPartial>;
|
|
170
|
-
|
|
171
|
-
// If we have a filePath, it means the extension is correct, choose the parser.
|
|
172
|
-
if (endsWith(filePath, '.split')) {
|
|
173
|
-
log.warn(logPrefix + '.split mocks will be deprecated soon in favor of YAML files, which provide more targeting power. Take a look in our documentation.');
|
|
174
|
-
mockData = readSplitConfigFile(log, filePath);
|
|
175
|
-
} else {
|
|
176
|
-
mockData = readYAMLConfigFile(log, filePath);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return mockData;
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
}
|