Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 42 additions & 15 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,37 @@ const GLOBAL_RESTRICTED_REQUIRES = [
},
]

const SRC_RESTRICTED_SYNTAX = [
{
// Inline `.evaluate(<fn>)` callbacks (Playwright/Puppeteer) are serialized with
// `toString()` and run in chromium — coverage counters inside would ReferenceError.
selector:
"CallExpression[callee.property.name='evaluate']" +
":matches([arguments.0.type='ArrowFunctionExpression'], [arguments.0.type='FunctionExpression'])",
message:
'Move the inline `.evaluate(...)` callback into a `*-browser-scripts.js` file ' +
'(NYC-excluded in nyc.config.js) and import it here.',
},
{
// Static-analysis bundlers (esbuild, webpack, rollup) only see literals as require
// arguments; once any transform (e.g. NYC) wraps them, this shape breaks bundling.
selector: "CallExpression[callee.name='require'][arguments.0.type='ConditionalExpression']",
message: 'Use `cond ? require(\'a\') : require(\'b\')` instead of `require(cond ? \'a\' : \'b\')`.',
},
]

// Matches only probe positions; a genuine count (`writeMapPrefix(Object.keys(x).length)`) must stay allowed.
const OBJECT_KEYS_LENGTH_PROBE = {
selector:
':matches(BinaryExpression[right.value=0], BinaryExpression[left.value=0], UnaryExpression[operator="!"],' +
' IfStatement, ConditionalExpression, LogicalExpression, WhileStatement, DoWhileStatement)' +
" > MemberExpression[property.name='length']" +
" > CallExpression[callee.object.name='Object'][callee.property.name='keys']",
message: 'Do not probe emptiness with `Object.keys(obj).length`; the keys array is allocated on every call. ' +
'Track presence with a boolean at the assignment site, probe a known key (`obj.field !== undefined`), or ' +
'return `undefined` when there is nothing to report instead of an empty object.',
Comment thread
BridgeAR marked this conversation as resolved.
}

