diff --git a/src/lsp/providers/diagnosticsProvider.ts b/src/lsp/providers/diagnosticsProvider.ts index 152f3b7..e76bf49 100644 --- a/src/lsp/providers/diagnosticsProvider.ts +++ b/src/lsp/providers/diagnosticsProvider.ts @@ -6,37 +6,35 @@ import { import { State } from '../util/state' import { isCssDoc } from '../util/css' import { findClassNamesInRange } from '../util/find' -import { getClassNameParts } from '../util/getClassNameAtPosition' -const dlv = require('dlv') +import { getClassNameMeta } from '../util/getClassNameMeta' function provideCssDiagnostics(state: State, document: TextDocument): void { const classNames = findClassNamesInRange(document, undefined, 'css') let diagnostics: Diagnostic[] = classNames .map(({ className, range }) => { - const parts = getClassNameParts(state, className) - if (!parts) return null + const meta = getClassNameMeta(state, className) + if (!meta) return null - const info = dlv(state.classNames.classNames, parts) let message: string - if (Array.isArray(info)) { + if (Array.isArray(meta)) { message = `\`@apply\` cannot be used with \`.${className}\` because it is included in multiple rulesets.` - } else if (info.__source !== 'utilities') { + } else if (meta.source !== 'utilities') { message = `\`@apply\` cannot be used with \`.${className}\` because it is not a utility.` - } else if (info.__context && info.__context.length > 0) { - if (info.__context.length === 1) { - message = `\`@apply\` cannot be used with \`.${className}\` because it is nested inside of an at-rule (${info.__context[0]}).` + } 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 (${info.__context.join( + message = `\`@apply\` cannot be used with \`.${className}\` because it is nested inside of at-rules (${meta.context.join( ', ' )}).` } - } else if (info.__pseudo && info.__pseudo.length > 0) { - if (info.__pseudo.length === 1) { - message = `\`@apply\` cannot be used with \`.${className}\` because its definition includes a pseudo-selector (${info.__pseudo[0]})` + } 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 (${info.__pseudo.join( + message = `\`@apply\` cannot be used with \`.${className}\` because its definition includes pseudo-selectors (${meta.pseudo.join( ', ' )})` } diff --git a/src/lsp/util/getClassNameDecls.ts b/src/lsp/util/getClassNameDecls.ts new file mode 100644 index 0000000..a04ce94 --- /dev/null +++ b/src/lsp/util/getClassNameDecls.ts @@ -0,0 +1,20 @@ +import { State } from './state' +import { getClassNameParts } from './getClassNameAtPosition' +import removeMeta from './removeMeta' +const dlv = require('dlv') + +export function getClassNameDecls( + state: State, + className: string +): Record | Record[] | null { + const parts = getClassNameParts(state, className) + if (!parts) return null + + const info = dlv(state.classNames.classNames, parts) + + if (Array.isArray(info)) { + return info.map(removeMeta) + } + + return removeMeta(info) +} diff --git a/src/lsp/util/getClassNameMeta.ts b/src/lsp/util/getClassNameMeta.ts new file mode 100644 index 0000000..9ec86cd --- /dev/null +++ b/src/lsp/util/getClassNameMeta.ts @@ -0,0 +1,28 @@ +import { State, ClassNameMeta } from './state' +import { getClassNameParts } from './getClassNameAtPosition' +const dlv = require('dlv') + +export function getClassNameMeta( + state: State, + className: string +): ClassNameMeta | ClassNameMeta[] { + const parts = getClassNameParts(state, className) + if (!parts) return null + const info = dlv(state.classNames.classNames, parts) + + if (Array.isArray(info)) { + return info.map((i) => ({ + source: i.__source, + pseudo: i.__pseudo, + scope: i.__scope, + context: i.__context, + })) + } + + return { + source: info.__source, + pseudo: info.__pseudo, + scope: info.__scope, + context: info.__context, + } +} diff --git a/src/lsp/util/state.ts b/src/lsp/util/state.ts index fc474eb..dad7e76 100644 --- a/src/lsp/util/state.ts +++ b/src/lsp/util/state.ts @@ -53,3 +53,10 @@ export type DocumentClassName = { className: string range: Range } + +export type ClassNameMeta = { + source: 'base' | 'components' | 'utilities' + pseudo: string[] + scope: string[] + context: string[] +}