diff --git a/src/lsp/providers/diagnostics/getInvalidConfigPathDiagnostics.ts b/src/lsp/providers/diagnostics/getInvalidConfigPathDiagnostics.ts index ccf52fcb1aa3b88bd1b73aa9963e0e7729b29cca..95293341d536810ead06332a6125e96c6a77a776 100644 --- a/src/lsp/providers/diagnostics/getInvalidConfigPathDiagnostics.ts +++ b/src/lsp/providers/diagnostics/getInvalidConfigPathDiagnostics.ts @@ -9,274 +9,219 @@ 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 { State, Settings } from '../../util/state' -import { isCssDoc } from '../../util/css' - if (typeof path === 'string') return path - return path.reduce((acc, cur, i) => { - if (i === 0) return cur - if (cur.includes('.')) return `${acc}[${cur}]` - return `${acc}.${cur}` import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' -} - -function validateConfigPath( +import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' state: State, - path: string | string[], - base: string[] = [] +import { State, Settings } from '../../util/state' ): +import { State, Settings } from '../../util/state' | { isValid: true; value: any } +import { State, Settings } from '../../util/state' | { isValid: false; reason: string; suggestions: string[] } { +import { State, Settings } from '../../util/state' let keys = Array.isArray(path) ? path : stringToPath(path) +import { State, Settings } from '../../util/state' let value = dlv(state.config, [...base, ...keys]) + +import { State, Settings } from '../../util/state' let suggestions: string[] = [] import { State, Settings } from '../../util/state' -import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' function findAlternativePath(): string[] { + +import { State, Settings } from '../../util/state' let points = combinations('123456789'.substr(0, keys.length - 1)).map((x) => +import { State, Settings } from '../../util/state' x.split('').map((x) => parseInt(x, 10)) +import { State, Settings } from '../../util/state' ) -import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' import { findAll, indexToPosition } from '../../util/find' +import { State, Settings } from '../../util/state' .map((p) => { +import { State, Settings } from '../../util/state' let result = [] - let i = 0 -import { isCssDoc } from '../../util/css' +import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' -import { isCssDoc } from '../../util/css' import { State, Settings } from '../../util/state' - i = x -import { isCssDoc } from '../../util/css' import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' - result.push(keys.slice(i).join('.')) - return result - }) - .slice(1) // skip original path +import { closest } from '../../util/closest' +import { State, Settings } from '../../util/state' import { isCssDoc } from '../../util/css' -import isObject from '../../../util/isObject' +import { State, Settings } from '../../util/state' import { isCssDoc } from '../../util/css' -import { closest } from '../../util/closest' - ) - } import { State, Settings } from '../../util/state' -import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' -import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' import { State, Settings } from '../../util/state' -import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' +import { isCssDoc } from '../../util/css' import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' - let parentPath = [...base, ...keys.slice(0, keys.length - 1)] -import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' +import { State, Settings } from '../../util/state' import { isCssDoc } from '../../util/css' -import { State, Settings } from '../../util/state' import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' - if (isObject(parentValue)) { - let closestValidKey = closest( - keys[keys.length - 1], +import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' -import isObject from '../../../util/isObject' - (key) => validateConfigPath(state, [...parentPath, key]).isValid - ) -import { findAll, indexToPosition } from '../../util/find' import { State, Settings } from '../../util/state' - if (closestValidKey) { -import { findAll, indexToPosition } from '../../util/find' import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' -import { findAll, indexToPosition } from '../../util/find' +import { State, Settings } from '../../util/state' import { isCssDoc } from '../../util/css' - ) +import { isCssDoc } from '../../util/css' -import { findAll, indexToPosition } from '../../util/find' +function pathToString(path: string | string[]): string { import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' - } - } else { - let altPath = findAlternativePath() - if (altPath) { - return { -import { stringToPath } from '../../util/stringToPath' import { State, Settings } from '../../util/state' - reason: `${reason} Did you mean '${pathToString(altPath)}'?`, suggestions: [pathToString(altPath)], +import { State, Settings } from '../../util/state' } - } + +import { State, Settings } from '../../util/state' } import { State, Settings } from '../../util/state' -import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' return { +import { State, Settings } from '../../util/state' isValid: false, +import { State, Settings } from '../../util/state' reason, +import { State, Settings } from '../../util/state' suggestions, - } -import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' + if (cur.includes('.')) return `${acc}[${cur}]` - if ( +import { State, Settings } from '../../util/state' !( +import { State, Settings } from '../../util/state' typeof value === 'string' || +import { State, Settings } from '../../util/state' typeof value === 'number' || +import { State, Settings } from '../../util/state' value instanceof String || +import { State, Settings } from '../../util/state' value instanceof Number || +import { State, Settings } from '../../util/state' Array.isArray(value) +import { State, Settings } from '../../util/state' import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' -import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' +import { State, Settings } from '../../util/state' ) { +import { State, Settings } from '../../util/state' let reason = `'${pathToString( + +import { State, Settings } from '../../util/state' path +import { State, Settings } from '../../util/state' )}' was found but does not resolve to a string.` import { State, Settings } from '../../util/state' -import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' if (isObject(value)) { +import { State, Settings } from '../../util/state' let validKeys = Object.keys(value).filter( +import { State, Settings } from '../../util/state' (key) => validateConfigPath(state, [...keys, key], base).isValid -import { findAll, indexToPosition } from '../../util/find' import { State, Settings } from '../../util/state' if (validKeys.length) { - suggestions.push( +import { State, Settings } from '../../util/state' ...validKeys.map((validKey) => pathToString([...keys, validKey])) - ) +import { State, Settings } from '../../util/state' reason += ` Did you mean something like '${suggestions[0]}'?` - } - } - return { - isValid: false, - reason, -import { stringToPath } from '../../util/stringToPath' +import { State, Settings } from '../../util/state' import { closest } from '../../util/closest' import { stringToPath } from '../../util/stringToPath' -import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' - } import { State, Settings } from '../../util/state' -import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' - // The value resolves successfully, but we need to check that there // 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' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { State, Settings } from '../../util/state' -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { isCssDoc } from '../../util/css' -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { findAll, indexToPosition } from '../../util/find' -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { stringToPath } from '../../util/stringToPath' -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import isObject from '../../../util/isObject' -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 { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { absoluteRange } from '../../util/absoluteRange' - } + } -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { combinations } from '../../util/combinations' -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' const dlv = require('dlv') -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' - } - } -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' function pathToString(path: string | string[]): string { -import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' - -import { State, Settings } from '../../util/state' if (typeof path === 'string') return path -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' return path.reduce((acc, cur, i) => { -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' if (i === 0) return cur -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' if (cur.includes('.')) return `${acc}[${cur}]` -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' return `${acc}.${cur}` -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' }, '') - } - } +function validateConfigPath( import { State, Settings } from '../../util/state' -import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' - return { - isValid: false, - reason, -import { State, Settings } from '../../util/state' import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' -import { State, Settings } from '../../util/state' - } - } - -import { State, Settings } from '../../util/state' function validateConfigPath( -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' state: State, -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' path: string | string[], +function validateConfigPath( import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' -import { State, Settings } from '../../util/state' +): - -import { State, Settings } from '../../util/state' import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' -import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' +import isObject from '../../../util/isObject' - state: State, + } -import { State, Settings } from '../../util/state' import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' -import { findAll, indexToPosition } from '../../util/find' -import { State, Settings } from '../../util/state' | { isValid: true; value: any } -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' | { isValid: false; reason: string; suggestions: string[] } { import { State, Settings } from '../../util/state' +import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' let keys = Array.isArray(path) ? path : stringToPath(path) -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' let value = dlv(state.config, [...base, ...keys]) - -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' let suggestions: string[] = [] - +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { State, Settings } from '../../util/state' -import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' - +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' -import { State, Settings } from '../../util/state' +function validateConfigPath( import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' -import { isCssDoc } from '../../util/css' -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' -import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' -import { State, Settings } from '../../util/state' import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' -import { findAll, indexToPosition } from '../../util/find' - if (!boundaries) return [] - ranges.push(...boundaries.css) +function validateConfigPath( import { getLanguageBoundaries } from '../../util/getLanguageBoundaries' - -import { State, Settings } from '../../util/state' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' -import { closest } from '../../util/closest' -import { State, Settings } from '../../util/state' import { isCssDoc } from '../../util/css' +import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver' +import isObject from '../../../util/isObject' -import { State, Settings } from '../../util/state' +import { stringToPath } from '../../util/stringToPath' import { isCssDoc } from '../../util/css' -import { State, Settings } from '../../util/state' - /(?\s|^)(?config|theme)\((?['"])(?[^)]+)\k\)/g, + } import { State, Settings } from '../../util/state' -import { isCssDoc } from '../../util/css' import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types' +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) - - if (result.isValid === true) { return null } @@ -295,10 +244,9 @@ severity: severity === 'error' ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning, -import { State, Settings } from '../../util/state' + state: State, import { findAll, indexToPosition } from '../../util/find' -import isObject from '../../../util/isObject' - suggestions: result.suggestions, + suggestions, }) }) }) diff --git a/src/lsp/util/combinations.ts b/src/lsp/util/combinations.ts deleted file mode 100644 index 2c9868b207b01b60cc0789b800058285257e187a..0000000000000000000000000000000000000000 --- a/src/lsp/util/combinations.ts +++ /dev/null @@ -1,13 +0,0 @@ -export function combinations(str: string): string[] { - let fn = function (active: string, rest: string, a: string[]) { - if (!active && !rest) return - if (!rest) { - a.push(active) - } else { - fn(active + rest[0], rest.slice(1), a) - fn(active, rest.slice(1), a) - } - return a - } - return fn('', str, []) -} diff --git a/src/lsp/util/getClassNameAtPosition.ts b/src/lsp/util/getClassNameAtPosition.ts index 7418b2f157723967380453978a082e42fdb9ce49..083832ca5e8b2707a1405fdbcd83f6c163e18f65 100644 --- a/src/lsp/util/getClassNameAtPosition.ts +++ b/src/lsp/util/getClassNameAtPosition.ts @@ -1,5 +1,4 @@ import { State } from './state' -import { combinations } from './combinations' const dlv = require('dlv') export function getClassNameParts(state: State, className: string): string[] { @@ -42,3 +41,17 @@ } return false }) } + +function combinations(str: string): string[] { + let fn = function (active: string, rest: string, a: string[]) { + if (!active && !rest) return + if (!rest) { + a.push(active) + } else { + fn(active + rest[0], rest.slice(1), a) + fn(active, rest.slice(1), a) + } + return a + } + return fn('', str, []) +}