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
6 changes: 4 additions & 2 deletions developer-extension/tsconfig.webpack.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

"compilerOptions": {
"baseUrl": ".",
"module": "ES6",
"module": "preserve",
"target": "esnext",
"jsx": "react",
"lib": ["ES2022", "DOM"],
"types": ["chrome", "react", "react-dom", "jasmine"],
"skipLibCheck": true
"skipLibCheck": true,
"allowImportingTsExtensions": true,
"noEmit": true
},

"include": ["src"]
Expand Down
4 changes: 2 additions & 2 deletions eslint-local-rules/disallowEnumExports.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { SymbolFlags } = require('typescript')
import { SymbolFlags } from 'typescript'

/**
* This rule forbids exporting 'enums'. It serves two purposes:
Expand Down Expand Up @@ -34,7 +34,7 @@ const { SymbolFlags } = require('typescript')
* [1]: https://www.typescriptlang.org/tsconfig#isolatedModules
* [2]: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export
*/
module.exports = {
export default {
meta: {
docs: {
description: 'Disallow export of enums.',
Expand Down
4 changes: 2 additions & 2 deletions eslint-local-rules/disallowGenericUtils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const path = require('path')
import path from 'path'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import path from 'path'
import path from 'node:path'


module.exports = {
export default {
meta: {
docs: {
description: 'Disallow the use of too generic utility file names',
Expand Down
2 changes: 1 addition & 1 deletion eslint-local-rules/disallowNonScripts.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
export default {
meta: {
docs: {
description: 'Disallow JS files that are not used as a "script"',
Expand Down
17 changes: 11 additions & 6 deletions eslint-local-rules/disallowProtectedDirectoryImport.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
const path = require('path')
const { minimatch } = require('minimatch')
const resolve = require('eslint-module-utils/resolve').default
const moduleVisitor = require('eslint-module-utils/moduleVisitor').default
const importType = require('eslint-plugin-import/lib/core/importType').default
import path from 'node:path'
import { minimatch } from 'minimatch'

module.exports = {
import resolvePackage from 'eslint-module-utils/resolve.js'
import moduleVisitorPackage from 'eslint-module-utils/moduleVisitor.js'
import importTypePackage from 'eslint-plugin-import/lib/core/importType.js'

const moduleVisitor = moduleVisitorPackage.default
const importType = importTypePackage.default
const resolve = resolvePackage.default
Comment on lines +4 to +10

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 Badge Preserve default exports when importing ESLint helper utilities

The refactor to ESM imports replaces require('…').default with import … from '…'; const fn = imported.default. In ESM, the value bound by import foo from 'pkg' is already the default export; accessing .default again yields undefined when the module exports a function. As a result moduleVisitor, importType, and resolve are undefined and the rule throws as soon as it runs. Import the default directly (import moduleVisitor from 'eslint-module-utils/moduleVisitor.js') or fall back to the object when default is missing.

Useful? React with 👍 / 👎.

Copy link
Collaborator Author

@thomas-lebeau thomas-lebeau Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these modules are weird, we need the default key from the default export 🙄

[Module: null prototype] {
  CASE_SENSITIVE_FS: false,
  __esModule: true,
  default: {
    __esModule: true,
    CASE_SENSITIVE_FS: false,
    fileExistsWithCaseSync: [Function: fileExistsWithCaseSync],
    relative: [Function: relative],
    default: [Function: resolve] { relative: [Function: relative] }
  },
  fileExistsWithCaseSync: [Function: fileExistsWithCaseSync],
  'module.exports': {
    __esModule: true,
    CASE_SENSITIVE_FS: false,
    fileExistsWithCaseSync: [Function: fileExistsWithCaseSync],
    relative: [Function: relative],
    default: [Function: resolve] { relative: [Function: relative] }
  },
  relative: [Function: relative]
}

Comment on lines +4 to +10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ question: ‏Not from this PR, but are we using internals here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems so

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, maybe eslint-plugin-import/lib/core/importType.js is internal :D


export default {
meta: {
docs: {
description:
Expand Down
6 changes: 3 additions & 3 deletions eslint-local-rules/disallowSideEffects.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const path = require('path')
import path from 'path'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import path from 'path'
import path from 'node:path'

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would that work for you if I fix these in a separate PR using import/enforce-node-protocol-usage? there is a lot more than these few instances.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wip: #3943


module.exports = {
export default {
meta: {
docs: {
description:
Expand All @@ -22,7 +22,7 @@ module.exports = {
},
}

const packagesRoot = path.resolve(__dirname, '..', 'packages')
const packagesRoot = path.resolve(import.meta.dirname, '..', 'packages')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge import.meta.dirname usage requires a newer Node than project declares

The rule now resolves packagesRoot via path.resolve(import.meta.dirname, …). import.meta.dirname is only available starting with Node 22; with the current project setup (no engine bump and the repository historically using Node 18/20), this property is undefined, causing the rule to crash when ESLint is loaded. To remain compatible with supported Node versions, compute the directory using fileURLToPath(new URL('.', import.meta.url)) or similar.

Useful? React with 👍 / 👎.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we use node 24


// Those modules are known to have side effects when evaluated
const pathsWithSideEffect = new Set([
Expand Down
2 changes: 1 addition & 1 deletion eslint-local-rules/disallowSpecImport.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
export default {
meta: {
docs: {
description: 'Disallow importing spec file code to avoid to execute the tests from the imported spec file twice',
Expand Down
2 changes: 1 addition & 1 deletion eslint-local-rules/disallowTestImportExportFromSrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
export default {
meta: {
docs: {
description:
Expand Down
2 changes: 1 addition & 1 deletion eslint-local-rules/disallowUrlConstructorPatchValues.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
export default {
meta: {
docs: {
description: 'Disallow problematic URL constructor patched values.',
Expand Down
2 changes: 1 addition & 1 deletion eslint-local-rules/disallowZoneJsPatchedValues.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const PROBLEMATIC_IDENTIFIERS = {
removeEventListener: 'Use `addEventListener().stop` from @datadog/browser-core instead',
}

module.exports = {
export default {
meta: {
docs: {
description: 'Disallow problematic ZoneJs patched values.',
Expand Down
15 changes: 10 additions & 5 deletions eslint-local-rules/enforceProdDepsImports.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
const fs = require('fs')
const moduleVisitor = require('eslint-module-utils/moduleVisitor').default
const importType = require('eslint-plugin-import/lib/core/importType').default
const pkgUp = require('eslint-module-utils/pkgUp').default
import fs from 'node:fs'

import moduleVisitorPackage from 'eslint-module-utils/moduleVisitor.js'
import importTypePackage from 'eslint-plugin-import/lib/core/importType.js'
import pkgUpPackage from 'eslint-module-utils/pkgUp.js'

const moduleVisitor = moduleVisitorPackage.default
const pkgUp = pkgUpPackage.default
const importType = importTypePackage.default
Comment on lines +3 to +9

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 Badge Default import handling breaks ESLint rule initialisation

Similar to the protected-directory rule, these helpers are now imported via import … from … and immediately dereferenced with .default. When eslint-module-utils/eslint-plugin-import are ESM bundles, the default import already returns the function; .default is undefined and the rule fails at runtime (TypeError: pkgUp is not a function). Linting will abort before running. Use the default import directly or guard against missing default.

Useful? React with 👍 / 👎.


// The import/no-extraneous-dependencies rule cannot catch this issue[1] where we imported an
// aliased package in production code, because it resolves[2] the alias to the real package name, and
Expand All @@ -15,7 +20,7 @@ const pkgUp = require('eslint-module-utils/pkgUp').default

const packageJsonCache = new Map()

module.exports = {
export default {
meta: {
docs: {
description: 'Forbids importing non-prod dependencies in prod files',
Expand Down
39 changes: 26 additions & 13 deletions eslint-local-rules/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
import disallowSideEffects from './disallowSideEffects.js'
import disallowEnumExports from './disallowEnumExports.js'
import disallowSpecImport from './disallowSpecImport.js'
import disallowProtectedDirectoryImport from './disallowProtectedDirectoryImport.js'
import disallowTestImportExportFromSrc from './disallowTestImportExportFromSrc.js'
import disallowZoneJsPatchedValues from './disallowZoneJsPatchedValues.js'
import disallowUrlConstructorPatchValues from './disallowUrlConstructorPatchValues.js'
import disallowGenericUtils from './disallowGenericUtils.js'
import disallowNonScripts from './disallowNonScripts.js'
import enforceProdDepsImports from './enforceProdDepsImports.js'
import secureCommandExecution from './secureCommandExecution.js'
import monitorUntilCommentRules from './monitorUntilCommentRules.js'

// Declare the local rules used by the Browser SDK
//
// See https://eslint.org/docs/developer-guide/working-with-rules for documentation on how to write
Expand All @@ -6,17 +19,17 @@
// You can use https://astexplorer.net/ to explore the parsed data structure of a code snippet.
// Choose '@typescript-eslint/parser' as a parser to have the exact same structure as our ESLint
// parser.
module.exports = {
'disallow-side-effects': require('./disallowSideEffects'),
'disallow-enum-exports': require('./disallowEnumExports'),
'disallow-spec-import': require('./disallowSpecImport'),
'disallow-protected-directory-import': require('./disallowProtectedDirectoryImport'),
'disallow-test-import-export-from-src': require('./disallowTestImportExportFromSrc'),
'disallow-zone-js-patched-values': require('./disallowZoneJsPatchedValues'),
'disallow-url-constructor-patched-values': require('./disallowUrlConstructorPatchValues.js'),
'disallow-generic-utils': require('./disallowGenericUtils'),
'disallow-non-scripts': require('./disallowNonScripts'),
'enforce-prod-deps-imports': require('./enforceProdDepsImports.js'),
'secure-command-execution': require('./secureCommandExecution'),
...require('./monitorUntilCommentRules'),
export default {
'disallow-side-effects': disallowSideEffects,
'disallow-enum-exports': disallowEnumExports,
'disallow-spec-import': disallowSpecImport,
'disallow-protected-directory-import': disallowProtectedDirectoryImport,
'disallow-test-import-export-from-src': disallowTestImportExportFromSrc,
'disallow-zone-js-patched-values': disallowZoneJsPatchedValues,
'disallow-url-constructor-patched-values': disallowUrlConstructorPatchValues,
'disallow-generic-utils': disallowGenericUtils,
'disallow-non-scripts': disallowNonScripts,
'enforce-prod-deps-imports': enforceProdDepsImports,
'secure-command-execution': secureCommandExecution,
...monitorUntilCommentRules,
}
2 changes: 1 addition & 1 deletion eslint-local-rules/monitorUntilCommentRules.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const METHODS_TO_CHECK = ['addTelemetryDebug', 'addTelemetryMetrics']
const MONITOR_COMMENT_FORMAT = /^\s*monitor-until: (\d{4}-\d{2}-\d{2}|forever)/

module.exports = {
export default {
'enforce-monitor-until-comment': {
meta: {
docs: {
Expand Down
2 changes: 1 addition & 1 deletion eslint-local-rules/secureCommandExecution.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
export default {
meta: {
docs: {
description: 'Check command execution within nodejs scripts',
Expand Down
6 changes: 3 additions & 3 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ export default tseslint.config(

{
// JS files. Allow weaker typings since TS can't infer types as accurately as TS files.
files: ['**/*.js', '**/*.mjs'],
files: ['**/*.{js,mjs}'],
rules: {
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
Expand Down Expand Up @@ -432,9 +432,9 @@ export default tseslint.config(
},

{
files: ['**/webpack.*.ts'],
files: ['**/webpack.*.{ts,mts}', 'eslint-local-rules/**/*.js'],
rules: {
// Webpack configuration files are expected to use a default export.
// Webpack configuration files and eslint rules files are expected to use a default export.
'import/no-default-export': 'off',
},
},
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
"workspaces": [
"packages/*",
"developer-extension",
"performances"
"performances",
"test/e2e"
],
"type": "module",
"scripts": {
"postinstall": "scripts/cli init_submodule",
"build": "lerna run build --stream",
Expand All @@ -15,7 +17,7 @@
"build:docs:json": "typedoc --logLevel Verbose --json ./docs.json",
"build:docs:html": "typedoc --out ./docs",
"format": "prettier --check .",
"lint": "scripts/cli lint .",
"lint": "NODE_OPTIONS='--max-old-space-size=4096' eslint .",
"typecheck": "tsc -b --noEmit true",
"dev": "node scripts/dev-server.ts",
"release": "scripts/cli release",
Expand Down
File renamed without changes.
File renamed without changes.
5 changes: 0 additions & 5 deletions scripts/cli
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ cmd_typecheck () {
tsc -p "$project_path" --noEmit true
}

cmd_lint () {
local project_path="${1}"
eslint "$project_path"
}

cmd_init_submodule () {
git submodule update --init
}
Expand Down
10 changes: 5 additions & 5 deletions scripts/dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import HtmlWebpackPlugin from 'html-webpack-plugin'
import webpack from 'webpack'
import cors from 'cors'
import webpackBase from '../webpack.base.ts'
import logsConfig from '../packages/logs/webpack.config.ts'
import rumSlimConfig from '../packages/rum-slim/webpack.config.ts'
import rumConfig from '../packages/rum/webpack.config.ts'
import flaggingConfig from '../packages/flagging/webpack.config.ts'
import workerConfig from '../packages/worker/webpack.config.ts'
import logsConfig from '../packages/logs/webpack.config.mts'
import rumSlimConfig from '../packages/rum-slim/webpack.config.mts'
import rumConfig from '../packages/rum/webpack.config.mts'
import flaggingConfig from '../packages/flagging/webpack.config.mts'
import workerConfig from '../packages/worker/webpack.config.mts'
import { printLog, runMain } from './lib/executionUtils.ts'

const sandboxPath = './sandbox'
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/lib/helpers/playwright.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { PlaywrightWorkerOptions } from '@playwright/test'
import type { BrowserConfiguration } from '../../../browsers.conf'
import { getBuildInfos } from '../../../envUtils'
import packageJson from '../../../../package.json'
import { getBuildInfos } from '../../../envUtils.ts'
import packageJson from '../../../../package.json' with { type: 'json' }

export const DEV_SERVER_BASE_URL = 'http://localhost:8080'

Expand Down
3 changes: 3 additions & 0 deletions test/e2e/package.json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ question: ‏I remember seeing an explanation for this in Slack. How can we keep the explanation in the codebase so we don't forget why we need this as private?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test/e2e is not type: module because in some scenario we import some build cjs files (example)

Indeed this is a bit of a hack, but this PR already improve things and we can always review the e2e test to not rely on these cjs file later.

I can't add comment to a package.json file, I guess blaming this file will make this PR (and this comment) visible.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"private": true
}
3 changes: 3 additions & 0 deletions test/e2e/playwright.base.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ export const config: Config = {
use: {
trace: isCi ? 'off' : 'retain-on-failure',
},

webServer: isLocal
? {
stdout: 'pipe',
cwd: path.join(__dirname, '../..'),
command: 'yarn dev',
url: DEV_SERVER_BASE_URL,
reuseExistingServer: true,
Expand Down
5 changes: 3 additions & 2 deletions test/e2e/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
"moduleResolution": "node",
"resolveJsonModule": true,
"target": "ES2022",
"module": "ES2020",
"module": "preserve",
"types": ["node", "ajv"],
"allowJs": true,
"noEmit": true
"noEmit": true,
"allowImportingTsExtensions": true
}
}
4 changes: 0 additions & 4 deletions test/envUtils.d.ts

This file was deleted.

26 changes: 9 additions & 17 deletions test/envUtils.js → test/envUtils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const os = require('os')
import os from 'os'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import os from 'os'
import os from 'node:os'


function getIp() {
return Object.values(os.networkInterfaces())
export function getIp() {
return (Object.values(os.networkInterfaces()) as os.NetworkInterfaceInfo[][])
.flat()
.find(({ family, internal }) => family === 'IPv4' && !internal).address
.find(({ family, internal }) => family === 'IPv4' && !internal)!.address
}

function getBuildInfos() {
export function getBuildInfos() {
const ciInfos = getCIInfos()
if (ciInfos) {
return ciInfos
Expand All @@ -17,8 +17,8 @@ function getBuildInfos() {
}
}

function getRunId() {
return process.env.CI_JOB_ID || process.env.USER
export function getRunId() {
return process.env.CI_JOB_ID || process.env.USER || 'n/a'
}

function getCIInfos() {
Expand All @@ -32,24 +32,16 @@ function getLocalInfos() {
return `${process.env.USER} ${new Date().toLocaleString()}`
}

function getTestReportDirectory() {
export function getTestReportDirectory() {
if (process.env.CI_JOB_NAME) {
return `test-report/${process.env.CI_JOB_NAME}`
}
}

function getCoverageReportDirectory() {
export function getCoverageReportDirectory() {
if (process.env.CI_JOB_NAME) {
return `coverage/${process.env.CI_JOB_NAME}`
}

return 'coverage'
}

module.exports = {
getRunId,
getBuildInfos,
getIp,
getTestReportDirectory,
getCoverageReportDirectory,
}
11 changes: 3 additions & 8 deletions test/unit/browsers.conf.js → test/unit/browsers.conf.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// Capabilities: https://www.browserstack.com/automate/capabilities

/**
* @type {Array<import('../browsers.conf').BrowserConfiguration>}
*/
const browserConfigurations = [
import type { BrowserConfiguration } from '../browsers.conf'

export const browserConfigurations: BrowserConfiguration[] = [
{
sessionName: 'Edge',
name: 'Edge',
Expand Down Expand Up @@ -47,7 +46,3 @@ const browserConfigurations = [
device: 'iPhone 13',
},
]

module.exports = {
browserConfigurations,
}
Loading