X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=common%2Fmodules%2Fbase.jsm;h=b581186ea703f0418ef196f4562d0a5bffdf4abd;hb=refs%2Fheads%2Fupstream;hp=13bd9a03e93fcd3b88a5400ba38061e5b25bf08a;hpb=eeed0be1a8abf7e3c97f43b63c1d595e940fef21;p=dactyl.git diff --git a/common/modules/base.jsm b/common/modules/base.jsm index 13bd9a0..b581186 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -1,109 +1,73 @@ -// Copyright (c) 2009-2011 by Kris Maglione +// Copyright (c) 2009-2014 Kris Maglione // // This work is licensed for reuse under an MIT license. Details are // given in the LICENSE.txt file included with this file. "use strict"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cr = Components.results; -var Cu = Components.utils; +var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +var Cs = new Proxy(Components.stack, { + get: function Cs_get(target, prop) Components.stack.caller[prop] +}); + +function module(url) { + let obj = {}; + Cu.import(url, obj); + return obj; +} + +var { XPCOMUtils } = module("resource://gre/modules/XPCOMUtils.jsm"); try { - var ctypes; - Components.utils.import("resource://gre/modules/ctypes.jsm"); + var ctypes = module("resource://gre/modules/ctypes.jsm"); } catch (e) {} let objproto = Object.prototype; -let { __lookupGetter__, __lookupSetter__, hasOwnProperty, propertyIsEnumerable } = objproto; +let { __lookupGetter__, __lookupSetter__, __defineGetter__, __defineSetter__, + hasOwnProperty, propertyIsEnumerable } = objproto; -if (typeof XPCSafeJSObjectWrapper === "undefined") - this.XPCSafeJSObjectWrapper = XPCNativeWrapper; - -if (!XPCNativeWrapper.unwrap) - XPCNativeWrapper.unwrap = function unwrap(obj) { - if (hasOwnProperty.call(obj, "wrappedJSObject")) - return obj.wrappedJSObject; - return obj; - }; -if (!Object.create) - Object.create = function create(proto, props) { - let obj = { __proto__: proto }; - for (let k in properties(props || {})) - Object.defineProperty(obj, k, props[k]); - return obj; - }; -if (!Object.defineProperty) - Object.defineProperty = function defineProperty(obj, prop, desc) { - let value = desc.value; - if ("value" in desc) - if (desc.writable && !__lookupGetter__.call(obj, prop) - && !__lookupSetter__.call(obj, prop)) - try { - obj[prop] = value; - } - catch (e if e instanceof TypeError) {} - else { - objproto.__defineGetter__.call(obj, prop, function () value); - if (desc.writable) - objproto.__defineSetter__.call(obj, prop, function (val) { value = val; }); - } +hasOwnProperty = Function.call.bind(hasOwnProperty); +propertyIsEnumerable = Function.call.bind(propertyIsEnumerable); - if ("get" in desc) - objproto.__defineGetter__.call(obj, prop, desc.get); - if ("set" in desc) - objproto.__defineSetter__.call(obj, prop, desc.set); - }; -if (!Object.defineProperties) - Object.defineProperties = function defineProperties(obj, props) { - for (let [k, v] in Iterator(props)) - Object.defineProperty(obj, k, v); - } -if (!Object.freeze) - Object.freeze = function freeze(obj) {}; -if (!Object.getOwnPropertyDescriptor) - Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(obj, prop) { - if (!hasOwnProperty.call(obj, prop)) - return undefined; - let desc = { - configurable: true, - enumerable: propertyIsEnumerable.call(obj, prop) - }; - var get = __lookupGetter__.call(obj, prop), - set = __lookupSetter__.call(obj, prop); - if (!get && !set) { - desc.value = obj[prop]; - desc.writable = true; - } - if (get) - desc.get = get; - if (set) - desc.set = set; - return desc; - }; -if (!Object.getOwnPropertyNames) - Object.getOwnPropertyNames = function getOwnPropertyNames(obj, _debugger) { - // This is an ugly and unfortunately necessary hack. - if (hasOwnProperty.call(obj, "__iterator__")) { - var oldIter = obj.__iterator__; - delete obj.__iterator__; +// Gecko 24. +if (!("find" in Array.prototype)) + Object.defineProperty(Array.prototype, "find", { + configurable: true, + writable: true, + value: function Array_find(pred, self) { + for (let [i, elem] in Iterator(this)) + if (pred.call(self, elem, i, this)) + return elem; } - let res = [k for (k in obj) if (hasOwnProperty.call(obj, k))]; - if (oldIter !== undefined) { - obj.__iterator__ = oldIter; - res.push("__iterator__"); + }); + +if (!("findIndex" in Array.prototype)) + Object.defineProperty(Array.prototype, "findIndex", { + configurable: true, + writable: true, + value: function Array_findIndex(pred, self) { + for (let [i, elem] in Iterator(this)) + if (pred.call(self, elem, i, this)) + return i; + return -1; } - return res; - }; -if (!Object.getPrototypeOf) - Object.getPrototypeOf = function getPrototypeOf(obj) obj.__proto__; -if (!Object.keys) - Object.keys = function keys(obj) - Object.getOwnPropertyNames(obj).filter(function (k) propertyIsEnumerable.call(obj, k)); + }); + +function require(module_, target) { + if (/^[A-Za-z0-9]+:/.test(module_)) + return module(module_); + return JSMLoader.load(module_, target); +} + +function lazyRequire(module, names, target) { + for (let name of names) + memoize(target || this, name, name => require(module)[name]); +} -let getGlobalForObject = Cu.getGlobalForObject || function (obj) obj.__parent__; +let jsmodules = { lazyRequire: lazyRequire }; +jsmodules.jsmodules = jsmodules; + +function toString() "[module-global " + this.NAME + "]"; let use = {}; let loaded = {}; @@ -111,84 +75,85 @@ let currentModule; let global = this; function defineModule(name, params, module) { if (!module) - module = getGlobalForObject(params); + module = this; module.NAME = name; module.EXPORTED_SYMBOLS = params.exports || []; - defineModule.loadLog.push("defineModule " + name); + if (!~module.EXPORTED_SYMBOLS.indexOf("File")) + delete module.File; + + defineModule.loadLog.push("[Begin " + name + "]"); + defineModule.prefix += " "; + for (let [, mod] in Iterator(params.require || [])) - require(module, mod); + require(mod, module); - for (let [, mod] in Iterator(params.use || [])) - if (loaded.hasOwnProperty(mod)) - require(module, mod, "use"); - else { - use[mod] = use[mod] || []; - use[mod].push(module); - } + module._lastModule = currentModule; currentModule = module; + module.startTime = Date.now(); } defineModule.loadLog = []; Object.defineProperty(defineModule.loadLog, "push", { value: function (val) { - if (false) + val = defineModule.prefix + val; + if (true) defineModule.dump(val + "\n"); this[this.length] = Date.now() + " " + val; } }); -defineModule.dump = function dump_() { - let msg = Array.map(arguments, function (msg) { +defineModule.prefix = ""; +defineModule.dump = function dump_(...args) { + let msg = args.map(function (msg) { if (loaded.util && typeof msg == "object") msg = util.objectToString(msg); return msg; }).join(", "); - let name = loaded.config ? config.name : "dactyl"; dump(String.replace(msg, /\n?$/, "\n") - .replace(/^./gm, name + ": $&")); + .replace(/^./gm, JSMLoader.name + ": $&")); } defineModule.modules = []; -defineModule.times = { all: 0 }; -defineModule.time = function time(major, minor, func, self) { +defineModule.time = function time(major, minor, func, self, ...args) { let time = Date.now(); if (typeof func !== "function") func = self[func]; try { - var res = func.apply(self, Array.slice(arguments, 4)); + var res = func.apply(self, args); } catch (e) { loaded.util && util.reportError(e); } - let delta = Date.now() - time; - defineModule.times.all += delta; - defineModule.times[major] = (defineModule.times[major] || 0) + delta; - if (minor) { - defineModule.times[":" + minor] = (defineModule.times[":" + minor] || 0) + delta; - defineModule.times[major + ":" + minor] = (defineModule.times[major + ":" + minor] || 0) + delta; - } + JSMLoader.times.add(major, minor, Date.now() - time); return res; } function endModule() { - defineModule.loadLog.push("endModule " + currentModule.NAME); - - for (let [, mod] in Iterator(use[currentModule.NAME] || [])) - require(mod, currentModule.NAME, "use"); + defineModule.prefix = defineModule.prefix.slice(0, -2); + defineModule.loadLog.push("(End " + currentModule.NAME + ")"); loaded[currentModule.NAME] = 1; + require(currentModule.NAME, jsmodules); + currentModule = currentModule._lastModule; } -function require(obj, name, from) { +function require_(obj, name, from, targetName) { try { if (arguments.length === 1) [obj, name] = [{}, obj]; + let caller = Components.stack.caller; + if (!loaded[name]) - defineModule.loadLog.push((from || "require") + ": loading " + name + (obj.NAME ? " into " + obj.NAME : "")); + defineModule.loadLog.push((from || "require") + ": loading " + name + + " into " + (targetName || obj.NAME || caller.filename + ":" + caller.lineNumber)); JSMLoader.load(name + ".jsm", obj); + + if (!loaded[name] && obj != jsmodules) + JSMLoader.load(name + ".jsm", jsmodules); + return obj; } catch (e) { @@ -196,50 +161,96 @@ function require(obj, name, from) { if (loaded.util) util.reportError(e); else - defineModule.dump(" " + (e.filename || e.fileName) + ":" + e.lineNumber + ": " + e +"\n"); + defineModule.dump(" " + (e.filename || e.fileName) + ":" + e.lineNumber + ": " + e + "\n"); } } defineModule("base", { - // sed -n 's/^(const|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt + // sed -n 's/^(const|var|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt exports: [ - "ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Module", "JSMLoader", "Object", "Runnable", - "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMUtils", "XPCSafeJSObjectWrapper", - "array", "bind", "call", "callable", "ctypes", "curry", "debuggerProperties", "defineModule", - "deprecated", "endModule", "forEach", "isArray", "isGenerator", "isinstance", "isObject", - "isString", "isSubclass", "iter", "iterAll", "iterOwnProperties","keys", "memoize", "octal", - "properties", "require", "set", "update", "values", "withCallerGlobal" - ], - use: ["config", "services", "util"] -}, this); - -function Runnable(self, func, args) { - return { - __proto__: Runnable.prototype, - run: function () { func.apply(self, args || []); } - }; -} -Runnable.prototype.QueryInterface = XPCOMUtils.generateQI([Ci.nsIRunnable]); + "Cc", + "Ci", + "Class", + "Cr", + "Cs", + "Cu", + "ErrorBase", + "Finished", + "JSMLoader", + "Module", + "RealSet", + "Set", + "Struct", + "StructBase", + "Timer", + "UTF8", + "XPCOM", + "XPCOMShim", + "XPCOMUtils", + "array", + "bind", + "call", + "callable", + "ctypes", + "curry", + "defineModule", + "deprecated", + "endModule", + "forEach", + "hasOwnProperty", + "isArray", + "isGenerator", + "isObject", + "isString", + "isSubclass", + "isinstance", + "iter", + "iterAll", + "iterOwnProperties", + "keys", + "literal", + "memoize", + "modujle", + "octal", + "properties", + "require", + "set", + "update", + "values", + ] +}); -/** - * Returns a list of all of the top-level properties of an object, by - * way of the debugger. - * - * @param {object} obj - * @returns [jsdIProperty] - */ -function debuggerProperties(obj) { - if (loaded.services && services.debugger.isOn) { - let res = {}; - services.debugger.wrapValue(obj).getProperties(res, {}); - return res.value; - } +this.lazyRequire("cache", ["cache"]); +this.lazyRequire("config", ["config"]); +this.lazyRequire("messages", ["_", "Messages"]); +this.lazyRequire("promises", ["Task", "promises"]); +this.lazyRequire("services", ["services"]); +this.lazyRequire("storage", ["File"]); +this.lazyRequire("util", ["FailedAssertion", "util"]); + +literal.files = {}; +literal.locations = {}; +function literal(/* comment */) { + let { caller } = Components.stack; + while (caller && caller.language != 2) + caller = caller.caller; + + let file = caller.filename.replace(/.* -> /, ""); + let key = "literal:" + file + ":" + caller.lineNumber; + return cache.get(key, function() { + let source = literal.files[file] || File.readURL(file); + literal.files[file] = source; + + let match = RegExp("(?:.*\\n){" + (caller.lineNumber - 1) + "}" + + ".*literal\\(/\\*([^]*?)\\*/\\)").exec(source); + return match[1]; + }); } /** * Iterates over the names of all of the top-level properties of an * object or, if prototypes is given, all of the properties in the - * prototype chain below the top. Uses the debugger if possible. + * prototype chain below the top. * * @param {object} obj The object to inspect. * @param {boolean} properties Whether to inspect the prototype chain @@ -247,34 +258,57 @@ function debuggerProperties(obj) { * @returns {Generator} */ function prototype(obj) - /* Temporary hack: */ typeof obj === "xml" || obj.__proto__ !== obj.__proto__ ? null : obj.__proto__ || Object.getPrototypeOf(obj) || XPCNativeWrapper.unwrap(obj).__proto__ || Object.getPrototypeOf(XPCNativeWrapper.unwrap(obj)); -function properties(obj, prototypes, debugger_) { +function properties(obj, prototypes) { let orig = obj; - let seen = { dactylPropertyNames: true }; + let seen = RealSet(["dactylPropertyNames"]); try { if ("dactylPropertyNames" in obj && !prototypes) for (let key in values(obj.dactylPropertyNames)) - if (key in obj && !set.add(seen, key)) + if (key in obj && !seen.add(key)) yield key; } catch (e) {} - for (; obj; obj = prototypes && prototype(obj)) { + function props(obj) { + // Grr. try { - if (sandbox.Object.getOwnPropertyNames || !debugger_ || !services.debugger.isOn) - var iter = values(Object.getOwnPropertyNames(obj)); + return Object.getOwnPropertyNames(obj); } - catch (e) {} - if (!iter) - iter = (prop.name.stringValue for (prop in values(debuggerProperties(obj)))); + catch (e) { + if (e.result === Cr.NS_ERROR_FAILURE) { + // This is being thrown for PDF.js content windows, + // currently. + let filter = function filter(prop) { + try { + return prop in obj; + } + catch (e) { + util.reportError("Filtering properties for " + + String.quote(obj) + ", " + + "error checking presence of " + + String.quote(prop) + ": " + e); + } + return false; + }; + return array.uniq([k for (k in obj)].concat( + Object.getOwnPropertyNames( + XPCNativeWrapper.unwrap(obj)) + .filter(filter))); + } + else if (!e.stack) { + throw Error(e); + } + } + } - for (let key in iter) - if (!prototypes || !set.add(seen, key) && obj != orig) + for (; obj; obj = prototypes && prototype(obj)) { + for (let key of props(obj)) + if (!prototypes || !seen.add(key) && obj != orig) yield key; } } @@ -286,19 +320,28 @@ function iterOwnProperties(obj) { function deprecated(alternative, fn) { if (isObject(fn)) - return Class.Property(iter(fn).map(function ([k, v]) [k, callable(v) ? deprecated(alternative, v) : v]) + return Class.Property(iter(fn).map(([k, v]) => [k, + callable(v) ? deprecated(alternative, v) + : v]) .toObject()); - let name, func = callable(fn) ? fn : function () this[fn].apply(this, arguments); + let name, + func = callable(fn) ? fn + : function () this[fn].apply(this, arguments); function deprecatedMethod() { - let obj = this.className ? this.className + "#" : + let obj = !this ? "" : + this.className ? this.className + "#" : this.constructor.className ? this.constructor.className + "#" : ""; - deprecated.warn(func, obj + (fn.name || name), alternative); + deprecated.warn(func, + obj + (fn.realName || fn.name || name || "").replace(/__/g, "."), + alternative); return func.apply(this, arguments); } + if (func.name) + deprecatedMethod.realName = func.name; return callable(fn) ? deprecatedMethod : Class.Property({ get: function () deprecatedMethod, @@ -307,17 +350,22 @@ function deprecated(alternative, fn) { } deprecated.warn = function warn(func, name, alternative, frame) { if (!func.seenCaller) - func.seenCaller = set([ - "resource://dactyl" + JSMLoader.suffix + "/javascript.jsm", - "resource://dactyl" + JSMLoader.suffix + "/util.jsm" + func.seenCaller = RealSet([ + "resource://dactyl/javascript.jsm", + "resource://dactyl/util.jsm" ]); + if (!(loaded.util && util && loaded.config && config.protocolLoaded)) { + dump("DACTYL: deprecated method called too early [" + [name, alternative] + "]:\n" + Error().stack + "\n\n"); + return; + } + frame = frame || Components.stack.caller.caller; + let filename = util.fixURI(frame.filename || "unknown"); - if (!set.add(func.seenCaller, filename)) - util.dactyl(func).warn( - util.urlPath(filename) + ":" + frame.lineNumber + ": " + - name + " is deprecated: Please use " + alternative + " instead"); + if (!func.seenCaller.add(filename)) + util.dactyl(func).warn([util.urlPath(filename), frame.lineNumber, " "].join(":") + + _("warn.deprecated", name, alternative)); } /** @@ -328,10 +376,15 @@ deprecated.warn = function warn(func, name, alternative, frame) { * @returns {Generator} */ function keys(obj) iter(function keys() { - for (var k in obj) - if (hasOwnProperty.call(obj, k)) + if (isinstance(obj, ["Map"])) + for (let [k, v] of obj) yield k; + else + for (var k in obj) + if (hasOwnProperty(obj, k)) + yield k; }()); + /** * Iterates over all of the top-level, iterable property values of an * object. @@ -340,18 +393,47 @@ function keys(obj) iter(function keys() { * @returns {Generator} */ function values(obj) iter(function values() { - if (isinstance(obj, ["Generator", "Iterator"])) + if (isinstance(obj, ["Map"])) + for (let [k, v] of obj) + yield v; + else if (isinstance(obj, ["Generator", "Iterator", Iter])) for (let k in obj) yield k; + else if (iter.iteratorProp in obj) + for (let v of obj) + yield v; else for (var k in obj) - if (hasOwnProperty.call(obj, k)) + if (hasOwnProperty(obj, k)) yield obj[k]; }()); var forEach = deprecated("iter.forEach", function forEach() iter.forEach.apply(iter, arguments)); var iterAll = deprecated("iter", function iterAll() iter.apply(null, arguments)); +var RealSet = Set; +let Set_add = RealSet.prototype.add; +RealSet.prototype.add = function RealSet_add(val) { + let res = this.has(val); + Set_add.apply(this, arguments); + return res; +}; + +RealSet.prototype.difference = function RealSet_difference(set) { + return RealSet(i for (i of this) if (!set.has(i))); +}; + +RealSet.prototype.intersection = function RealSet_intersection(set) { + return RealSet(i for (i of this) if (set.has(i))); +}; + +RealSet.prototype.union = function RealSet_union(set) { + let res = RealSet(this); + for (let item of set) + res.add(item); + return res; +}; + /** * Utility for managing sets of strings. Given an array, returns an * object with one key for each value thereof. @@ -359,13 +441,13 @@ var iterAll = deprecated("iter", function iterAll() iter.apply(null, arguments)) * @param {[string]} ary @optional * @returns {object} */ -function set(ary) { +this.Set = deprecated("RealSet", function Set(ary) { let obj = {}; if (ary) for (let val in values(ary)) obj[val] = true; return obj; -} +}); /** * Adds an element to a set and returns true if the element was * previously contained. @@ -374,11 +456,18 @@ function set(ary) { * @param {string} key The key to add. * @returns boolean */ -set.add = curry(function set_add(set, key) { - let res = this.has(set, key); - set[key] = true; - return res; -}); +Set.add = deprecated("RealSet#add", + curry(function Set__add(set, key) { + if (isinstance(set, ["Set"])) { + let res = set.has(key); + set.add(key); + return res; + } + + let res = this.has(set, key); + set[key] = true; + return res; + })); /** * Returns true if the given set contains the given key. * @@ -386,8 +475,14 @@ set.add = curry(function set_add(set, key) { * @param {string} key The key to check. * @returns {boolean} */ -set.has = curry(function set_has(set, key) hasOwnProperty.call(set, key) && - propertyIsEnumerable.call(set, key)); +Set.has = deprecated("hasOwnProperty or Set#has", + curry(function Set__has(set, key) { + if (isinstance(set, ["Set"])) + return set.has(key); + + return hasOwnProperty(set, key) && + propertyIsEnumerable(set, key); + })); /** * Returns a new set containing the members of the first argument which * do not exist in any of the other given arguments. @@ -395,13 +490,15 @@ set.has = curry(function set_has(set, key) hasOwnProperty.call(set, key) && * @param {object} set The set. * @returns {object} */ -set.subtract = function set_subtract(set) { - set = update({}, set); - for (let i = 1; i < arguments.length; i++) - for (let k in keys(arguments[i])) - delete set[k]; - return set; -}; +Set.subtract = deprecated("RealSet#difference", + function set_subtract(set) { + set = update({}, set); + for (let i = 1; i < arguments.length; i++) + for (let k in keys(arguments[i])) + delete set[k]; + return set; + }); + /** * Removes an element from a set and returns true if the element was * previously contained. @@ -410,10 +507,25 @@ set.subtract = function set_subtract(set) { * @param {string} key The key to remove. * @returns boolean */ -set.remove = curry(function set_remove(set, key) { - let res = set.has(set, key); - delete set[key]; - return res; +Set.remove = deprecated("RealSet#delete", + curry(function Set__remove(set, key) { + if (isinstance(set, ["Set"])) + return set.delete(key); + + let res = set.has(set, key); + delete set[key]; + return res; + })); + +function set() { + deprecated.warn(set, "set", "Set"); + return Set.apply(this, arguments); +} +Object.keys(Set).forEach(function (meth) { + set[meth] = function proxy() { + deprecated.warn(proxy, "set." + meth, "Set." + meth); + return Set[meth].apply(Set, arguments); + }; }); /** @@ -444,32 +556,30 @@ function curry(fn, length, self, acc) { return fn; // Close over function with 'this' - function close(self, fn) function () fn.apply(self, Array.slice(arguments)); + function close(self, fn) (...args) => fn.apply(self, args); if (acc == null) acc = []; - return function curried() { - let args = acc.concat(Array.slice(arguments)); - + function curried(...args) { // The curried result should preserve 'this' - if (arguments.length == 0) + if (args.length == 0) return close(self || this, curried); + let args = acc.concat(args); + if (args.length >= length) return fn.apply(self || this, args); return curry(fn, length, self || this, args); }; + curried.realName = fn.realName || fn.name; + return curried; } -if (curry.bind) - var bind = function bind(func) func.bind.apply(func, Array.slice(arguments, bind.length)); -else - var bind = function bind(func, self) { - let args = Array.slice(arguments, bind.length); - return function bound() func.apply(self, args.concat(Array.slice(arguments))); - }; +var bind = function bind(meth, self, ...args) + let (func = callable(meth) ? meth : self[meth]) + func.bind.apply(func, [self].concat(args)); /** * Returns true if both arguments are functions and @@ -539,10 +649,8 @@ function isObject(obj) typeof obj === "object" && obj != null || obj instanceof * is not the case when using (obj instanceof Array). */ var isArray = - Array.isArray - // This is bloody stupid. - ? function isArray(val) Array.isArray(val) || val && val.constructor && val.constructor.name === "Array" - : function isArray(val) objproto.toString.call(val) == "[object Array]"; + // This is bloody stupid. + function isArray(val) Array.isArray(val) || val && val.constructor && val.constructor.name === "Array"; /** * Returns true if and only if its sole argument is an @@ -565,10 +673,10 @@ function isString(val) objproto.toString.call(val) == "[object String]"; * Returns true if and only if its sole argument may be called * as a function. This includes classes and function objects. */ -function callable(val) typeof val === "function"; +function callable(val) typeof val === "function" && !(val instanceof Ci.nsIDOMElement); -function call(fn) { - fn.apply(arguments[1], Array.slice(arguments, 2)); +function call(fn, self, ...args) { + fn.apply(self, args); return fn; } @@ -582,42 +690,41 @@ function call(fn) { */ function memoize(obj, key, getter) { if (arguments.length == 1) { - obj = update({}, obj); - for (let prop in Object.getOwnPropertyNames(obj)) { + let res = update(Object.create(obj), obj); + for (let prop of Object.getOwnPropertyNames(obj)) { let get = __lookupGetter__.call(obj, prop); if (get) - memoize(obj, prop, get); + memoize(res, prop, get); } - return obj; + return res; } - Object.defineProperty(obj, key, { - configurable: true, - enumerable: true, + try { + Object.defineProperty(obj, key, { + configurable: true, + enumerable: true, - get: function g_replaceProperty() ( - Class.replaceProperty(this.instance || this, key, null), - Class.replaceProperty(this.instance || this, key, getter.call(this, key))), + get: function g_replaceProperty() { + try { + Class.replaceProperty(this.instance || this, key, null); + return Class.replaceProperty(this.instance || this, key, getter.call(this, key)); + } + catch (e) { + util.reportError(e); + } + }, - set: function s_replaceProperty(val) - Class.replaceProperty(this.instance || this, key, val) - }); + set: function s_replaceProperty(val) + Class.replaceProperty(this.instance || this, key, val) + }); + } + catch (e) { + obj[key] = getter.call(obj, key); + } } -let sandbox = Cu.Sandbox(this); +let sandbox = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].createInstance()); sandbox.__proto__ = this; -/** - * Wraps a function so that when called, the global object of the caller - * is prepended to its arguments. - */ -// Hack to get around lack of access to caller in strict mode. -var withCallerGlobal = Cu.evalInSandbox(, Cu.Sandbox(this), "1.8"); /** * Updates an object with the properties of another object. Getters @@ -646,16 +753,18 @@ function update(target) { if (desc.value instanceof Class.Property) desc = desc.value.init(k, target) || desc.value; - if (typeof desc.value === "function" && target.__proto__) { - let func = desc.value.wrapped || desc.value; - func.__defineGetter__("super", function () Object.getPrototypeOf(target)[k]); - func.superapply = function superapply(self, args) - let (meth = Object.getPrototypeOf(target)[k]) - meth && meth.apply(self, args); - func.supercall = function supercall(self) - func.superapply(self, Array.slice(arguments, 1)); - } try { + if (typeof desc.value === "function" && target.__proto__ && !(desc.value instanceof Ci.nsIDOMElement /* wtf? */)) { + let func = desc.value.wrapped || desc.value; + if (!func.superapply) { + func.__defineGetter__("super", function get_super() Object.getPrototypeOf(target)[k]); + func.superapply = function superapply(self, args) + let (meth = Object.getPrototypeOf(target)[k]) + meth && meth.apply(self, args); + func.supercall = function supercall(self, ...args) + func.superapply(self, args); + } + } Object.defineProperty(target, k, desc); } catch (e) {} @@ -687,27 +796,31 @@ function update(target) { * * @returns {function} The constructor for the resulting class. */ -function Class() { +function Class(...args) { - var args = Array.slice(arguments); if (isString(args[0])) var name = args.shift(); var superclass = Class; if (callable(args[0])) superclass = args.shift(); - var Constructor = eval(String.replace(, + var Constructor = eval(String.replace('\n\ + (function constructor(PARAMS) { \n\ + var self = Object.create(Constructor.prototype); \n\ + self.instance = self; \n\ + self.globalInstance = self; \n\ + \n\ + if ("_metaInit_" in self && self._metaInit_) \n\ + self._metaInit_.apply(self, arguments); \n\ + \n\ + var res = self.init.apply(self, arguments); \n\ + return res !== undefined ? res : self; \n\ + })', "constructor", (name || superclass.className).replace(/\W/g, "_")) - .replace("PARAMS", /^function .*?\((.*?)\)/.exec(args[0] && args[0].init || Class.prototype.init)[1] - .replace(/\b(self|res|Constructor)\b/g, "$1_"))); + .replace("PARAMS", + /^function .*?\((.*?)\)/ + .exec(args[0] && args[0].init || Class.prototype.init)[1] + .replace(/\b(self|res|Constructor)\b/g, "$1_"))); Constructor.className = name || superclass.className || superclass.name; @@ -723,10 +836,15 @@ function Class() { } Class.extend(Constructor, superclass, args[0]); + memoize(Constructor, "bound", Class.makeClosure); + if (Iter && array) // Hack. :/ + Object.defineProperty(Constructor, "closure", + deprecated("bound", { get: function closure() this.bound })); update(Constructor, args[1]); + Constructor.__proto__ = superclass; - args = args.slice(2); - Array.forEach(args, function (obj) { + + args.slice(2).forEach(function (obj) { if (callable(obj)) obj = obj.prototype; update(Constructor.prototype, obj); @@ -734,21 +852,14 @@ function Class() { return Constructor; } -if (Cu.getGlobalForObject) - Class.objectGlobal = function (caller) { - try { - return Cu.getGlobalForObject(caller); - } - catch (e) { - return null; - } - }; -else - Class.objectGlobal = function (caller) { - while (caller.__parent__) - caller = caller.__parent__; - return caller; - }; +Class.objectGlobal = function (object) { + try { + return Cu.getGlobalForObject(object); + } + catch (e) { + return null; + } +}; /** * @class Class.Property @@ -791,9 +902,9 @@ Class.extend = function extend(subclass, superclass, overrides) { * * @param {function(string)} getter The function which returns the * property's value. - * @return {Class.Property} + * @returns {Class.Property} */ -Class.memoize = function memoize(getter, wait) +Class.Memoize = function Memoize(getter, wait) Class.Property({ configurable: true, enumerable: true, @@ -801,37 +912,59 @@ Class.memoize = function memoize(getter, wait) let done = false; if (wait) + // Crazy, yeah, I know. -- Kris this.get = function replace() { let obj = this.instance || this; Object.defineProperty(obj, key, { configurable: true, enumerable: false, get: function get() { - util.waitFor(function () done); + util.waitFor(() => done); return this[key]; } }); - util.yieldable(function () { + Task.spawn(function () { let wait; for (var res in getter.call(obj)) { if (wait !== undefined) - yield wait; + yield promises.sleep(wait); wait = res; } Class.replaceProperty(obj, key, res); done = true; - })(); + }); return this[key]; }; else - this.get = function replace() { + this.get = function g_Memoize() { let obj = this.instance || this; - Class.replaceProperty(obj, key, null); - return Class.replaceProperty(obj, key, getter.call(this, key)); + try { + Class.replaceProperty(obj, key, null); + return Class.replaceProperty(obj, key, getter.call(this, key)); + } + catch (e) { + util.reportError(e); + } }; - this.set = function replace(val) Class.replaceProperty(this.instance || this, val); + this.set = function s_Memoize(val) Class.replaceProperty(this.instance || this, key, val); + } + }); + +Class.memoize = deprecated("Class.Memoize", function memoize() Class.Memoize.apply(this, arguments)); + +/** + * Updates the given object with the object in the target class's + * prototype. + */ +Class.Update = function Update(obj) + Class.Property({ + configurable: true, + enumerable: true, + writable: true, + init: function (key, target) { + this.value = update({}, target[key], obj); } }); @@ -847,20 +980,23 @@ Class.prototype = { */ init: function c_init() {}, + get instance() ({}), + set instance(val) Class.replaceProperty(this, "instance", val), + withSavedValues: function withSavedValues(names, callback, self) { - let vals = names.map(function (name) this[name], this); + let vals = names.map(name => this[name]); try { return callback.call(self || this); } finally { - names.forEach(function (name, i) this[name] = vals[i], this); + names.forEach((name, i) => { this[name] = vals[i]; }); } }, toString: function C_toString() { if (this.toStringParams) - var params = "(" + this.toStringParams.map(function (m) isArray(m) ? "[" + m + "]" : - isString(m) ? m.quote() : String(m)) + var params = "(" + this.toStringParams.map(m => (isArray(m) ? "[" + m + "]" : + isString(m) ? m.quote() : String(m))) .join(", ") + ")"; return "[instance " + this.constructor.className + (params || "") + "]"; }, @@ -875,47 +1011,117 @@ Class.prototype = { * @returns {nsITimer} The timer which backs this timeout. */ timeout: function timeout(callback, timeout) { - const self = this; - function timeout_notify(timer) { - if (self.stale || + let timeout_notify = (timer) => { + if (this.stale || util.rehashing && !isinstance(Cu.getGlobalForObject(callback), ["BackstagePass"])) return; - util.trapErrors(callback, self); - } - return services.Timer(timeout_notify, timeout || 0, services.Timer.TYPE_ONE_SHOT); - } -}; -Class.makeClosure = function makeClosure() { - const self = this; - function closure(fn) { - function _closure() { + this.timeouts.splice(this.timeouts.indexOf(timer), 1); try { - return fn.apply(self, arguments); + callback.call(this); } - catch (e if !(e instanceof FailedAssertion)) { - util.reportError(e); - throw e.stack ? e : Error(e); + catch (e) { + try { + util.dump("Error invoking timer callback registered at " + + [frame.filename, frame.lineNumber, ""].join(":")); + util.reportError(e); + } + catch (e) { + Cu.reportError(e); + } } + }; + let frame = Components.stack.caller; + let timer = services.Timer(timeout_notify, timeout || 0, services.Timer.TYPE_ONE_SHOT); + this.timeouts.push(timer); + return timer; + }, + timeouts: [], + + /** + * Updates this instance with the properties of the given objects. + * Like the update function, but with special semantics for + * localized properties. + */ + update: function update() { + // XXX: Duplication. + + for (let i = 0; i < arguments.length; i++) { + let src = arguments[i]; + Object.getOwnPropertyNames(src || {}).forEach((k) => { + let desc = Object.getOwnPropertyDescriptor(src, k); + if (desc.value instanceof Class.Property) + desc = desc.value.init(k, this) || desc.value; + + if (typeof desc.value === "function") { + let func = desc.value.wrapped || desc.value; + if (!func.superapply) { + func.__defineGetter__("super", () => Object.getPrototypeOf(this)[k]); + + func.superapply = function superapply(self, args) { + let meth = Object.getPrototypeOf(self)[k]; + return meth && meth.apply(self, args); + }; + + func.supercall = function supercall(self, ...args) { + return func.superapply(self, args); + } + } + } + + try { + if ("value" in desc && (this.localizedProperties.has(k) || this.magicalProperties.has(k))) + this[k] = desc.value; + else + Object.defineProperty(this, k, desc); + } + catch (e) {} + }, this); + } + return this; + }, + + localizedProperties: RealSet(), + magicalProperties: RealSet() +}; +for (let name in properties(Class.prototype)) { + let desc = Object.getOwnPropertyDescriptor(Class.prototype, name); + desc.enumerable = false; + Object.defineProperty(Class.prototype, name, desc); +} + +var closureHooks = { + get: function closure_get(target, prop) { + if (hasOwnProperty(target._closureCache, prop)) + return target._closureCache[prop]; + + let p = target[prop] + if (callable(p)) + return target._closureCache[prop] = p.bind(target); + return p; + } + + /* + getOwnPropertyNames: function getOwnPropertyNames(target) { + return [k for (k in properties(target, true))]; + }, + + getOwnPropertyDescriptor: function getOwnPropertyDescriptor(target, prop) { + let self = this; + return { + configurable: false, + writable: false, + get value() self.get(target, prop) } - _closure.wrapped = fn; - return _closure; } + */ +}; + +Class.makeClosure = function makeClosure() { + this._closureCache = {}; - iter(properties(this), properties(this, true)).forEach(function (k) { - if (!__lookupGetter__.call(this, k) && callable(this[k])) - closure[k] = closure(this[k]); - else if (!(k in closure)) - Object.defineProperty(closure, k, { - configurable: true, - enumerable: true, - get: function get_proxy() self[k], - set: function set_proxy(val) self[k] = val, - }); - }, this); - - return closure; + return new Proxy(this, closureHooks); }; -memoize(Class.prototype, "closure", Class.makeClosure); +memoize(Class.prototype, "bound", Class.makeClosure); /** * A base class generator for classes which implement XPCOM interfaces. @@ -928,25 +1134,45 @@ memoize(Class.prototype, "closure", Class.makeClosure); function XPCOM(interfaces, superClass) { interfaces = Array.concat(interfaces); - let shim = interfaces.reduce(function (shim, iface) shim.QueryInterface(iface), - Cc["@dactyl.googlecode.com/base/xpc-interface-shim"].createInstance()); + let shim = XPCOMShim(interfaces); + + let res = Class("XPCOM(" + interfaces + ")", superClass || Class, + update(iter([k, + v === undefined || callable(v) ? stub : v] + for ([k, v] in Iterator(shim))).toObject(), + { QueryInterface: XPCOMUtils.generateQI(interfaces) })); - let res = Class("XPCOM(" + interfaces + ")", superClass || Class, update( - iter.toObject([k, v === undefined || callable(v) ? function stub() null : v] - for ([k, v] in Iterator(shim))), - { QueryInterface: XPCOMUtils.generateQI(interfaces) })); - shim = interfaces = null; return res; } +function XPCOMShim(interfaces) { + let ip = services.InterfacePointer({ + QueryInterface: function (iid) { + if (iid.equals(Ci.nsISecurityCheckedComponent)) + throw Cr.NS_ERROR_NO_INTERFACE; + return this; + }, + getHelperForLanguage: function () null, + getInterfaces: function (count) { count.value = 0; } + }); + return (interfaces || []).reduce((shim, iface) => shim.QueryInterface(Ci[iface]), + ip.data); +}; +let stub = Class.Property({ + configurable: true, + enumerable: false, + value: function stub() null, + writable: true +}); /** * An abstract base class for classes that wish to inherit from Error. */ var ErrorBase = Class("ErrorBase", Error, { level: 2, - init: function EB_init(message, level) { - level = level || 0; - update(this, Error(message)) + init: function EB_init(message, level=0) { + let error = Error(message); + update(this, error); + this.stack = error.stack; this.message = message; let frame = Components.stack; @@ -956,9 +1182,16 @@ var ErrorBase = Class("ErrorBase", Error, { } this.fileName = frame.filename; this.lineNumber = frame.lineNumber; - } + }, + toString: function () String(this.message) }); +/** + * An Error subclass to throw in order to stop sourcing a plugin without + * printing a stack trace. + */ +var Finished = Class("Finished", ErrorBase); + /** * Constructs a new Module class and instantiates an instance into the current * module global object. @@ -968,18 +1201,33 @@ var ErrorBase = Class("ErrorBase", Error, { * @param {Object} classProperties Properties to be applied to the class constructor. * @returns {Class} */ -function Module(name, prototype) { - let init = callable(prototype) ? 4 : 3; - const module = Class.apply(Class, Array.slice(arguments, 0, init)); - let instance = module(); - module.className = name.toLowerCase(); - - instance.INIT = update(Object.create(Module.INIT), - arguments[init] || {}); - - currentModule[module.className] = instance; - defineModule.modules.push(instance); - return module; +function Module(name, prototype, ...args) { + try { + let init = callable(prototype) ? 2 : 1; + let proto = callable(prototype) ? args[0] : prototype; + + proto._metaInit_ = function () { + module.prototype._metaInit_ = null; + currentModule[name.toLowerCase()] = this; + }; + + const module = Class.apply(Class, [name, prototype, ...args.slice(0, init)]); + let instance = module(); + module.className = name.toLowerCase(); + + instance.INIT = update(Object.create(Module.INIT), + args[init] || {}); + + currentModule[module.className] = instance; + defineModule.modules.push(instance); + return module; + } + catch (e) { + if (typeof e === "string") + e = Error(e); + + dump(e.fileName + ":" + e.lineNumber + ": " + e + "\n" + (e.stack || Error().stack)); + } } Module.INIT = { init: function Module_INIT_init(dactyl, modules, window) { @@ -998,7 +1246,7 @@ Module.INIT = { module.isLocalModule = true; modules.jsmodules[this.constructor.className] = module; - locals.reverse().forEach(function (fn, i) update(objs[i], fn.apply(module, args))) + locals.reverse().forEach((fn, i) => { update(objs[i], fn.apply(module, args)); }); memoize(module, "closure", Class.makeClosure); module.instance = module; @@ -1025,17 +1273,13 @@ Module.INIT = { * * @returns {function} The constructor for the new Struct. */ -function Struct() { - if (!/^[A-Z]/.test(arguments[0])) - var args = Array.slice(arguments, 0); - else { - var className = arguments[0]; - args = Array.slice(arguments, 1); - } +function Struct(...args) { + if (/^[A-Z]/.test(args[0])) + var className = args.shift(); const Struct = Class(className || "Struct", StructBase, { length: args.length, - members: array.toObject(args.map(function (v, k) [v, k])) + members: array.toObject(args.map((v, k) => [v, k])) }); args.forEach(function (name, i) { Struct.prototype.__defineGetter__(name, function () this[i]); @@ -1043,15 +1287,18 @@ function Struct() { }); return Struct; } -let StructBase = Class("StructBase", Array, { +var StructBase = Class("StructBase", Array, { init: function struct_init() { for (let i = 0; i < arguments.length; i++) if (arguments[i] != undefined) this[i] = arguments[i]; }, + get toStringParams() this, + clone: function struct_clone() this.constructor.apply(null, this.slice()), + bound: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "bound")), closure: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "closure")), get: function struct_get(key, val) this[this.members[key]], @@ -1091,16 +1338,16 @@ let StructBase = Class("StructBase", Array, { localize: function localize(key, defaultValue) { let i = this.prototype.members[key]; - Object.defineProperty(this.prototype, i, require("messages").Messages.Localized(defaultValue).init(key, this.prototype)); + Object.defineProperty(this.prototype, i, Messages.Localized(defaultValue).init(key, this.prototype)); return this; } }); var Timer = Class("Timer", { - init: function init(minInterval, maxInterval, callback, self) { + init: function init(minInterval, maxInterval, callback, self=this) { this._timer = services.Timer(); this.callback = callback; - this.self = self || this; + this.self = self; this.minInterval = minInterval; this.maxInterval = maxInterval; this.doneAt = 0; @@ -1121,7 +1368,7 @@ var Timer = Class("Timer", { } catch (e) { if (typeof util === "undefined") - dump("dactyl: " + e + "\n" + (e.stack || Error().stack)); + dump(JSMLoader.name + ": " + e + "\n" + (e.stack || Error().stack)); else util.reportError(e); } @@ -1207,9 +1454,14 @@ function octal(decimal) parseInt(decimal, 8); * function. * * @param {object} obj + * @param {nsIJSIID} iface The interface to which to query all elements. * @returns {Generator} */ -function iter(obj) { +iter.iteratorProp = "@@iterator" in [] ? "@@iterator" : "iterator"; +function iter(obj, iface) { + if (arguments.length == 2 && iface instanceof Ci.nsIJSIID) + return iter(obj).map(item => item.QueryInterface(iface)); + let args = arguments; let res = Iterator(obj); @@ -1219,8 +1471,12 @@ function iter(obj) { for (let j in iter(args[i])) yield j; })(); - else if (isinstance(obj, ["Iterator", "Generator"])) + else if (isinstance(obj, ["Iterator", "Generator", "Array"])) ; + else if (isinstance(obj, [Ci.nsIDOMHTMLCollection, Ci.nsIDOMNodeList])) + res = array.iterItems(obj); + else if (iter.iteratorProp in obj && callable(obj[iter.iteratorProp]) && !("__iterator__" in obj)) + res = (x for (x of obj)); else if (ctypes && ctypes.CData && obj instanceof ctypes.CData) { while (obj.constructor instanceof ctypes.PointerType) obj = obj.contents; @@ -1234,9 +1490,8 @@ function iter(obj) { else return iter({}); } - else if (isinstance(obj, [Ci.nsIDOMHTMLCollection, Ci.nsIDOMNodeList])) - res = array.iterItems(obj); - else if (obj instanceof Ci.nsIDOMNamedNodeMap) + else if (Ci.nsIDOMNamedNodeMap && obj instanceof Ci.nsIDOMNamedNodeMap || + Ci.nsIDOMMozNamedAttrMap && obj instanceof Ci.nsIDOMMozNamedAttrMap) res = (function () { for (let i = 0; i < obj.length; i++) yield [obj.name, obj]; @@ -1264,17 +1519,7 @@ function iter(obj) { return iter(obj.enumerator()); return iter(obj.enumerator); } - res.__noSuchMethod__ = function __noSuchMethod__(meth, args) { - if (meth in iter) - var res = iter[meth].apply(iter, [this].concat(args)); - else - res = let (ary = array(this)) - ary[meth] ? ary[meth].apply(ary, args) : ary.__noSuchMethod__(meth, args); - if (isinstance(res, ["Iterator", "Generator"])) - return iter(res); - return res; - }; - return res; + return Iter(res); } update(iter, { toArray: function toArray(iter) array(iter).array, @@ -1294,21 +1539,21 @@ update(iter, { every: function every(iter, pred, self) { pred = pred || util.identity; - for (let elem in iter) + for (let elem of iter) if (!pred.call(self, elem)) return false; return true; }, some: function every(iter, pred, self) { pred = pred || util.identity; - for (let elem in iter) + for (let elem of iter) if (pred.call(self, elem)) return true; return false; }, filter: function filter(iter, pred, self) { - for (let elem in iter) + for (let elem of iter) if (pred.call(self, elem)) yield elem; }, @@ -1322,13 +1567,13 @@ update(iter, { * @param {object} self The this object for *fn*. */ forEach: function forEach(iter, func, self) { - for (let val in iter) + for (let val of iter) func.call(self, val); }, indexOf: function indexOf(iter, elem) { let i = 0; - for (let item in iter) { + for (let item of iter) { if (item == elem) return i; i++; @@ -1344,7 +1589,7 @@ update(iter, { * @returns {Array} */ map: function map(iter, func, self) { - for (let i in iter) + for (let i of iter) yield func.call(self, i); }, @@ -1354,21 +1599,32 @@ update(iter, { */ nth: function nth(iter, pred, n, self) { if (typeof pred === "number") - [pred, n] = [function () true, pred]; // Hack. + [pred, n] = [() => true, pred]; // Hack. - for (let elem in iter) + for (let elem of iter) if (pred.call(self, elem) && n-- === 0) return elem; return undefined; }, + /** + * Analog of Array.find method. Returns the first item in the + * iterator for which `pred` returns true. + */ + find: function find(iter, pred, self) { + for (let elem of iter) + if (pred.call(self, elem)) + return elem; + return undefined; + }, + sort: function sort(iter, fn, self) array(this.toArray(iter).sort(fn, self)), uniq: function uniq(iter) { - let seen = {}; - for (let item in iter) - if (!set.add(seen, item)) + let seen = RealSet(); + for (let item of iter) + if (!seen.add(item)) yield item; }, @@ -1388,6 +1644,37 @@ update(iter, { } }); +const Iter = Class("Iter", { + init: function init(iter) { + this.iter = iter; + if ("__iterator__" in iter) + this.iter = iter.__iterator__(); + + if (this.iter.finalize) + this.finalize = function finalize() this.iter.finalize.apply(this.iter, arguments); + }, + + next: function next() this.iter.next(), + + send: function send() this.iter.send.apply(this.iter, arguments), + + __iterator__: function () this.iter +}); +iter.Iter = Iter; + +function arrayWrap(fn) { + function wrapper() { + let res = fn.apply(this, arguments); + if (isArray(res)) + return array(res); + if (isinstance(res, ["Iterator", "Generator"])) + return iter(res); + return res; + } + wrapper.wrapped = fn; + return wrapper; +} + /** * Array utility methods. */ @@ -1398,23 +1685,25 @@ var array = Class("array", Array, { else if (ary.length) ary = Array.slice(ary); - return { - __proto__: ary, - __iterator__: function () this.iterItems(), - __noSuchMethod__: function (meth, args) { - var res = array[meth].apply(null, [this.array].concat(args)); - if (isArray(res)) - return array(res); - if (isinstance(res, ["Iterator", "Generator"])) - return iter(res); - return res; - }, - array: ary, - toString: function () this.array.toString(), - concat: function () this.__noSuchMethod__("concat", Array.slice(arguments)), - filter: function () this.__noSuchMethod__("filter", Array.slice(arguments)), - map: function () this.__noSuchMethod__("map", Array.slice(arguments)) - }; + let self = this; + return new Proxy(ary, { + get: function array_get(target, prop) { + if (prop in array && callable(array[prop])) + return arrayWrap(array[prop].bind(array, target)); + + if (prop == "array") + return target; + + let p = target[prop]; + if (!/^\d+$/.test(prop) && + prop != "toString" && + prop != "toSource" && + callable(p)) + return arrayWrap(p); + + return p; + } + }); } }, { /** @@ -1423,7 +1712,7 @@ var array = Class("array", Array, { * as such: * [["a", "b"], ["c", "d"]] -> { a: "b", c: "d" } * - * @param {Array[]} assoc + * @param {[Array]} assoc * @... {string} 0 - Key * @... 1 - Value */ @@ -1445,7 +1734,7 @@ var array = Class("array", Array, { * @param {Array} ary * @returns {Array} */ - compact: function compact(ary) ary.filter(function (item) item != null), + compact: function compact(ary) ary.filter(item => item != null), /** * Returns true if each element of ary1 is equal to the @@ -1456,7 +1745,7 @@ var array = Class("array", Array, { * @returns {boolean} */ equals: function (ary1, ary2) - ary1.length === ary2.length && Array.every(ary1, function (e, i) e === ary2[i]), + ary1.length === ary2.length && Array.every(ary1, (e, i) => e === ary2[i]), /** * Flattens an array, such that all elements of the array are @@ -1543,8 +1832,45 @@ var array = Class("array", Array, { } }); +/* Make Minefield not explode, because Minefield exploding is not fun. */ +let iterProto = Iter.prototype; +Object.keys(iter).forEach(function (k) { + iterProto[k] = function (...args) { + let res = iter[k].apply(iter, [this].concat(args)); + if (isinstance(res, ["Iterator", "Generator"])) + return Iter(res); + return res; + }; +}); + +Object.keys(array).forEach(function (k) { + if (!(k in iterProto)) + iterProto[k] = function (...args) { + let res = array[k].apply(array, [this.toArray()].concat(args)); + if (isinstance(res, ["Iterator", "Generator"])) + return Iter(res); + if (isArray(res)) + return array(res); + return res; + }; +}); + +Object.getOwnPropertyNames(Array.prototype).forEach(function (k) { + if (!(k in iterProto) && callable(Array.prototype[k])) + iterProto[k] = function () { + let ary = iter(this).toArray(); + let res = ary[k].apply(ary, arguments); + if (isArray(res)) + return array(res); + return res; + }; +}); + +Object.defineProperty(Class.prototype, "closure", + deprecated("bound", { get: function closure() this.bound })); + endModule(); // catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack);} -// vim: set fdm=marker sw=4 ts=4 et ft=javascript: +// vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript: