Home

tailwind-ctp-intellisense @de6273dad2cf0c9577b33c3f25b67a4e78561450 - refs - log -
-
https://git.jolheiser.com/tailwind-ctp-intellisense.git
Tailwind intellisense + Catppuccin
tailwind-ctp-intellisense / src / lsp / providers / diagnosticsProvider.ts
- raw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import {
  TextDocument,
  Diagnostic,
  DiagnosticSeverity,
} from 'vscode-languageserver'
import { State } from '../util/state'
import { isCssDoc } from '../util/css'
import {
  findClassNamesInRange,
  findClassListsInDocument,
  getClassNamesInClassList,
} from '../util/find'
import { getClassNameMeta } from '../util/getClassNameMeta'
import { getClassNameDecls } from '../util/getClassNameDecls'
import { equal } from '../../util/array'

function getCssDiagnostics(state: State, document: TextDocument): Diagnostic[] {
  const classNames = findClassNamesInRange(document, undefined, 'css')

  let diagnostics: Diagnostic[] = classNames
    .map(({ className, range }) => {
      const meta = getClassNameMeta(state, className)
      if (!meta) return null

      let message: string

      if (Array.isArray(meta)) {
        message = `\`@apply\` cannot be used with \`.${className}\` because it is included in multiple rulesets.`
      } else if (meta.source !== 'utilities') {
        message = `\`@apply\` cannot be used with \`.${className}\` because it is not a utility.`
      } else if (meta.context && meta.context.length > 0) {
        if (meta.context.length === 1) {
          message = `\`@apply\` cannot be used with \`.${className}\` because it is nested inside of an at-rule (${meta.context[0]}).`
        } else {
          message = `\`@apply\` cannot be used with \`.${className}\` because it is nested inside of at-rules (${meta.context.join(
            ', '
          )}).`
        }
      } else if (meta.pseudo && meta.pseudo.length > 0) {
        if (meta.pseudo.length === 1) {
          message = `\`@apply\` cannot be used with \`.${className}\` because its definition includes a pseudo-selector (${meta.pseudo[0]})`
        } else {
          message = `\`@apply\` cannot be used with \`.${className}\` because its definition includes pseudo-selectors (${meta.pseudo.join(
            ', '
          )})`
        }
      }

      if (!message) return null

      return {
        severity: DiagnosticSeverity.Error,
        range,
        message,
      }
    })
    .filter(Boolean)

  return diagnostics
}

function getConflictDiagnostics(
  state: State,
  document: TextDocument
): Diagnostic[] {
  let diagnostics: Diagnostic[] = []
  const classLists = findClassListsInDocument(state, document)

  classLists.forEach((classList) => {
    const classNames = getClassNamesInClassList(classList)

    classNames.forEach((className, index) => {
      let otherClassNames = classNames.filter((_className, i) => i !== index)
      otherClassNames.forEach((otherClassName) => {
        let decls = getClassNameDecls(state, className.className)
        if (!decls) return

        let otherDecls = getClassNameDecls(state, otherClassName.className)
        if (!otherDecls) return

        let meta = getClassNameMeta(state, className.className)
        let otherMeta = getClassNameMeta(state, otherClassName.className)

        if (
          equal(Object.keys(decls), Object.keys(otherDecls)) &&
          !Array.isArray(meta) &&
          !Array.isArray(otherMeta) &&
          equal(meta.context, otherMeta.context) &&
          equal(meta.pseudo, otherMeta.pseudo)
        ) {
          diagnostics.push({
            range: className.range,
            severity: DiagnosticSeverity.Warning,
            message: `You can’t use \`${className.className}\` and \`${otherClassName.className}\` together`,
            relatedInformation: [
              {
                message: otherClassName.className,
                location: {
                  uri: document.uri,
                  range: otherClassName.range,
                },
              },
            ],
          })
        }
      })
    })
  })

  return diagnostics
}

export async function provideDiagnostics(
  state: State,
  document: TextDocument
): Promise<void> {
  state.editor.connection.sendDiagnostics({
    uri: document.uri,
    diagnostics: [
      ...getConflictDiagnostics(state, document),
      ...(isCssDoc(state, document) ? getCssDiagnostics(state, document) : []),
    ],
  })
}