// Reviewed function shouldBe(expected, actual, msg) { if (msg === void 0) msg = ""; else msg = " for " + msg; if (actual !== expected) throw new Error("bad value" + msg + ": " + actual + ". Expected " + expected); } function shouldBeAsync(expected, run) { let actual; var hadError = false; run().then(function(value) { actual = value; }, function(error) { hadError = true; actual = error; }); drainMicrotasks(); if (hadError) throw actual; shouldBe(expected, actual); } class BaseWrongClass { baseClassValue() { return "wrong #1"; } get property() { return "wrong #2"; } } function shouldBeAsyncAndStoreBind(expected, run) { shouldBeAsync(expected, run); shouldBeAsync(expected, run.bind({})); shouldBeAsync(expected, run.bind(1)); shouldBeAsync(expected, run.bind(undefined)); const obj = { property : 'wrong value #1', baseClassValue : () => 'worng value #2' }; shouldBeAsync(expected, run.bind(obj)); shouldBeAsync(expected, run.bind(new BaseWrongClass())); } class BaseClass { baseClassValue() { return "BaseClassValue"; } get property() { return "test!"; } } function runSomething(callback) { callback(); } class ChildClass extends BaseClass { classValue() { return "classValue"; } get classProperty() { return "classProperty"; } asyncValueExp() { return async x => 'value'; } asyncValueBody() { return async x => { return 'value'; }; } asyncThisPropExp() { return async x => this.classProperty; } asyncThisPropBody() { return async x => { return this.classProperty; }; } asyncThisPropWithAwaitBody() { return async x => { var self = this.classProperty; self = await 'abc'; return this.classProperty; }; } asyncThisPropInEvalExp() { return async x => eval('this.classProperty'); } asyncThisPropInEvalBody() { return async x => { return eval('this.classProperty'); }; } asyncThisPropInEvalWithAwaitBody() { return async x => { var self = eval('this.classProperty'); await 'abc'; return eval('this.classProperty'); }; } asyncThisValueExp() { return async x => this.classValue(); } asyncThisValueBody() { return async x => { return this.classValue(); }; } asyncThisValueBodyWithAwait() { return async x => { var self = this.classValue(); await 'self'; return this.classValue(); }; } asyncThisValueInEvalExp() { return async x => eval('this.classValue()'); } asyncThisValueInEvalBody() { return async x => { return eval('this.classValue()'); }; } asyncThisValueInEvalWithAwaitBody() { return async x => { var self = eval('this.classValue()'); await 'self'; return eval('this.classValue()'); }; } } shouldBeAsyncAndStoreBind("value", new ChildClass().asyncValueExp()); shouldBeAsyncAndStoreBind("value", new ChildClass().asyncValueBody()); shouldBeAsyncAndStoreBind("classProperty", new ChildClass().asyncThisPropExp()); shouldBeAsyncAndStoreBind("classProperty", new ChildClass().asyncThisPropBody()); shouldBeAsyncAndStoreBind("classProperty", new ChildClass().asyncThisPropWithAwaitBody()); shouldBeAsyncAndStoreBind("classProperty", new ChildClass().asyncThisPropWithAwaitBody()); shouldBeAsyncAndStoreBind("classProperty", new ChildClass().asyncThisPropInEvalExp()); shouldBeAsyncAndStoreBind("classProperty", new ChildClass().asyncThisPropInEvalBody()); shouldBeAsyncAndStoreBind("classProperty", new ChildClass().asyncThisPropInEvalWithAwaitBody()); shouldBeAsyncAndStoreBind("classValue", new ChildClass().asyncThisValueExp()); shouldBeAsyncAndStoreBind("classValue", new ChildClass().asyncThisValueBody()); shouldBeAsyncAndStoreBind("classValue", new ChildClass().asyncThisValueBodyWithAwait()); shouldBeAsyncAndStoreBind("classValue", new ChildClass().asyncThisValueInEvalExp()); shouldBeAsyncAndStoreBind("classValue", new ChildClass().asyncThisValueInEvalBody()); shouldBeAsyncAndStoreBind("classValue", new ChildClass().asyncThisValueInEvalWithAwaitBody()); class ChildClass2 extends BaseClass { constructor() { super(); this.value = 'internalValue'; return async () => this.classValue() + ' ' + this.classProperty; } classStaticValue() { return "classStaticValue"; } classValue() { return this.value; } get classProperty() { return "classProperty"; } } shouldBeAsyncAndStoreBind("internalValue classProperty", new ChildClass2()); class ChildClass3 extends BaseClass { constructor() { super(); this.internalValue = 'internalValue'; return async () => { var self = this.classValue() + ' ' + this.classProperty; await 'self'; return this.classValue() + ' ' + this.classProperty; } } classValue() { return "classValue"; } get classProperty() { return "classProperty"; } } shouldBeAsyncAndStoreBind("classValue classProperty", new ChildClass3()); var promiseHolder = {}; var promise = new Promise((resolve, reject) => { promiseHolder.resolve = resolve; promiseHolder.reject = reject; }); class ChildClass4 extends BaseClass { constructor() { var arr = async () => { var doSomeStaff = () => {}; doSomeStaff(); await promise; return this.classValue() + ' ' + this.classProperty; }; arr(); super(); this.internalValue = 'internalValue'; return async () => { await 'await'; promiseHolder.resolve(); return this.classValue() + ' ' + this.classProperty;; }; } classValue() { return "classValue"; } get classProperty() { return "classProperty"; } } shouldBeAsyncAndStoreBind("classValue classProperty", new ChildClass4()); class ChildClass5 extends BaseClass { constructor(result) { const arr = async () => this.id; arr().then(()=>{}, e => { result.error = e; }); } } class ChildClass6 extends BaseClass { constructor(result) { const arr = async () => { let z = this.id; }; arr().then(()=>{}, e => { result.error = e; }); super(); } } class ChildClass7 extends BaseClass { constructor(result) { const arr = async () => this.id; arr().then(()=>{}, e => { result.error = e; }); super(); } } class ChildClass8 extends BaseClass { constructor(result) { const arr = async () => { let i = this.id; super(); }; arr().then(()=>{}, e => { result.error = e; }); } } function checkTDZDuringCreate(klass) { let asyncError = {}; try { var c = new klass(asyncError); } catch(e) { // We do not care about this error } drainMicrotasks(); const error = asyncError.error instanceof ReferenceError && asyncError.error.toString() === 'ReferenceError: Cannot access uninitialized variable.'; if (!error) throw new Error('TDZ error is expected, but appeared:' + asyncError.error); } checkTDZDuringCreate(ChildClass5); checkTDZDuringCreate(ChildClass6); checkTDZDuringCreate(ChildClass7); checkTDZDuringCreate(ChildClass8);