feature-toggle-api 3.4.1 → 4.0.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/README.md +115 -96
- package/dist/feature-toggle.d.ts +120 -0
- package/dist/feature-toggle.js +388 -0
- package/dist/feature-toggle.min.cjs +2 -0
- package/dist/feature-toggle.min.cjs.map +1 -0
- package/dist/feature-toggle.min.js +2 -0
- package/dist/feature-toggle.min.js.map +1 -0
- package/dist/feature-toggle.umd.min.js +2 -0
- package/dist/feature-toggle.umd.min.js.map +1 -0
- package/dist/html-plugin.umd.min.js +2 -0
- package/dist/html-plugin.umd.min.js.map +1 -0
- package/dist/url-plugin.umd.min.js +2 -0
- package/dist/url-plugin.umd.min.js.map +1 -0
- package/examples/01_basic_esmodule.js +10 -0
- package/examples/02_basic_cjsmodule.cjs +6 -0
- package/examples/{basic.html → 03_basic_scripttag.html} +3 -2
- package/examples/{example-htmlplugin.html → 04_example-htmlplugin.html} +2 -2
- package/examples/{example-urlplugin.html → 05_example-urlplugin.html} +2 -2
- package/examples/{withListener.html → 06_withListener.html} +1 -1
- package/package.json +32 -38
- package/plugin-html.js +1 -1
- package/plugin-url.js +1 -1
- package/rollup.config.js +107 -0
- package/src/{index.js → featureToggle.ts} +172 -51
- package/src/index.ts +10 -0
- package/src/plugins/htmlplugin/{plugin-html.js → plugin-html.ts} +22 -10
- package/src/plugins/urlplugin/{plugin-url.js → plugin-url.ts} +36 -10
- package/tests/featuretoggle.test.ts +407 -0
- package/tests/polyfills.ts +20 -0
- package/tsconfig.cjs.json +12 -0
- package/tsconfig.json +12 -0
- package/feature-toggle-api.js +0 -273
- package/feature-toggle-api.min.js +0 -1
- package/feature-toggle-api.module.js +0 -273
- package/spec/support/index.spec.js +0 -378
- package/spec/support/jasmine.json +0 -11
- package/spec/support/polyfills.js +0 -6
- package/src/index.cjs.js +0 -8
package/feature-toggle-api.js
DELETED
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
4
|
-
|
|
5
|
-
var parseToFn = function parseToFn(fnOrBool) {
|
|
6
|
-
if (typeof fnOrBool == 'boolean') return function () {
|
|
7
|
-
return fnOrBool;
|
|
8
|
-
};
|
|
9
|
-
return fnOrBool;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
var getKey = function getKey(name, variant) {
|
|
13
|
-
var _name = name.toLowerCase();
|
|
14
|
-
|
|
15
|
-
if (typeof variant == 'string') {
|
|
16
|
-
_name += "#" + variant.toLowerCase();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return _name;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
function initVisibilities() {
|
|
23
|
-
var visibilities = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
24
|
-
var returnVisibilities = {};
|
|
25
|
-
Object.keys(visibilities).forEach(function (key) {
|
|
26
|
-
if (key.startsWith('_')) return;
|
|
27
|
-
returnVisibilities[getKey(key)] = parseToFn(visibilities[key]);
|
|
28
|
-
});
|
|
29
|
-
return returnVisibilities;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function featuretoggleapi() {
|
|
33
|
-
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
34
|
-
var globals = {
|
|
35
|
-
datas: {},
|
|
36
|
-
listeners: {},
|
|
37
|
-
visibilities: initVisibilities(config),
|
|
38
|
-
showLogs: false,
|
|
39
|
-
usedPlugins: []
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
function init(api) {
|
|
43
|
-
if (config._plugins) {
|
|
44
|
-
if (!Array.isArray(config._plugins)) throw new Error('featuretoggleapi()-constructor: config.plugins must be an array.');
|
|
45
|
-
|
|
46
|
-
config._plugins.forEach(function (plugin) {
|
|
47
|
-
if (typeof plugin !== 'function') throw new Error('featuretoggleapi()-constructor: config.plugins needs functions as entries, not ' + _typeof(plugin) + '.');
|
|
48
|
-
|
|
49
|
-
_addPlugin(plugin, api);
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
triggerEvent('init');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function _addPlugin(plugin, api) {
|
|
57
|
-
plugin(api);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function triggerEvent(eventtype, param) {
|
|
61
|
-
(globals.listeners[eventtype] || []).forEach(function (listener) {
|
|
62
|
-
listener(param);
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
var log = function log(message) {
|
|
67
|
-
if (!globals.showLogs) return; //Nur Browser können Syntaxhighlighting die anderen geben die Nachricht einfach aus und schneiden
|
|
68
|
-
//die styletags raus
|
|
69
|
-
|
|
70
|
-
if (typeof window === 'undefined') {
|
|
71
|
-
var loggedMessage = message.replace(/<b>/g, "");
|
|
72
|
-
console.log(loggedMessage);
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
var hasBoldTag = message.indexOf('<b>') != -1;
|
|
77
|
-
var hasVisibleKeyword = message.indexOf('visible') != -1;
|
|
78
|
-
var hasHiddenKeyword = message.indexOf('hidden') != -1;
|
|
79
|
-
|
|
80
|
-
var _message = message.replace('visible', '%cvisible');
|
|
81
|
-
|
|
82
|
-
_message = _message.replace('hidden', '%chidden');
|
|
83
|
-
if (hasVisibleKeyword) console.log(_message, "color:green;font-weight:bold;");else if (hasHiddenKeyword) console.log(_message, "color:red;font-weight:bold;");else if (hasBoldTag) {
|
|
84
|
-
_message = _message.replace('<b>', '%c');
|
|
85
|
-
var parts = [_message, 'font-weight:bold;'];
|
|
86
|
-
console.log.apply(null, parts);
|
|
87
|
-
} else console.log(message);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
var logAndReturn = function logAndReturn(returnValue, message) {
|
|
91
|
-
log(message);
|
|
92
|
-
log('');
|
|
93
|
-
return returnValue;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
var getVisibility = function getVisibility(visibilityFn, functionname, name, variant, data) {
|
|
97
|
-
if (visibilityFn == null) return undefined;
|
|
98
|
-
var calculatedVisibility = visibilityFn({
|
|
99
|
-
name: name,
|
|
100
|
-
variant: variant,
|
|
101
|
-
data: data
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
if (typeof calculatedVisibility == 'boolean') {
|
|
105
|
-
return calculatedVisibility;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return logAndReturn(false, "The ".concat(functionname, " returns ").concat(calculatedVisibility, ". => Please return true or false. This result (and all non-boolean results) will return false."));
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
function parseKey(key) {
|
|
112
|
-
var parts = key.split('#');
|
|
113
|
-
return {
|
|
114
|
-
name: parts[0],
|
|
115
|
-
variant: parts.length > 1 ? parts[1] : undefined,
|
|
116
|
-
data: globals.datas[key]
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
/*
|
|
120
|
-
the following calls are possible:
|
|
121
|
-
visibility(name,result);
|
|
122
|
-
visibility(name,variant,result);
|
|
123
|
-
visibility(name,variant,data,result);
|
|
124
|
-
|
|
125
|
-
=>
|
|
126
|
-
param1: name
|
|
127
|
-
param2: result || variant
|
|
128
|
-
param3: result || data
|
|
129
|
-
param4: result
|
|
130
|
-
*/
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
function visibilityFnParams(param1, param2, param3, param4) {
|
|
134
|
-
//name must always be set
|
|
135
|
-
if (param1 == undefined) throw new Error('feature.visibility(): 1st parameter name must be defined');
|
|
136
|
-
if (arguments.length == 1) throw new Error('feature.visibility(): 2nd parameter name must be a boolean or function, but is empty');
|
|
137
|
-
var name = param1,
|
|
138
|
-
variant = null,
|
|
139
|
-
data = null,
|
|
140
|
-
result = null;
|
|
141
|
-
|
|
142
|
-
if (param3 == undefined && param4 == undefined) {
|
|
143
|
-
result = param2;
|
|
144
|
-
} else if (param4 == undefined) {
|
|
145
|
-
variant = param2;
|
|
146
|
-
result = param3;
|
|
147
|
-
} else {
|
|
148
|
-
variant = param2;
|
|
149
|
-
data = param3;
|
|
150
|
-
result = param4;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
name: name,
|
|
155
|
-
variant: variant,
|
|
156
|
-
data: data,
|
|
157
|
-
result: result
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function getEvent(name, variant, data, result) {
|
|
162
|
-
var event;
|
|
163
|
-
event = {
|
|
164
|
-
name: name,
|
|
165
|
-
variant: variant,
|
|
166
|
-
data: data
|
|
167
|
-
};
|
|
168
|
-
event.key = getKey(event.name, event.variant);
|
|
169
|
-
if (result == null) return event;
|
|
170
|
-
event.visibilityFunction = parseToFn(result);
|
|
171
|
-
event.result = event.visibilityFunction({
|
|
172
|
-
name: event.name,
|
|
173
|
-
variant: event.variant,
|
|
174
|
-
data: event.data || {},
|
|
175
|
-
_internalCall: true,
|
|
176
|
-
description: 'When attaching a function, the result must be calculated internally. You can filter this out with the _internalCall:true -Flag.'
|
|
177
|
-
});
|
|
178
|
-
return event;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function isVisible(name, variant, data) {
|
|
182
|
-
var visibilities = globals.visibilities;
|
|
183
|
-
log("\nCheck Visibility of <b>Feature \"".concat(name, "\", variant \"").concat(variant == undefined ? '' : variant, "\"").concat(data ? " with data " + JSON.stringify(data) : "", "."));
|
|
184
|
-
if (name == undefined) throw new Error('The attribute "name" is required for tag <feature></feature>. Example: <feature name="aname"></feature>');
|
|
185
|
-
var requiredFn = visibilities['_required'];
|
|
186
|
-
var requiredFnExists = visibilities['_required'] != null;
|
|
187
|
-
var requiredFnResult = getVisibility(requiredFn, 'requiredVisibility', name, variant, data);
|
|
188
|
-
var visibilityFnKey = getKey(name, variant);
|
|
189
|
-
var visibilityFn = visibilities[visibilityFnKey];
|
|
190
|
-
var visibilityFnExists = visibilities[visibilityFnKey] != null;
|
|
191
|
-
var visibilityFnResult = getVisibility(visibilityFn, 'visibility function', name, variant, data);
|
|
192
|
-
var variantExists = variant != null;
|
|
193
|
-
var visibilityOnlyNameFnKey = getKey(name, null);
|
|
194
|
-
var visibilityOnlyNameFn = visibilities[visibilityOnlyNameFnKey];
|
|
195
|
-
var visibilityOnlyNameFnExists = visibilities[visibilityOnlyNameFnKey] != null;
|
|
196
|
-
var visibilityOnlyNameFnResult = getVisibility(visibilityOnlyNameFn, 'visibility function (only name)', name, variant, data);
|
|
197
|
-
var defaultFn = visibilities['_default'];
|
|
198
|
-
var defaultFnExists = visibilities['_default'] != null;
|
|
199
|
-
var defaultFnResult = getVisibility(defaultFn, 'defaultVisibility', name, variant, data);
|
|
200
|
-
if (!requiredFnExists) log("No requiredVisibility rule specified for this feature.");else if (requiredFnExists && requiredFnResult === true) log("The requiredVisibility rule returns true. This feature will be shown when no other rule rejects it.");else if (requiredFnExists && requiredFnResult === false) return logAndReturn(false, "The requiredVisibility rule returns false. This feature will be hidden.");
|
|
201
|
-
if (visibilityFnExists) return logAndReturn(visibilityFnResult, "The visibility rule returns ".concat(visibilityFnResult, ". This feature will be ").concat(visibilityFnResult ? 'visible' : 'hidden', "."));
|
|
202
|
-
log('No visibility rule found matching name and variant.');
|
|
203
|
-
if (variantExists && typeof visibilityOnlyNameFnResult == 'boolean') return logAndReturn(visibilityOnlyNameFnResult, "Found a visibility rule for name ".concat(name, " without variants. The rule returns ").concat(visibilityOnlyNameFnResult, ". => This feature will be ").concat(visibilityOnlyNameFnResult ? 'visible' : 'hidden', "."));else if (variantExists) log("No rules found for name ".concat(name, " without variants."));
|
|
204
|
-
if (defaultFnExists) return logAndReturn(defaultFnResult, "Found a defaultVisibility rule. The rule returns ".concat(defaultFnResult, ". => This feature will be ").concat(defaultFnResult ? 'visible' : 'hidden', "."));
|
|
205
|
-
log("No default rule found.");
|
|
206
|
-
if (requiredFnExists) return logAndReturn(true, "Only the requiredVisibility rule was found. This returned true. => This feature will be visible.");
|
|
207
|
-
return logAndReturn(false, 'No rules were found. This feature will be hidden.');
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
var api = {
|
|
211
|
-
name: 'feature-toggle-api',
|
|
212
|
-
setData: function setData(nameParam, variantOrDataParam, dataParam) {
|
|
213
|
-
if (nameParam == undefined) throw new Error('setData(): The name must of the feature must be defined, but ist undefined');
|
|
214
|
-
var variant = dataParam != undefined ? variantOrDataParam : undefined;
|
|
215
|
-
var data = dataParam || variantOrDataParam;
|
|
216
|
-
var event = getEvent(nameParam, variant, data);
|
|
217
|
-
globals.datas[event.key] = event.data;
|
|
218
|
-
triggerEvent('visibilityrule', event);
|
|
219
|
-
},
|
|
220
|
-
on: function on(eventtype, fn, config) {
|
|
221
|
-
globals.listeners[eventtype] = globals.listeners[eventtype] || [];
|
|
222
|
-
globals.listeners[eventtype].push(fn);
|
|
223
|
-
triggerEvent('registerEvent', {
|
|
224
|
-
type: eventtype
|
|
225
|
-
});
|
|
226
|
-
if (config != undefined && config.ignorePreviousRules) return;
|
|
227
|
-
Object.keys(globals.visibilities).forEach(function (key) {
|
|
228
|
-
var event = parseKey(key, globals);
|
|
229
|
-
var rule = globals.visibilities[key];
|
|
230
|
-
event.result = rule(event);
|
|
231
|
-
fn(event);
|
|
232
|
-
});
|
|
233
|
-
},
|
|
234
|
-
trigger: triggerEvent,
|
|
235
|
-
showLogs: function showLogs(_showLogs) {
|
|
236
|
-
globals.showLogs = _showLogs == undefined ? true : _showLogs;
|
|
237
|
-
},
|
|
238
|
-
isVisible: isVisible,
|
|
239
|
-
|
|
240
|
-
/*
|
|
241
|
-
the following function calls are possible:
|
|
242
|
-
visibility(name,result);
|
|
243
|
-
visibility(name,variant,result);
|
|
244
|
-
visibility(name,variant,data,result);
|
|
245
|
-
*/
|
|
246
|
-
visibility: function visibility(param1, param2, param3, param4) {
|
|
247
|
-
var params = visibilityFnParams(param1, param2, param3, param4);
|
|
248
|
-
var event = getEvent(params.name, params.variant, params.data, params.result);
|
|
249
|
-
globals.visibilities[event.key] = event.visibilityFunction;
|
|
250
|
-
globals.datas[event.key] = event.data;
|
|
251
|
-
triggerEvent('visibilityrule', event);
|
|
252
|
-
},
|
|
253
|
-
requiredVisibility: function requiredVisibility(fn) {
|
|
254
|
-
if (typeof fn != "function") throw new Error('feature.requiredVisibility(): 1st parameter must be a function, but is ' + _typeof(fn));
|
|
255
|
-
globals.visibilities['_required'] = parseToFn(fn);
|
|
256
|
-
},
|
|
257
|
-
defaultVisibility: function defaultVisibility(fn) {
|
|
258
|
-
if (typeof fn != "function") throw new Error('feature.defaultVisibility(): 1st parameter must be a function, but is ' + _typeof(fn));
|
|
259
|
-
globals.visibilities['_default'] = parseToFn(fn);
|
|
260
|
-
},
|
|
261
|
-
addPlugin: function addPlugin(plugin) {
|
|
262
|
-
if (globals.usedPlugins.includes(plugin)) return;
|
|
263
|
-
|
|
264
|
-
_addPlugin(plugin, api);
|
|
265
|
-
|
|
266
|
-
globals.usedPlugins.push(plugin);
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
init(api);
|
|
270
|
-
return api;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
window.featureToggleApi = featuretoggleapi;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";function _typeof(e){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var parseToFn=function(e){return"boolean"==typeof e?function(){return e}:e},getKey=function(e,i){e=e.toLowerCase();return"string"==typeof i&&(e+="#"+i.toLowerCase()),e};function initVisibilities(){var i=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},t={};return Object.keys(i).forEach(function(e){e.startsWith("_")||(t[getKey(e)]=parseToFn(i[e]))}),t}function featuretoggleapi(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},c={datas:{},listeners:{},visibilities:initVisibilities(e),showLogs:!1,usedPlugins:[]};function t(e,i){e(i)}function r(e,i){(c.listeners[e]||[]).forEach(function(e){e(i)})}function d(e){var i,t,n,r;c.showLogs&&("undefined"!=typeof window?(i=-1!=e.indexOf("<b>"),t=-1!=e.indexOf("visible"),n=-1!=e.indexOf("hidden"),r=(r=e.replace("visible","%cvisible")).replace("hidden","%chidden"),t?console.log(r,"color:green;font-weight:bold;"):n?console.log(r,"color:red;font-weight:bold;"):i?(r=r.replace("<b>","%c"),console.log.apply(null,[r,"font-weight:bold;"])):console.log(e)):(e=e.replace(/<b>/g,""),console.log(e)))}function b(e,i){return d(i),d(""),e}function y(e,i,t,n,r){if(null!=e){r=e({name:t,variant:n,data:r});return"boolean"==typeof r?r:b(!1,"The ".concat(i," returns ").concat(r,". => Please return true or false. This result (and all non-boolean results) will return false."))}}function l(e,i,t,n){t={name:e,variant:i,data:t};return t.key=getKey(t.name,t.variant),null==n||(t.visibilityFunction=parseToFn(n),t.result=t.visibilityFunction({name:t.name,variant:t.variant,data:t.data||{},_internalCall:!0,description:"When attaching a function, the result must be calculated internally. You can filter this out with the _internalCall:true -Flag."})),t}var i={name:"feature-toggle-api",setData:function(e,i,t){if(null==e)throw new Error("setData(): The name must of the feature must be defined, but ist undefined");i=l(e,null!=t?i:void 0,t||i);c.datas[i.key]=i.data,r("visibilityrule",i)},on:function(e,n,i){c.listeners[e]=c.listeners[e]||[],c.listeners[e].push(n),r("registerEvent",{type:e}),null!=i&&i.ignorePreviousRules||Object.keys(c.visibilities).forEach(function(e){var i,t,i={name:(t=(i=e).split("#"))[0],variant:1<t.length?t[1]:void 0,data:c.datas[i]},e=c.visibilities[e];i.result=e(i),n(i)})},trigger:r,showLogs:function(e){c.showLogs=null==e||e},isVisible:function(e,i,t){var n=c.visibilities;if(d('\nCheck Visibility of <b>Feature "'.concat(e,'", variant "').concat(null==i?"":i,'"').concat(t?" with data "+JSON.stringify(t):"",".")),null==e)throw new Error('The attribute "name" is required for tag <feature></feature>. Example: <feature name="aname"></feature>');var r=n._required,l=null!=n._required,o=y(r,"requiredVisibility",e,i,t),u=getKey(e,i),a=n[u],s=null!=n[u],f=y(a,"visibility function",e,i,t),r=null!=i,u=getKey(e,null),a=n[u],u=(n[u],y(a,"visibility function (only name)",e,i,t)),a=n._default,n=null!=n._default,t=y(a,"defaultVisibility",e,i,t);if(l){if(l&&!0===o)d("The requiredVisibility rule returns true. This feature will be shown when no other rule rejects it.");else if(l&&!1===o)return b(!1,"The requiredVisibility rule returns false. This feature will be hidden.")}else d("No requiredVisibility rule specified for this feature.");return s?b(f,"The visibility rule returns ".concat(f,". This feature will be ").concat(f?"visible":"hidden",".")):(d("No visibility rule found matching name and variant."),r&&"boolean"==typeof u?b(u,"Found a visibility rule for name ".concat(e," without variants. The rule returns ").concat(u,". => This feature will be ").concat(u?"visible":"hidden",".")):(r&&d("No rules found for name ".concat(e," without variants.")),n?b(t,"Found a defaultVisibility rule. The rule returns ".concat(t,". => This feature will be ").concat(t?"visible":"hidden",".")):(d("No default rule found."),l?b(!0,"Only the requiredVisibility rule was found. This returned true. => This feature will be visible."):b(!1,"No rules were found. This feature will be hidden."))))},visibility:function(e,i,t,n){n=function(e,i,t,n){if(null==e)throw new Error("feature.visibility(): 1st parameter name must be defined");if(1==arguments.length)throw new Error("feature.visibility(): 2nd parameter name must be a boolean or function, but is empty");var r=null,l=null,o=null,o=null==t&&null==n?i:null==n?(r=i,t):(r=i,l=t,n);return{name:e,variant:r,data:l,result:o}}(e,i,t,n),n=l(n.name,n.variant,n.data,n.result);c.visibilities[n.key]=n.visibilityFunction,c.datas[n.key]=n.data,r("visibilityrule",n)},requiredVisibility:function(e){if("function"!=typeof e)throw new Error("feature.requiredVisibility(): 1st parameter must be a function, but is "+_typeof(e));c.visibilities._required=parseToFn(e)},defaultVisibility:function(e){if("function"!=typeof e)throw new Error("feature.defaultVisibility(): 1st parameter must be a function, but is "+_typeof(e));c.visibilities._default=parseToFn(e)},addPlugin:function(e){c.usedPlugins.includes(e)||(t(e,i),c.usedPlugins.push(e))}};return function(i){if(e._plugins){if(!Array.isArray(e._plugins))throw new Error("featuretoggleapi()-constructor: config.plugins must be an array.");e._plugins.forEach(function(e){if("function"!=typeof e)throw new Error("featuretoggleapi()-constructor: config.plugins needs functions as entries, not "+_typeof(e)+".");t(e,i)})}r("init")}(i),i}window.featureToggleApi=featuretoggleapi;
|
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
4
|
-
|
|
5
|
-
var parseToFn = function parseToFn(fnOrBool) {
|
|
6
|
-
if (typeof fnOrBool == 'boolean') return function () {
|
|
7
|
-
return fnOrBool;
|
|
8
|
-
};
|
|
9
|
-
return fnOrBool;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
var getKey = function getKey(name, variant) {
|
|
13
|
-
var _name = name.toLowerCase();
|
|
14
|
-
|
|
15
|
-
if (typeof variant == 'string') {
|
|
16
|
-
_name += "#" + variant.toLowerCase();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return _name;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
function initVisibilities() {
|
|
23
|
-
var visibilities = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
24
|
-
var returnVisibilities = {};
|
|
25
|
-
Object.keys(visibilities).forEach(function (key) {
|
|
26
|
-
if (key.startsWith('_')) return;
|
|
27
|
-
returnVisibilities[getKey(key)] = parseToFn(visibilities[key]);
|
|
28
|
-
});
|
|
29
|
-
return returnVisibilities;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function featuretoggleapi() {
|
|
33
|
-
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
34
|
-
var globals = {
|
|
35
|
-
datas: {},
|
|
36
|
-
listeners: {},
|
|
37
|
-
visibilities: initVisibilities(config),
|
|
38
|
-
showLogs: false,
|
|
39
|
-
usedPlugins: []
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
function init(api) {
|
|
43
|
-
if (config._plugins) {
|
|
44
|
-
if (!Array.isArray(config._plugins)) throw new Error('featuretoggleapi()-constructor: config.plugins must be an array.');
|
|
45
|
-
|
|
46
|
-
config._plugins.forEach(function (plugin) {
|
|
47
|
-
if (typeof plugin !== 'function') throw new Error('featuretoggleapi()-constructor: config.plugins needs functions as entries, not ' + _typeof(plugin) + '.');
|
|
48
|
-
|
|
49
|
-
_addPlugin(plugin, api);
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
triggerEvent('init');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function _addPlugin(plugin, api) {
|
|
57
|
-
plugin(api);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function triggerEvent(eventtype, param) {
|
|
61
|
-
(globals.listeners[eventtype] || []).forEach(function (listener) {
|
|
62
|
-
listener(param);
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
var log = function log(message) {
|
|
67
|
-
if (!globals.showLogs) return; //Nur Browser können Syntaxhighlighting die anderen geben die Nachricht einfach aus und schneiden
|
|
68
|
-
//die styletags raus
|
|
69
|
-
|
|
70
|
-
if (typeof window === 'undefined') {
|
|
71
|
-
var loggedMessage = message.replace(/<b>/g, "");
|
|
72
|
-
console.log(loggedMessage);
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
var hasBoldTag = message.indexOf('<b>') != -1;
|
|
77
|
-
var hasVisibleKeyword = message.indexOf('visible') != -1;
|
|
78
|
-
var hasHiddenKeyword = message.indexOf('hidden') != -1;
|
|
79
|
-
|
|
80
|
-
var _message = message.replace('visible', '%cvisible');
|
|
81
|
-
|
|
82
|
-
_message = _message.replace('hidden', '%chidden');
|
|
83
|
-
if (hasVisibleKeyword) console.log(_message, "color:green;font-weight:bold;");else if (hasHiddenKeyword) console.log(_message, "color:red;font-weight:bold;");else if (hasBoldTag) {
|
|
84
|
-
_message = _message.replace('<b>', '%c');
|
|
85
|
-
var parts = [_message, 'font-weight:bold;'];
|
|
86
|
-
console.log.apply(null, parts);
|
|
87
|
-
} else console.log(message);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
var logAndReturn = function logAndReturn(returnValue, message) {
|
|
91
|
-
log(message);
|
|
92
|
-
log('');
|
|
93
|
-
return returnValue;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
var getVisibility = function getVisibility(visibilityFn, functionname, name, variant, data) {
|
|
97
|
-
if (visibilityFn == null) return undefined;
|
|
98
|
-
var calculatedVisibility = visibilityFn({
|
|
99
|
-
name: name,
|
|
100
|
-
variant: variant,
|
|
101
|
-
data: data
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
if (typeof calculatedVisibility == 'boolean') {
|
|
105
|
-
return calculatedVisibility;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return logAndReturn(false, "The ".concat(functionname, " returns ").concat(calculatedVisibility, ". => Please return true or false. This result (and all non-boolean results) will return false."));
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
function parseKey(key) {
|
|
112
|
-
var parts = key.split('#');
|
|
113
|
-
return {
|
|
114
|
-
name: parts[0],
|
|
115
|
-
variant: parts.length > 1 ? parts[1] : undefined,
|
|
116
|
-
data: globals.datas[key]
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
/*
|
|
120
|
-
the following calls are possible:
|
|
121
|
-
visibility(name,result);
|
|
122
|
-
visibility(name,variant,result);
|
|
123
|
-
visibility(name,variant,data,result);
|
|
124
|
-
|
|
125
|
-
=>
|
|
126
|
-
param1: name
|
|
127
|
-
param2: result || variant
|
|
128
|
-
param3: result || data
|
|
129
|
-
param4: result
|
|
130
|
-
*/
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
function visibilityFnParams(param1, param2, param3, param4) {
|
|
134
|
-
//name must always be set
|
|
135
|
-
if (param1 == undefined) throw new Error('feature.visibility(): 1st parameter name must be defined');
|
|
136
|
-
if (arguments.length == 1) throw new Error('feature.visibility(): 2nd parameter name must be a boolean or function, but is empty');
|
|
137
|
-
var name = param1,
|
|
138
|
-
variant = null,
|
|
139
|
-
data = null,
|
|
140
|
-
result = null;
|
|
141
|
-
|
|
142
|
-
if (param3 == undefined && param4 == undefined) {
|
|
143
|
-
result = param2;
|
|
144
|
-
} else if (param4 == undefined) {
|
|
145
|
-
variant = param2;
|
|
146
|
-
result = param3;
|
|
147
|
-
} else {
|
|
148
|
-
variant = param2;
|
|
149
|
-
data = param3;
|
|
150
|
-
result = param4;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
name: name,
|
|
155
|
-
variant: variant,
|
|
156
|
-
data: data,
|
|
157
|
-
result: result
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function getEvent(name, variant, data, result) {
|
|
162
|
-
var event;
|
|
163
|
-
event = {
|
|
164
|
-
name: name,
|
|
165
|
-
variant: variant,
|
|
166
|
-
data: data
|
|
167
|
-
};
|
|
168
|
-
event.key = getKey(event.name, event.variant);
|
|
169
|
-
if (result == null) return event;
|
|
170
|
-
event.visibilityFunction = parseToFn(result);
|
|
171
|
-
event.result = event.visibilityFunction({
|
|
172
|
-
name: event.name,
|
|
173
|
-
variant: event.variant,
|
|
174
|
-
data: event.data || {},
|
|
175
|
-
_internalCall: true,
|
|
176
|
-
description: 'When attaching a function, the result must be calculated internally. You can filter this out with the _internalCall:true -Flag.'
|
|
177
|
-
});
|
|
178
|
-
return event;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function isVisible(name, variant, data) {
|
|
182
|
-
var visibilities = globals.visibilities;
|
|
183
|
-
log("\nCheck Visibility of <b>Feature \"".concat(name, "\", variant \"").concat(variant == undefined ? '' : variant, "\"").concat(data ? " with data " + JSON.stringify(data) : "", "."));
|
|
184
|
-
if (name == undefined) throw new Error('The attribute "name" is required for tag <feature></feature>. Example: <feature name="aname"></feature>');
|
|
185
|
-
var requiredFn = visibilities['_required'];
|
|
186
|
-
var requiredFnExists = visibilities['_required'] != null;
|
|
187
|
-
var requiredFnResult = getVisibility(requiredFn, 'requiredVisibility', name, variant, data);
|
|
188
|
-
var visibilityFnKey = getKey(name, variant);
|
|
189
|
-
var visibilityFn = visibilities[visibilityFnKey];
|
|
190
|
-
var visibilityFnExists = visibilities[visibilityFnKey] != null;
|
|
191
|
-
var visibilityFnResult = getVisibility(visibilityFn, 'visibility function', name, variant, data);
|
|
192
|
-
var variantExists = variant != null;
|
|
193
|
-
var visibilityOnlyNameFnKey = getKey(name, null);
|
|
194
|
-
var visibilityOnlyNameFn = visibilities[visibilityOnlyNameFnKey];
|
|
195
|
-
var visibilityOnlyNameFnExists = visibilities[visibilityOnlyNameFnKey] != null;
|
|
196
|
-
var visibilityOnlyNameFnResult = getVisibility(visibilityOnlyNameFn, 'visibility function (only name)', name, variant, data);
|
|
197
|
-
var defaultFn = visibilities['_default'];
|
|
198
|
-
var defaultFnExists = visibilities['_default'] != null;
|
|
199
|
-
var defaultFnResult = getVisibility(defaultFn, 'defaultVisibility', name, variant, data);
|
|
200
|
-
if (!requiredFnExists) log("No requiredVisibility rule specified for this feature.");else if (requiredFnExists && requiredFnResult === true) log("The requiredVisibility rule returns true. This feature will be shown when no other rule rejects it.");else if (requiredFnExists && requiredFnResult === false) return logAndReturn(false, "The requiredVisibility rule returns false. This feature will be hidden.");
|
|
201
|
-
if (visibilityFnExists) return logAndReturn(visibilityFnResult, "The visibility rule returns ".concat(visibilityFnResult, ". This feature will be ").concat(visibilityFnResult ? 'visible' : 'hidden', "."));
|
|
202
|
-
log('No visibility rule found matching name and variant.');
|
|
203
|
-
if (variantExists && typeof visibilityOnlyNameFnResult == 'boolean') return logAndReturn(visibilityOnlyNameFnResult, "Found a visibility rule for name ".concat(name, " without variants. The rule returns ").concat(visibilityOnlyNameFnResult, ". => This feature will be ").concat(visibilityOnlyNameFnResult ? 'visible' : 'hidden', "."));else if (variantExists) log("No rules found for name ".concat(name, " without variants."));
|
|
204
|
-
if (defaultFnExists) return logAndReturn(defaultFnResult, "Found a defaultVisibility rule. The rule returns ".concat(defaultFnResult, ". => This feature will be ").concat(defaultFnResult ? 'visible' : 'hidden', "."));
|
|
205
|
-
log("No default rule found.");
|
|
206
|
-
if (requiredFnExists) return logAndReturn(true, "Only the requiredVisibility rule was found. This returned true. => This feature will be visible.");
|
|
207
|
-
return logAndReturn(false, 'No rules were found. This feature will be hidden.');
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
var api = {
|
|
211
|
-
name: 'feature-toggle-api',
|
|
212
|
-
setData: function setData(nameParam, variantOrDataParam, dataParam) {
|
|
213
|
-
if (nameParam == undefined) throw new Error('setData(): The name must of the feature must be defined, but ist undefined');
|
|
214
|
-
var variant = dataParam != undefined ? variantOrDataParam : undefined;
|
|
215
|
-
var data = dataParam || variantOrDataParam;
|
|
216
|
-
var event = getEvent(nameParam, variant, data);
|
|
217
|
-
globals.datas[event.key] = event.data;
|
|
218
|
-
triggerEvent('visibilityrule', event);
|
|
219
|
-
},
|
|
220
|
-
on: function on(eventtype, fn, config) {
|
|
221
|
-
globals.listeners[eventtype] = globals.listeners[eventtype] || [];
|
|
222
|
-
globals.listeners[eventtype].push(fn);
|
|
223
|
-
triggerEvent('registerEvent', {
|
|
224
|
-
type: eventtype
|
|
225
|
-
});
|
|
226
|
-
if (config != undefined && config.ignorePreviousRules) return;
|
|
227
|
-
Object.keys(globals.visibilities).forEach(function (key) {
|
|
228
|
-
var event = parseKey(key, globals);
|
|
229
|
-
var rule = globals.visibilities[key];
|
|
230
|
-
event.result = rule(event);
|
|
231
|
-
fn(event);
|
|
232
|
-
});
|
|
233
|
-
},
|
|
234
|
-
trigger: triggerEvent,
|
|
235
|
-
showLogs: function showLogs(_showLogs) {
|
|
236
|
-
globals.showLogs = _showLogs == undefined ? true : _showLogs;
|
|
237
|
-
},
|
|
238
|
-
isVisible: isVisible,
|
|
239
|
-
|
|
240
|
-
/*
|
|
241
|
-
the following function calls are possible:
|
|
242
|
-
visibility(name,result);
|
|
243
|
-
visibility(name,variant,result);
|
|
244
|
-
visibility(name,variant,data,result);
|
|
245
|
-
*/
|
|
246
|
-
visibility: function visibility(param1, param2, param3, param4) {
|
|
247
|
-
var params = visibilityFnParams(param1, param2, param3, param4);
|
|
248
|
-
var event = getEvent(params.name, params.variant, params.data, params.result);
|
|
249
|
-
globals.visibilities[event.key] = event.visibilityFunction;
|
|
250
|
-
globals.datas[event.key] = event.data;
|
|
251
|
-
triggerEvent('visibilityrule', event);
|
|
252
|
-
},
|
|
253
|
-
requiredVisibility: function requiredVisibility(fn) {
|
|
254
|
-
if (typeof fn != "function") throw new Error('feature.requiredVisibility(): 1st parameter must be a function, but is ' + _typeof(fn));
|
|
255
|
-
globals.visibilities['_required'] = parseToFn(fn);
|
|
256
|
-
},
|
|
257
|
-
defaultVisibility: function defaultVisibility(fn) {
|
|
258
|
-
if (typeof fn != "function") throw new Error('feature.defaultVisibility(): 1st parameter must be a function, but is ' + _typeof(fn));
|
|
259
|
-
globals.visibilities['_default'] = parseToFn(fn);
|
|
260
|
-
},
|
|
261
|
-
addPlugin: function addPlugin(plugin) {
|
|
262
|
-
if (globals.usedPlugins.includes(plugin)) return;
|
|
263
|
-
|
|
264
|
-
_addPlugin(plugin, api);
|
|
265
|
-
|
|
266
|
-
globals.usedPlugins.push(plugin);
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
init(api);
|
|
270
|
-
return api;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
module.exports = featuretoggleapi;
|