Skip to content

Commit

Permalink
📦️ update typescript-eslint (#3192)
Browse files Browse the repository at this point in the history
* 📦️ update typescript-eslint and adjust config

We still use the ("legacy setup")[1] on purpose: we'll upgrade to a flat
config in a separate PR, when we upgrade ESLint.

[1]: https://typescript-eslint.io/getting-started/legacy-eslint-setup

Rule changes:

* @typescript-eslint/ban-types have been split in multiple rules, most
  of them are enabled by default. The configuration we used has been
  ported to @typescript-eslint/no-restricted-types

* no-throw-literal isn't needed anymore as the new rule
  @typescript-eslint/only-throw-error is covering the same thing and
  more.

* @typescript-eslint/no-var-requires was replaced with
  @typescript-eslint/no-require-imports.

* @typescript-eslint/no-unused-experessions was turned on in the
  recommended rules, but we have a few cases where we avoid using an
  `if` like `foo && bar()` that raise that error, so I disabled the rule
  for now.

* 🚨 fix lint issues related to typescript-eslint update

* The new @typescript-eslint/only-throw-error reports quite a few (valid)
  cases where we don't throw errors. I ignored those as issues as this was
  generally what we wanted.

* Some eslint-disable comments were not needed, so I removed them

* Optional properties and arguments that also accept `undefined` now
  raise an error

* typescript-eslint is also better at finding unused variables in catch
  clauses

* And other minor things...

* Turn on rule no-unused-expressions

* Update developer-extension/src/panel/components/tabs/infosTab.tsx

Co-authored-by: Thomas Lebeau <thomas.lebeau@datadoghq.com>

---------

Co-authored-by: zcy <congyao.zheng@datadoghq.com>
Co-authored-by: Thomas Lebeau <thomas.lebeau@datadoghq.com>
  • Loading branch information
3 people authored Dec 17, 2024
1 parent b9b2592 commit db5520f
Show file tree
Hide file tree
Showing 33 changed files with 139 additions and 99 deletions.
27 changes: 22 additions & 5 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,26 @@ module.exports = {
'./performances/tsconfig.json',
],
sourceType: 'module',

// Without this option, typescript-eslint fails to lint .js files because we don't use
// `allowJs: true` in the TypeScript configuration. Same issue as
// https://github.com/typescript-eslint/typescript-eslint/issues/9749.
//
// Enabling `allowJs` would be a better solution, but right now it's not possible because of a
// pretty small reason with big implications: `webpack.base.js` includes
// `tsconfig-paths-webpack-plugin`, and this file includes Node.js types via a <reference>
// directive (see https://unpkg.com/browse/tsconfig-paths-webpack-plugin@4.2.0/lib/plugin.d.ts).
//
// Because of this, Node.js types are included in the whole project, and because some of them
// are slightly different from the DOM/Browser types, some annoying typecheck errors are raised.
//
// So, ideally, we should:
// * add `allowJs: true` in the TypeScript configuration
// * have different tsconfig.json configurations for packages and scripts
// * when typechecking, run `tsc` multiple time with each configuration (like we do for the
// developer-extension)
// * then remove this option
disallowAutomaticSingleRunInference: true,
},
plugins: [
'eslint-plugin-import',
Expand Down Expand Up @@ -60,7 +80,6 @@ module.exports = {
'no-return-await': 'error',
'no-sequences': 'error',
'no-template-curly-in-string': 'error',
'no-throw-literal': 'error',
'no-undef-init': 'error',
'no-unreachable': 'error',
'no-useless-concat': 'error',
Expand Down Expand Up @@ -94,14 +113,12 @@ module.exports = {
'ts-check': 'allow-with-description',
},
],
'@typescript-eslint/ban-types': [
'@typescript-eslint/no-restricted-types': [
'error',
{
types: {
/* eslint-disable id-denylist */
Object: { message: 'Avoid using the `Object` type. Did you mean `object`?' },
object: false,
Function: { message: 'Avoid using the `Function` type. Prefer a specific function type, like `() => void`.' },
Boolean: { message: 'Avoid using the `Boolean` type. Did you mean `boolean`?' },
Number: { message: 'Avoid using the `Number` type. Did you mean `number`?' },
String: { message: 'Avoid using the `String` type. Did you mean `string`?' },
Expand Down Expand Up @@ -288,7 +305,7 @@ module.exports = {
node: true,
},
rules: {
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-require-imports': 'off',
},
},
{
Expand Down
2 changes: 1 addition & 1 deletion developer-extension/src/panel/components/panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function Panel() {
const [activeTab, setActiveTab] = useState<string | null>(DEFAULT_PANEL_TAB)
function updateActiveTab(activeTab: string | null) {
setActiveTab(activeTab)
activeTab && datadogRum.startView(activeTab)
datadogRum.startView(activeTab!)
}

return (
Expand Down
2 changes: 1 addition & 1 deletion developer-extension/src/panel/components/tabs/infosTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ function Entry({
}

const handleClearClick = () => {
onChange && onChange(null)
onChange?.(null)
reloadPage()
}

Expand Down
1 change: 1 addition & 0 deletions developer-extension/src/panel/hooks/useSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export function useSettings() {
// If we don't have settings yet, it means that we are still loading them from the storage. Throw
// the promise so it'll be caught by the Suspense boundary.
if (!settings) {
// eslint-disable-next-line @typescript-eslint/only-throw-error
throw storageLoadingPromise
}

Expand Down
1 change: 0 additions & 1 deletion developer-extension/src/panel/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// The default eslint-plugin-import resolver does not support "exports" fields in package.json yet.
// Ignore the error until the default resolver supports it, or we switch to a different resolver.
// https://github.com/import-js/eslint-plugin-import/issues/1810
// eslint-disable-next-line import/no-unresolved
import '@mantine/core/styles.layer.css'

import './global.css'
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
"@types/cors": "2.8.17",
"@types/express": "4.17.21",
"@types/jasmine": "3.10.18",
"@typescript-eslint/eslint-plugin": "7.18.0",
"@typescript-eslint/parser": "7.18.0",
"@typescript-eslint/eslint-plugin": "8.16.0",
"@typescript-eslint/parser": "8.16.0",
"@wdio/browserstack-service": "8.40.6",
"@wdio/cli": "8.40.6",
"@wdio/jasmine-framework": "8.40.6",
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/boot/init.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ describe('defineGlobal', () => {
it('catches the errors thrown by the queued callbacks', () => {
const myError = 'Ooops!'
const onReady = () => {
// eslint-disable-next-line @typescript-eslint/only-throw-error
throw myError
}
const myGlobal: any = {
Expand Down
3 changes: 1 addition & 2 deletions packages/core/src/browser/browser.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export interface WeakRefConstructor {

// Those are native API types that are not official supported by TypeScript yet

// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface CookieStore extends EventTarget {}

export interface CookieStoreEventMap {
Expand All @@ -65,5 +66,3 @@ export type CookieChangeEvent = Event & {
changed: CookieChangeItem[]
deleted: CookieChangeItem[]
}

export interface CookieStore extends EventTarget {}
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ describe('validateAndBuildConfiguration', () => {
it('should catch errors and log them', () => {
const myError = 'Ooops!'
const beforeSend = () => {
// eslint-disable-next-line @typescript-eslint/only-throw-error
throw myError
}
const configuration = validateAndBuildConfiguration({ clientToken, beforeSend })!
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/domain/console/consoleObservable.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ describe('console error observable', () => {
const error = new Error('foo')
;(error as DatadogError).dd_fingerprint = 'my-fingerprint'

// eslint-disable-next-line no-console
console.error(error)

const consoleLog = notifyLog.calls.mostRecent().args[0]
Expand All @@ -129,7 +128,6 @@ describe('console error observable', () => {
const error = new Error('foo')
;(error as any).dd_fingerprint = 2

// eslint-disable-next-line no-console
console.error(error)

const consoleLog = notifyLog.calls.mostRecent().args[0]
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/domain/context/contextManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function createContextManager(customerDataTracker?: CustomerDataTracker)
setContext: (newContext: Context) => {
if (getType(newContext) === 'object') {
context = sanitize(newContext)
customerDataTracker && customerDataTracker.updateCustomerData(context)
customerDataTracker?.updateCustomerData(context)
} else {
contextManager.clearContext()
}
Expand All @@ -26,19 +26,19 @@ export function createContextManager(customerDataTracker?: CustomerDataTracker)

setContextProperty: (key: string, property: any) => {
context[key] = sanitize(property)
customerDataTracker && customerDataTracker.updateCustomerData(context)
customerDataTracker?.updateCustomerData(context)
changeObservable.notify()
},

removeContextProperty: (key: string) => {
delete context[key]
customerDataTracker && customerDataTracker.updateCustomerData(context)
customerDataTracker?.updateCustomerData(context)
changeObservable.notify()
},

clearContext: () => {
context = {}
customerDataTracker && customerDataTracker.resetCustomerData()
customerDataTracker?.resetCustomerData()
changeObservable.notify()
},

Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/domain/error/trackRuntimeError.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ describe('instrumentOnError', () => {
it('should notify unhandled string', (done) => {
const error = 'foo' as any
setTimeout(() => {
// eslint-disable-next-line no-throw-literal
throw error
})
collectAsyncCalls(onErrorSpy, 1, () => {
Expand All @@ -127,7 +126,6 @@ describe('instrumentOnError', () => {
it('should notify unhandled object', (done) => {
const error = { a: 'foo' } as any
setTimeout(() => {
// eslint-disable-next-line no-throw-literal
throw error
})
collectAsyncCalls(onErrorSpy, 1, () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ const EXPIRED_SESSION: SessionState = { isExpired: '1' }

describe('with lock access disabled', () => {
beforeEach(() => {
sessionStoreStrategy.isLockEnabled && pending('lock-access required')
if (sessionStoreStrategy.isLockEnabled) {
pending('lock-access required')
}
})

it('should persist session when process returns a value', () => {
Expand Down Expand Up @@ -99,7 +101,9 @@ const EXPIRED_SESSION: SessionState = { isExpired: '1' }

describe('with lock access enabled', () => {
beforeEach(() => {
!sessionStoreStrategy.isLockEnabled && pending('lock-access not enabled')
if (!sessionStoreStrategy.isLockEnabled) {
pending('lock-access not enabled')
}
})

it('should persist session when process returns a value', () => {
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/domain/session/sessionStoreOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ export function processSessionStoreOperations(
expireSession(processedSession)
} else {
expandSessionState(processedSession)
isLockEnabled ? persistWithLock(processedSession) : persistSession(processedSession)
if (isLockEnabled) {
persistWithLock(processedSession)
} else {
persistSession(processedSession)
}
}
}
if (isLockEnabled) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function selectLocalStorageStrategy(): SessionStoreStrategyType | undefin
const retrievedId = localStorage.getItem(testKey)
localStorage.removeItem(testKey)
return id === retrievedId ? { type: 'LocalStorage' } : undefined
} catch (e) {
} catch {
return undefined
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/tools/catchUserErrors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe('catchUserErrors', () => {
const displaySpy = spyOn(display, 'error')
const myError = 'Ooops!'
const wrappedFn = catchUserErrors(() => {
// eslint-disable-next-line @typescript-eslint/only-throw-error
throw myError
}, 'Error during callback')
expect(wrappedFn()).toBe(undefined)
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/tools/experimentalFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export enum ExperimentalFeature {

const enabledExperimentalFeatures: Set<ExperimentalFeature> = new Set()

export function initFeatureFlags(enableExperimentalFeatures?: string[] | undefined) {
export function initFeatureFlags(enableExperimentalFeatures: string[] | undefined) {
if (Array.isArray(enableExperimentalFeatures)) {
addExperimentalFeatures(
enableExperimentalFeatures.filter((flag): flag is ExperimentalFeature =>
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/tools/monitor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ describe('monitor', () => {

@monitored
monitoredStringErrorThrowing() {
// eslint-disable-next-line no-throw-literal
// eslint-disable-next-line @typescript-eslint/only-throw-error
throw 'string error'
}

@monitored
monitoredObjectErrorThrowing() {
// eslint-disable-next-line no-throw-literal
// eslint-disable-next-line @typescript-eslint/only-throw-error
throw { foo: 'bar' }
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/tools/serialisation/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ export interface Context {

export type ContextValue = string | number | boolean | Context | ContextArray | undefined | null

// eslint-disable-next-line @typescript-eslint/no-empty-interface
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface ContextArray extends Array<ContextValue> {}
2 changes: 1 addition & 1 deletion packages/core/src/tools/serialisation/sanitize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Context, ContextArray, ContextValue } from './context'
import type { ObjectWithToJsonMethod } from './jsonStringify'
import { detachToJsonMethod } from './jsonStringify'

// eslint-disable-next-line @typescript-eslint/ban-types
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
type PrimitivesAndFunctions = string | number | boolean | undefined | null | symbol | bigint | Function
type ExtendedContextValue = PrimitivesAndFunctions | object | ExtendedContext | ExtendedContextArray
type ExtendedContext = { [key: string]: ExtendedContextValue }
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/tools/stackTrace/handlingStack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function createHandlingStack(): string {
if (!error.stack) {
try {
throw error
} catch (e) {
} catch {
noop()
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/tools/utils/responseUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export function isServerError(status: number) {
export function tryToClone(response: Response): Response | undefined {
try {
return response.clone()
} catch (e) {
} catch {
// clone can throw if the response has already been used by another instrumentation or is disturbed
return
}
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/transport/httpRequest.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe('httpRequest', () => {
}
let notQueuedFetch: Promise<never>
interceptor.withFetch(() => {
notQueuedFetch = Promise.reject()
notQueuedFetch = Promise.reject(new Error())
return notQueuedFetch
})

Expand Down Expand Up @@ -118,7 +118,7 @@ describe('httpRequest', () => {
pending('no fetch keepalive support')
}

interceptor.withFetch(() => Promise.reject())
interceptor.withFetch(() => Promise.reject(new Error()))
interceptor.withMockXhr((xhr) => {
setTimeout(() => {
xhr.complete(429)
Expand Down
4 changes: 2 additions & 2 deletions packages/logs/src/boot/logsPublicApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ describe('logs entry', () => {
(
logsMessage: LogsMessage,
logger: Logger,
commonContext?: CommonContext | undefined,
date?: TimeStamp | undefined
commonContext: CommonContext | undefined,
date: TimeStamp | undefined
) => void
>
let startLogs: jasmine.Spy<StartLogs>
Expand Down
2 changes: 1 addition & 1 deletion packages/logs/src/boot/logsPublicApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export interface LogsPublicApi extends PublicApi {
*
* See [Access internal context](https://docs.datadoghq.com/logs/log_collection/javascript/#access-internal-context) for further information.
*/
getInternalContext: (startTime?: number | undefined) => InternalContext | undefined
getInternalContext: (startTime?: number) => InternalContext | undefined

/**
* Set user information to all events, stored in `@usr`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ describe('runtime error collection', () => {
error.cause = nestedError
;({ stop: stopRuntimeErrorCollection } = startRuntimeErrorCollection(configuration, lifeCycle))
setTimeout(() => {
// eslint-disable-next-line @typescript-eslint/only-throw-error
throw error
})

Expand Down
4 changes: 4 additions & 0 deletions packages/rum-core/src/browser/htmlDomUtils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ describe('isTextNode', () => {
]

parameters.forEach(([element, result]) => {
// eslint-disable-next-line @typescript-eslint/no-base-to-string
it(`should return ${String(result)} for "${String(element)}"`, () => {
expect(isTextNode(element)).toBe(result)
})
Expand All @@ -37,6 +38,7 @@ describe('isCommentNode', () => {
]

parameters.forEach(([element, result]) => {
// eslint-disable-next-line @typescript-eslint/no-base-to-string
it(`should return ${String(result)} for "${String(element)}"`, () => {
expect(isCommentNode(element)).toBe(result)
})
Expand All @@ -53,6 +55,7 @@ describe('isElementNode', () => {
]

parameters.forEach(([element, result]) => {
// eslint-disable-next-line @typescript-eslint/no-base-to-string
it(`should return ${String(result)} for "${String(element)}"`, () => {
expect(isElementNode(element)).toBe(result)
})
Expand Down Expand Up @@ -119,6 +122,7 @@ if (!isIE()) {
]

parameters.forEach(([element, result]) => {
// eslint-disable-next-line @typescript-eslint/no-base-to-string
it(`should return ${String(result)} for "${String(element)}"`, () => {
expect(isNodeShadowHost(element)).toBe(result)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe('trackInteractionToNextPaint', () => {
setViewEnd = interactionToNextPaintTracking.setViewEnd

registerCleanupTask(() => {
interactionToNextPaintTracking.stop
interactionToNextPaintTracking.stop()
resetExperimentalFeatures()
interactionCountMock.clear()
})
Expand Down
Loading

0 comments on commit db5520f

Please sign in to comment.