import { joinWithAnd } from '../util/joinWithAnd' ; import { State , Settings } from '../util/state' ; import type { TextDocument , DiagnosticSeverity } from 'vscode-languageserver' ; import { CssConflictDiagnostic , DiagnosticKind } from './types' ; import { findClassListsInDocument , getClassNamesInClassList } from '../util/find' ; import { getClassNameDecls } from '../util/getClassNameDecls' ; import { getClassNameMeta } from '../util/getClassNameMeta' ; import { equal } from '../util/array' ; import * as jit from '../util/jit' ; export async function getCssConflictDiagnostics ( state , document , settings ) { let severity = settings . tailwindCSS . lint . cssConflict ; if ( severity === 'ignore' ) return [ ] ; let diagnostics = [ ] ; const classLists = await findClassListsInDocument ( state , document ) ; classLists . forEach ( ( classList ) => { const classNames = getClassNamesInClassList ( classList ) ; classNames . forEach ( ( className , index ) => { if ( state . jit ) { let { rules } = jit . generateRules ( state , [ className . className ] ) ; if ( rules . length !== 1 ) { return ; } let rule = rules [ 0 ] ; let context ; let properties = [ ] ; rule . walkDecls ( ( { prop } ) => { properties . push ( prop ) ; } ) ; let otherClassNames = classNames . filter ( ( _className , i ) => i !== index ) ; let conflictingClassNames = otherClassNames . filter ( ( otherClassName ) => { let { rules } = jit . generateRules ( state , [ otherClassName . className ] ) ; if ( rules . length !== 1 ) { return false ; } let otherRule = rules [ 0 ] ; let otherProperties = [ ] ; otherRule . walkDecls ( ( { prop } ) => { otherProperties . push ( prop ) ; } ) ; if ( ! equal ( properties , otherProperties ) ) { return false ; } if ( ! context ) { context = jit . getRuleContext ( state , rule , className . className ) ; } let otherContext = jit . getRuleContext ( state , otherRule , otherClassName . className ) ; if ( ! equal ( context , otherContext ) ) { return false ; } return true ; } ) ; if ( conflictingClassNames . length === 0 ) return ; diagnostics . push ( { code : DiagnosticKind . CssConflict , className , otherClassNames : conflictingClassNames , range : className . range , severity : severity === 'error' ? 1 : 2 , message : `'${ className . className }' applies the same CSS ${ properties . length === 1 ? 'property' : 'properties' } as ${ joinWithAnd ( conflictingClassNames . map ( ( conflictingClassName ) => `'${ conflictingClassName . className }'` ) ) }.` , relatedInformation : conflictingClassNames . map ( ( conflictingClassName ) => { return { message : conflictingClassName . className , location : { uri : document . uri , range : conflictingClassName . range } } ; } ) } ) ; return ; } let decls = getClassNameDecls ( state , className . className ) ; if ( ! decls ) return ; let properties = Object . keys ( decls ) ; let meta = getClassNameMeta ( state , className . className ) ; let otherClassNames = classNames . filter ( ( _className , i ) => i !== index ) ; let conflictingClassNames = otherClassNames . filter ( ( otherClassName ) => { let otherDecls = getClassNameDecls ( state , otherClassName . className ) ; if ( ! otherDecls ) return false ; let otherMeta = getClassNameMeta ( state , otherClassName . className ) ; return ( equal ( properties , Object . keys ( otherDecls ) ) && ! Array . isArray ( meta ) && ! Array . isArray ( otherMeta ) && equal ( meta . context , otherMeta . context ) && equal ( meta . pseudo , otherMeta . pseudo ) && meta . scope === otherMeta . scope ) ; } ) ; if ( conflictingClassNames . length === 0 ) return ; diagnostics . push ( { code : DiagnosticKind . CssConflict , className , otherClassNames : conflictingClassNames , range : className . range , severity : severity === 'error' ? 1 : 2 , message : `'${ className . className }' applies the same CSS ${ properties . length === 1 ? 'property' : 'properties' } as ${ joinWithAnd ( conflictingClassNames . map ( ( conflictingClassName ) => `'${ conflictingClassName . className }'` ) ) }.` , relatedInformation : conflictingClassNames . map ( ( conflictingClassName ) => { return { message : conflictingClassName . className , location : { uri : document . uri , range : conflictingClassName . range } } ; } ) } ) ; } ) ; } ) ; return diagnostics ; }