export default [
{
name: 'dd-trace/global-ignore',
Expand Down Expand Up @@ -643,21 +674,7 @@ export default [
'eslint-rules/eslint-prefer-set-service-name': 'error',
'eslint-rules/eslint-timer-unref': 'error',

'no-restricted-syntax': ['error', {
// Inline `.evaluate(<fn>)` callbacks (Playwright/Puppeteer) are serialized with
// `toString()` and run in chromium — coverage counters inside would ReferenceError.
selector:
"CallExpression[callee.property.name='evaluate']" +
":matches([arguments.0.type='ArrowFunctionExpression'], [arguments.0.type='FunctionExpression'])",
message:
'Move the inline `.evaluate(...)` callback into a `*-browser-scripts.js` file ' +
'(NYC-excluded in nyc.config.js) and import it here.',
}, {
// Static-analysis bundlers (esbuild, webpack, rollup) only see literals as require
// arguments; once any transform (e.g. NYC) wraps them, this shape breaks bundling.
selector: "CallExpression[callee.name='require'][arguments.0.type='ConditionalExpression']",
message: 'Use `cond ? require(\'a\') : require(\'b\')` instead of `require(cond ? \'a\' : \'b\')`.',
}],
'no-restricted-syntax': ['error', ...SRC_RESTRICTED_SYNTAX],

'n/no-restricted-require': ['error', [
...GLOBAL_RESTRICTED_REQUIRES,
Expand Down Expand Up @@ -793,6 +810,16 @@ export default [
'unicorn/prefer-optional-catch-binding': 'error',
},
},
{
name: 'dd-trace/packages/src',
files: [
'packages/*/src/**/*.js',
'packages/*/src/**/*.mjs',
],
rules: {
'no-restricted-syntax': ['error', ...SRC_RESTRICTED_SYNTAX, OBJECT_KEYS_LENGTH_PROBE],
},
},
{
name: 'dd-trace/config-sync',
files: [
Expand Down
14 changes: 4 additions & 10 deletions packages/datadog-instrumentations/src/cucumber.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ let pickleByFile = {}
const pickleResultByFile = {}

let skippableSuites = []
let skippableSuitesCoverage = {}
let skippableSuitesCoverage
let skippedSuitesCoverage = {}
let itrCorrelationId = ''
let isForcedToRun = false
Expand Down Expand Up @@ -153,12 +153,6 @@ function isValidKnownTests (receivedKnownTests) {
return !!receivedKnownTests.cucumber
}

function hasSkippableSuitesCoverage () {
return skippableSuitesCoverage &&
typeof skippableSuitesCoverage === 'object' &&
Object.keys(skippableSuitesCoverage).length > 0
}

function isTiaCoverageBackfillEnabled () {
return isItrEnabled && isCoverageReportUploadEnabled
}
Expand All @@ -172,7 +166,7 @@ function shouldReportCodeCoverageLinesPct (hasBackfilledCoverage) {
}

function getSkippedSuitesCoverageForRun () {
return isSuitesSkipped && isTiaCoverageBackfillEnabled() && hasSkippableSuitesCoverage()
return isSuitesSkipped && isTiaCoverageBackfillEnabled() && skippableSuitesCoverage !== undefined
? skippableSuitesCoverage
: {}
}
Expand All @@ -188,7 +182,7 @@ function getCucumberTestSessionCoverageFiles () {

function resetSuiteSkippingRunState () {
skippableSuites = []
skippableSuitesCoverage = {}
skippableSuitesCoverage = undefined
skippedSuitesCoverage = {}
skippedSuites = []
isSuitesSkipped = false
Expand Down Expand Up @@ -1143,7 +1137,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin

errorSkippableRequest = skippableResponse.err
skippableSuites = skippableResponse.skippableSuites ?? []
skippableSuitesCoverage = skippableResponse.skippableSuitesCoverage ?? {}
skippableSuitesCoverage = skippableResponse.skippableSuitesCoverage

if (!errorSkippableRequest) {
const filteredPickles = isCoordinator
Expand Down
2 changes: 2 additions & 0 deletions packages/datadog-instrumentations/src/fastify.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ function wrapHookDone (ctx, request, reply, req, name, doneCallback) {
ctx.error = error
publishError(ctx)

// eslint-disable-next-line no-restricted-syntax -- arbitrary cookie names; publishing {} sets a WAF address
const hasCookies = request.cookies && Object.keys(request.cookies).length > 0

if (cookieParserReadCh.hasSubscribers && hasCookies && !cookiesPublished.has(req)) {
Expand Down Expand Up @@ -193,6 +194,7 @@ function preHandler (request, reply, done) {
const res = getRes(reply)
const ctx = { req, res }

// eslint-disable-next-line no-restricted-syntax -- arbitrary body keys; publishing {} sets a WAF address
const hasBody = request.body && Object.keys(request.body).length > 0

// For multipart/form-data, the body is not available until after preValidation hook
Expand Down
24 changes: 9 additions & 15 deletions packages/datadog-instrumentations/src/jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ const jestSessionState = (globalThis[JEST_SESSION_STATE] ||= {})
const RETRY_TIMES = Symbol.for('RETRY_TIMES')

let skippableSuites = []
let skippableSuitesCoverage = {}
let skippableSuitesCoverage
let skippedSuitesCoverage = {}
let knownTests = {}
let isCodeCoverageEnabled = false
Expand All @@ -133,7 +133,7 @@ let isTestManagementTestsEnabled = false
let testManagementTests = {}
let testManagementAttemptToFixRetries = 0
let isImpactedTestsEnabled = false
let modifiedFiles = {}
let modifiedFiles
let repositoryRoot
let lastCoverageMap
let lastCoverageMapRootDir
Expand Down Expand Up @@ -690,8 +690,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {

if (this.isImpactedTestsEnabled) {
try {
const hasImpactedTests = Object.keys(modifiedFiles).length > 0
this.modifiedFiles = hasImpactedTests ? modifiedFiles : this.testEnvironmentOptions._ddModifiedFiles
this.modifiedFiles = modifiedFiles ?? this.testEnvironmentOptions._ddModifiedFiles
} catch (e) {
log.error('Error parsing impacted tests', e)
this.isImpactedTestsEnabled = false
Expand Down Expand Up @@ -2491,12 +2490,6 @@ function getRepositoryRootFromTest (test, fallbackRootDir) {
return getRepositoryRootFromConfig(test?.context?.config, fallbackRootDir)
}

function hasSkippableSuitesCoverage () {
return skippableSuitesCoverage &&
typeof skippableSuitesCoverage === 'object' &&
Object.keys(skippableSuitesCoverage).length > 0
}

function shouldCollectJestCoverageForTia () {
return shouldReportJestSuiteCoverageForTia() ||
(isJestCoverageBackfillSupported && isItrEnabled && isCoverageReportUploadEnabled)
Expand Down Expand Up @@ -2607,7 +2600,7 @@ function resetLibraryConfiguration () {
testManagementTests = {}
testManagementAttemptToFixRetries = 0
isImpactedTestsEnabled = false
modifiedFiles = {}
modifiedFiles = undefined
repositoryRoot = undefined
}

Expand All @@ -2629,13 +2622,14 @@ function applySuiteSkipping (originalTests, rootDir, frameworkVersion) {

isSuitesSkipped ||= jestSuitesToRun.suitesToRun.length !== originalTests.length
numSkippedSuites += jestSuitesToRun.skippedSuites.length
skippedSuitesCoverage = isSuitesSkipped && isTiaCoverageBackfillEnabled() && hasSkippableSuitesCoverage()
const hasSkippableSuitesCoverage = skippableSuitesCoverage !== undefined
skippedSuitesCoverage = isSuitesSkipped && isTiaCoverageBackfillEnabled() && hasSkippableSuitesCoverage
? skippableSuitesCoverage
: {}
coverageBackfillContexts = isSuitesSkipped && isTiaCoverageBackfillEnabled()
? getTestContexts(originalTests)
: undefined
coverageBackfillFiles = isSuitesSkipped && isTiaCoverageBackfillEnabled() && hasSkippableSuitesCoverage()
coverageBackfillFiles = isSuitesSkipped && isTiaCoverageBackfillEnabled() && hasSkippableSuitesCoverage
? getCoverageBackfillFiles(skippableSuitesCoverage, repositoryRoot, getTestSuitePath)
: undefined

Expand Down Expand Up @@ -3024,10 +3018,10 @@ function getCliWrapper (isNewJestVersion) {
skippableSuitesCoverage: receivedSkippableSuitesCoverage,
} = skippableSuitesResponse || await getChannelPromise(skippableSuitesCh)
if (err) {
skippableSuitesCoverage = {}
skippableSuitesCoverage = undefined
} else {
skippableSuites = receivedSkippableSuites
skippableSuitesCoverage = receivedSkippableSuitesCoverage || {}
skippableSuitesCoverage = receivedSkippableSuitesCoverage
}
skippedSuitesCoverage = {}
} catch (err) {
Expand Down
16 changes: 5 additions & 11 deletions packages/datadog-instrumentations/src/mocha/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ let suitesToSkip = []
let isSuitesSkipped = false
let areAllSuitesSkipped = false
let skippedSuites = []
let skippableSuitesCoverage = {}
let skippableSuitesCoverage
let skippedSuitesCoverage = {}
let itrCorrelationId = ''
let isForcedToRun = false
Expand Down Expand Up @@ -203,12 +203,6 @@ function getFilteredSuites (originalSuites) {
}, { suitesToRun: [], skippedSuites: new Set(), suitesToSkipForRun })
}

function hasSkippableSuitesCoverage () {
return skippableSuitesCoverage &&
typeof skippableSuitesCoverage === 'object' &&
Object.keys(skippableSuitesCoverage).length > 0
}

function isTiaCoverageBackfillEnabled () {
return config.isItrEnabled && config.isCoverageReportUploadEnabled
}
Expand Down Expand Up @@ -239,7 +233,7 @@ function shouldReportCodeCoverageLinesPct (hasBackfilledCoverage) {
}

function getSkippedSuitesCoverageForRun () {
return isSuitesSkipped && isTiaCoverageBackfillEnabled() && hasSkippableSuitesCoverage()
return isSuitesSkipped && isTiaCoverageBackfillEnabled() && skippableSuitesCoverage !== undefined
? skippableSuitesCoverage
: {}
}
Expand All @@ -257,7 +251,7 @@ function resetSuiteSkippingRunState () {
isSuitesSkipped = false
areAllSuitesSkipped = false
skippedSuites = []
skippableSuitesCoverage = {}
skippableSuitesCoverage = undefined
skippedSuitesCoverage = {}
untestedCoverage = undefined
config.repositoryRoot = undefined
Expand Down Expand Up @@ -927,11 +921,11 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
} = response || {}
if (!response || err) {
suitesToSkip = []
skippableSuitesCoverage = {}
skippableSuitesCoverage = undefined
} else {
suitesToSkip = skippableSuites
itrCorrelationId = responseItrCorrelationId
skippableSuitesCoverage = responseSkippableSuitesCoverage || {}
skippableSuitesCoverage = responseSkippableSuitesCoverage
}
if (localSuites) {
suitesToSkip = getSuitesToSkipFromPaths(localSuites)
Expand Down
2 changes: 2 additions & 0 deletions packages/datadog-instrumentations/src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ const visitedParams = new WeakSet()
function wrapHandleRequest (original) {
return function wrappedHandleRequest (...args) {
const req = args[0]
// eslint-disable-next-line no-restricted-syntax -- arbitrary param names; publishing {} sets a WAF address
if (routerParamStartCh.hasSubscribers && !visitedParams.has(req.params) && Object.keys(req.params).length) {
visitedParams.add(req.params)

Expand Down Expand Up @@ -635,6 +636,7 @@ function wrapParam (original) {
args[1] = shimmer.wrapFunction(args[1], (originalFn) => {
return function wrappedFn (...fnArgs) {
const req = fnArgs[0]
// eslint-disable-next-line no-restricted-syntax -- arbitrary param names; publishing {} sets a WAF address
if (routerParamStartCh.hasSubscribers && Object.keys(req.params).length && !visitedParams.has(req.params)) {
visitedParams.add(req.params)

Expand Down
2 changes: 1 addition & 1 deletion packages/datadog-plugin-azure-functions/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ function setSpanLinks (triggerType, tracer, span, ctx) {
: triggerMetadata.propertiesArray

const addLinkFromProperties = (props) => {
if (!props || Object.keys(props).length === 0) return
if (!props) return
const spanContext = tracer.extract('text_map', props)
if (spanContext) {
span.addLink({ context: spanContext })
Expand Down
19 changes: 4 additions & 15 deletions packages/datadog-plugin-cypress/src/cypress-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ class CypressPlugin {
testsToSkip = []
skippedTests = []
skippedTestIds = new Set()
skippableTestsCoverage = {}
skippableTestsCoverage
testSessionCoverageMap = createCoverageMap()
hasForcedToRunSuites = false
hasUnskippableSuites = false
Expand Down Expand Up @@ -566,7 +566,7 @@ class CypressPlugin {
this.testsToSkip = []
this.skippedTests = []
this.skippedTestIds = new Set()
this.skippableTestsCoverage = {}
this.skippableTestsCoverage = undefined
this.testSessionCoverageMap = createCoverageMap()
this.hasForcedToRunSuites = false
this.hasUnskippableSuites = false
Expand Down Expand Up @@ -679,17 +679,6 @@ class CypressPlugin {
return this.repositoryRoot || this.rootDir || process.cwd()
}

/**
* Returns whether the backend supplied skipped-test coverage data.
*
* @returns {boolean}
*/
hasSkippableTestsCoverage () {
return !!(this.skippableTestsCoverage &&
typeof this.skippableTestsCoverage === 'object' &&
Object.keys(this.skippableTestsCoverage).length > 0)
}

/**
* Returns whether skipped test coverage should be backfilled into the session coverage map.
*
Expand All @@ -699,7 +688,7 @@ class CypressPlugin {
return this.isItrEnabled &&
this.isCoverageReportUploadEnabled &&
this.isTestsSkipped &&
this.hasSkippableTestsCoverage()
this.skippableTestsCoverage !== undefined
}

/**
Expand Down Expand Up @@ -1162,7 +1151,7 @@ class CypressPlugin {
} else {
const { skippableTests, correlationId, skippableTestsCoverage } = skippableTestsResponse
this.testsToSkip = skippableTests || []
this.skippableTestsCoverage = skippableTestsCoverage || {}
this.skippableTestsCoverage = skippableTestsCoverage
this.itrCorrelationId = correlationId
incrementCountMetric(TELEMETRY_ITR_SKIPPED, { testLevel: 'test' }, this.testsToSkip.length)
}
Expand Down
1 change: 1 addition & 0 deletions packages/datadog-plugin-openai-agents/src/integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ class OpenAIAgentsIntegration {

this.#tagger.tagTextIO(ddSpan, inputValue, outputValue)

// eslint-disable-next-line no-restricted-syntax -- agents-core builds metadata before the plugin receives it
if (info.metadata && Object.keys(info.metadata).length > 0) {
this.#tagger.tagMetadata(ddSpan, info.metadata)
}
Expand Down
Loading
Loading