improve support for tailwindcss v2
parent
0cce870c13
commit
2c05f5df3a
File diff suppressed because it is too large
Load Diff
|
@ -5,15 +5,15 @@
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"author": "Brad Cornes <hello@bradley.dev>",
|
"author": "Brad Cornes <hello@bradley.dev>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "0.4.3",
|
"version": "0.5.0",
|
||||||
"homepage": "https://github.com/tailwindcss/intellisense",
|
"homepage": "https://github.com/tailwindlabs/tailwindcss-intellisense",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/tailwindcss/intellisense/issues",
|
"url": "https://github.com/tailwindlabs/tailwindcss-intellisense/issues",
|
||||||
"email": "hello@bradley.dev"
|
"email": "hello@bradley.dev"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/tailwindcss/intellisense.git"
|
"url": "https://github.com/tailwindlabs/tailwindcss-intellisense.git"
|
||||||
},
|
},
|
||||||
"publisher": "bradlc",
|
"publisher": "bradlc",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
@ -177,6 +177,7 @@
|
||||||
"@types/node": "^13.9.3",
|
"@types/node": "^13.9.3",
|
||||||
"@types/vscode": "^1.32.0",
|
"@types/vscode": "^1.32.0",
|
||||||
"@zeit/ncc": "^0.22.0",
|
"@zeit/ncc": "^0.22.0",
|
||||||
|
"bufferutil": "^4.0.2",
|
||||||
"callsite": "^1.0.0",
|
"callsite": "^1.0.0",
|
||||||
"chokidar": "^3.3.1",
|
"chokidar": "^3.3.1",
|
||||||
"debounce": "^1.2.0",
|
"debounce": "^1.2.0",
|
||||||
|
@ -196,11 +197,12 @@
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"semver": "^7.3.2",
|
"semver": "^7.3.2",
|
||||||
"stack-trace": "0.0.10",
|
"stack-trace": "0.0.10",
|
||||||
"tailwindcss-language-service": "0.0.3",
|
"tailwindcss-language-service": "0.0.4",
|
||||||
"terser": "^4.6.12",
|
"terser": "^4.6.12",
|
||||||
"tiny-invariant": "^1.1.0",
|
"tiny-invariant": "^1.1.0",
|
||||||
"tslint": "^5.16.0",
|
"tslint": "^5.16.0",
|
||||||
"typescript": "^3.8.3",
|
"typescript": "^3.8.3",
|
||||||
|
"utf-8-validate": "^5.0.3",
|
||||||
"vsce": "^1.76.1",
|
"vsce": "^1.76.1",
|
||||||
"vscode-languageclient": "^6.1.3",
|
"vscode-languageclient": "^6.1.3",
|
||||||
"vscode-languageserver": "^6.1.1",
|
"vscode-languageserver": "^6.1.1",
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import selectorParser from 'postcss-selector-parser'
|
import selectorParser from 'postcss-selector-parser'
|
||||||
import fs from 'fs'
|
|
||||||
import path from 'path'
|
|
||||||
import dset from 'dset'
|
import dset from 'dset'
|
||||||
import dlv from 'dlv'
|
import dlv from 'dlv'
|
||||||
|
|
||||||
|
@ -83,48 +81,43 @@ async function process(groups) {
|
||||||
const contextKeys = baseKeys.slice(0, baseKeys.length - 1)
|
const contextKeys = baseKeys.slice(0, baseKeys.length - 1)
|
||||||
const index = []
|
const index = []
|
||||||
|
|
||||||
const existing = dlv(tree, baseKeys)
|
const existing = dlv(tree, [...baseKeys, '__info'])
|
||||||
if (typeof existing !== 'undefined') {
|
if (typeof existing !== 'undefined') {
|
||||||
if (Array.isArray(existing)) {
|
if (Array.isArray(existing)) {
|
||||||
const scopeIndex = existing.findIndex(
|
|
||||||
(x) =>
|
|
||||||
x.__scope === classNames[i].scope &&
|
|
||||||
arraysEqual(existing.__context, context)
|
|
||||||
)
|
|
||||||
if (scopeIndex > -1) {
|
|
||||||
keys.unshift(scopeIndex)
|
|
||||||
index.push(scopeIndex)
|
|
||||||
} else {
|
|
||||||
keys.unshift(existing.length)
|
|
||||||
index.push(existing.length)
|
index.push(existing.length)
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (
|
dset(tree, [...baseKeys, '__info'], [existing])
|
||||||
existing.__scope !== classNames[i].scope ||
|
|
||||||
!arraysEqual(existing.__context, context)
|
|
||||||
) {
|
|
||||||
dset(tree, baseKeys, [existing])
|
|
||||||
keys.unshift(1)
|
|
||||||
index.push(1)
|
index.push(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (classNames[i].__rule) {
|
if (classNames[i].__rule) {
|
||||||
dset(tree, [...baseKeys, ...index, '__rule'], true)
|
dset(tree, [...baseKeys, '__info', ...index, '__rule'], true)
|
||||||
dset(tree, [...baseKeys, ...index, '__source'], group.source)
|
|
||||||
|
|
||||||
dsetEach(tree, [...baseKeys, ...index], decls)
|
|
||||||
}
|
|
||||||
dset(tree, [...baseKeys, ...index, '__pseudo'], classNames[i].__pseudo)
|
|
||||||
dset(tree, [...baseKeys, ...index, '__scope'], classNames[i].scope)
|
|
||||||
dset(
|
dset(
|
||||||
tree,
|
tree,
|
||||||
[...baseKeys, ...index, '__context'],
|
[...baseKeys, '__info', ...index, '__source'],
|
||||||
|
group.source
|
||||||
|
)
|
||||||
|
|
||||||
|
dsetEach(tree, [...baseKeys, '__info', ...index], decls)
|
||||||
|
}
|
||||||
|
dset(
|
||||||
|
tree,
|
||||||
|
[...baseKeys, '__info', ...index, '__pseudo'],
|
||||||
|
classNames[i].__pseudo
|
||||||
|
)
|
||||||
|
dset(
|
||||||
|
tree,
|
||||||
|
[...baseKeys, '__info', ...index, '__scope'],
|
||||||
|
classNames[i].scope
|
||||||
|
)
|
||||||
|
dset(
|
||||||
|
tree,
|
||||||
|
[...baseKeys, '__info', ...index, '__context'],
|
||||||
context.concat([]).reverse()
|
context.concat([]).reverse()
|
||||||
)
|
)
|
||||||
|
|
||||||
// common context
|
// common context
|
||||||
context.push(...classNames[i].__pseudo)
|
context.push(...classNames[i].__pseudo.map((x) => `&${x}`))
|
||||||
|
|
||||||
for (let i = 0; i < contextKeys.length; i++) {
|
for (let i = 0; i < contextKeys.length; i++) {
|
||||||
if (typeof commonContext[contextKeys[i]] === 'undefined') {
|
if (typeof commonContext[contextKeys[i]] === 'undefined') {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
{
|
{
|
||||||
"name": "tailwindcss-language-service",
|
"name": "tailwindcss-language-service",
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ctrl/tinycolor": "^3.1.4",
|
"@ctrl/tinycolor": "^3.1.4",
|
||||||
"@types/moo": "^0.5.3",
|
"@types/moo": "^0.5.3",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "tailwindcss-language-service",
|
"name": "tailwindcss-language-service",
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
|
|
|
@ -57,7 +57,10 @@ function completionsFromClassList(
|
||||||
for (let i = parts.length - 1; i > 0; i--) {
|
for (let i = parts.length - 1; i > 0; i--) {
|
||||||
let keys = parts.slice(0, i).filter(Boolean)
|
let keys = parts.slice(0, i).filter(Boolean)
|
||||||
subset = dlv(state.classNames.classNames, keys)
|
subset = dlv(state.classNames.classNames, keys)
|
||||||
if (typeof subset !== 'undefined' && typeof subset.__rule === 'undefined') {
|
if (
|
||||||
|
typeof subset !== 'undefined' &&
|
||||||
|
typeof dlv(subset, ['__info', '__rule']) === 'undefined'
|
||||||
|
) {
|
||||||
isSubset = true
|
isSubset = true
|
||||||
subsetKey = keys
|
subsetKey = keys
|
||||||
replacementRange = {
|
replacementRange = {
|
||||||
|
@ -74,21 +77,45 @@ function completionsFromClassList(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// console.log(Object.keys(isSubset ? subset : state.classNames.classNames))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isIncomplete: false,
|
isIncomplete: false,
|
||||||
items: Object.keys(isSubset ? subset : state.classNames.classNames)
|
items: Object.keys(isSubset ? subset : state.classNames.classNames)
|
||||||
|
.filter((k) => k !== '__info')
|
||||||
|
.filter((className) => isContextItem(state, [...subsetKey, className]))
|
||||||
|
.map(
|
||||||
|
(className, index): CompletionItem => {
|
||||||
|
return {
|
||||||
|
label: className + sep,
|
||||||
|
kind: 9,
|
||||||
|
documentation: null,
|
||||||
|
command: {
|
||||||
|
title: '',
|
||||||
|
command: 'editor.action.triggerSuggest',
|
||||||
|
},
|
||||||
|
sortText: '-' + naturalExpand(index),
|
||||||
|
data: [...subsetKey, className],
|
||||||
|
textEdit: {
|
||||||
|
newText: className + sep,
|
||||||
|
range: replacementRange,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.concat(
|
||||||
|
Object.keys(isSubset ? subset : state.classNames.classNames)
|
||||||
|
.filter((className) =>
|
||||||
|
dlv(state.classNames.classNames, [
|
||||||
|
...subsetKey,
|
||||||
|
className,
|
||||||
|
'__info',
|
||||||
|
])
|
||||||
|
)
|
||||||
.map((className, index) => {
|
.map((className, index) => {
|
||||||
let label = className
|
|
||||||
let kind: CompletionItemKind = 21
|
let kind: CompletionItemKind = 21
|
||||||
let documentation: string = null
|
let documentation: string = null
|
||||||
let command: any
|
|
||||||
let sortText = naturalExpand(index)
|
|
||||||
if (isContextItem(state, [...subsetKey, className])) {
|
|
||||||
kind = 9
|
|
||||||
command = { title: '', command: 'editor.action.triggerSuggest' }
|
|
||||||
label += sep
|
|
||||||
sortText = '-' + sortText // move to top
|
|
||||||
} else {
|
|
||||||
const color = getColor(state, [className])
|
const color = getColor(state, [className])
|
||||||
if (color !== null) {
|
if (color !== null) {
|
||||||
kind = 16
|
kind = 16
|
||||||
|
@ -96,28 +123,29 @@ function completionsFromClassList(
|
||||||
documentation = color.toRgbString()
|
documentation = color.toRgbString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const item = {
|
return {
|
||||||
label,
|
label: className,
|
||||||
kind,
|
kind,
|
||||||
documentation,
|
documentation,
|
||||||
command,
|
sortText: naturalExpand(index),
|
||||||
sortText,
|
|
||||||
data: [...subsetKey, className],
|
data: [...subsetKey, className],
|
||||||
textEdit: {
|
textEdit: {
|
||||||
newText: label,
|
newText: className,
|
||||||
range: replacementRange,
|
range: replacementRange,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filter && !filter(item)) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return item
|
|
||||||
})
|
})
|
||||||
.filter((item) => item !== null),
|
)
|
||||||
|
.filter((item) => {
|
||||||
|
if (item === null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (filter && !filter(item)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +227,10 @@ function provideAtApplyCompletions(
|
||||||
},
|
},
|
||||||
(item) => {
|
(item) => {
|
||||||
if (item.kind === 9) {
|
if (item.kind === 9) {
|
||||||
return semver.gte(state.version, '2.0.0-alpha.1') || flagEnabled(state, 'applyComplexClasses')
|
return (
|
||||||
|
semver.gte(state.version, '2.0.0-alpha.1') ||
|
||||||
|
flagEnabled(state, 'applyComplexClasses')
|
||||||
|
)
|
||||||
}
|
}
|
||||||
let validated = validateApply(state, item.data)
|
let validated = validateApply(state, item.data)
|
||||||
return validated !== null && validated.isApplyable === true
|
return validated !== null && validated.isApplyable === true
|
||||||
|
@ -708,8 +739,8 @@ export function resolveCompletionItem(
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
const className = dlv(state.classNames.classNames, item.data)
|
const className = dlv(state.classNames.classNames, [...item.data, '__info'])
|
||||||
if (isContextItem(state, item.data)) {
|
if (item.kind === 9) {
|
||||||
item.detail = state.classNames.context[
|
item.detail = state.classNames.context[
|
||||||
item.data[item.data.length - 1]
|
item.data[item.data.length - 1]
|
||||||
].join(', ')
|
].join(', ')
|
||||||
|
@ -729,13 +760,19 @@ export function resolveCompletionItem(
|
||||||
}
|
}
|
||||||
|
|
||||||
function isContextItem(state: State, keys: string[]): boolean {
|
function isContextItem(state: State, keys: string[]): boolean {
|
||||||
const item = dlv(state.classNames.classNames, keys)
|
const item = dlv(state.classNames.classNames, [keys])
|
||||||
return Boolean(
|
|
||||||
isObject(item) &&
|
if (!isObject(item)) {
|
||||||
!item.__rule &&
|
return false
|
||||||
!Array.isArray(item) &&
|
}
|
||||||
state.classNames.context[keys[keys.length - 1]]
|
if (!state.classNames.context[keys[keys.length - 1]]) {
|
||||||
)
|
return false
|
||||||
|
}
|
||||||
|
if (Object.keys(item).filter((x) => x !== '__info').length > 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return isObject(item.__info) && !item.__info.__rule
|
||||||
}
|
}
|
||||||
|
|
||||||
function stringifyDecls(obj: any): string {
|
function stringifyDecls(obj: any): string {
|
||||||
|
|
|
@ -89,13 +89,17 @@ function provideClassNameHover(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const css = stringifyCss(
|
||||||
|
className.className,
|
||||||
|
dlv(state.classNames.classNames, [...parts, '__info'])
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!css) return null
|
||||||
|
|
||||||
return {
|
return {
|
||||||
contents: {
|
contents: {
|
||||||
language: 'css',
|
language: 'css',
|
||||||
value: stringifyCss(
|
value: css,
|
||||||
className.className,
|
|
||||||
dlv(state.classNames.classNames, parts)
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
range: className.range,
|
range: className.range,
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ export function getColor(
|
||||||
state: State,
|
state: State,
|
||||||
keys: string[]
|
keys: string[]
|
||||||
): TinyColor | string | null {
|
): TinyColor | string | null {
|
||||||
const item = dlv(state.classNames.classNames, keys)
|
const item = dlv(state.classNames.classNames, [...keys, '__info'])
|
||||||
if (!item.__rule) return null
|
if (!item.__rule) return null
|
||||||
const props = Object.keys(removeMeta(item))
|
const props = Object.keys(removeMeta(item))
|
||||||
if (props.length === 0) return null
|
if (props.length === 0) return null
|
||||||
|
|
|
@ -8,8 +8,9 @@ export function getClassNameParts(state: State, className: string): string[] {
|
||||||
let parts: string[] = className.split(separator)
|
let parts: string[] = className.split(separator)
|
||||||
|
|
||||||
if (parts.length === 1) {
|
if (parts.length === 1) {
|
||||||
return dlv(state.classNames.classNames, [className, '__rule']) === true ||
|
return dlv(state.classNames.classNames, [className, '__info', '__rule']) ===
|
||||||
Array.isArray(dlv(state.classNames.classNames, [className]))
|
true ||
|
||||||
|
Array.isArray(dlv(state.classNames.classNames, [className, '__info']))
|
||||||
? [className]
|
? [className]
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
|
@ -34,8 +35,8 @@ export function getClassNameParts(state: State, className: string): string[] {
|
||||||
|
|
||||||
return possibilities.find((key) => {
|
return possibilities.find((key) => {
|
||||||
if (
|
if (
|
||||||
dlv(state.classNames.classNames, [...key, '__rule']) === true ||
|
dlv(state.classNames.classNames, [...key, '__info', '__rule']) === true ||
|
||||||
Array.isArray(dlv(state.classNames.classNames, [...key]))
|
Array.isArray(dlv(state.classNames.classNames, [...key, '__info']))
|
||||||
) {
|
) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ export function getClassNameDecls(
|
||||||
const parts = getClassNameParts(state, className)
|
const parts = getClassNameParts(state, className)
|
||||||
if (!parts) return null
|
if (!parts) return null
|
||||||
|
|
||||||
const info = dlv(state.classNames.classNames, parts)
|
const info = dlv(state.classNames.classNames, [...parts, '__info'])
|
||||||
|
|
||||||
if (Array.isArray(info)) {
|
if (Array.isArray(info)) {
|
||||||
return info.map(removeMeta)
|
return info.map(removeMeta)
|
||||||
|
|
|
@ -10,7 +10,7 @@ export function getClassNameMeta(
|
||||||
? classNameOrParts
|
? classNameOrParts
|
||||||
: getClassNameParts(state, classNameOrParts)
|
: getClassNameParts(state, classNameOrParts)
|
||||||
if (!parts) return null
|
if (!parts) return null
|
||||||
const info = dlv(state.classNames.classNames, parts)
|
const info = dlv(state.classNames.classNames, [...parts, '__info'])
|
||||||
|
|
||||||
if (Array.isArray(info)) {
|
if (Array.isArray(info)) {
|
||||||
return info.map((i) => ({
|
return info.map((i) => ({
|
||||||
|
|
Loading…
Reference in New Issue