Skip to content

Commit 25521ac

Browse files
committed
feat: Add inlay hints for missing JSX attributes. Disabled by default, enable with tsEssentialPlugins.inlayHints.missingJsxAttributes.enabled #208
1 parent 149119c commit 25521ac

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

src/configurationType.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,11 @@ export type Configuration = {
685685
*/
686686
declareMissingPropertyQuickfixOtherFiles: boolean
687687
/**
688+
* @recommended {".svg": {
689+
* "importPath": "$path?react",
690+
* "prefix": "Svg",
691+
* "nameCasing": "pascal"
692+
* },
688693
* @default {}
689694
*/
690695
filesAutoImport: {
@@ -708,6 +713,10 @@ export type Configuration = {
708713
iconPost?: string
709714
}
710715
}
716+
/**
717+
* @default false
718+
*/
719+
'inlayHints.missingJsxAttributes.enabled': boolean
711720
}
712721

713722
// scrapped using search editor. config: caseInsensitive, context lines: 0, regex: const fix\w+ = "[^ ]+"

src/extension.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import moreCompletions from './moreCompletions'
1717
import { mergeSettingsFromScopes } from './mergeSettings'
1818
import codeActionProvider from './codeActionProvider'
1919
import nonTsCommands from './nonTsCommands'
20+
import inlayHints from './inlayHints'
2021

2122
let isActivated = false
2223
// let erroredStatusBarItem: vscode.StatusBarItem | undefined
@@ -96,6 +97,7 @@ export const activateTsPlugin = (tsApi: { configurePlugin; onCompletionAccepted
9697

9798
figIntegration()
9899
vueVolarSupport()
100+
inlayHints()
99101

100102
if (process.env.PLATFORM === 'node' && process.env.NODE_ENV === 'development') {
101103
require('./autoPluginReload').default()

src/inlayHints.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import * as vscode from 'vscode'
2+
import { watchExtensionSetting } from '@zardoy/vscode-utils/build/settings'
3+
import { getExtensionSetting, registerActiveDevelopmentCommand } from 'vscode-framework'
4+
5+
// todo respect enabled setting, deactivate
6+
export default () => {
7+
const provider = new (class implements vscode.InlayHintsProvider {
8+
eventEmitter = new vscode.EventEmitter<void>()
9+
onDidChangeInlayHints = this.eventEmitter.event
10+
provideInlayHints(document: vscode.TextDocument, range: vscode.Range, token: vscode.CancellationToken): vscode.ProviderResult<vscode.InlayHint[]> {
11+
const diagnostics = vscode.languages.getDiagnostics(document.uri)
12+
const jsxMissingAttributesErrors = diagnostics.filter(({ code, source }) => (code === 2740 || code === 2739) && source === 'ts')
13+
return jsxMissingAttributesErrors
14+
.flatMap(({ range, message }) => {
15+
const regex = /: (?<prop>[\w, ]+)(?:, and (?<more>\d+) more)?\.?$/
16+
const match = regex.exec(message)
17+
if (!match) return null as never
18+
const props = match.groups!.prop!.split(', ')
19+
const { more } = match.groups!
20+
let text = ` ${props.map(prop => `${prop}!`).join(', ')}`
21+
if (more) text += `, and ${more} more`
22+
return {
23+
kind: vscode.InlayHintKind.Type,
24+
label: text,
25+
tooltip: `Inlay hint: Missing attributes`,
26+
position: range.end,
27+
paddingLeft: true,
28+
} satisfies vscode.InlayHint
29+
// return [...props, ...(more ? [more] : [])].map((prop) => ({
30+
// kind: vscode.InlayHintKind.Type,
31+
// label: prop,
32+
// tooltip: 'Missing attribute',
33+
// position:
34+
// }))
35+
})
36+
.filter(Boolean)
37+
}
38+
})()
39+
let disposables = [] as vscode.Disposable[]
40+
41+
const manageEnablement = () => {
42+
if (getExtensionSetting('inlayHints.missingJsxAttributes.enabled')) {
43+
vscode.languages.registerInlayHintsProvider('typescriptreact,javascript,javascriptreact'.split(','), provider)
44+
vscode.languages.onDidChangeDiagnostics(e => {
45+
for (const uri of e.uris) {
46+
if (uri === vscode.window.activeTextEditor?.document.uri) provider.eventEmitter.fire()
47+
}
48+
})
49+
} else {
50+
for (const d of disposables) d.dispose()
51+
disposables = []
52+
}
53+
}
54+
55+
manageEnablement()
56+
watchExtensionSetting('inlayHints.missingJsxAttributes.enabled', manageEnablement)
57+
}

0 commit comments

Comments
 (0)