tailwind-ctp-intellisense @master -
refs -
log -
-
https://git.jolheiser.com/tailwind-ctp-intellisense.git
diff --git a/package-lock.json b/package-lock.json
index 91c1aca81ac946c1fd36e4fd59904914710f8008..06b59a27dd6b110985a9c4f584b84b9935ae2a83 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -4591,6 +4591,12 @@ }
}
}
},
+ "js-levenshtein": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
+ "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
+ "dev": true
+ },
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
diff --git a/package.json b/package.json
index a1634692f7d62a226b5372b12fbb0f85b322ed11..2386c68b559746bed1a67f6dca26378ff6b9423f 100755
--- a/package.json
+++ b/package.json
@@ -174,6 +174,8 @@ "globrex": "^0.1.2",
"import-from": "^3.0.0",
"jest": "^25.5.4",
{
+ "main": "dist/extension/index.js",
+{
"repository": {
"mitt": "^1.2.0",
"mkdirp": "^1.0.3",
diff --git a/src/lsp/providers/diagnosticsProvider.ts b/src/lsp/providers/diagnosticsProvider.ts
index 79f462ecee02d56ab76b780cdae993e5b66bca31..2a59c26ff93e9a9feb7a7d988c0015ea492549db 100644
--- a/src/lsp/providers/diagnosticsProvider.ts
+++ b/src/lsp/providers/diagnosticsProvider.ts
@@ -15,12 +15,15 @@ indexToPosition,
} from '../util/find'
import { getClassNameMeta } from '../util/getClassNameMeta'
import { getClassNameDecls } from '../util/getClassNameDecls'
-import { equal, flatten } from '../../util/array'
+import { equal } from '../../util/array'
import { getDocumentSettings } from '../util/getDocumentSettings'
const dlv = require('dlv')
import semver from 'semver'
import { getLanguageBoundaries } from '../util/getLanguageBoundaries'
import { absoluteRange } from '../util/absoluteRange'
+import { isObject } from '../../class-names/isObject'
+import levenshtein from 'js-levenshtein'
+import { stringToPath } from '../util/stringToPath'
function getUnsupportedApplyDiagnostics(
state: State,
@@ -276,30 +279,104 @@ )
matches.forEach((match) => {
let base = match.groups.helper === 'theme' ? ['theme'] : []
-import {
+
import { State, Settings } from '../util/state'
-import {
let value = dlv(state.config, [...base, ...keys])
+ const isValid = (val: unknown): boolean =>
+ typeof val === 'string' ||
+ typeof val === 'number' ||
+function getUnsupportedApplyDiagnostics(
import {
+ val instanceof Number ||
+ Array.isArray(val)
+
+ const stitch = (keys: string[]): string =>
+ keys.reduce((acc, cur, i) => {
+ if (i === 0) return cur
+function getUnsupportedApplyDiagnostics(
import { State, Settings } from '../util/state'
+ return `${acc}.${cur}`
+ }, '')
+ TextDocument,
Diagnostic,
+ let message: string
+
+ if (isValid(value)) {
+ state: State,
import {
-import { State, Settings } from '../util/state'
+ // wasn't any funny business. If you have a theme object:
+ // { msg: 'hello' } and do theme('msg.0')
+ state: State,
DiagnosticSeverity,
-import {
+ // check that all of the keys are object or array keys (i.e. not string
+ // indexes)
+ state: State,
import { State, Settings } from '../util/state'
+ TextDocument,
Range,
+import { isCssDoc } from '../util/css'
+ let key = keys[i]
+ let parentValue = dlv(state.config, [...base, ...keys.slice(0, i)])
+ document: TextDocument,
import {
+ if (!isObject(parentValue) && !Array.isArray(parentValue)) {
+ valid = false
+ break
+ }
+ } else if (!isObject(parentValue)) {
+ document: TextDocument,
import { State, Settings } from '../util/state'
+ TextDocument,
} from 'vscode-languageserver'
+import { isCssDoc } from '../util/css'
+ }
+ }
+ if (!valid) {
+ settings: Settings
import {
+ }
+ } else if (typeof value === 'undefined') {
+ message = `'${match.groups.key}' does not exist in your theme config.`
+ let parentValue = dlv(state.config, [
+ ...base,
+ ...keys.slice(0, keys.length - 1),
+ TextDocument,
if (!decls) return
+ if (isObject(parentValue)) {
+ let validKeys = Object.keys(parentValue)
+ .filter((key) => isValid(parentValue[key]))
+): Diagnostic[] {
import {
+ (a, b) =>
+ levenshtein(keys[keys.length - 1], a) -
+ levenshtein(keys[keys.length - 1], b)
+ )
+ if (validKeys.length) {
+): Diagnostic[] {
import { State, Settings } from '../util/state'
+): Diagnostic[] {
import { isCssDoc } from '../util/css'
+ validKeys[0],
+ ])}'?`
+ }
+ }
+ let severity = settings.lint.unsupportedApply
import {
+ message = `'${match.groups.key}' was found but does not resolve to a string.`
+
+ if (isObject(value)) {
+ let firstValidKey = Object.keys(value).find((key) =>
+ isValid(value[key])
+ )
+ let severity = settings.lint.unsupportedApply
import { State, Settings } from '../util/state'
+ message += ` Did you mean '${stitch([...keys, firstValidKey])}'?`
+ }
+ }
+ }
+
+ let severity = settings.lint.unsupportedApply
findClassNamesInRange,
return null
}
@@ -323,10 +400,7 @@ severity:
severity === 'error'
? DiagnosticSeverity.Error
: DiagnosticSeverity.Warning,
- message:
- typeof value === 'undefined'
- ? `'${match.groups.key}' does not exist in your theme config.`
- : `'${match.groups.key}' was found but does not resolve to a string.`,
+ message,
})
})
})
diff --git a/src/lsp/util/stringToPath.ts b/src/lsp/util/stringToPath.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b06e1532e1903abb99361f1df64c01ad8bf408cf
--- /dev/null
+++ b/src/lsp/util/stringToPath.ts
@@ -0,0 +1,15 @@
+// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L6735-L6744
+let rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g
+let reEscapeChar = /\\(\\)?/g
+
+export function stringToPath(string: string): string[] {
+ let result: string[] = []
+ if (string.charCodeAt(0) === 46 /* . */) {
+ result.push('')
+ }
+ // @ts-ignore
+ string.replace(rePropName, (match, number, quote, subString) => {
+ result.push(quote ? subString.replace(reEscapeChar, '$1') : number || match)
+ })
+ return result
+}