status-go/geth/jail/internal/promise/js.go

319 lines
4.9 KiB
Go

package promise
const src = `'use strict';
/**
* @constructor
*/
function Promise(resolver) {
if (typeof resolver !== 'function' && typeof resolver !== 'undefined') {
throw new TypeError();
}
if (typeof this !== 'object' || (this && this.then)) {
throw new TypeError();
}
var self = this;
// states
// 0: pending
// 1: resolving
// 2: rejecting
// 3: resolved
// 4: rejected
var state = 0;
var val = 0;
var next = [];
var fn = null;
var er = null;
this.promise = this;
this.resolve = function resolve(v) {
fn = self.fn;
er = self.er;
if (!state) {
val = v;
state = 1;
setImmediate(fire);
}
return self;
};
this.reject = function reject(v) {
fn = self.fn;
er = self.er;
if (!state) {
val = v;
state = 2;
setImmediate(fire);
}
return self;
};
this._p = 1;
this.then = function then(_fn, _er) {
if (!(this._p === 1)) {
throw new TypeError();
}
var p = new Promise();
p.fn = _fn;
p.er = _er;
switch (state) {
case 3:
p.resolve(val);
break;
case 4:
p.reject(val);
break;
default:
next.push(p);
break;
}
return p;
};
this.catch = function _catch(_er) {
return self.then(null, _er);
};
var finish = function finish(type) {
state = type || 4;
next.map(function(p) {
state === 3 && p.resolve(val) || p.reject(val);
});
};
try {
if (typeof resolver === 'function') {
resolver(this.resolve, this.reject);
}
} catch (e) {
this.reject(e);
}
return this;
// ref: reference to 'then' function
// cb, ec, cn: successCallback, failureCallback, notThennableCallback
function thennable (ref, cb, ec, cn) {
if ((typeof val === 'object' || typeof val === 'function') && typeof ref === 'function') {
try {
// cnt protects against abuse calls from spec checker
var cnt = 0;
ref.call(val, function(v) {
if (cnt++) {
return;
}
val = v;
cb();
}, function(v) {
if (cnt++) {
return;
}
val = v;
ec();
})
} catch (e) {
val = e;
ec();
}
} else {
cn();
}
}
function fire() {
// check if it's a thenable
var ref;
try {
ref = val && val.then;
} catch (e) {
val = e;
state = 2;
return fire();
}
thennable(ref, function() {
state = 1;
fire();
}, function() {
state = 2;
fire();
}, function() {
try {
if (state === 1 && typeof fn === 'function') {
val = fn(val);
} else if (state === 2 && typeof er === 'function') {
val = er(val);
state = 1;
}
} catch (e) {
val = e;
return finish();
}
if (val === self) {
val = TypeError();
finish();
} else {
thennable(ref, function() {
finish(3);
}, finish, function() {
finish(state === 1 && 3);
});
}
});
}
}
Promise.resolve = function resolve(value) {
if (!(this._p === 1)) {
throw new TypeError();
}
if (value instanceof Promise) {
return value;
}
return new Promise(function(resolve) {
resolve(value);
});
};
Promise.reject = function reject(value) {
if (!(this._p === 1)) {
throw new TypeError();
}
return new Promise(function(resolve, reject) {
reject(value);
});
};
Promise.all = function all(arr) {
if (!(this._p === 1)) {
throw new TypeError();
}
if (!(arr instanceof Array)) {
return Promise.reject(TypeError());
}
var p = new Promise();
function done(e, v) {
if (v) {
return p.resolve(v);
}
if (e) {
return p.reject(e);
}
var unresolved = arr.reduce(function(cnt, v) {
if (v && v.then) {
return cnt + 1;
}
return cnt;
}, 0);
if (unresolved === 0) {
p.resolve(arr);
}
arr.map(function(v, i) {
if (v && v.then) {
v.then(function(r) {
arr[i] = r;
done();
return r;
}, done);
}
});
}
done();
return p;
}
Promise.race = function race(arr) {
if (!(this._p === 1)) {
throw TypeError();
}
if (!(arr instanceof Array)) {
return Promise.reject(TypeError());
}
if (arr.length === 0) {
return new Promise();
}
var p = new Promise();
function done(e, v) {
if (v) {
return p.resolve(v);
}
if (e) {
return p.reject(e);
}
var unresolved = arr.reduce(function(cnt, v) {
if (v && v.then) {
return cnt + 1;
}
return cnt;
}, 0);
if (unresolved === 0) {
p.resolve(arr);
}
arr.map(function(v, i) {
if (v && v.then) {
v.then(function(r) {
done(null, r);
}, done);
}
});
}
done();
return p;
}
Promise._p = 1;
`