Skip to content

Commit

Permalink
Add class deprecation diagnostics
Browse files Browse the repository at this point in the history
  • Loading branch information
thecrypticace committed Nov 8, 2024
1 parent 386394c commit a31c7ae
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/tailwindcss-language-server/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function getDefaultSettings(): Settings {
rootFontSize: 16,
lint: {
cssConflict: 'warning',
deprecatedClass: 'warning',
invalidApply: 'error',
invalidScreen: 'error',
invalidVariant: 'error',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
isInvalidScreenDiagnostic,
isInvalidVariantDiagnostic,
isRecommendedVariantOrderDiagnostic,
isDeprecatedClassDiagnostic,
} from '../diagnostics/types'
import { flatten, dedupeBy } from '../util/array'
import { provideCssConflictCodeActions } from './provideCssConflictCodeActions'
Expand Down Expand Up @@ -74,7 +75,8 @@ export async function doCodeActions(
isInvalidTailwindDirectiveDiagnostic(diagnostic) ||
isInvalidScreenDiagnostic(diagnostic) ||
isInvalidVariantDiagnostic(diagnostic) ||
isRecommendedVariantOrderDiagnostic(diagnostic)
isRecommendedVariantOrderDiagnostic(diagnostic) ||
isDeprecatedClassDiagnostic(diagnostic)
) {
return provideSuggestionCodeActions(state, params, diagnostic)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { State } from '../util/state'
import type { CodeActionParams, CodeAction } from 'vscode-languageserver'
import type {
DeprecatedClassDiagnostic,
InvalidConfigPathDiagnostic,
InvalidTailwindDirectiveDiagnostic,
InvalidScreenDiagnostic,
Expand All @@ -12,6 +13,7 @@ export function provideSuggestionCodeActions(
_state: State,
params: CodeActionParams,
diagnostic:
| DeprecatedClassDiagnostic
| InvalidConfigPathDiagnostic
| InvalidTailwindDirectiveDiagnostic
| InvalidScreenDiagnostic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import { getInvalidVariantDiagnostics } from './getInvalidVariantDiagnostics'
import { getInvalidConfigPathDiagnostics } from './getInvalidConfigPathDiagnostics'
import { getInvalidTailwindDirectiveDiagnostics } from './getInvalidTailwindDirectiveDiagnostics'
import { getRecommendedVariantOrderDiagnostics } from './getRecommendedVariantOrderDiagnostics'
import { getDeprecatedClassDiagnostics } from './getDeprecatedClassDiagnostics'

export async function doValidate(
state: State,
document: TextDocument,
only: DiagnosticKind[] = [
DiagnosticKind.Deprecation,
DiagnosticKind.CssConflict,
DiagnosticKind.InvalidApply,
DiagnosticKind.InvalidScreen,
Expand All @@ -26,6 +28,9 @@ export async function doValidate(

return settings.tailwindCSS.validate
? [
...(only.includes(DiagnosticKind.Deprecation)
? await getDeprecatedClassDiagnostics(state, document, settings)
: []),
...(only.includes(DiagnosticKind.CssConflict)
? await getCssConflictDiagnostics(state, document, settings)
: []),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { joinWithAnd } from '../util/joinWithAnd'
import type { State, Settings } from '../util/state'
import { type DeprecatedClassDiagnostic, DiagnosticKind } from './types'
import { findClassListsInDocument, getClassNamesInClassList } from '../util/find'
import type { TextDocument } from 'vscode-languageserver-textdocument'

export async function getDeprecatedClassDiagnostics(
state: State,
document: TextDocument,
settings: Settings,
): Promise<DeprecatedClassDiagnostic[]> {
// Only v4 projects can report deprecations
if (!state.v4) return []

let severity = settings.tailwindCSS.lint.deprecatedClass
if (severity === 'ignore') return []

let deprecatedClasses = new Set(
state.classList.filter(([_, meta]) => meta.deprecated ?? false).map(([className]) => className),
)

let diagnostics: DeprecatedClassDiagnostic[] = []
let classLists = await findClassListsInDocument(state, document)

for (let classList of classLists) {
let classNames = getClassNamesInClassList(classList, state.blocklist)

for (let className of classNames) {
if (!deprecatedClasses.has(className.className)) continue

diagnostics.push({
code: DiagnosticKind.DeprecatedClass,
className,
range: className.range,
severity:
severity === 'error'
? 1 /* DiagnosticSeverity.Error */
: 2 /* DiagnosticSeverity.Warning */,
message: `'${className.className}' is deprecated.`,
suggestions: [],
})
}
}

return diagnostics
}
14 changes: 14 additions & 0 deletions packages/tailwindcss-language-service/src/diagnostics/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,24 @@ export enum DiagnosticKind {
InvalidApply = 'invalidApply',
InvalidScreen = 'invalidScreen',
InvalidVariant = 'invalidVariant',
DeprecatedClass = 'deprecatedClass',
InvalidConfigPath = 'invalidConfigPath',
InvalidTailwindDirective = 'invalidTailwindDirective',
RecommendedVariantOrder = 'recommendedVariantOrder',
}

export type DeprecatedClassDiagnostic = Diagnostic & {
code: DiagnosticKind.DeprecatedClass
className: DocumentClassName
suggestions: string[]
}

export function isDeprecatedClassDiagnostic(
diagnostic: AugmentedDiagnostic,
): diagnostic is DeprecatedClassDiagnostic {
return diagnostic.code === DiagnosticKind.DeprecatedClass
}

export type CssConflictDiagnostic = Diagnostic & {
code: DiagnosticKind.CssConflict
className: DocumentClassName
Expand Down Expand Up @@ -90,6 +103,7 @@ export function isRecommendedVariantOrderDiagnostic(
}

export type AugmentedDiagnostic =
| DeprecatedClassDiagnostic
| CssConflictDiagnostic
| InvalidApplyDiagnostic
| InvalidScreenDiagnostic
Expand Down
2 changes: 2 additions & 0 deletions packages/tailwindcss-language-service/src/util/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export type TailwindCssSettings = {
colorDecorators: boolean
lint: {
cssConflict: DiagnosticSeveritySetting
deprecatedClass: DiagnosticSeveritySetting
invalidApply: DiagnosticSeveritySetting
invalidScreen: DiagnosticSeveritySetting
invalidVariant: DiagnosticSeveritySetting
Expand Down Expand Up @@ -91,6 +92,7 @@ export interface Variant {
export interface ClassMetadata {
color: culori.Color | KeywordColor | null
modifiers?: string[]
deprecated?: boolean
}

export interface State {
Expand Down
1 change: 1 addition & 0 deletions packages/vscode-tailwindcss/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Fix display of color swatches using new v4 oklch color palette ([#1073](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1073))
- Properly validate `theme(…)` function paths in v4 ([#1074](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1074))
- Show all potential class conflicts in v4 projects ([#1077](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1077))
- Add support for detecting deprecated classes ([#1084](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1084))

## 0.12.11

Expand Down
4 changes: 4 additions & 0 deletions packages/vscode-tailwindcss/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ Unknown or invalid path used with the [`theme` helper](https://tailwindcss.com/d

Class names on the same HTML element which apply the same CSS property or properties. **Default: `warning`**

#### `tailwindCSS.lint.deprecatedClass`

Use of a deprecated class. **Default: `warning`**

#### `tailwindCSS.lint.recommendedVariantOrder`

Class variants not in the recommended order (applies in [JIT mode](https://tailwindcss.com/docs/just-in-time-mode) only). **Default: `warning`**
Expand Down
11 changes: 11 additions & 0 deletions packages/vscode-tailwindcss/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,17 @@
"markdownDescription": "Class names on the same HTML element which apply the same CSS property or properties",
"scope": "language-overridable"
},
"tailwindCSS.lint.deprecatedClass": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"markdownDescription": "Use of a deprecated utility class",
"scope": "language-overridable"
},
"tailwindCSS.lint.invalidApply": {
"type": "string",
"enum": [
Expand Down

0 comments on commit a31c7ae

Please sign in to comment.