Skip to content

chore: convert ESLint files from .js/.mjs to .ts#109310

Merged
JoshuaKGoldberg merged 1 commit intomasterfrom
eslint-plugin-scraps-typed
Mar 2, 2026
Merged

chore: convert ESLint files from .js/.mjs to .ts#109310
JoshuaKGoldberg merged 1 commit intomasterfrom
eslint-plugin-scraps-typed

Conversation

@JoshuaKGoldberg
Copy link
Member

@JoshuaKGoldberg JoshuaKGoldberg commented Feb 25, 2026

Directly changes files from .mjs to .mts. I would have preferred the cleaner .ts but that will require adding "type": "module" to package.json, which is more work (which would be a great followup!). .ts, building on #109319's switching the package to be ESM by default. Imports are now TypeScript-style extension-less ones.

Now that the plugin's files are typed, this applies a few types cleanups:

This PR should have no changes to the lint rules' behavior. The only runtime code changes are for deleting unused parameters.

Fixes https://linear.app/getsentry/issue/ENG-6930/convert-eslint-files-from-jsmjs-to-ts-and-add-types

@github-actions github-actions bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Feb 25, 2026
@JoshuaKGoldberg JoshuaKGoldberg force-pushed the eslint-plugin-scraps-typed branch from 45c26ec to 6dc8082 Compare February 25, 2026 12:54
@JoshuaKGoldberg JoshuaKGoldberg force-pushed the eslint-plugin-scraps-typed branch from 6dc8082 to 21c9406 Compare February 25, 2026 13:12
@JoshuaKGoldberg JoshuaKGoldberg force-pushed the eslint-plugin-scraps-typed branch from 21c9406 to 877d1ae Compare February 25, 2026 13:16
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Feb 25, 2026
@github-actions
Copy link
Contributor

🚨 Warning: This pull request contains Frontend and Backend changes!

It's discouraged to make changes to Sentry's Frontend and Backend in a single pull request. The Frontend and Backend are not atomically deployed. If the changes are interdependent of each other, they must be separated into two pull requests and be made forward or backwards compatible, such that the Backend or Frontend can be safely deployed independently.

Have questions? Please ask in the #discuss-dev-infra channel.

