diff --git a/src/lsp/providers/diagnostics/getInvalidConfigPathDiagnostics.ts b/src/lsp/providers/diagnostics/getInvalidConfigPathDiagnostics.ts
index 95293341d536810ead06332a6125e96c6a77a776..ccf52fcb1aa3b88bd1b73aa9963e0e7729b29cca 100644
--- a/src/lsp/providers/diagnostics/getInvalidConfigPathDiagnostics.ts
+++ b/src/lsp/providers/diagnostics/getInvalidConfigPathDiagnostics.ts
@@ -9,153 +9,297 @@ import isObject from '../../../util/isObject'
import { closest } from '../../util/closest'
import { absoluteRange } from '../../util/absoluteRange'
import { State, Settings } from '../../util/state'
-import { State, Settings } from '../../util/state'
-import { State, Settings } from '../../util/state'
import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+import { closest } from '../../util/closest'
import { State, Settings } from '../../util/state'
-import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
import { State, Settings } from '../../util/state'
-import { isCssDoc } from '../../util/css'
import { State, Settings } from '../../util/state'
-import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
+import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
import { State, Settings } from '../../util/state'
-import { findAll, indexToPosition } from '../../util/find'
+ let text = document.getText(range)
import { State, Settings } from '../../util/state'
-import { stringToPath } from '../../util/stringToPath'
+import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
import { State, Settings } from '../../util/state'
-import isObject from '../../../util/isObject'
import { State, Settings } from '../../util/state'
-import { closest } from '../../util/closest'
-import { State, Settings } from '../../util/state'
+import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
- let diagnostics: InvalidConfigPathDiagnostic[] = []
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
import { State, Settings } from '../../util/state'
+ text
import { State, Settings } from '../../util/state'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
- if (isCssDoc(state, document)) {
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
import { isCssDoc } from '../../util/css'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+export function getInvalidConfigPathDiagnostics(
import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+export function getInvalidConfigPathDiagnostics(
import { findAll, indexToPosition } from '../../util/find'
- ranges.push(...boundaries.css)
+import { State, Settings } from '../../util/state'
}
- ranges.forEach((range) => {
+import { State, Settings } from '../../util/state'
import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
+import { stringToPath } from '../../util/stringToPath'
-import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
import { State, Settings } from '../../util/state'
- /(?<prefix>\s|^)(?<helper>config|theme)\((?<quote>['"])(?<key>[^)]+)\k<quote>\)/g,
- text
-import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
import { isCssDoc } from '../../util/css'
import { State, Settings } from '../../util/state'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
- matches.forEach((match) => {
- let base = match.groups.helper === 'theme' ? ['theme'] : []
- let keys = stringToPath(match.groups.key)
let value = dlv(state.config, [...base, ...keys])
import { State, Settings } from '../../util/state'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
const isValid = (val: unknown): boolean =>
+import { State, Settings } from '../../util/state'
typeof val === 'string' ||
+import { State, Settings } from '../../util/state'
typeof val === 'number' ||
+import { State, Settings } from '../../util/state'
val instanceof String ||
+import { State, Settings } from '../../util/state'
val instanceof Number ||
+import { State, Settings } from '../../util/state'
Array.isArray(val)
import { State, Settings } from '../../util/state'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
const stitch = (keys: string[]): string =>
+
+import { State, Settings } from '../../util/state'
keys.reduce((acc, cur, i) => {
+import { State, Settings } from '../../util/state'
if (i === 0) return cur
+import { State, Settings } from '../../util/state'
if (cur.includes('.')) return `${acc}[${cur}]`
+ )
+
+import { State, Settings } from '../../util/state'
return `${acc}.${cur}`
+import { State, Settings } from '../../util/state'
}, '')
import { State, Settings } from '../../util/state'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
let message: string
+import { State, Settings } from '../../util/state'
let suggestions: string[] = []
import { State, Settings } from '../../util/state'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
if (isValid(value)) {
+import { State, Settings } from '../../util/state'
// The value resolves successfully, but we need to check that there
+import { State, Settings } from '../../util/state'
// wasn't any funny business. If you have a theme object:
+import { State, Settings } from '../../util/state'
// { msg: 'hello' } and do theme('msg.0')
+import { State, Settings } from '../../util/state'
// this will resolve to 'h', which is probably not intentional, so we
+import { State, Settings } from '../../util/state'
// check that all of the keys are object or array keys (i.e. not string
+ })
+import { State, Settings } from '../../util/state'
// indexes)
+
+import { State, Settings } from '../../util/state'
let valid = true
+import { State, Settings } from '../../util/state'
for (let i = keys.length - 1; i >= 0; i--) {
+ )
+ }
+
+import { State, Settings } from '../../util/state'
let key = keys[i]
+import { State, Settings } from '../../util/state'
let parentValue = dlv(state.config, [...base, ...keys.slice(0, i)])
+import { State, Settings } from '../../util/state'
if (/^[0-9]+$/.test(key)) {
+import { State, Settings } from '../../util/state'
if (!isObject(parentValue) && !Array.isArray(parentValue)) {
+
+import { State, Settings } from '../../util/state'
valid = false
+import { State, Settings } from '../../util/state'
break
+import { State, Settings } from '../../util/state'
}
+import { State, Settings } from '../../util/state'
} else if (!isObject(parentValue)) {
+import { State, Settings } from '../../util/state'
valid = false
+import { State, Settings } from '../../util/state'
break
+import { State, Settings } from '../../util/state'
}
+import { State, Settings } from '../../util/state'
}
+import { State, Settings } from '../../util/state'
if (!valid) {
+import { State, Settings } from '../../util/state'
message = `'${match.groups.key}' does not exist in your theme config.`
+import { State, Settings } from '../../util/state'
import { stringToPath } from '../../util/stringToPath'
-import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
+import { State, Settings } from '../../util/state'
+import { State, Settings } from '../../util/state'
} else if (typeof value === 'undefined') {
+ }
+import { State, Settings } from '../../util/state'
message = `'${match.groups.key}' does not exist in your theme config.`
+import { State, Settings } from '../../util/state'
let parentValue = dlv(state.config, [
+import { State, Settings } from '../../util/state'
...base,
+import { State, Settings } from '../../util/state'
...keys.slice(0, keys.length - 1),
+import { State, Settings } from '../../util/state'
])
+import { State, Settings } from '../../util/state'
if (isObject(parentValue)) {
+import { State, Settings } from '../../util/state'
let closestValidKey = closest(
+ }
+ }
+import { State, Settings } from '../../util/state'
keys[keys.length - 1],
+
+import { State, Settings } from '../../util/state'
Object.keys(parentValue).filter((key) => isValid(parentValue[key]))
+import { State, Settings } from '../../util/state'
)
+import { State, Settings } from '../../util/state'
if (closestValidKey) {
+import { State, Settings } from '../../util/state'
suggestions.push(
+ }
+ }
+
+import { State, Settings } from '../../util/state'
stitch([...keys.slice(0, keys.length - 1), closestValidKey])
+import { State, Settings } from '../../util/state'
)
+import { State, Settings } from '../../util/state'
message += ` Did you mean '${suggestions[0]}'?`
+ typeof value === 'number' ||
+ value instanceof String ||
+ value instanceof Number ||
+ Array.isArray(value)
+ )
+ ) {
+ if (severity === 'ignore') return []
import { stringToPath } from '../../util/stringToPath'
+ path
+ )}' was found but does not resolve to a string.`
+import { State, Settings } from '../../util/state'
import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+ if (isObject(value)) {
+ let validKeys = Object.keys(value).filter(
+ (key) => validateConfigPath(state, [...keys, key], base).isValid
+import { State, Settings } from '../../util/state'
import { stringToPath } from '../../util/stringToPath'
+import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+ let diagnostics: InvalidConfigPathDiagnostic[] = []
import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
-import { closest } from '../../util/closest'
+ suggestions.push(
+ ...validKeys.map((validKey) => pathToString([...keys, validKey]))
+ )
+ reason += ` Did you mean something like '${suggestions[0]}'?`
+ }
+ }
+ return {
+ isValid: false,
+ reason,
+ suggestions,
+ }
+ }
+import { State, Settings } from '../../util/state'
import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+ // The value resolves successfully, but we need to check that there
+ // wasn't any funny business. If you have a theme object:
+ // { msg: 'hello' } and do theme('msg.0')
+ let diagnostics: InvalidConfigPathDiagnostic[] = []
import { closest } from '../../util/closest'
+ // check that all of the keys are object or array keys (i.e. not string
+ // indexes)
+ let isValid = true
+ let ranges: Range[] = []
import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
+import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
import { State, Settings } from '../../util/state'
+import { isCssDoc } from '../../util/css'
import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+ document: TextDocument,
+ if (/^[0-9]+$/.test(key)) {
+ if (!isObject(parentValue) && !Array.isArray(parentValue)) {
+ isValid = false
+ let ranges: Range[] = []
import { closest } from '../../util/closest'
+ }
+ } else if (!isObject(parentValue)) {
+ isValid = false
+ break
+ let severity = settings.lint.invalidConfigPath
import { isCssDoc } from '../../util/css'
-import { closest } from '../../util/closest'
+ }
+ if (!isValid) {
+ let reason = `'${pathToString(path)}' does not exist in your theme config.`
+
+ let altPath = findAlternativePath()
+ if (isCssDoc(state, document)) {
import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
+ return {
+ isValid: false,
+ reason: `${reason} Did you mean '${pathToString(altPath)}'?`,
+ if (isCssDoc(state, document)) {
import { closest } from '../../util/closest'
-import { findAll, indexToPosition } from '../../util/find'
+ }
+ }
+
+ return {
+import { State, Settings } from '../../util/state'
)
-import { closest } from '../../util/closest'
+ let severity = settings.lint.invalidConfigPath
import { stringToPath } from '../../util/stringToPath'
+ suggestions: [],
+import { State, Settings } from '../../util/state'
import isObject from '../../../util/isObject'
+import { isCssDoc } from '../../util/css'
+import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
import isObject from '../../../util/isObject'
-import { closest } from '../../util/closest'
+
+ return {
+ isValid: true,
+ value,
+import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
import isObject from '../../../util/isObject'
+}
+
+export function getInvalidConfigPathDiagnostics(
+ state: State,
+ document: TextDocument,
+ settings: Settings
+): InvalidConfigPathDiagnostic[] {
+ let severity = settings.lint.invalidConfigPath
+import { State, Settings } from '../../util/state'
import { closest } from '../../util/closest'
+
+import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
- message += ` Did you mean something like '${suggestions[0]}'?`
+ let ranges: Range[] = []
-import { stringToPath } from '../../util/stringToPath'
+
+import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
-import { stringToPath } from '../../util/stringToPath'
+import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
+ } else {
+ let boundaries = getLanguageBoundaries(state, document)
+ if (!boundaries) return []
+ ranges.push(...boundaries.css)
+ }
import { State, Settings } from '../../util/state'
+import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+ ranges.forEach((range) => {
+import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
+import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
import { State, Settings } from '../../util/state'
+import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+ text
+ )
import { State, Settings } from '../../util/state'
+import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+ matches.forEach((match) => {
+ let base = match.groups.helper === 'theme' ? ['theme'] : []
+ let result = validateConfigPath(state, match.groups.key, base)
import { State, Settings } from '../../util/state'
+import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+ if (result.isValid === true) {
return null
}
@@ -176,11 +323,10 @@ severity:
severity === 'error'
? DiagnosticSeverity.Error
: DiagnosticSeverity.Warning,
-import { State, Settings } from '../../util/state'
import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+ let base = match.groups.helper === 'theme' ? ['theme'] : []
-import { State, Settings } from '../../util/state'
ranges.push(undefined)
+import { stringToPath } from '../../util/stringToPath'
})
})
})