UNPKG

dd-trace

Version:

Datadog APM tracing client for JavaScript

62 lines (49 loc) 2.27 kB
'use strict' // Custom transforms registered via InstrumentationMatcher.addTransform(). // // Use this file for transforms that are not yet supported upstream in // @apm-js-collab/code-transformer (Orchestrion) or that cannot land there // for dd-trace-specific reasons. Once a transform is available natively in // the library, replace the custom registration with the built-in option and // remove the entry here. const assert = require('node:assert') const clone = require('../../../../../vendor/dist/rfdc')({ proto: false, circles: false }) const { parse, query } = require('./compiler') module.exports = { waitForAsyncEnd } /** * Injects a wait for `ctx.asyncEndPromise` into a generated `tracePromise` * wrapper's native-Promise fulfillment handler. * * @param {object} _state * @param {import('estree').CallExpression} node * @returns {void} */ function waitForAsyncEnd (_state, node) { const onFulfilled = node.arguments[0] const statements = onFulfilled?.body?.body if (!statements || query(onFulfilled.body, '[id.name=__apm$asyncEndPromise]').length > 0) { return } const returnIndex = statements.findIndex(statement => statement.type === 'ReturnStatement' && statement.argument ) // The generated fulfillment handler always ends in a return; a miss means the // upstream template changed and the caller's try/catch falls back to the // unwrapped source. assert(returnIndex !== -1, 'waitForAsyncEnd: no return statement to wait on') const waitStatements = parse(` function wrapper () { const __apm$asyncEndPromise = __apm$ctx.asyncEndPromise; if (__apm$asyncEndPromise && typeof __apm$asyncEndPromise.then === 'function') { return __apm$asyncEndPromise.then(() => __apm$result, () => __apm$result); } } `).body[0].body.body // Resolve to whatever the fulfillment handler returns (its return argument), // so a subscriber that reassigned `__apm$ctx.result` in `asyncEnd` still wins. const returnArgument = statements[returnIndex].argument const { arguments: onSettled } = waitStatements[1].consequent.body[0].argument onSettled[0].body = clone(returnArgument) onSettled[1].body = clone(returnArgument) statements.splice(returnIndex, 0, ...waitStatements) }