michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: module.metadata = { michael@0: "stability": "unstable" michael@0: }; michael@0: michael@0: const create = Object.create; michael@0: const prototypeOf = Object.getPrototypeOf; michael@0: michael@0: /** michael@0: * Returns a new namespace, function that may can be used to access an michael@0: * namespaced object of the argument argument. Namespaced object are associated michael@0: * with owner objects via weak references. Namespaced objects inherit from the michael@0: * owners ancestor namespaced object. If owner's ancestor is `null` then michael@0: * namespaced object inherits from given `prototype`. Namespaces can be used michael@0: * to define internal APIs that can be shared via enclosing `namespace` michael@0: * function. michael@0: * @examples michael@0: * const internals = ns(); michael@0: * internals(object).secret = secret; michael@0: */ michael@0: function ns() { michael@0: const map = new WeakMap(); michael@0: return function namespace(target) { michael@0: if (!target) // If `target` is not an object return `target` itself. michael@0: return target; michael@0: // If target has no namespaced object yet, create one that inherits from michael@0: // the target prototype's namespaced object. michael@0: if (!map.has(target)) michael@0: map.set(target, create(namespace(prototypeOf(target) || null))); michael@0: michael@0: return map.get(target); michael@0: }; michael@0: }; michael@0: michael@0: // `Namespace` is a e4x function in the scope, so we export the function also as michael@0: // `ns` as alias to avoid clashing. michael@0: exports.ns = ns; michael@0: exports.Namespace = ns;