From 154d443c88d7e08bd8a51da190a06a312976c6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Tue, 22 Mar 2022 19:42:05 +0900 Subject: [PATCH] fix(es/compat): Fix regression of `es2015` (#4119) --- .../tests/fixture/issue-4108/1/input/.swcrc | 10 + .../tests/fixture/issue-4108/1/input/index.ts | 506 +++++++++++ .../fixture/issue-4108/1/output/index.ts | 832 ++++++++++++++++++ .../vercel/full/next-31419/1/output/index.js | 24 +- .../src/es2015/block_scoping/mod.rs | 29 + 5 files changed, 1391 insertions(+), 10 deletions(-) create mode 100644 crates/swc/tests/fixture/issue-4108/1/input/.swcrc create mode 100644 crates/swc/tests/fixture/issue-4108/1/input/index.ts create mode 100644 crates/swc/tests/fixture/issue-4108/1/output/index.ts diff --git a/crates/swc/tests/fixture/issue-4108/1/input/.swcrc b/crates/swc/tests/fixture/issue-4108/1/input/.swcrc new file mode 100644 index 00000000000..2e22ad5e2be --- /dev/null +++ b/crates/swc/tests/fixture/issue-4108/1/input/.swcrc @@ -0,0 +1,10 @@ +{ + "jsc": { + "parser": { + "syntax": "typescript", + "tsx": true, + "decorators": false + }, + "target": "es5" + } +} \ No newline at end of file diff --git a/crates/swc/tests/fixture/issue-4108/1/input/index.ts b/crates/swc/tests/fixture/issue-4108/1/input/index.ts new file mode 100644 index 00000000000..74ffdfe6dff --- /dev/null +++ b/crates/swc/tests/fixture/issue-4108/1/input/index.ts @@ -0,0 +1,506 @@ +import { + Keypair, + Commitment, + Connection, + RpcResponseAndContext, + SignatureStatus, + SimulatedTransactionResponse, + Transaction, + TransactionInstruction, + TransactionSignature, + Blockhash, + FeeCalculator, +} from '@solana/web3.js'; + +import { WalletNotConnectedError } from '@solana/wallet-adapter-base'; + +interface BlockhashAndFeeCalculator { + blockhash: Blockhash; + feeCalculator: FeeCalculator; +} + +export const getErrorForTransaction = async (connection: Connection, txid: string) => { + // wait for all confirmation before geting transaction + await connection.confirmTransaction(txid, 'max'); + + const tx = await connection.getParsedConfirmedTransaction(txid); + + const errors: string[] = []; + if (tx?.meta && tx.meta.logMessages) { + tx.meta.logMessages.forEach(log => { + const regex = /Error: (.*)/gm; + let m; + while ((m = regex.exec(log)) !== null) { + // This is necessary to avoid infinite loops with zero-width matches + if (m.index === regex.lastIndex) { + regex.lastIndex++; + } + + if (m.length > 1) { + errors.push(m[1]); + } + } + }); + } + + return errors; +}; + +export enum SequenceType { + Sequential, + Parallel, + StopOnFailure, +} + +export async function sendTransactionsWithManualRetry( + connection: Connection, + wallet: any, + instructions: TransactionInstruction[][], + signers: Keypair[][], +): Promise<(string | undefined)[]> { + let stopPoint = 0; + let tries = 0; + let lastInstructionsLength = null; + let toRemoveSigners: Record = {}; + instructions = instructions.filter((instr, i) => { + if (instr.length > 0) { + return true; + } else { + toRemoveSigners[i] = true; + return false; + } + }); + let ids: string[] = []; + let filteredSigners = signers.filter((_, i) => !toRemoveSigners[i]); + + while (stopPoint < instructions.length && tries < 3) { + instructions = instructions.slice(stopPoint, instructions.length); + filteredSigners = filteredSigners.slice(stopPoint, filteredSigners.length); + + if (instructions.length === lastInstructionsLength) tries = tries + 1; + else tries = 0; + + try { + if (instructions.length === 1) { + const id = await sendTransactionWithRetry(connection, wallet, instructions[0], filteredSigners[0], 'single'); + ids.push(id.txid); + stopPoint = 1; + } else { + const { txs } = await sendTransactions( + connection, + wallet, + instructions, + filteredSigners, + SequenceType.StopOnFailure, + 'single', + ); + ids = ids.concat(txs.map(t => t.txid)); + } + } catch (e) { + console.error(e); + } + console.log( + 'Died on ', + stopPoint, + 'retrying from instruction', + instructions[stopPoint], + 'instructions length is', + instructions.length, + ); + lastInstructionsLength = instructions.length; + } + + return ids; +} + +export const sendTransactions = async ( + connection: Connection, + wallet: any, + instructionSet: TransactionInstruction[][], + signersSet: Keypair[][], + sequenceType: SequenceType = SequenceType.Parallel, + commitment: Commitment = 'singleGossip', + successCallback: (txid: string, ind: number) => void = (txid, ind) => { }, + failCallback: (reason: string, ind: number) => boolean = (txid, ind) => false, + block?: BlockhashAndFeeCalculator, + beforeTransactions: Transaction[] = [], + afterTransactions: Transaction[] = [], +): Promise<{ number: number; txs: { txid: string; slot: number }[] }> => { + if (!wallet.publicKey) throw new WalletNotConnectedError(); + + const unsignedTxns: Transaction[] = beforeTransactions; + + if (!block) { + block = await connection.getRecentBlockhash(commitment); + } + + for (let i = 0; i < instructionSet.length; i++) { + const instructions = instructionSet[i]; + const signers = signersSet[i]; + + if (instructions.length === 0) { + continue; + } + + let transaction = new Transaction(); + instructions.forEach(instruction => transaction.add(instruction)); + transaction.recentBlockhash = block.blockhash; + transaction.setSigners( + // fee payed by the wallet owner + wallet.publicKey, + ...signers.map(s => s.publicKey), + ); + + if (signers.length > 0) { + transaction.partialSign(...signers); + } + + unsignedTxns.push(transaction); + } + unsignedTxns.push(...afterTransactions); + + const partiallySignedTransactions = unsignedTxns.filter(t => + t.signatures.find(sig => sig.publicKey.equals(wallet.publicKey)), + ); + const fullySignedTransactions = unsignedTxns.filter( + t => !t.signatures.find(sig => sig.publicKey.equals(wallet.publicKey)), + ); + let signedTxns = await wallet.signAllTransactions(partiallySignedTransactions); + signedTxns = fullySignedTransactions.concat(signedTxns); + const pendingTxns: Promise<{ txid: string; slot: number }>[] = []; + + console.log('Signed txns length', signedTxns.length, 'vs handed in length', instructionSet.length); + for (let i = 0; i < signedTxns.length; i++) { + const signedTxnPromise = sendSignedTransaction({ + connection, + signedTransaction: signedTxns[i], + }); + + if (sequenceType !== SequenceType.Parallel) { + try { + await signedTxnPromise.then(({ txid, slot }) => successCallback(txid, i)); + pendingTxns.push(signedTxnPromise); + } catch (e) { + console.log('Failed at txn index:', i); + console.log('Caught failure:', e); + + failCallback(signedTxns[i], i); + if (sequenceType === SequenceType.StopOnFailure) { + return { + number: i, + txs: await Promise.all(pendingTxns), + }; + } + } + } else { + pendingTxns.push(signedTxnPromise); + } + } + + if (sequenceType !== SequenceType.Parallel) { + const result = await Promise.all(pendingTxns); + return { number: signedTxns.length, txs: result }; + } + + return { number: signedTxns.length, txs: await Promise.all(pendingTxns) }; +}; + +export const sendTransaction = async ( + connection: Connection, + wallet: any, + instructions: TransactionInstruction[] | Transaction, + signers: Keypair[], + awaitConfirmation = true, + commitment: Commitment = 'singleGossip', + includesFeePayer: boolean = false, + block?: BlockhashAndFeeCalculator, +) => { + if (!wallet.publicKey) throw new WalletNotConnectedError(); + + let transaction: Transaction; + if (instructions instanceof Transaction) { + transaction = instructions; + } else { + transaction = new Transaction(); + instructions.forEach(instruction => transaction.add(instruction)); + transaction.recentBlockhash = (block || (await connection.getRecentBlockhash(commitment))).blockhash; + + if (includesFeePayer) { + transaction.setSigners(...signers.map(s => s.publicKey)); + } else { + transaction.setSigners( + // fee payed by the wallet owner + wallet.publicKey, + ...signers.map(s => s.publicKey), + ); + } + + if (signers.length > 0) { + transaction.partialSign(...signers); + } + if (!includesFeePayer) { + transaction = await wallet.signTransaction(transaction); + } + } + + const rawTransaction = transaction.serialize(); + let options = { + skipPreflight: true, + commitment, + }; + + const txid = await connection.sendRawTransaction(rawTransaction, options); + let slot = 0; + + if (awaitConfirmation) { + const confirmation = await awaitTransactionSignatureConfirmation(txid, DEFAULT_TIMEOUT, connection, commitment); + + if (!confirmation) throw new Error('Timed out awaiting confirmation on transaction'); + slot = confirmation?.slot || 0; + + if (confirmation?.err) { + const errors = await getErrorForTransaction(connection, txid); + + console.log(errors); + throw new Error(`Raw transaction ${txid} failed`); + } + } + + return { txid, slot }; +}; + +export const sendTransactionWithRetry = async ( + connection: Connection, + wallet: any, + instructions: TransactionInstruction[], + signers: Keypair[], + commitment: Commitment = 'singleGossip', + includesFeePayer: boolean = false, + block?: BlockhashAndFeeCalculator, + beforeSend?: () => void, +) => { + if (!wallet.publicKey) throw new WalletNotConnectedError(); + + let transaction = new Transaction(); + instructions.forEach(instruction => transaction.add(instruction)); + transaction.recentBlockhash = (block || (await connection.getRecentBlockhash(commitment))).blockhash; + + if (includesFeePayer) { + transaction.setSigners(...signers.map(s => s.publicKey)); + } else { + transaction.setSigners( + // fee payed by the wallet owner + wallet.publicKey, + ...signers.map(s => s.publicKey), + ); + } + + if (signers.length > 0) { + transaction.partialSign(...signers); + } + if (!includesFeePayer) { + transaction = await wallet.signTransaction(transaction); + } + + if (beforeSend) { + beforeSend(); + } + + const { txid, slot } = await sendSignedTransaction({ + connection, + signedTransaction: transaction, + }); + + return { txid, slot }; +}; + +export const getUnixTs = () => { + return new Date().getTime() / 1000; +}; + +const DEFAULT_TIMEOUT = 15000; + +export async function sendSignedTransaction({ + signedTransaction, + connection, + timeout = DEFAULT_TIMEOUT, +}: { + signedTransaction: Transaction; + connection: Connection; + sendingMessage?: string; + sentMessage?: string; + successMessage?: string; + timeout?: number; +}): Promise<{ txid: string; slot: number }> { + const rawTransaction = signedTransaction.serialize(); + + const startTime = getUnixTs(); + let slot = 0; + const txid: TransactionSignature = await connection.sendRawTransaction(rawTransaction, { + skipPreflight: true, + }); + + console.log('Started awaiting confirmation for', txid); + + let done = false; + (async () => { + while (!done && getUnixTs() - startTime < timeout) { + connection.sendRawTransaction(rawTransaction, { + skipPreflight: true, + }); + await sleep(500); + } + })(); + try { + const confirmation = await awaitTransactionSignatureConfirmation(txid, timeout, connection, 'recent', true); + + if (!confirmation) throw new Error('Timed out awaiting confirmation on transaction'); + + if (confirmation.err) { + console.error(confirmation.err); + throw new Error('Transaction failed: Custom instruction error'); + } + + slot = confirmation?.slot || 0; + } catch (err: any) { + console.error('Timeout Error caught', err); + if (err.timeout) { + throw new Error('Timed out awaiting confirmation on transaction'); + } + let simulateResult: SimulatedTransactionResponse | null = null; + try { + simulateResult = (await simulateTransaction(connection, signedTransaction, 'single')).value; + } catch (e) { } + if (simulateResult && simulateResult.err) { + if (simulateResult.logs) { + for (let i = simulateResult.logs.length - 1; i >= 0; --i) { + const line = simulateResult.logs[i]; + if (line.startsWith('Program log: ')) { + throw new Error('Transaction failed: ' + line.slice('Program log: '.length)); + } + } + } + throw new Error(JSON.stringify(simulateResult.err)); + } + // throw new Error('Transaction failed'); + } finally { + done = true; + } + + console.log('Latency', txid, getUnixTs() - startTime); + return { txid, slot }; +} + +async function simulateTransaction( + connection: Connection, + transaction: Transaction, + commitment: Commitment, +): Promise> { + // @ts-ignore + transaction.recentBlockhash = await connection._recentBlockhash( + // @ts-ignore + connection._disableBlockhashCaching, + ); + + const signData = transaction.serializeMessage(); + // @ts-ignore + const wireTransaction = transaction._serialize(signData); + const encodedTransaction = wireTransaction.toString('base64'); + const config: any = { encoding: 'base64', commitment }; + const args = [encodedTransaction, config]; + + // @ts-ignore + const res = await connection._rpcRequest('simulateTransaction', args); + if (res.error) { + throw new Error('failed to simulate transaction: ' + res.error.message); + } + return res.result; +} + +async function awaitTransactionSignatureConfirmation( + txid: TransactionSignature, + timeout: number, + connection: Connection, + commitment: Commitment = 'recent', + queryStatus = false, +): Promise { + let done = false; + let status: SignatureStatus | null | void = { + slot: 0, + confirmations: 0, + err: null, + }; + let subId = 0; + status = await new Promise(async (resolve, reject) => { + setTimeout(() => { + if (done) { + return; + } + done = true; + console.log('Rejecting for timeout...'); + reject({ timeout: true }); + }, timeout); + try { + subId = connection.onSignature( + txid, + (result, context) => { + done = true; + status = { + err: result.err, + slot: context.slot, + confirmations: 0, + }; + if (result.err) { + console.log('Rejected via websocket', result.err); + reject(status); + } else { + console.log('Resolved via websocket', result); + resolve(status); + } + }, + commitment, + ); + } catch (e) { + done = true; + console.error('WS error in setup', txid, e); + } + while (!done && queryStatus) { + // eslint-disable-next-line no-loop-func + (async () => { + try { + const signatureStatuses = await connection.getSignatureStatuses([txid]); + status = signatureStatuses && signatureStatuses.value[0]; + if (!done) { + if (!status) { + console.log('REST null result for', txid, status); + } else if (status.err) { + console.log('REST error for', txid, status); + done = true; + reject(status.err); + } else if (!status.confirmations) { + console.log('REST no confirmations for', txid, status); + } else { + console.log('REST confirmation for', txid, status); + done = true; + resolve(status); + } + } + } catch (e) { + if (!done) { + console.log('REST connection error: txid', txid, e); + } + } + })(); + await sleep(2000); + } + }); + + //@ts-ignore + if (connection._signatureSubscriptions[subId]) connection.removeSignatureListener(subId); + done = true; + console.log('Returning status', status); + return status; +} +export function sleep(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); +} diff --git a/crates/swc/tests/fixture/issue-4108/1/output/index.ts b/crates/swc/tests/fixture/issue-4108/1/output/index.ts new file mode 100644 index 00000000000..fc185f4bd30 --- /dev/null +++ b/crates/swc/tests/fixture/issue-4108/1/output/index.ts @@ -0,0 +1,832 @@ +import * as swcHelpers from "@swc/helpers"; +import regeneratorRuntime from "regenerator-runtime"; +import { Transaction } from "@solana/web3.js"; +import { WalletNotConnectedError } from "@solana/wallet-adapter-base"; +export var getErrorForTransaction = function() { + var _ref = swcHelpers.asyncToGenerator(regeneratorRuntime.mark(function _callee(connection, txid) { + var tx, errors; + return regeneratorRuntime.wrap(function _callee$(_ctx) { + while(1)switch(_ctx.prev = _ctx.next){ + case 0: + _ctx.next = 2; + return connection.confirmTransaction(txid, "max"); + case 2: + _ctx.next = 4; + return connection.getParsedConfirmedTransaction(txid); + case 4: + tx = _ctx.sent; + errors = []; + if ((tx === null || tx === void 0 ? void 0 : tx.meta) && tx.meta.logMessages) { + tx.meta.logMessages.forEach(function(log) { + var regex = /Error: (.*)/gm; + var m; + while((m = regex.exec(log)) !== null){ + // This is necessary to avoid infinite loops with zero-width matches + if (m.index === regex.lastIndex) { + regex.lastIndex++; + } + if (m.length > 1) { + errors.push(m[1]); + } + } + }); + } + return _ctx.abrupt("return", errors); + case 8: + case "end": + return _ctx.stop(); + } + }, _callee); + })); + return function getErrorForTransaction(connection, txid) { + return _ref.apply(this, arguments); + }; +}(); +export var SequenceType; +(function(SequenceType) { + SequenceType[SequenceType["Sequential"] = 0] = "Sequential"; + SequenceType[SequenceType["Parallel"] = 1] = "Parallel"; + SequenceType[SequenceType["StopOnFailure"] = 2] = "StopOnFailure"; +})(SequenceType || (SequenceType = {})); +export function sendTransactionsWithManualRetry(connection, wallet, instructions, signers) { + return _sendTransactionsWithManualRetry.apply(this, arguments); +} +function _sendTransactionsWithManualRetry() { + _sendTransactionsWithManualRetry = swcHelpers.asyncToGenerator(regeneratorRuntime.mark(function _callee(connection, wallet, instructions, signers) { + var stopPoint, tries, lastInstructionsLength, toRemoveSigners, ids, filteredSigners, id, txs; + return regeneratorRuntime.wrap(function _callee$(_ctx) { + while(1)switch(_ctx.prev = _ctx.next){ + case 0: + stopPoint = 0; + tries = 0; + lastInstructionsLength = null; + toRemoveSigners = {}; + instructions = instructions.filter(function(instr, i) { + if (instr.length > 0) { + return true; + } else { + toRemoveSigners[i] = true; + return false; + } + }); + ids = []; + filteredSigners = signers.filter(function(_, i) { + return !toRemoveSigners[i]; + }); + case 7: + if (!(stopPoint < instructions.length && tries < 3)) { + _ctx.next = 33; + break; + } + instructions = instructions.slice(stopPoint, instructions.length); + filteredSigners = filteredSigners.slice(stopPoint, filteredSigners.length); + if (instructions.length === lastInstructionsLength) tries = tries + 1; + else tries = 0; + _ctx.prev = 11; + if (!(instructions.length === 1)) { + _ctx.next = 20; + break; + } + _ctx.next = 15; + return sendTransactionWithRetry(connection, wallet, instructions[0], filteredSigners[0], "single"); + case 15: + id = _ctx.sent; + ids.push(id.txid); + stopPoint = 1; + _ctx.next = 24; + break; + case 20: + _ctx.next = 22; + return sendTransactions(connection, wallet, instructions, filteredSigners, SequenceType.StopOnFailure, "single"); + case 22: + txs = _ctx.sent.txs; + ids = ids.concat(txs.map(function(t) { + return t.txid; + })); + case 24: + _ctx.next = 29; + break; + case 26: + _ctx.prev = 26; + _ctx.t0 = _ctx["catch"](11); + console.error(_ctx.t0); + case 29: + console.log("Died on ", stopPoint, "retrying from instruction", instructions[stopPoint], "instructions length is", instructions.length); + lastInstructionsLength = instructions.length; + _ctx.next = 7; + break; + case 33: + return _ctx.abrupt("return", ids); + case 34: + case "end": + return _ctx.stop(); + } + }, _callee, null, [ + [ + 11, + 26 + ] + ]); + })); + return _sendTransactionsWithManualRetry.apply(this, arguments); +} +export var sendTransactions = function() { + var _ref = swcHelpers.asyncToGenerator(regeneratorRuntime.mark(function _callee(connection, wallet, instructionSet, signersSet) { + var sequenceType, commitment, successCallback, failCallback, block, beforeTransactions, afterTransactions, _unsignedTxns, unsignedTxns, i, _transaction, instructions, signers, transaction, _transaction1, partiallySignedTransactions, fullySignedTransactions, signedTxns, pendingTxns, i1, signedTxnPromise, result, _args = arguments; + return regeneratorRuntime.wrap(function _callee$(_ctx) { + while(1)switch(_ctx.prev = _ctx.next){ + case 0: + sequenceType = _args.length > 4 && _args[4] !== void 0 ? _args[4] : SequenceType.Parallel, commitment = _args.length > 5 && _args[5] !== void 0 ? _args[5] : "singleGossip", successCallback = _args.length > 6 && _args[6] !== void 0 ? _args[6] : function(txid, ind) {}, failCallback = _args.length > 7 && _args[7] !== void 0 ? _args[7] : function(txid, ind) { + return false; + }, block = _args.length > 8 ? _args[8] : void 0, beforeTransactions = _args.length > 9 && _args[9] !== void 0 ? _args[9] : [], afterTransactions = _args.length > 10 && _args[10] !== void 0 ? _args[10] : []; + ; + if (wallet.publicKey) { + _ctx.next = 4; + break; + } + throw new WalletNotConnectedError(); + case 4: + unsignedTxns = beforeTransactions; + if (block) { + _ctx.next = 9; + break; + } + _ctx.next = 8; + return connection.getRecentBlockhash(commitment); + case 8: + block = _ctx.sent; + case 9: + i = 0; + case 10: + if (!(i < instructionSet.length)) { + _ctx.next = 25; + break; + } + ; + instructions = instructionSet[i]; + signers = signersSet[i]; + if (!(instructions.length === 0)) { + _ctx.next = 16; + break; + } + return _ctx.abrupt("continue", 22); + case 16: + transaction = new Transaction(); + instructions.forEach(function(instruction) { + return transaction.add(instruction); + }); + transaction.recentBlockhash = block.blockhash; + (_transaction = transaction).setSigners.apply(_transaction, [ + // fee payed by the wallet owner + wallet.publicKey, + ].concat(swcHelpers.toConsumableArray(signers.map(function(s) { + return s.publicKey; + })))); + if (signers.length > 0) { + ; + (_transaction1 = transaction).partialSign.apply(_transaction1, swcHelpers.toConsumableArray(signers)); + } + unsignedTxns.push(transaction); + case 22: + i++; + _ctx.next = 10; + break; + case 25: + (_unsignedTxns = unsignedTxns).push.apply(_unsignedTxns, swcHelpers.toConsumableArray(afterTransactions)); + partiallySignedTransactions = unsignedTxns.filter(function(t) { + return t.signatures.find(function(sig) { + return sig.publicKey.equals(wallet.publicKey); + }); + }); + fullySignedTransactions = unsignedTxns.filter(function(t) { + return !t.signatures.find(function(sig) { + return sig.publicKey.equals(wallet.publicKey); + }); + }); + _ctx.next = 30; + return wallet.signAllTransactions(partiallySignedTransactions); + case 30: + signedTxns = _ctx.sent; + signedTxns = fullySignedTransactions.concat(signedTxns); + pendingTxns = []; + console.log("Signed txns length", signedTxns.length, "vs handed in length", instructionSet.length); + i1 = 0; + case 35: + if (!(i1 < signedTxns.length)) { + _ctx.next = 61; + break; + } + signedTxnPromise = sendSignedTransaction({ + connection: connection, + signedTransaction: signedTxns[i1] + }); + if (!(sequenceType !== SequenceType.Parallel)) { + _ctx.next = 57; + break; + } + _ctx.prev = 38; + _ctx.next = 41; + return signedTxnPromise.then(function(param) { + var txid = param.txid, slot = param.slot; + return successCallback(txid, i1); + }); + case 41: + pendingTxns.push(signedTxnPromise); + _ctx.next = 55; + break; + case 44: + _ctx.prev = 44; + _ctx.t0 = _ctx["catch"](38); + console.log("Failed at txn index:", i1); + console.log("Caught failure:", _ctx.t0); + failCallback(signedTxns[i1], i1); + if (!(sequenceType === SequenceType.StopOnFailure)) { + _ctx.next = 55; + break; + } + _ctx.t1 = i1; + _ctx.next = 53; + return Promise.all(pendingTxns); + case 53: + _ctx.t2 = _ctx.sent; + return _ctx.abrupt("return", { + number: _ctx.t1, + txs: _ctx.t2 + }); + case 55: + _ctx.next = 58; + break; + case 57: + { + pendingTxns.push(signedTxnPromise); + } + case 58: + i1++; + _ctx.next = 35; + break; + case 61: + if (!(sequenceType !== SequenceType.Parallel)) { + _ctx.next = 66; + break; + } + _ctx.next = 64; + return Promise.all(pendingTxns); + case 64: + result = _ctx.sent; + return _ctx.abrupt("return", { + number: signedTxns.length, + txs: result + }); + case 66: + _ctx.t3 = signedTxns.length; + _ctx.next = 69; + return Promise.all(pendingTxns); + case 69: + _ctx.t4 = _ctx.sent; + return _ctx.abrupt("return", { + number: _ctx.t3, + txs: _ctx.t4 + }); + case 71: + case "end": + return _ctx.stop(); + } + }, _callee, null, [ + [ + 38, + 44 + ] + ]); + })); + return function sendTransactions(connection, wallet, instructionSet, signersSet) { + return _ref.apply(this, arguments); + }; +}(); +export var sendTransaction = function() { + var _ref = swcHelpers.asyncToGenerator(regeneratorRuntime.mark(function _callee(connection, wallet, instructions, signers) { + var awaitConfirmation, commitment, includesFeePayer, block, transaction, _transaction, _transaction2, _transaction3, rawTransaction, options, txid, slot, confirmation, errors, _args = arguments; + return regeneratorRuntime.wrap(function _callee$(_ctx) { + while(1)switch(_ctx.prev = _ctx.next){ + case 0: + awaitConfirmation = _args.length > 4 && _args[4] !== void 0 ? _args[4] : true, commitment = _args.length > 5 && _args[5] !== void 0 ? _args[5] : "singleGossip", includesFeePayer = _args.length > 6 && _args[6] !== void 0 ? _args[6] : false, block = _args.length > 7 ? _args[7] : void 0; + if (wallet.publicKey) { + _ctx.next = 3; + break; + } + throw new WalletNotConnectedError(); + case 3: + ; + if (!swcHelpers._instanceof(instructions, Transaction)) { + _ctx.next = 8; + break; + } + { + transaction = instructions; + } + _ctx.next = 22; + break; + case 8: + transaction = new Transaction(); + instructions.forEach(function(instruction) { + return transaction.add(instruction); + }); + _ctx.t0 = block; + if (_ctx.t0) { + _ctx.next = 15; + break; + } + _ctx.next = 14; + return connection.getRecentBlockhash(commitment); + case 14: + _ctx.t0 = _ctx.sent; + case 15: + transaction.recentBlockhash = _ctx.t0.blockhash; + if (includesFeePayer) { + ; + (_transaction = transaction).setSigners.apply(_transaction, swcHelpers.toConsumableArray(signers.map(function(s) { + return s.publicKey; + }))); + } else { + ; + (_transaction2 = transaction).setSigners.apply(_transaction2, [ + // fee payed by the wallet owner + wallet.publicKey, + ].concat(swcHelpers.toConsumableArray(signers.map(function(s) { + return s.publicKey; + })))); + } + if (signers.length > 0) { + ; + (_transaction3 = transaction).partialSign.apply(_transaction3, swcHelpers.toConsumableArray(signers)); + } + if (includesFeePayer) { + _ctx.next = 22; + break; + } + _ctx.next = 21; + return wallet.signTransaction(transaction); + case 21: + transaction = _ctx.sent; + case 22: + rawTransaction = transaction.serialize(); + options = { + skipPreflight: true, + commitment: commitment + }; + _ctx.next = 26; + return connection.sendRawTransaction(rawTransaction, options); + case 26: + txid = _ctx.sent; + slot = 0; + if (!awaitConfirmation) { + _ctx.next = 41; + break; + } + _ctx.next = 31; + return awaitTransactionSignatureConfirmation(txid, DEFAULT_TIMEOUT, connection, commitment); + case 31: + confirmation = _ctx.sent; + if (confirmation) { + _ctx.next = 34; + break; + } + throw new Error("Timed out awaiting confirmation on transaction"); + case 34: + slot = (confirmation === null || confirmation === void 0 ? void 0 : confirmation.slot) || 0; + if (!(confirmation === null || confirmation === void 0 ? void 0 : confirmation.err)) { + _ctx.next = 41; + break; + } + _ctx.next = 38; + return getErrorForTransaction(connection, txid); + case 38: + errors = _ctx.sent; + console.log(errors); + throw new Error("Raw transaction ".concat(txid, " failed")); + case 41: + return _ctx.abrupt("return", { + txid: txid, + slot: slot + }); + case 42: + case "end": + return _ctx.stop(); + } + }, _callee); + })); + return function sendTransaction(connection, wallet, instructions, signers) { + return _ref.apply(this, arguments); + }; +}(); +export var sendTransactionWithRetry = function() { + var _ref = swcHelpers.asyncToGenerator(regeneratorRuntime.mark(function _callee(connection, wallet, instructions, signers) { + var commitment, includesFeePayer, block, beforeSend, transaction, _transaction, _transaction4, _transaction5, ref, txid, slot, _args = arguments; + return regeneratorRuntime.wrap(function _callee$(_ctx) { + while(1)switch(_ctx.prev = _ctx.next){ + case 0: + commitment = _args.length > 4 && _args[4] !== void 0 ? _args[4] : "singleGossip", includesFeePayer = _args.length > 5 && _args[5] !== void 0 ? _args[5] : false, block = _args.length > 6 ? _args[6] : void 0, beforeSend = _args.length > 7 ? _args[7] : void 0; + if (wallet.publicKey) { + _ctx.next = 3; + break; + } + throw new WalletNotConnectedError(); + case 3: + transaction = new Transaction(); + instructions.forEach(function(instruction) { + return transaction.add(instruction); + }); + _ctx.t0 = block; + if (_ctx.t0) { + _ctx.next = 10; + break; + } + _ctx.next = 9; + return connection.getRecentBlockhash(commitment); + case 9: + _ctx.t0 = _ctx.sent; + case 10: + transaction.recentBlockhash = _ctx.t0.blockhash; + if (includesFeePayer) { + ; + (_transaction = transaction).setSigners.apply(_transaction, swcHelpers.toConsumableArray(signers.map(function(s) { + return s.publicKey; + }))); + } else { + ; + (_transaction4 = transaction).setSigners.apply(_transaction4, [ + // fee payed by the wallet owner + wallet.publicKey, + ].concat(swcHelpers.toConsumableArray(signers.map(function(s) { + return s.publicKey; + })))); + } + if (signers.length > 0) { + ; + (_transaction5 = transaction).partialSign.apply(_transaction5, swcHelpers.toConsumableArray(signers)); + } + if (includesFeePayer) { + _ctx.next = 17; + break; + } + _ctx.next = 16; + return wallet.signTransaction(transaction); + case 16: + transaction = _ctx.sent; + case 17: + if (beforeSend) { + beforeSend(); + } + _ctx.next = 20; + return sendSignedTransaction({ + connection: connection, + signedTransaction: transaction + }); + case 20: + ref = _ctx.sent; + txid = ref.txid; + slot = ref.slot; + return _ctx.abrupt("return", { + txid: txid, + slot: slot + }); + case 24: + case "end": + return _ctx.stop(); + } + }, _callee); + })); + return function sendTransactionWithRetry(connection, wallet, instructions, signers) { + return _ref.apply(this, arguments); + }; +}(); +export var getUnixTs = function() { + return new Date().getTime() / 1000; +}; +var DEFAULT_TIMEOUT = 15000; +export function sendSignedTransaction(_) { + return _sendSignedTransaction.apply(this, arguments); +} +function _sendSignedTransaction() { + _sendSignedTransaction = swcHelpers.asyncToGenerator(regeneratorRuntime.mark(function _callee1(param) { + var signedTransaction, connection, _timeout, timeout, rawTransaction, startTime, slot, txid, done, confirmation, simulateResult, i, line; + return regeneratorRuntime.wrap(function _callee$(_ctx1) { + while(1)switch(_ctx1.prev = _ctx1.next){ + case 0: + signedTransaction = param.signedTransaction, connection = param.connection, _timeout = param.timeout, timeout = _timeout === void 0 ? DEFAULT_TIMEOUT : _timeout; + rawTransaction = signedTransaction.serialize(); + startTime = getUnixTs(); + slot = 0; + _ctx1.next = 6; + return connection.sendRawTransaction(rawTransaction, { + skipPreflight: true + }); + case 6: + txid = _ctx1.sent; + console.log("Started awaiting confirmation for", txid); + done = false; + swcHelpers.asyncToGenerator(regeneratorRuntime.mark(function _callee() { + return regeneratorRuntime.wrap(function _callee$(_ctx) { + while(1)switch(_ctx.prev = _ctx.next){ + case 0: + if (!(!done && getUnixTs() - startTime < timeout)) { + _ctx.next = 6; + break; + } + connection.sendRawTransaction(rawTransaction, { + skipPreflight: true + }); + _ctx.next = 4; + return sleep(500); + case 4: + _ctx.next = 0; + break; + case 6: + case "end": + return _ctx.stop(); + } + }, _callee); + }))(); + _ctx1.prev = 10; + _ctx1.next = 13; + return awaitTransactionSignatureConfirmation(txid, timeout, connection, "recent", true); + case 13: + confirmation = _ctx1.sent; + if (confirmation) { + _ctx1.next = 16; + break; + } + throw new Error("Timed out awaiting confirmation on transaction"); + case 16: + if (!confirmation.err) { + _ctx1.next = 19; + break; + } + console.error(confirmation.err); + throw new Error("Transaction failed: Custom instruction error"); + case 19: + slot = (confirmation === null || confirmation === void 0 ? void 0 : confirmation.slot) || 0; + _ctx1.next = 47; + break; + case 22: + _ctx1.prev = 22; + _ctx1.t0 = _ctx1["catch"](10); + console.error("Timeout Error caught", _ctx1.t0); + if (!_ctx1.t0.timeout) { + _ctx1.next = 27; + break; + } + throw new Error("Timed out awaiting confirmation on transaction"); + case 27: + simulateResult = null; + _ctx1.prev = 28; + _ctx1.next = 31; + return simulateTransaction(connection, signedTransaction, "single"); + case 31: + simulateResult = _ctx1.sent.value; + _ctx1.next = 36; + break; + case 34: + _ctx1.prev = 34; + _ctx1.t1 = _ctx1["catch"](28); + case 36: + if (!(simulateResult && simulateResult.err)) { + _ctx1.next = 47; + break; + } + if (!simulateResult.logs) { + _ctx1.next = 46; + break; + } + i = simulateResult.logs.length - 1; + case 39: + if (!(i >= 0)) { + _ctx1.next = 46; + break; + } + line = simulateResult.logs[i]; + if (!line.startsWith("Program log: ")) { + _ctx1.next = 43; + break; + } + throw new Error("Transaction failed: " + line.slice("Program log: ".length)); + case 43: + --i; + _ctx1.next = 39; + break; + case 46: + throw new Error(JSON.stringify(simulateResult.err)); + case 47: + _ctx1.prev = 47; + done = true; + return _ctx1.finish(47); + case 50: + console.log("Latency", txid, getUnixTs() - startTime); + return _ctx1.abrupt("return", { + txid: txid, + slot: slot + }); + case 52: + case "end": + return _ctx1.stop(); + } + }, _callee1, null, [ + [ + 10, + 22, + 47, + 50 + ], + [ + 28, + 34 + ] + ]); + })); + return _sendSignedTransaction.apply(this, arguments); +} +function simulateTransaction(connection, transaction, commitment) { + return _simulateTransaction.apply(this, arguments); +} +function _simulateTransaction() { + _simulateTransaction = swcHelpers.asyncToGenerator(regeneratorRuntime.mark(function _callee(connection, transaction, commitment) { + var signData, wireTransaction, encodedTransaction, config, args, res; + return regeneratorRuntime.wrap(function _callee$(_ctx) { + while(1)switch(_ctx.prev = _ctx.next){ + case 0: + _ctx.next = 2; + return connection._recentBlockhash(// @ts-ignore + connection._disableBlockhashCaching); + case 2: + // @ts-ignore + transaction.recentBlockhash = _ctx.sent; + signData = transaction.serializeMessage(); + wireTransaction = transaction._serialize(signData); + encodedTransaction = wireTransaction.toString("base64"); + config = { + encoding: "base64", + commitment: commitment + }; + args = [ + encodedTransaction, + config + ]; + _ctx.next = 10; + return connection._rpcRequest("simulateTransaction", args); + case 10: + res = _ctx.sent; + if (!res.error) { + _ctx.next = 13; + break; + } + throw new Error("failed to simulate transaction: " + res.error.message); + case 13: + return _ctx.abrupt("return", res.result); + case 14: + case "end": + return _ctx.stop(); + } + }, _callee); + })); + return _simulateTransaction.apply(this, arguments); +} +function awaitTransactionSignatureConfirmation(txid, timeout, connection) { + return _awaitTransactionSignatureConfirmation.apply(this, arguments); +} +function _awaitTransactionSignatureConfirmation() { + _awaitTransactionSignatureConfirmation = swcHelpers.asyncToGenerator(regeneratorRuntime.mark(function _callee2(txid, timeout, connection) { + var commitment, queryStatus, done, status, subId, _args = arguments; + return regeneratorRuntime.wrap(function _callee$(_ctx2) { + while(1)switch(_ctx2.prev = _ctx2.next){ + case 0: + commitment = _args.length > 3 && _args[3] !== void 0 ? _args[3] : "recent", queryStatus = _args.length > 4 && _args[4] !== void 0 ? _args[4] : false; + done = false; + status = { + slot: 0, + confirmations: 0, + err: null + }; + subId = 0; + _ctx2.next = 6; + return new Promise(function() { + var _ref = swcHelpers.asyncToGenerator(regeneratorRuntime.mark(function _callee3(resolve, reject) { + return regeneratorRuntime.wrap(function _callee$(_ctx3) { + while(1)switch(_ctx3.prev = _ctx3.next){ + case 0: + setTimeout(function() { + if (done) { + return; + } + done = true; + console.log("Rejecting for timeout..."); + reject({ + timeout: true + }); + }, timeout); + try { + subId = connection.onSignature(txid, function(result, context) { + done = true; + status = { + err: result.err, + slot: context.slot, + confirmations: 0 + }; + if (result.err) { + console.log("Rejected via websocket", result.err); + reject(status); + } else { + console.log("Resolved via websocket", result); + resolve(status); + } + }, commitment); + } catch (e) { + done = true; + console.error("WS error in setup", txid, e); + } + case 2: + if (!(!done && queryStatus)) { + _ctx3.next = 8; + break; + } + // eslint-disable-next-line no-loop-func + swcHelpers.asyncToGenerator(regeneratorRuntime.mark(function _callee() { + var signatureStatuses; + return regeneratorRuntime.wrap(function _callee$(_ctx) { + while(1)switch(_ctx.prev = _ctx.next){ + case 0: + _ctx.prev = 0; + _ctx.next = 3; + return connection.getSignatureStatuses([ + txid + ]); + case 3: + signatureStatuses = _ctx.sent; + status = signatureStatuses && signatureStatuses.value[0]; + if (!done) { + if (!status) { + console.log("REST null result for", txid, status); + } else if (status.err) { + console.log("REST error for", txid, status); + done = true; + reject(status.err); + } else if (!status.confirmations) { + console.log("REST no confirmations for", txid, status); + } else { + console.log("REST confirmation for", txid, status); + done = true; + resolve(status); + } + } + _ctx.next = 11; + break; + case 8: + _ctx.prev = 8; + _ctx.t0 = _ctx["catch"](0); + if (!done) { + console.log("REST connection error: txid", txid, _ctx.t0); + } + case 11: + case "end": + return _ctx.stop(); + } + }, _callee, null, [ + [ + 0, + 8 + ] + ]); + }))(); + _ctx3.next = 6; + return sleep(2000); + case 6: + _ctx3.next = 2; + break; + case 8: + case "end": + return _ctx3.stop(); + } + }, _callee3); + })); + return function(resolve, reject) { + return _ref.apply(this, arguments); + }; + }()); + case 6: + status = _ctx2.sent; + //@ts-ignore + if (connection._signatureSubscriptions[subId]) connection.removeSignatureListener(subId); + done = true; + console.log("Returning status", status); + return _ctx2.abrupt("return", status); + case 11: + case "end": + return _ctx2.stop(); + } + }, _callee2); + })); + return _awaitTransactionSignatureConfirmation.apply(this, arguments); +} +export function sleep(ms) { + return new Promise(function(resolve) { + return setTimeout(resolve, ms); + }); +} diff --git a/crates/swc/tests/vercel/full/next-31419/1/output/index.js b/crates/swc/tests/vercel/full/next-31419/1/output/index.js index e136c2c8faa..f8f96837fd8 100644 --- a/crates/swc/tests/vercel/full/next-31419/1/output/index.js +++ b/crates/swc/tests/vercel/full/next-31419/1/output/index.js @@ -2,19 +2,23 @@ import * as a from "@swc/helpers"; import b from "regenerator-runtime"; Promise.all(assignAll).then(function() { var c = a.asyncToGenerator(b.mark(function a(c) { - var d, e, f; + var d, e, f, g; return b.wrap(function(a) { for(;;)switch(a.prev = a.next){ case 0: - for(f in d = function(f) { - var a = obj[f]; - e += "'".concat(a.id, "', "); - var c = yield listOfUser(a.id); - c.forEach(function(b) { - insertQuery += 'INSERT INTO "TABLE"("UUID", id, other_ids_here) VALUES (\''.concat(uuidv4(), "', '").concat(a.id, "', now());"); - }); - }, e = 'DELETE FROM "TABLE" WHERE "UUID" IN ( ', obj)d(f); - case 3: + d = 'DELETE FROM "TABLE" WHERE "UUID" IN ( ', a.t0 = regeneratorRuntime.keys(obj); + case 2: + if ((a.t1 = a.t0()).done) { + a.next = 12; + break; + } + return f = obj[e = a.t1.value], d += "'".concat(f.id, "', "), a.next = 8, listOfUser(f.id); + case 8: + (g = a.sent).forEach(function(a) { + insertQuery += 'INSERT INTO "TABLE"("UUID", id, other_ids_here) VALUES (\''.concat(uuidv4(), "', '").concat(f.id, "', now());"); + }), a.next = 2; + break; + case 12: case "end": return a.stop(); } diff --git a/crates/swc_ecma_transforms_compat/src/es2015/block_scoping/mod.rs b/crates/swc_ecma_transforms_compat/src/es2015/block_scoping/mod.rs index bde94a6c282..94454d68622 100644 --- a/crates/swc_ecma_transforms_compat/src/es2015/block_scoping/mod.rs +++ b/crates/swc_ecma_transforms_compat/src/es2015/block_scoping/mod.rs @@ -126,6 +126,16 @@ impl BlockScoping { return; } } + { + // This is a hack. + // We need to revisit this + let mut v = YieldFinder { found: false }; + body_stmt.visit_with(&mut v); + if v.found { + self.scope.pop(); + return; + } + } // if let Some(ScopeKind::ForLetLoop { @@ -1016,3 +1026,22 @@ impl Visit for FunctionFinder { /// https://github.com/swc-project/swc/issues/2622 fn visit_while_stmt(&mut self, _: &WhileStmt) {} } + +#[derive(Debug)] +struct YieldFinder { + found: bool, +} + +impl Visit for YieldFinder { + noop_visit_type!(); + + fn visit_arrow_expr(&mut self, _: &ArrowExpr) {} + + fn visit_constructor(&mut self, _: &Constructor) {} + + fn visit_function(&mut self, _: &Function) {} + + fn visit_yield_expr(&mut self, _: &YieldExpr) { + self.found = true; + } +}