diagnostics
parent
8eaa5c9326
commit
41b8fd104e
|
@ -0,0 +1,79 @@
|
|||
import {
|
||||
TextDocument,
|
||||
Diagnostic,
|
||||
DiagnosticSeverity,
|
||||
} from 'vscode-languageserver'
|
||||
import { State } from '../util/state'
|
||||
import { isCssDoc } from '../util/css'
|
||||
import { findClassNamesInRange } from '../util/find'
|
||||
import { getClassNameParts } from '../util/getClassNameAtPosition'
|
||||
const dlv = require('dlv')
|
||||
|
||||
function provideCssDiagnostics(state: State, document: TextDocument): void {
|
||||
const classNames = findClassNamesInRange(document)
|
||||
|
||||
let diagnostics: Diagnostic[] = classNames
|
||||
.map(({ className, range }) => {
|
||||
const parts = getClassNameParts(state, className)
|
||||
if (!parts) return null
|
||||
const info = dlv(state.classNames.classNames, parts)
|
||||
let message: string
|
||||
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 {
|
||||
message = `\`@apply\` cannot be used with \`.${className}\` because it is nested inside of at-rules (${info.__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 {
|
||||
message = `\`@apply\` cannot be used with \`.${className}\` because its definition includes pseudo-selectors (${info.__pseudo.join(
|
||||
', '
|
||||
)})`
|
||||
}
|
||||
}
|
||||
|
||||
if (!message) return null
|
||||
|
||||
return {
|
||||
severity: DiagnosticSeverity.Error,
|
||||
range,
|
||||
message,
|
||||
// source: 'ex',
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
// if (state.editor.capabilities.diagnosticRelatedInformation) {
|
||||
// diagnostic.relatedInformation = [
|
||||
// {
|
||||
// location: {
|
||||
// uri: document.uri,
|
||||
// range: Object.assign({}, diagnostic.range),
|
||||
// },
|
||||
// message: '',
|
||||
// },
|
||||
// {
|
||||
// location: {
|
||||
// uri: document.uri,
|
||||
// range: Object.assign({}, diagnostic.range),
|
||||
// },
|
||||
// message: '',
|
||||
// },
|
||||
// ]
|
||||
// }
|
||||
|
||||
state.editor.connection.sendDiagnostics({ uri: document.uri, diagnostics })
|
||||
}
|
||||
|
||||
export async function provideDiagnostics(
|
||||
state: State,
|
||||
document: TextDocument
|
||||
): Promise<void> {
|
||||
if (isCssDoc(state, document)) {
|
||||
return provideCssDiagnostics(state, document)
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import {
|
|||
import { provideHover } from './providers/hoverProvider'
|
||||
import { URI } from 'vscode-uri'
|
||||
import { getDocumentSettings } from './util/getDocumentSettings'
|
||||
import { provideDiagnostics } from './providers/diagnosticsProvider'
|
||||
|
||||
let state: State = { enabled: false }
|
||||
let connection = createConnection(ProposedFeatures.all)
|
||||
|
@ -45,6 +46,9 @@ documents.onDidOpen((event) => {
|
|||
documents.onDidClose((event) => {
|
||||
documentSettings.delete(event.document.uri)
|
||||
})
|
||||
documents.onDidChangeContent((change) => {
|
||||
provideDiagnostics(state, change.document)
|
||||
})
|
||||
documents.listen(connection)
|
||||
|
||||
connection.onInitialize(
|
||||
|
@ -64,6 +68,10 @@ connection.onInitialize(
|
|||
capabilities: {
|
||||
configuration:
|
||||
capabilities.workspace && !!capabilities.workspace.configuration,
|
||||
diagnosticRelatedInformation:
|
||||
capabilities.textDocument &&
|
||||
capabilities.textDocument.publishDiagnostics &&
|
||||
capabilities.textDocument.publishDiagnostics.relatedInformation,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ export const CSS_LANGUAGES = [
|
|||
'stylus',
|
||||
]
|
||||
|
||||
function isCssDoc(state: State, doc: TextDocument): boolean {
|
||||
export function isCssDoc(state: State, doc: TextDocument): boolean {
|
||||
const userCssLanguages = Object.keys(
|
||||
state.editor.userLanguages
|
||||
).filter((lang) => CSS_LANGUAGES.includes(state.editor.userLanguages[lang]))
|
||||
|
|
|
@ -72,7 +72,7 @@ export function findJsxStrings(str: string): StringInfo[] {
|
|||
|
||||
export function findClassNamesInRange(
|
||||
doc: TextDocument,
|
||||
range: Range
|
||||
range?: Range
|
||||
): DocumentClassName[] {
|
||||
const classLists = findClassListsInRange(doc, range)
|
||||
return [].concat.apply(
|
||||
|
@ -111,10 +111,11 @@ export function findClassNamesInRange(
|
|||
|
||||
export function findClassListsInRange(
|
||||
doc: TextDocument,
|
||||
range: Range
|
||||
range?: Range
|
||||
): DocumentClassList[] {
|
||||
const text = doc.getText(range)
|
||||
const matches = findAll(/(@apply\s+)(?<classList>[^;}]+)[;}]/g, text)
|
||||
const globalStart: Position = range ? range.start : { line: 0, character: 0 }
|
||||
|
||||
return matches.map((match) => {
|
||||
const start = indexToPosition(text, match.index + match[1].length)
|
||||
|
@ -126,12 +127,12 @@ export function findClassListsInRange(
|
|||
classList: match.groups.classList,
|
||||
range: {
|
||||
start: {
|
||||
line: range.start.line + start.line,
|
||||
character: range.start.character + start.character,
|
||||
line: globalStart.line + start.line,
|
||||
character: globalStart.character + start.character,
|
||||
},
|
||||
end: {
|
||||
line: range.start.line + end.line,
|
||||
character: range.start.character + end.character,
|
||||
line: globalStart.line + end.line,
|
||||
character: globalStart.character + end.character,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ export type EditorState = {
|
|||
userLanguages: Record<string, string>
|
||||
capabilities: {
|
||||
configuration: boolean
|
||||
diagnosticRelatedInformation: boolean
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue