diff options
Diffstat (limited to 'tools/addon-sdk-1.12/lib/sdk/core')
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/core/heritage.js | 146 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/core/namespace.js | 43 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/core/promise.js | 230 |
3 files changed, 419 insertions, 0 deletions
diff --git a/tools/addon-sdk-1.12/lib/sdk/core/heritage.js b/tools/addon-sdk-1.12/lib/sdk/core/heritage.js new file mode 100644 index 0000000..1c62e6c --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/core/heritage.js @@ -0,0 +1,146 @@ +/* vim:set ts=2 sw=2 sts=2 expandtab */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +'use strict'; + +module.metadata = { + "stability": "unstable" +}; + +var getPrototypeOf = Object.getPrototypeOf; +var getNames = Object.getOwnPropertyNames; +var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; +var create = Object.create; +var freeze = Object.freeze; +var unbind = Function.call.bind(Function.bind, Function.call); + +// This shortcut makes sure that we do perform desired operations, even if +// associated methods have being overridden on the used object. +var owns = unbind(Object.prototype.hasOwnProperty); +var apply = unbind(Function.prototype.apply); +var slice = Array.slice || unbind(Array.prototype.slice); +var reduce = Array.reduce || unbind(Array.prototype.reduce); +var map = Array.map || unbind(Array.prototype.map); +var concat = Array.concat || unbind(Array.prototype.concat); + +// Utility function to get own properties descriptor map. +function getOwnPropertyDescriptors(object) { + return reduce(getNames(object), function(descriptor, name) { + descriptor[name] = getOwnPropertyDescriptor(object, name); + return descriptor; + }, {}); +} + +/** + * Takes `source` object as an argument and returns identical object + * with the difference that all own properties will be non-enumerable + */ +function obscure(source) { + var descriptor = reduce(getNames(source), function(descriptor, name) { + var property = getOwnPropertyDescriptor(source, name); + property.enumerable = false; + descriptor[name] = property; + return descriptor; + }, {}); + return create(getPrototypeOf(source), descriptor); +} +exports.obscure = obscure; + +/** + * Takes arbitrary number of source objects and returns fresh one, that + * inherits from the same prototype as a first argument and implements all + * own properties of all argument objects. If two or more argument objects + * have own properties with the same name, the property is overridden, with + * precedence from right to left, implying, that properties of the object on + * the left are overridden by a same named property of the object on the right. + */ +var mix = function(source) { + var descriptor = reduce(slice(arguments), function(descriptor, source) { + return reduce(getNames(source), function(descriptor, name) { + descriptor[name] = getOwnPropertyDescriptor(source, name); + return descriptor; + }, descriptor); + }, {}); + + return create(getPrototypeOf(source), descriptor); +}; +exports.mix = mix; + +/** + * Returns a frozen object with that inherits from the given `prototype` and + * implements all own properties of the given `properties` object. + */ +function extend(prototype, properties) { + return freeze(create(prototype, getOwnPropertyDescriptors(properties))); +} +exports.extend = extend; + +/** + * Returns a constructor function with a proper `prototype` setup. Returned + * constructor's `prototype` inherits from a given `options.extends` or + * `Class.prototype` if omitted and implements all the properties of the + * given `option`. If `options.implemens` array is passed, it's elements + * will be mixed into prototype as well. Also, `options.extends` can be + * a function or a prototype. If function than it's prototype is used as + * an ancestor of the prototype, if it's an object that it's used directly. + * Also `options.implements` may contain functions or objects, in case of + * functions their prototypes are used for mixing. + */ +var Class = new function() { + function prototypeOf(input) { + return typeof(input) === 'function' ? input.prototype : input; + } + var none = freeze([]); + + return function Class(options) { + // Create descriptor with normalized `options.extends` and + // `options.implements`. + var descriptor = { + // Normalize extends property of `options.extends` to a prototype object + // in case it's constructor. If property is missing that fallback to + // `Type.prototype`. + extends: owns(options, 'extends') ? + prototypeOf(options.extends) : Class.prototype, + // Normalize `options.implements` to make sure that it's array of + // prototype objects instead of constructor functions. + implements: owns(options, 'implements') ? + freeze(map(options.implements, prototypeOf)) : none + }; + + // Create array of property descriptors who's properties will be defined + // on the resulting prototype. Note: Using reflection `concat` instead of + // method as it may be overridden. + var descriptors = concat(descriptor.implements, options, descriptor); + // Create `prototype` that inherits from given ancestor passed as + // `options.extends`, falling back to `Type.prototype`, implementing all + // properties of given `options.implements` and `options` itself. + var prototype = extend(descriptor.extends, mix.apply(mix, descriptors)); + + // Note: we use reflection `apply` in the constructor instead of method + // call since later may be overridden. + function constructor() { + return apply(prototype.constructor, create(prototype), arguments); + } + constructor.prototype = prototype; + return freeze(constructor); + }; +} +Class.prototype = extend(null, obscure({ + constructor: function constructor() { + this.initialize.apply(this, arguments); + return this; + }, + initialize: function initialize() { + // Do your initialization logic here + }, + // Copy useful properties from `Object.prototype`. + toString: Object.prototype.toString, + toLocaleString: Object.prototype.toLocaleString, + toSource: Object.prototype.toSource, + valueOf: Object.prototype.valueOf, + isPrototypeOf: Object.prototype.isPrototypeOf +})); +exports.Class = freeze(Class); diff --git a/tools/addon-sdk-1.12/lib/sdk/core/namespace.js b/tools/addon-sdk-1.12/lib/sdk/core/namespace.js new file mode 100644 index 0000000..3ceb73b --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/core/namespace.js @@ -0,0 +1,43 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +module.metadata = { + "stability": "unstable" +}; + +const create = Object.create; +const prototypeOf = Object.getPrototypeOf; + +/** + * Returns a new namespace, function that may can be used to access an + * namespaced object of the argument argument. Namespaced object are associated + * with owner objects via weak references. Namespaced objects inherit from the + * owners ancestor namespaced object. If owner's ancestor is `null` then + * namespaced object inherits from given `prototype`. Namespaces can be used + * to define internal APIs that can be shared via enclosing `namespace` + * function. + * @examples + * const internals = ns(); + * internals(object).secret = secret; + */ +function ns() { + const map = new WeakMap(); + return function namespace(target) { + if (!target) // If `target` is not an object return `target` itself. + return target; + // If target has no namespaced object yet, create one that inherits from + // the target prototype's namespaced object. + if (!map.has(target)) + map.set(target, create(namespace(prototypeOf(target) || null))); + + return map.get(target); + }; +}; + +// `Namespace` is a e4x function in the scope, so we export the function also as +// `ns` as alias to avoid clashing. +exports.ns = ns; +exports.Namespace = ns; diff --git a/tools/addon-sdk-1.12/lib/sdk/core/promise.js b/tools/addon-sdk-1.12/lib/sdk/core/promise.js new file mode 100644 index 0000000..2506c80 --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/core/promise.js @@ -0,0 +1,230 @@ +/* vim:set ts=2 sw=2 sts=2 expandtab */ +/*jshint asi: true undef: true es5: true node: true browser: true devel: true + forin: true latedef: false */ +/*global define: true, Cu: true, __URI__: true */ +;(function(id, factory) { // Module boilerplate :( + if (typeof(define) === 'function') { // RequireJS + define(factory); + } else if (typeof(require) === 'function') { // CommonJS + factory.call(this, require, exports, module); + } else if (~String(this).indexOf('BackstagePass')) { // JSM + factory(function require(uri) { + var imports = {}; + this['Components'].utils.import(uri, imports); + return imports; + }, this, { uri: __URI__, id: id }); + this.EXPORTED_SYMBOLS = Object.keys(this); + } else { // Browser or alike + var globals = this + factory(function require(id) { + return globals[id]; + }, (globals[id] = {}), { uri: document.location.href + '#' + id, id: id }); + } +}).call(this, 'loader', function(require, exports, module) { + +'use strict'; + +module.metadata = { + "stability": "unstable" +}; + +function resolution(value) { + /** + Returns non-standard compliant (`then` does not returns a promise) promise + that resolves to a given `value`. Used just internally only. + **/ + return { then: function then(resolve) { resolve(value) } } +} + +function rejection(reason) { + /** + Returns non-standard compliant promise (`then` does not returns a promise) + that rejects with a given `reason`. This is used internally only. + **/ + return { then: function then(resolve, reject) { reject(reason) } } +} + +function attempt(f) { + /** + Returns wrapper function that delegates to `f`. If `f` throws then captures + error and returns promise that rejects with a thrown error. Otherwise returns + return value. (Internal utility) + **/ + return function effort(options) { + try { return f(options) } + catch(error) { return rejection(error) } + } +} + +function isPromise(value) { + /** + Returns true if given `value` is promise. Value is assumed to be promise if + it implements `then` method. + **/ + return value && typeof(value.then) === 'function' +} + +function defer(prototype) { + /** + Returns object containing following properties: + - `promise` Eventual value representation implementing CommonJS [Promises/A] + (http://wiki.commonjs.org/wiki/Promises/A) API. + - `resolve` Single shot function that resolves returned `promise` with a given + `value` argument. + - `reject` Single shot function that rejects returned `promise` with a given + `reason` argument. + + Given `prototype` argument is used as a prototype of the returned `promise` + allowing one to implement additional API. If prototype is not passed then + it falls back to `Object.prototype`. + + ## Examples + + // Simple usage. + var deferred = defer() + deferred.promise.then(console.log, console.error) + deferred.resolve(value) + + // Advanced usage + var prototype = { + get: function get(name) { + return this.then(function(value) { + return value[name]; + }) + } + } + + var foo = defer(prototype) + deferred.promise.get('name').then(console.log) + deferred.resolve({ name: 'Foo' }) + //=> 'Foo' + */ + var pending = [], result + prototype = (prototype || prototype === null) ? prototype : Object.prototype + + // Create an object implementing promise API. + var promise = Object.create(prototype, { + then: { value: function then(resolve, reject) { + // create a new deferred using a same `prototype`. + var deferred = defer(prototype) + // If `resolve / reject` callbacks are not provided. + resolve = resolve ? attempt(resolve) : resolution + reject = reject ? attempt(reject) : rejection + + // Create a listeners for a enclosed promise resolution / rejection that + // delegate to an actual callbacks and resolve / reject returned promise. + function resolved(value) { deferred.resolve(resolve(value)) } + function rejected(reason) { deferred.resolve(reject(reason)) } + + // If promise is pending register listeners. Otherwise forward them to + // resulting resolution. + if (pending) pending.push([ resolved, rejected ]) + else result.then(resolved, rejected) + + return deferred.promise + }} + }) + + var deferred = { + promise: promise, + resolve: function resolve(value) { + /** + Resolves associated `promise` to a given `value`, unless it's already + resolved or rejected. + **/ + if (pending) { + // store resolution `value` as a promise (`value` itself may be a + // promise), so that all subsequent listeners can be forwarded to it, + // which either resolves immediately or forwards if `value` is + // a promise. + result = isPromise(value) ? value : resolution(value) + // forward all pending observers. + while (pending.length) result.then.apply(result, pending.shift()) + // mark promise as resolved. + pending = null + } + }, + reject: function reject(reason) { + /** + Rejects associated `promise` with a given `reason`, unless it's already + resolved / rejected. + **/ + deferred.resolve(rejection(reason)) + } + } + + return deferred +} +exports.defer = defer + +function resolve(value, prototype) { + /** + Returns a promise resolved to a given `value`. Optionally second `prototype` + arguments my be provided to be used as a prototype for a returned promise. + **/ + var deferred = defer(prototype) + deferred.resolve(value) + return deferred.promise +} +exports.resolve = resolve + +function reject(reason, prototype) { + /** + Returns a promise that is rejected with a given `reason`. Optionally second + `prototype` arguments my be provided to be used as a prototype for a returned + promise. + **/ + var deferred = defer(prototype) + deferred.reject(reason) + return deferred.promise +} +exports.reject = reject + +var promised = (function() { + // Note: Define shortcuts and utility functions here in order to avoid + // slower property accesses and unnecessary closure creations on each + // call of this popular function. + + var call = Function.call + var concat = Array.prototype.concat + + // Utility function that does following: + // execute([ f, self, args...]) => f.apply(self, args) + function execute(args) { return call.apply(call, args) } + + // Utility function that takes promise of `a` array and maybe promise `b` + // as arguments and returns promise for `a.concat(b)`. + function promisedConcat(promises, unknown) { + return promises.then(function(values) { + return resolve(unknown).then(function(value) { + return values.concat([ value ]) + }) + }) + } + + return function promised(f, prototype) { + /** + Returns a wrapped `f`, which when called returns a promise that resolves to + `f(...)` passing all the given arguments to it, which by the way may be + promises. Optionally second `prototype` argument may be provided to be used + a prototype for a returned promise. + + ## Example + + var promise = promised(Array)(1, promise(2), promise(3)) + promise.then(console.log) // => [ 1, 2, 3 ] + **/ + + return function promised() { + // create array of [ f, this, args... ] + return concat.apply([ f, this ], arguments). + // reduce it via `promisedConcat` to get promised array of fulfillments + reduce(promisedConcat, resolve([], prototype)). + // finally map that to promise of `f.apply(this, args...)` + then(execute) + } + } +})() +exports.promised = promised + +}) |