UNPKG

feature-u

Version:

Feature Based Project Organization for React

1,500 lines (1,318 loc) 348 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define("FeatureU", [], factory); else if(typeof exports === 'object') exports["FeatureU"] = factory(); else root["FeatureU"] = factory(); })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 35); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; // shim for using process in browser var process = module.exports = {}; // cached from whatever global is present so that test runners that stub it // don't break things. But we need to wrap it in a try catch in case it is // wrapped in strict mode code which doesn't define any globals. It's inside a // function because try/catches deoptimize in certain engines. var cachedSetTimeout; var cachedClearTimeout; function defaultSetTimout() { throw new Error('setTimeout has not been defined'); } function defaultClearTimeout() { throw new Error('clearTimeout has not been defined'); } (function () { try { if (typeof setTimeout === 'function') { cachedSetTimeout = setTimeout; } else { cachedSetTimeout = defaultSetTimout; } } catch (e) { cachedSetTimeout = defaultSetTimout; } try { if (typeof clearTimeout === 'function') { cachedClearTimeout = clearTimeout; } else { cachedClearTimeout = defaultClearTimeout; } } catch (e) { cachedClearTimeout = defaultClearTimeout; } })(); function runTimeout(fun) { if (cachedSetTimeout === setTimeout) { //normal enviroments in sane situations return setTimeout(fun, 0); } // if setTimeout wasn't available but was latter defined if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { cachedSetTimeout = setTimeout; return setTimeout(fun, 0); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedSetTimeout(fun, 0); } catch (e) { try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedSetTimeout.call(null, fun, 0); } catch (e) { // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error return cachedSetTimeout.call(this, fun, 0); } } } function runClearTimeout(marker) { if (cachedClearTimeout === clearTimeout) { //normal enviroments in sane situations return clearTimeout(marker); } // if clearTimeout wasn't available but was latter defined if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { cachedClearTimeout = clearTimeout; return clearTimeout(marker); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedClearTimeout(marker); } catch (e) { try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedClearTimeout.call(null, marker); } catch (e) { // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. // Some versions of I.E. have different rules for clearTimeout vs setTimeout return cachedClearTimeout.call(this, marker); } } } var queue = []; var draining = false; var currentQueue; var queueIndex = -1; function cleanUpNextTick() { if (!draining || !currentQueue) { return; } draining = false; if (currentQueue.length) { queue = currentQueue.concat(queue); } else { queueIndex = -1; } if (queue.length) { drainQueue(); } } function drainQueue() { if (draining) { return; } var timeout = runTimeout(cleanUpNextTick); draining = true; var len = queue.length; while (len) { currentQueue = queue; queue = []; while (++queueIndex < len) { if (currentQueue) { currentQueue[queueIndex].run(); } } queueIndex = -1; len = queue.length; } currentQueue = null; draining = false; runClearTimeout(timeout); } process.nextTick = function (fun) { var args = new Array(arguments.length - 1); if (arguments.length > 1) { for (var i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i]; } } queue.push(new Item(fun, args)); if (queue.length === 1 && !draining) { runTimeout(drainQueue); } }; // v8 likes predictible objects function Item(fun, array) { this.fun = fun; this.array = array; } Item.prototype.run = function () { this.fun.apply(null, this.array); }; process.title = 'browser'; process.browser = true; process.env = {}; process.argv = []; process.version = ''; // empty string to avoid regexp issues process.versions = {}; function noop() {} process.on = noop; process.addListener = noop; process.once = noop; process.off = noop; process.removeListener = noop; process.removeAllListeners = noop; process.emit = noop; process.prependListener = noop; process.prependOnceListener = noop; process.listeners = function (name) { return []; }; process.binding = function (name) { throw new Error('process.binding is not supported'); }; process.cwd = function () { return '/'; }; process.chdir = function (dir) { throw new Error('process.chdir is not supported'); }; process.umask = function () { return 0; }; /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = true; exports.default = verify; /** * A convenience assertion utility, typically used to validate * pre-conditions of a routine. * * **Advanced**: verify.prefix(msgPrefix) returns a higher-order * verify() function where all messages are prefixed. * * @param {truthy} condition - a "truthy" condition which * must be satisfied. * * @param {string} msg - a message clarifying the condition being * checked. * * @throws {Error} an Error is thrown when the supplied condition is * NOT met. * * @private */ function verify(condition, msg) { if (!condition) { // TODO: don't think there is any benefit in logging this console.error // console.error(`verify() constraint issue: ${msg}`); // supplement exception with error log (for react-native exposure) throw new Error(msg); } } verify.prefix = function (msgPrefix) { return function (condition, msg) { return verify(condition, msgPrefix + msg); }; }; /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /** * lodash 4.0.1 (Custom Build) <https://lodash.com/> * Build: `lodash modularize exports="npm" -o ./` * Copyright 2012-2016 The Dojo Foundation <http://dojofoundation.org/> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license <https://lodash.com/license> */ /** `Object#toString` result references. */ var stringTag = '[object String]'; /** Used for built-in method references. */ var objectProto = Object.prototype; /** * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) * of values. */ var objectToString = objectProto.toString; /** * Checks if `value` is classified as an `Array` object. * * @static * @memberOf _ * @type Function * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isArray([1, 2, 3]); * // => true * * _.isArray(document.body.children); * // => false * * _.isArray('abc'); * // => false * * _.isArray(_.noop); * // => false */ var isArray = Array.isArray; /** * Checks if `value` is object-like. A value is object-like if it's not `null` * and has a `typeof` result of "object". * * @static * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is object-like, else `false`. * @example * * _.isObjectLike({}); * // => true * * _.isObjectLike([1, 2, 3]); * // => true * * _.isObjectLike(_.noop); * // => false * * _.isObjectLike(null); * // => false */ function isObjectLike(value) { return !!value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) == 'object'; } /** * Checks if `value` is classified as a `String` primitive or object. * * @static * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isString('abc'); * // => true * * _.isString(1); * // => false */ function isString(value) { return typeof value == 'string' || !isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag; } module.exports = isString; /***/ }), /* 3 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /* WEBPACK VAR INJECTION */(function(global) { var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /** * Lodash (Custom Build) <https://lodash.com/> * Build: `lodash modularize exports="npm" -o ./` * Copyright JS Foundation and other contributors <https://js.foundation/> * Released under MIT license <https://lodash.com/license> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ /** `Object#toString` result references. */ var asyncTag = '[object AsyncFunction]', funcTag = '[object Function]', genTag = '[object GeneratorFunction]', nullTag = '[object Null]', proxyTag = '[object Proxy]', undefinedTag = '[object Undefined]'; /** Detect free variable `global` from Node.js. */ var freeGlobal = (typeof global === 'undefined' ? 'undefined' : _typeof(global)) == 'object' && global && global.Object === Object && global; /** Detect free variable `self`. */ var freeSelf = (typeof self === 'undefined' ? 'undefined' : _typeof(self)) == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function('return this')(); /** Used for built-in method references. */ var objectProto = Object.prototype; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var nativeObjectToString = objectProto.toString; /** Built-in value references. */ var _Symbol = root.Symbol, symToStringTag = _Symbol ? _Symbol.toStringTag : undefined; /** * The base implementation of `getTag` without fallbacks for buggy environments. * * @private * @param {*} value The value to query. * @returns {string} Returns the `toStringTag`. */ function baseGetTag(value) { if (value == null) { return value === undefined ? undefinedTag : nullTag; } return symToStringTag && symToStringTag in Object(value) ? getRawTag(value) : objectToString(value); } /** * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. * * @private * @param {*} value The value to query. * @returns {string} Returns the raw `toStringTag`. */ function getRawTag(value) { var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag]; try { value[symToStringTag] = undefined; var unmasked = true; } catch (e) {} var result = nativeObjectToString.call(value); if (unmasked) { if (isOwn) { value[symToStringTag] = tag; } else { delete value[symToStringTag]; } } return result; } /** * Converts `value` to a string using `Object.prototype.toString`. * * @private * @param {*} value The value to convert. * @returns {string} Returns the converted string. */ function objectToString(value) { return nativeObjectToString.call(value); } /** * Checks if `value` is classified as a `Function` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a function, else `false`. * @example * * _.isFunction(_); * // => true * * _.isFunction(/abc/); * // => false */ function isFunction(value) { if (!isObject(value)) { return false; } // The use of `Object#toString` avoids issues with the `typeof` operator // in Safari 9 which returns 'object' for typed arrays and other constructors. var tag = baseGetTag(value); return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; } /** * Checks if `value` is the * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(_.noop); * // => true * * _.isObject(null); * // => false */ function isObject(value) { var type = typeof value === 'undefined' ? 'undefined' : _typeof(value); return value != null && (type == 'object' || type == 'function'); } module.exports = isFunction; /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(16))) /***/ }), /* 4 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = true; exports.default = logf; var _verify = __webpack_require__(1); var _verify2 = _interopRequireDefault(_verify); var _lodash = __webpack_require__(2); var _lodash2 = _interopRequireDefault(_lodash); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /*-------------------------------------------------------------------------------- feature-u's logging utility: - can be enabled/disabled at run-time - all logging probes are prefixed with: ***feature-u*** - a simple layer on top of console.log() - for internal use only ... selected functions are exposed to the client through the UNDOCUMENTED launchApp.diag mechanism (for diagnostic purposes) API: + logf(msg [,obj]): void ... conditionally log probe when feature-u logging is enabled + logf.force(msg [,obj]): void ... unconditionally log probe + logf.isEnabled(): true/false ... is feature-u logging enabled or disabled + logf.enable(): void ... enable feature-u logging + logf.disable(): void ... disable feature-u logging + logf.elm2html(elm): htmlStr ... convert react elm into nicely formatted html markup > FOR PLUGIN PROJECTS: - support their own unique prefix by emitting a new higher-order logf function - STILL undocumented (at this point) + logf.newLogger(prefix): logf ... support plugin project logging with their own prefix (a HOF logger) --------------------------------------------------------------------------------*/ var msgPrefix = '***feature-u*** '; var _enabled = false; // API: logf(msg [,obj]): void ... conditionally log probe when feature-u logging is enabled function logf(msg, obj) { if (logf.isEnabled()) { logf.force(msg, obj); } } // API: logf.force(msg [,obj]): void ... unconditionally log probe logf.force = function (msg, obj) { msg = msgPrefix + msg; if (obj) { console.log(msg, obj); } else { console.log(msg); } }; // API: logf.isEnabled(): true/false ... is feature-u logging enabled or disabled logf.isEnabled = function () { return _enabled; }; // API: logf.enabled(): void ... enable feature-u logging logf.enable = function () { _enabled = true; logf('enabling logf()'); }; // API: logf.disable(): void ... disable feature-u logging logf.disable = function () { logf('disabling logf()'); _enabled = false; }; var elm2htmlOneTimeWarning = 'WARNING: By default any react element content is OMITTED.\n\nThis can be overridden by doing the following (before launchApp() is invoked):\n\n- To see the (rather verbose) raw object content, do this:\n launchApp.diag.logf.elm2html = (elm) => elm;\n\n- To see nicely formatted html markup, do this:\n import ReactDOMServer from \'react-dom/server\';\n ...\n launchApp.diag.logf.elm2html = (elm) => ReactDOMServer.renderToStaticMarkup(elm);\n\n'; // API: logf.elm2html(elm): htmlStr ... convert react elm into nicely formatted html markup // the default logf.elm2html() implementation OMITs the elm content // BECAUSE: // 1: we don't want to have a dependency on react-dom (for nicely formatted html markup) // 2: the raw object content is verbose and un-interpretable // HOWEVER: // 3: it can be overridden by the client (see one-time log entry above) logf.elm2html = function (elm) { // emit one-time warning if (elm2htmlOneTimeWarning) { logf(elm2htmlOneTimeWarning); elm2htmlOneTimeWarning = null; } // return indication of omission return 'OMITTED'; }; // API: logf.newLogger(prefix): logf ... support plugin project logging with their own prefix (a HOF logger) logf.newLogger = function (prefix) { var check = _verify2.default.prefix('logf.newLogger() parameter violation: '); check(prefix, 'prefix is required'); check((0, _lodash2.default)(prefix), 'prefix must be a string'); var newLogger = function newLogger(msg, obj) { // re-implement to hook into our .force() ... where the prefixing occurs if (logf.isEnabled()) { newLogger.force(msg, obj); } }; // this is where the magic happens (i.e. the additional prefixing) newLogger.force = function (msg, obj) { return logf.force(prefix + msg, obj); }; // apply all same logf.properties (for consistant API) // ... referencing original logf master // >>> NOTE: this means there is ONE enablement and elm2html(). // KIS: Keep it Simple // EX: by enabling logf, all plugin logging is enabled too // ALSO: by enabling plugin logging, ALL logging is enabled (logf, and other plugins) newLogger.isEnabled = logf.isEnabled; newLogger.enable = logf.enable; newLogger.disable = logf.disable; newLogger.elm2html = function (elm) { return logf.elm2html(elm); }; // always dereference original logf to pick up any function overrides //newLogger.newLogger = logf.newLogger; // NOT: we draw the line somewhere (in this simple implementation) // thats all folks return newLogger; }; /***/ }), /* 5 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /** * lodash (Custom Build) <https://lodash.com/> * Build: `lodash modularize exports="npm" -o ./` * Copyright jQuery Foundation and other contributors <https://jquery.org/> * Released under MIT license <https://lodash.com/license> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ /** `Object#toString` result references. */ var objectTag = '[object Object]'; /** * Checks if `value` is a host object in IE < 9. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a host object, else `false`. */ function isHostObject(value) { // Many host objects are `Object` objects that can coerce to strings // despite having improperly defined `toString` methods. var result = false; if (value != null && typeof value.toString != 'function') { try { result = !!(value + ''); } catch (e) {} } return result; } /** * Creates a unary function that invokes `func` with its argument transformed. * * @private * @param {Function} func The function to wrap. * @param {Function} transform The argument transform. * @returns {Function} Returns the new function. */ function overArg(func, transform) { return function (arg) { return func(transform(arg)); }; } /** Used for built-in method references. */ var funcProto = Function.prototype, objectProto = Object.prototype; /** Used to resolve the decompiled source of functions. */ var funcToString = funcProto.toString; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** Used to infer the `Object` constructor. */ var objectCtorString = funcToString.call(Object); /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var objectToString = objectProto.toString; /** Built-in value references. */ var getPrototype = overArg(Object.getPrototypeOf, Object); /** * Checks if `value` is object-like. A value is object-like if it's not `null` * and has a `typeof` result of "object". * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is object-like, else `false`. * @example * * _.isObjectLike({}); * // => true * * _.isObjectLike([1, 2, 3]); * // => true * * _.isObjectLike(_.noop); * // => false * * _.isObjectLike(null); * // => false */ function isObjectLike(value) { return !!value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) == 'object'; } /** * Checks if `value` is a plain object, that is, an object created by the * `Object` constructor or one with a `[[Prototype]]` of `null`. * * @static * @memberOf _ * @since 0.8.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. * @example * * function Foo() { * this.a = 1; * } * * _.isPlainObject(new Foo); * // => false * * _.isPlainObject([1, 2, 3]); * // => false * * _.isPlainObject({ 'x': 0, 'y': 0 }); * // => true * * _.isPlainObject(Object.create(null)); * // => true */ function isPlainObject(value) { if (!isObjectLike(value) || objectToString.call(value) != objectTag || isHostObject(value)) { return false; } var proto = getPrototype(value); if (proto === null) { return true; } var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; return typeof Ctor == 'function' && Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString; } module.exports = isPlainObject; /***/ }), /* 6 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /* WEBPACK VAR INJECTION */(function(process) { if (process.env.NODE_ENV === 'production') { module.exports = __webpack_require__(33); } else { module.exports = __webpack_require__(32); } /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) /***/ }), /* 7 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = true; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; exports.default = createFeature; exports.isFeatureProperty = isFeatureProperty; exports.extendFeatureProperty = extendFeatureProperty; var _verify = __webpack_require__(1); var _verify2 = _interopRequireDefault(_verify); var _lodash = __webpack_require__(2); var _lodash2 = _interopRequireDefault(_lodash); var _lodash3 = __webpack_require__(3); var _lodash4 = _interopRequireDefault(_lodash3); var _logf = __webpack_require__(4); var _logf2 = _interopRequireDefault(_logf); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** * Create a new {{book.api.Feature}} object, cataloging * {{book.api.AspectContent}} to be consumed by * {{book.api.launchApp}}. Each feature within an application * promotes it's own {{book.api.Feature}} object. * * For more information, please refer to * {{book.guide.detail_featureAndAspect}}. * * **Please Note** this function uses named parameters. * * @param {string} name the identity of the feature. Feature names * are guaranteed to be unique. Application code can use the Feature * name in various **single-source-of-truth** operations _(see * {{book.guide.bestPractices}})_. * * @param {boolean} [enabled=true] an indicator as to whether this * feature is enabled (true) or not (false). When used, this * indicator is typically based on a dynamic expression, allowing * packaged code to be dynamically enabled/disabled at run-time * _(please refer to: {{book.guide.enablement}})_. * * @param {fassets} [fassets] * an optional aspect that promotes feature assets used in * {{book.guide.crossCom}} (i.e. the Public Face of a feature). * `fassets` directives can both define resources, and/or declare a * resource contract (the intention to use a set of fasset resources). * Resources are accumulated across all features, and exposed through * the {{book.api.FassetsObject}}, and the {{book.api.withFassets}} * HoC. * * @param {appWillStartCB} [appWillStart] an optional * {{book.guide.appLifeCycle}} invoked one time, just before the app * starts up. This life-cycle hook can do any type of initialization, * and/or optionally supplement the app's top-level content (using a * non-null return) _(please refer to: {{book.guide.appWillStart}})_. * * @param {appInitCB} [appInit] an optional * {{book.guide.appLifeCycle}} invoked one time, later in the app * startup process. This life-cycle hook supports blocking async * initialization (by simply returning a promise) _(please refer to: * {{book.guide.appInit}})_. * * @param {appDidStartCB} [appDidStart] an optional * {{book.guide.appLifeCycle}} invoked one time, immediately after the * app has started _(please refer to: {{book.guide.appDidStart}})_. * * @param {AspectContent} [extendedAspect] additional aspects, as * defined by the feature-u's Aspect plugins (please refer to: * {{book.guide.detail_extendableAspects}} -and- * {{book.guide.extending}}). * * @return {Feature} a new Feature object (to be consumed by * launchApp()). * * @function createFeature */ function createFeature() { var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var name = _ref.name, _ref$enabled = _ref.enabled, enabled = _ref$enabled === undefined ? true : _ref$enabled, fassets = _ref.fassets, appWillStart = _ref.appWillStart, appInit = _ref.appInit, appDidStart = _ref.appDidStart, extendedAspect = _objectWithoutProperties(_ref, ['name', 'enabled', 'fassets', 'appWillStart', 'appInit', 'appDidStart']); // validate createFeature() parameters var check = _verify2.default.prefix('createFeature() parameter violation: '); // ... name check(name, 'name is required'); check((0, _lodash2.default)(name), 'name must be a string'); // ... enabled check(enabled === true || enabled === false, 'enabled must be a boolean'); // ... fasset: validation occurs in createFasset() // ... appWillStart if (appWillStart) { check((0, _lodash4.default)(appWillStart), 'appWillStart (when supplied) must be a function'); } // ... appInit if (appInit) { check((0, _lodash4.default)(appInit), 'appInit (when supplied) must be a function'); } // ... appDidStart if (appDidStart) { check((0, _lodash4.default)(appDidStart), 'appDidStart (when supplied) must be a function'); } // ... extendedAspect // ... this validation occurs by the Aspect itself (via launchApp()) // BECAUSE we don't know the Aspects in use UNTIL run-time (in launchApp) // create/return our new Feature object return _extends({ name: name, enabled: enabled, fassets: fassets, appWillStart: appWillStart, appInit: appInit, appDidStart: appDidStart }, extendedAspect); } /** * Maintain all VALID Feature properties. * * This is used to restrict Feature properties to ONLY valid ones: * - preventing user typos * - validation is employed at run-time in launchApp() * * Initially seeded with Feature builtins. * * Later, supplemented with extendFeatureProperty(name, owner) at run-time * (via Aspect plugins). * * @private */ var validFeatureProps = { // owner id of extension (ex: aspect's npm package name) // ========= name: 'builtin', enabled: 'builtin', publicFace: 'builtin', // OBSOLETE as of feature-u@1 ... still registered for the sole purpose of generating more specific error (see: createFassets.js) fassets: 'builtin', appWillStart: 'builtin', appInit: 'builtin', appDidStart: 'builtin' }; /** * Is the supplied name a valid Feature property? * * @param {string} name the property name to check. * * @param {boolean} true: valid Feature property, * false: NOT a Feature property * * @private */ function isFeatureProperty(name) { return validFeatureProps[name] ? true : false; } /** * Extend valid Feature properties to include the supplied name * ... used when extending APIs for * {{book.guide.extending_aspectCrossCommunication}}. * * **feature-u** keeps track of the agent that owns this extension * (using the owner parameter). This is used to prevent exceptions * when duplicate extension requests are made by the same owner. This * can happen when multiple instances of an aspect type are supported, * and also in unit testing. * * @param {string} name the property name to allow. * * @param {string} owner the requesting owner id of this extension * request. Use any string that uniquely identifies your utility * _(such as the aspect's npm package name)_. * * @throws {Error} when supplied name is already reserved by a different owner */ function extendFeatureProperty(name, owner) { // validate parameters var check = _verify2.default.prefix('extendFeatureProperty() parameter violation: '); check(name, 'name is required'); check((0, _lodash2.default)(name), 'name must be a string'); check(owner, 'owner is required'); check((0, _lodash2.default)(owner), 'owner must be a string'); // verify supplied name is NOT already reserved (by a different owner) if (isFeatureProperty(name) && // already reserved validFeatureProps[name] !== owner) { // by a different owner throw new Error('**ERROR** extendFeatureProperty(\'' + name + '\', \'' + owner + '\') ... \'Feature.' + name + '\' is already reserved by different owner.'); } // reserve it validFeatureProps[name] = owner; (0, _logf2.default)('invoking: extendFeatureProperty(\'' + name + '\', \'' + owner + '\') ... now validFeatureProps: ', validFeatureProps); } //*** //*** Specification: Feature //*** /** * @typedef {Object} Feature * * The Feature object is merely a lightweight container that holds * {{book.api.AspectContent}} of interest to **feature-u**. * * Each feature within an application promotes a Feature object (using * {{book.api.createFeature}}) which catalogs the aspects of that feature. * * Ultimately, all Feature objects are consumed by * {{book.api.launchApp}}. * * Feature content are simple key/value pairs (the key being an * Aspect.name with values of AspectContent). These aspects can * either be **built-in** (from core **feature-u**), or **extensions**. * * Here is an example: * * ```js * export default createFeature({ * name: 'featureA', // builtin aspect (name must be unique across all features within app) * enabled: true, // builtin aspect enabling/disabling feature * * fassets: { // builtin aspect promoting Public Face - Cross Feature Communication * define: { * 'api.openA': () => ..., * 'api.closeA': () => ..., * }, * }, * * appWillStart: (...) => ..., // builtin aspect (Application Life Cycle Hook) * appInit: (...) => ..., // ditto * appDidStart: (...) => ..., // ditto * * reducer: ..., // feature redux reducer (extended aspect from the feature-redux plugin) * logic: ..., // feature logic modules (extended aspect from the feature-redux-logic plugin) * }); * ``` * * For more information, please refer to * {{book.guide.detail_featureAndAspect}}. */ //*** //*** Specification: appWillStartCB //*** /** * An optional {{book.guide.appLifeCycle}} invoked one time, very * early in the app startup process. * * This life-cycle hook can do any type of general app-specific * initialization _(for example initializing a **PWA service * worker**)_. * * In addition, it can optionally inject static content in the app's * DOM root. Any return is interpreted as the app's new `rootAppElm` * _(an accumulative process)_. **IMPORTANT**: When this is used, the * supplied `curRootAppElm` MUST be included as part of this * definition (accommodating the accumulative process of other feature * injections)! **More information is available at * {{book.guide.injectingDomContent}}** * * For more information _(with examples)_, please refer to the * Guide's {{book.guide.appWillStart}}. * * **Please Note** this function uses named parameters. * * @callback appWillStartCB * * @param {Fassets} fassets the Fassets object used in cross-feature-communication. * * @param {reactElm} curRootAppElm - the current react app element * root. * * @return {reactElm|void} optionally, new top-level content (which in turn * must contain the supplied `curRootAppElm`). Use a void return * when top-level content is unchanged. */ //*** //*** Specification: appInitCB //*** /** * An optional {{book.guide.appLifeCycle}} invoked one time, later in * the app startup process. It supports blocking async * initialization. * * This hook is invoked when the app is **nearly up-and-running**. * * - The {{book.guide.detail_reactRegistration}} has already occurred * _(via the {{book.api.registerRootAppElmCB}} callback)_. As a * result, you can rely on utilities that require an app-specific * `rootAppElm` to exist. * * - You have access to the `getState()` and `dispatch()` function, * assuming you are using {{book.ext.redux}} (when detected by * **feature-u**'s plugable aspects). * * These parameters are actually injected by the * {{book.ext.featureRedux}} Aspect, and are examples of what can be * injected by any Aspect _(please refer your specific Aspect's * documentation to determine other parameters)_. * * Just like the {{book.api.appWillStartCB}} hook, you may perform any * type of general initialization that is required by your feature. * * However the **hallmark of this hook** is **you can block for any * asynchronous initialization to complete**. By simply returning a * promise, **feature-u** will wait for the process to complete. * * The user is kept advised of any long-running async processes. By * default an `'initializing feature: {feature.name}'` message is * used, but you can customize it through the supplied * {{book.api.showStatusCB}} function parameter. * * For more info with examples, please see the Guide's * {{book.guide.appInit}}. * * **Please Note** this function uses named parameters. * * @callback appInitCB * * @param {showStatusCB} showStatus the function that (when invoked) * will communicate a blocking "persistent" status message to the end * user. * * @param {Fassets} fassets the Fassets object used in cross-feature-communication. * * @param {Any} [getState] - the redux function returning the top-level * app state (when redux is in use). * * @param {function} [dispatch] - the redux dispatch() function (when * redux is in use). * * @param {any} [injectedAspectParams] - additional parameters * injected by Aspect plugins _(please refer your specific Aspect's * documentation to determine other parameters)_. The `getState` and * `dispatch` params (above) are examples of this. * * @return {Promise|void} optionally, a promise (for asynchronous * processes) - and feature-u will wait for the process to complete. * Use a void return (for synchronous processes) - and no blocking * will occur. */ //*** //*** Specification: appDidStartCB //*** /** * An optional {{book.guide.appLifeCycle}} invoked one time, * once the app startup process has completed. * * This life-cycle hook can be used to trigger **"the app is * running"** events. A typical usage is to **"kick start"** some * early application logic. * * Because the app is up-and-running at this time, you have access to * the `getState()` and `dispatch()` function ... assuming you are using * {{book.ext.redux}} (when detected by **feature-u**'s plugable aspects). * These parameters are actually injected by the * {{book.ext.featureRedux}} Aspect, and are examples of what can be * injected by any Aspect _(please refer your specific Aspect's * documentation to determine other parameters)_. * * For more info with examples, please see the Guide's * {{book.guide.appDidStart}}. * * **Please Note** this function uses named parameters. * * @callback appDidStartCB * * @param {Fassets} fassets the Fassets object used in cross-feature-communication. * * @param {Any} [getState] - the redux function returning the top-level * app state (when redux is in use). * * @param {function} [dispatch] - the redux dispatch() function (when * redux is in use). * * @param {any} [injectedAspectParams] - additional parameters * injected by Aspect plugins _(please refer your specific Aspect's * documentation to determine other parameters)_. The `getState` and * `dispatch` params (above) are examples of this. * * @return void */ //*** //*** Specification: fassets //*** /** * @typedef {BuiltInAspect} fassets * * A builtin aspect that publicly promotes feature-based resources * called `fassets` (feature assets). These resources are the basis * of {{book.guide.crossCom}}. You can think of this as the Public Face * of a feature. * * **SideBar**: The term `fassets` is a play on words. While it is * pronounced "facet" _and is loosely related to this term_, it is * spelled fassets (i.e. feature assets). * * Feature resources are accumulated across all features, and exposed * through the {{book.api.FassetsObject}}. They can also be referenced * via the {{book.api.withFassets}} HoC. * * The `fassets` aspect can both define resources, and/or declare a * resource contract (i.e. the intention to use a set of fasset * resources). This is accomplished via three separate `fassets` * directives: `define`, `use`, and `defineUse`. A good summary of * these directives can be found at * {{book.guide.crossCom_fassetsRecapPushOrPull}}. * * 1. **define**: define public resources, held in the * {{book.api.FassetsObject}} * * ```js * fassets: { * define: { * '{fassetsKey}': {fassetsValue} * * ... * * NOTES: * - fassetsKey MUST be unique * - are case-sensitive * - may contain federated namespace (via dots ".") * ... normalized in fassets object * ... ex: 'MainPage.launch' * - may be any valid JS identifier (less $ support) * - may NOT contain wildcards * ... i.e. must be defined completely * * // examples ... * 'openView': actions.view.open, // fassets.openView(viewName): Action * * // federated namespace example * 'selector.currentView': selector.currentView, // fassets.selector.currentView(appState): viewName * * // UI Component example * 'MainPage.cart.link': () => <Link to="/cart">Cart</Link>, * 'MainPage.cart.body': () => <Route path="/cart" component={ShoppingCart}/>, * } * } * ``` * * 2. **use**: specify public resource keys that will be **used** by the * containing feature (i.e. a resource contract) * * ```js * fassets: { * use: [ * '{fassetsKey}', * -or- * ['$fassetsKey', {required: true/false, type: $validationFn}], * * ... * * NOTES: * - each key will be supplied by other features * - this is a communication to other features (i.e. a contract) * ... saying: I plan to "use" these injections * HOWEVER: feature-u cannot strictly enforce this usage * ... enclosed feature should reference this * {fassetsKey} through fassets.get(), or withFassets() * - is case-sensitive * - may contain federated namespace (with dots ".") * ... ex: 'MainPage.launch' * - may be any valid JS identifier (less $ support) * - may contain wildcards (with "*") * ... ex: 'MainPage.*.link' * * // examples ... * 'MainPage.launch', * * // may contain wildcards ... * 'MainPage.*.link', * 'MainPage.*.body', * * // optionally supply options object, controlling optionality and data types * ['MainPage.*.link', { required: true, type: any }], // same as DEFAULTS * ['MainPage.*.link', { required: false, }], // optional of any type * ['MainPage.*.link', { type: comp }], // required of react component type * ['MainPage.*.link', { required: false, type: comp }], // optional of react component type * ] * } * ``` * * 3. **defineUse**: define public resources specified by other features (via * the `use` directive) * * ```js * fassets: { * defineUse: { * '{fassetsKey}': {fassetsValue} * * ... * * NOTES: * - this is identical to fassets.define EXCEPT: * - it MUST MATCH a fassets.use directive * ... using this directive, feature-u will perform additional * validation to unsure these entries match a use contract * * // examples ... * 'MainPage.cart.link': () => <Link to="/cart">Cart</Link>, * 'MainPage.cart.body': () => <Route path="/cart" component={ShoppingCart}/>, * } * } * ``` * * For more information, please refer to {{book.guide.crossCom}}, * {{book.api.FassetsObject}}, the {{book.api.withFassets}} HoC, * and the {{book.guide.crossCom_fassetsRecapPushOrPull}}. */ /***/ }), /* 8 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = true; exports.FassetsContext = undefined; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); exports.withFassets = withFassets; exports.fassetsProps = fassetsProps; var _react = __webpack_require__(6); var _react2 = _interopRequireDefault(_react); var _createReactContext = __webpack_require__(23); var _createReactContext2 = _interopRequireDefault(_createReactContext); var _verify = __webpack_require__(1); var _verify2 = _interopRequireDefault(_verify); var _lodash = __webpack_require__(3); var _lodash2 = _interopRequireDefault(_lodash); var _lodash3 = __webpack_require__(5); var _lodash4 = _interopRequireDefault(_lodash3); var _lodash5 = __webpack_require__(2); var _lodash6 = _interopRequireDefault(_lodash5); var _mySpace = __webpack_require__(12); var _isComponent = __webpack_require__(17); var _isComponent2 = _interopRequireDefault(_isComponent); var _logf = __webpack_require__(4); var _logf2 = _interopRequireDefault(_logf); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } // ponyfill react context, supporting older version of react var fassetsNotDefined = 'NO FassetsContext.Provider'; // report the React Context that is in-use var contextImpl = _react2.default.createContext === _createReactContext2.default ? 'native (React >16.3)' :