meta: {
type: 'problem',
docs: {
description: `Disallow imports from "${FORBIDDEN_PATH}" and autofix to "${REPLACEMENT_PATH}".`,
recommended: true,
Copy link
Member Author

Choose a reason for hiding this comment

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

This was typescript-eslint/typescript-eslint#8695 -> typescript-eslint/typescript-eslint#9025. The only "required" field for meta.docs is description, and arguably even that isn't really used anywhere. Requiring docs.recommended in earlier versions of typescript-eslint was a types bug.


create(context) {
defaultOptions: [{}],
create(context, [options = {}]) {
Copy link
Member Author

Choose a reason for hiding this comment

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

typescript-eslint's RuleCreator has a nice little benefit of adding in some options defaulting & merging. https://typescript-eslint.io/developers/custom-rules/#handling-rule-options

*/
export function shouldAnalyze(context) {
export function shouldAnalyze(context: TSESLint.RuleContext<string, unknown[]>) {
const sourceCode = context.sourceCode ?? context.getSourceCode();
Copy link
Member Author

Choose a reason for hiding this comment

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

[Question] context.getSourceCode() is deprecated. context.sourceCode always exists in the one ESLint version we use. I don't know of a need for a fallback. Was this kept in for a specific reason?

Copy link
Collaborator

Choose a reason for hiding this comment

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

i doubt it. let’s trust the types and remove it 👍

@JoshuaKGoldberg JoshuaKGoldberg marked this pull request as ready for review February 25, 2026 14:12
@JoshuaKGoldberg JoshuaKGoldberg requested review from a team as code owners February 25, 2026 14:12
@JoshuaKGoldberg JoshuaKGoldberg marked this pull request as draft February 25, 2026 14:48
@JoshuaKGoldberg
Copy link
Member Author

JoshuaKGoldberg commented Feb 25, 2026

Converting to draft while I address cursor's feedback.

Edit: and TkDodo's

Copy link
Collaborator

@TkDodo TkDodo left a comment

Choose a reason for hiding this comment

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

great work, thank you 🙏

*/
export function shouldAnalyze(context) {
export function shouldAnalyze(context: TSESLint.RuleContext<string, unknown[]>) {
const sourceCode = context.sourceCode ?? context.getSourceCode();
Copy link
Collaborator

Choose a reason for hiding this comment

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

i doubt it. let’s trust the types and remove it 👍

@JoshuaKGoldberg

This comment was marked as resolved.

JoshuaKGoldberg added a commit that referenced this pull request Feb 26, 2026
…ken's (#109326)

Similar to #109310, changes the test extensions from `*.spec.mjs` to
`*.spec.js`. The `m` is unnecessary because Jest is configured to treat
their syntax as ESM either way.

`static/eslint/eslintPluginScraps/src/rules/use-semantic-token.spec.js`
had some failures in the helper-function-generated invalid cases:

* Most were using the `invalidProperty` message ID instead of
`invalidPropertyWithSuggestion`, and missing `data.suggestedCategory`
* A few were actually not invalid at all and had zero errors
JoshuaKGoldberg added a commit that referenced this pull request Feb 27, 2026
I noticed while working on #109310 that the latest version of
[`@typescript-eslint/prefer-optional-chain`](https://typescript-eslint.io/rules/prefer-optional-chain)
wasn't being used. Some code snippets like this weren't being reported:

```ts
if (apple && apple.banana === "cherry") {
```

That was fixed by
typescript-eslint/typescript-eslint#11533. This
PR bumps typescript-eslint to the latest version and fixes new lint rule
reports. It was mostly prefer-optional-chain reports; others are noted
inline.
@JoshuaKGoldberg JoshuaKGoldberg changed the title chore: convert eslint-plugin-scraps files from .mjs to .mts chore: convert eslint-plugin-scraps files from .mjs to .ts Mar 2, 2026
@JoshuaKGoldberg JoshuaKGoldberg changed the title chore: convert eslint-plugin-scraps files from .mjs to .ts chore: convert internal ESLint plugin files from .mjs to .ts Mar 2, 2026
@JoshuaKGoldberg JoshuaKGoldberg force-pushed the eslint-plugin-scraps-typed branch from c1efe05 to 546749c Compare March 2, 2026 17:42
function getDisplayName(nameNode: TSESTree.JSXTagNameExpression) {
if (nameNode.type === 'JSXMemberExpression') {
return `${nameNode.object.name}.${nameNode.property.name}`;
return `${(nameNode.object as TSESTree.JSXIdentifier).name}.${nameNode.property.name}`;
Copy link
Member Author

Choose a reason for hiding this comment

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

nameNode.object as TSESTree.JSXIdentifier

This might be a potential bug in the rule: nameNode.object is typed as type JSXTagNameExpression = JSXIdentifier | JSXMemberExpression | JSXNamespacedName;. JSXMemberExpression doesn't have a .name; JSXNamespacedName's .name is a JSXIdentifier rather than the expected string.

Copy link
Member

Choose a reason for hiding this comment

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

Sounds legit—are you able to update this to handle the actual type more defensively?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done!

I used the fancy AST_NODE_TYPES enum from typescript-eslint too.

Copy link
Member Author

Choose a reason for hiding this comment

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

I split this out into #109725.

@JoshuaKGoldberg JoshuaKGoldberg force-pushed the eslint-plugin-scraps-typed branch 2 times, most recently from 6a4f9b5 to beaab7c Compare March 2, 2026 17:48
@JoshuaKGoldberg JoshuaKGoldberg changed the title chore: convert internal ESLint plugin files from .mjs to .ts chore: convert ESLint files from .js/.mjs to .ts Mar 2, 2026
@JoshuaKGoldberg JoshuaKGoldberg force-pushed the eslint-plugin-scraps-typed branch 2 times, most recently from 0772c3e to b588726 Compare March 2, 2026 18:06
@JoshuaKGoldberg JoshuaKGoldberg marked this pull request as ready for review March 2, 2026 18:33
@JoshuaKGoldberg JoshuaKGoldberg force-pushed the eslint-plugin-scraps-typed branch from b588726 to 8d06a5b Compare March 2, 2026 18:36
if (slotState.has(propName)) {
throw new TypeError(
`Duplicate prop configuration for: ${propName} in slot ${slot.componentNames.join(', ')}`
`Duplicate prop configuration for: ${propName} in slot ${Array.from(state.componentNames).join(', ')}`
Copy link
Member Author

Choose a reason for hiding this comment

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

TypeScript pointed out that slot.componentNames is optional. Was this meant to be state.componentNames?

Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Copy link
Member

@natemoo-re natemoo-re left a comment

Choose a reason for hiding this comment

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

Just a few notes that would be good to address before merge, but not worth blocking! Great work on this 🙌

function getDisplayName(nameNode: TSESTree.JSXTagNameExpression) {
if (nameNode.type === 'JSXMemberExpression') {
return `${nameNode.object.name}.${nameNode.property.name}`;
return `${(nameNode.object as TSESTree.JSXIdentifier).name}.${nameNode.property.name}`;
Copy link
Member

Choose a reason for hiding this comment

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

Sounds legit—are you able to update this to handle the actual type more defensively?

elementName = nameNode.name;
} else if (nameNode.type === 'JSXMemberExpression') {
elementName = `${nameNode.object.name}.${nameNode.property.name}`;
elementName = `${(nameNode.object as TSESTree.JSXIdentifier).name}.${nameNode.property.name}`;
Copy link
Member

Choose a reason for hiding this comment

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

Same issue here?

context.report({
node: translationArg,
message: 'td() must use ATTRIBUTE_METADATA[key].brief from @sentry/conventions',
messageId: 'forbidden',
Copy link
Member

Choose a reason for hiding this comment

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

Did we lose the message here?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, this message duplicates the forbidden message ID:

forbidden: 'td() must use ATTRIBUTE_METADATA[key].brief from @sentry/conventions',

message is an old legacy ESLint property that isn't even in the TSESLint types.

@JoshuaKGoldberg JoshuaKGoldberg merged commit 47fb0d1 into master Mar 2, 2026
84 of 86 checks passed
@JoshuaKGoldberg JoshuaKGoldberg deleted the eslint-plugin-scraps-typed branch March 2, 2026 20:24
@linear
Copy link

linear bot commented Mar 2, 2026

JoshuaKGoldberg added a commit that referenced this pull request Mar 2, 2026
…9725)

Followup to #109310: modifies the logic in `restrict-jsx-slot-children`
to:

* Behavior: handle namespaces and property accesses for JSX tags
* Internal: unified `getDisplayName` and the ad hoc stringification in
the `JSXAttribute` visitor

I split this out into its own PR because the way I wrote
`getDisplayName` triggered some reports from ESLint that I wanted to ask
about.

Fixes
https://linear.app/getsentry/issue/ENG-6933/followup-refactor-restrict-jsx-slot-childrens-getdisplayname
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants