/* a codemod for ensuring RTCPeerConnection is cleaned up in tests. * For each `new RTCPeerConnection` add a * `test.add_cleanup(() => pc.close())` * Only applies in promise_tests if there is no add_cleanup in the * test function body. */ export default function transformer(file, api) { const j = api.jscodeshift; return j(file.source) // find each RTCPeerConnection constructor .find(j.NewExpression, {callee: {type: 'Identifier', name: 'RTCPeerConnection'}}) // check it is inside a promise_test .filter(path => { // iterate parentPath until you find a CallExpression let nextPath = path.parentPath; while (nextPath && nextPath.value.type !== 'CallExpression') { nextPath = nextPath.parentPath; } return nextPath && nextPath.value.callee.name === 'promise_test'; }) // check there is no add_cleanup in the function body .filter(path => { let nextPath = path.parentPath; while (nextPath && nextPath.value.type !== 'CallExpression') { nextPath = nextPath.parentPath; } const body = nextPath.value.arguments[0].body; return j(body).find(j.Identifier, {name: 'add_cleanup'}).length === 0; }) .forEach(path => { // iterate parentPath until you find a CallExpression let nextPath = path.parentPath; while (nextPath && nextPath.value.type !== 'CallExpression') { nextPath = nextPath.parentPath; } const declaration = path.parentPath.parentPath.parentPath; const pc = path.parentPath.value.id; declaration.insertAfter( j.expressionStatement( j.callExpression( j.memberExpression( nextPath.node.arguments[0].params[0], j.identifier('add_cleanup') ), [j.arrowFunctionExpression([], j.callExpression( j.memberExpression(pc, j.identifier('close'), false), [] ) )] ) ) ); }) .toSource(); };