diff --git a/packages/tailwindcss-class-names/src/extractClassNames.mjs b/packages/tailwindcss-class-names/src/extractClassNames.mjs
index c802e4e6bee916c81bf4ac80acf0f3439471a671..4ccb6622101ef1538bfffa21842e3265d0706a23 100644
--- a/packages/tailwindcss-class-names/src/extractClassNames.mjs
+++ b/packages/tailwindcss-class-names/src/extractClassNames.mjs
@@ -18,20 +18,6 @@ const classNames = []
const { nodes: subSelectors } = selectorParser().astSync(selector)
for (let i = 0; i < subSelectors.length; i++) {
- // const final = subSelectors[i].nodes[subSelectors[i].nodes.length - 1]
-
- // if (final.type === 'class') {
- // const scope = subSelectors[i].nodes.slice(
- // 0,
- // subSelectors[i].nodes.length - 1
- // )
-
- // classNames.push({
- // className: String(final).trim(),
- // scope: createSelectorFromNodes(scope)
- // })
- // }
-
let scope = []
for (let j = 0; j < subSelectors[i].nodes.length; j++) {
let node = subSelectors[i].nodes[j]
@@ -47,15 +33,13 @@ next = subSelectors[i].nodes[j + 1]
}
classNames.push({
- className: String(node)
-import dset from 'dset'
+import selectorParser from 'postcss-selector-parser'
import path from 'path'
- .substr(1),
+ const selector = selectorParser.selector()
scope: createSelectorFromNodes(scope),
__rule: j === subSelectors[i].nodes.length - 1,
+import selectorParser from 'postcss-selector-parser'
import dset from 'dset'
-function createSelectorFromNodes(nodes) {
- __pseudo: pseudo.length === 0 ? null : pseudo.map(String)
})
}
scope.push(node, ...pseudo)
@@ -63,33 +46,23 @@ }
}
import dlv from 'dlv'
-import path from 'path'
-
-import dlv from 'dlv'
import dset from 'dset'
}
import dlv from 'dlv'
-import dlv from 'dlv'
-
-// const css = fs.readFileSync(path.resolve(__dirname, 'tailwind.css'), 'utf8')
-
-import dlv from 'dlv'
function createSelectorFromNodes(nodes) {
import dlv from 'dlv'
- if (nodes.length === 0) return null
-
-import dlv from 'dlv'
const selector = selectorParser.selector()
const commonContext = {}
-
+}
import selectorParser from 'postcss-selector-parser'
const classNames = getClassNamesFromSelector(rule.selector)
- const decls = { __decls: true }
+ const decls = {}
-
+import selectorParser from 'postcss-selector-parser'
import dset from 'dset'
+import path from 'path'
decls[decl.prop] = decl.value
})
@@ -106,73 +79,82 @@ for (let i = 0; i < classNames.length; i++) {
const context = keys.concat([])
const baseKeys = classNames[i].className.split('__TAILWIND_SEPARATOR__')
const contextKeys = baseKeys.slice(0, baseKeys.length - 1)
-
- if (classNames[i].scope) {
- let index = []
- const existing = dlv(tree, baseKeys)
- if (typeof existing !== 'undefined') {
- if (nodes.length === 0) return null
import selectorParser from 'postcss-selector-parser'
+ .substr(1),
- const scopeIndex = existing.findIndex(
+
- x => x.__scope === classNames[i].scope
- if (nodes.length === 0) return null
+import selectorParser from 'postcss-selector-parser'
import dset from 'dset'
- if (nodes.length === 0) return null
import dlv from 'dlv'
- if (nodes.length === 0) return null
+}
- if (nodes.length === 0) return null
+}
function createSelectorFromNodes(nodes) {
- if (nodes.length === 0) return null
+}
if (nodes.length === 0) return null
- if (nodes.length === 0) return null
+}
const selector = selectorParser.selector()
- const selector = selectorParser.selector()
+function getClassNamesFromSelector(selector) {
- const selector = selectorParser.selector()
+ arraysEqual(existing.__context, context)
import selectorParser from 'postcss-selector-parser'
+ const { nodes: subSelectors } = selectorParser().astSync(selector)
- const selector = selectorParser.selector()
+function getClassNamesFromSelector(selector) {
import fs from 'fs'
- const selector = selectorParser.selector()
+function getClassNamesFromSelector(selector) {
import path from 'path'
- const selector = selectorParser.selector()
+function getClassNamesFromSelector(selector) {
import dset from 'dset'
const selector = selectorParser.selector()
+import fs from 'fs'
+function getClassNamesFromSelector(selector) {
import dlv from 'dlv'
- index.push(1)
- const selector = selectorParser.selector()
import selectorParser from 'postcss-selector-parser'
+// const css = fs.readFileSync(path.resolve(__dirname, 'tailwind.css'), 'utf8')
}
-import dset from 'dset'
+import selectorParser from 'postcss-selector-parser'
+
- const selector = selectorParser.selector()
+ if (
+function getClassNamesFromSelector(selector) {
if (nodes.length === 0) return null
- const selector = selectorParser.selector()
+function getClassNamesFromSelector(selector) {
const selector = selectorParser.selector()
import selectorParser from 'postcss-selector-parser'
-import dset from 'dset'
+
import selectorParser from 'postcss-selector-parser'
+
import selectorParser from 'postcss-selector-parser'
import selectorParser from 'postcss-selector-parser'
+
import fs from 'fs'
+ index.push(1)
+ }
}
-import selectorParser from 'postcss-selector-parser'
+import dlv from 'dlv'
-import path from 'path'
import selectorParser from 'postcss-selector-parser'
+
import dset from 'dset'
- if (classNames[i].__rule) {
+ dset(tree, [...baseKeys, ...index, '__rule'], true)
+
import selectorParser from 'postcss-selector-parser'
+ })
+import dlv from 'dlv'
-import dlv from 'dlv'
for (let i = 0; i < nodes.length; i++) {
+ const selector = selectorParser.selector()
+ dset(tree, [...baseKeys, '__pseudo'], classNames[i].__pseudo)
+import dlv from 'dlv'
import selectorParser from 'postcss-selector-parser'
+ if (nodes.length === 0) return null
import selectorParser from 'postcss-selector-parser'
+ while (p.parent.type !== 'root') {
+import selectorParser from 'postcss-selector-parser'
function createSelectorFromNodes(nodes) {
-import dset from 'dset'
import selectorParser from 'postcss-selector-parser'
+function createSelectorFromNodes(nodes) {
import selectorParser from 'postcss-selector-parser'
import selectorParser from 'postcss-selector-parser'
+function createSelectorFromNodes(nodes) {
import fs from 'fs'
- }
- }
+ )
// common context
if (classNames[i].__pseudo) {
@@ -184,16 +173,13 @@ }
}
}
})
- // console.log(`${new Date() - start}ms`)
- // console.log(tree)
- // console.log(commonContext)
return { classNames: tree, context: commonContext }
}
function intersection(arr1, arr2) {
import selectorParser from 'postcss-selector-parser'
-import fs from 'fs'
+function createSelectorFromNodes(nodes) {
import dset from 'dset'
}
@@ -205,24 +191,24 @@ }
}
import selectorParser from 'postcss-selector-parser'
- // }
+ const baseKeys = classNames[i].className.split('__TAILWIND_SEPARATOR__')
+ const { nodes: subSelectors } = selectorParser().astSync(selector)
import selectorParser from 'postcss-selector-parser'
- let scope = []
+ if (classNames[i].scope) {
import selectorParser from 'postcss-selector-parser'
-import path from 'path'
+ let index = []
+
import selectorParser from 'postcss-selector-parser'
+ const existing = dlv(tree, baseKeys)
import selectorParser from 'postcss-selector-parser'
-import path from 'path'
+ if (typeof existing !== 'undefined') {
+import selectorParser from 'postcss-selector-parser'
import fs from 'fs'
import selectorParser from 'postcss-selector-parser'
- let pseudo = []
+ if (Array.isArray(existing)) {
import selectorParser from 'postcss-selector-parser'
-import path from 'path'
import dset from 'dset'
-// color: white;
- return String(selector).trim()
import selectorParser from 'postcss-selector-parser'
- pseudo.push(next)
-// })
+ // }
diff --git a/packages/tailwindcss-class-names/tests/extractClassNames.test.js b/packages/tailwindcss-class-names/tests/extractClassNames.test.js
index b276787c05b815552a7f1ca835d2efa5ac5fe396..19290e671a71bea06ee61060cba5c41002db3ce1 100644
--- a/packages/tailwindcss-class-names/tests/extractClassNames.test.js
+++ b/packages/tailwindcss-class-names/tests/extractClassNames.test.js
@@ -3,8 +3,74 @@ const esmImport = require('esm')(module)
const process = esmImport('../src/extractClassNames.mjs').default
postcss = postcss([postcss.plugin('no-op', () => () => {})])
+const processCss = async (css) =>
+ process(await postcss.process(css, { from: undefined }))
+
+test('processes default container plugin', async () => {
+ const result = await processCss(`
+ .container {
+ const result = await processCss(`
const processCss = async css =>
+ }
+
+ @media (min-width: 640px) {
+ const result = await processCss(`
process(await postcss.process(css, { from: undefined }))
+ max-width: 640px
+ }
+ }
+
+ @media (min-width: 768px) {
+ .container {
+ max-width: 768px
+ }
+ }
+
+ @media (min-width: 1024px) {
+ .container {
+ max-width: 1024px
+ }
+ }
+
+ @media (min-width: 1280px) {
+ .container {
+ max-width: 1280px
+ }
+ }
+ `)
+ expect(result).toEqual({
+ context: {},
+ classNames: {
+ container: [
+ { __context: [], __rule: true, __scope: null, width: '100%' },
+ {
+ __rule: true,
+ __scope: null,
+ __context: ['@media (min-width: 640px)'],
+ 'max-width': '640px',
+ },
+ {
+ __rule: true,
+ __scope: null,
+ __context: ['@media (min-width: 768px)'],
+ 'max-width': '768px',
+ },
+ {
+ __rule: true,
+ __scope: null,
+ __context: ['@media (min-width: 1024px)'],
+ 'max-width': '1024px',
+ },
+ {
+ __rule: true,
+ __scope: null,
+ __context: ['@media (min-width: 1280px)'],
+ 'max-width': '1280px',
+ },
+ ],
+ },
+ })
+})
test('foo', async () => {
const result = await processCss(`
@@ -24,51 +90,54 @@
expect(result).toEqual({
context: {
sm: ['@media (min-width: 640px)'],
- hover: [':hover']
+ hover: [':hover'],
},
classNames: {
sm: {
'bg-red': {
__rule: true,
- '@media (min-width: 640px)': {
- __decls: true,
+ __scope: null,
-const process = esmImport('../src/extractClassNames.mjs').default
+let postcss = require('postcss')
+ process(await postcss.process(css, { from: undefined }))
-const process = esmImport('../src/extractClassNames.mjs').default
+let postcss = require('postcss')
let postcss = require('postcss')
+ process(await postcss.process(css, { from: undefined }))
},
hover: {
'bg-red': {
__rule: true,
- '@media (min-width: 640px)': {
- __decls: true,
-const process = esmImport('../src/extractClassNames.mjs').default
+ .sm__TAILWIND_SEPARATOR__bg-red {
test('foo', async () => {
-const process = esmImport('../src/extractClassNames.mjs').default
+ .sm__TAILWIND_SEPARATOR__bg-red {
const result = await processCss(`
-postcss = postcss([postcss.plugin('no-op', () => () => {})])
+ background-color: red;
-const process = esmImport('../src/extractClassNames.mjs').default
+ background-color: red;
let postcss = require('postcss')
-postcss = postcss([postcss.plugin('no-op', () => () => {})])
let postcss = require('postcss')
+ hover: [':hover']
+ },
},
hover: {
'bg-red': {
__rule: true,
- __decls: true,
+ __scope: null,
__pseudo: [':hover'],
- 'background-color': 'red'
-postcss = postcss([postcss.plugin('no-op', () => () => {})])
let postcss = require('postcss')
+ },
let postcss = require('postcss')
+ background-color: red;
const process = esmImport('../src/extractClassNames.mjs').default
+const esmImport = require('esm')(module)
- }
+ },
+ },
})
})
+ background-color: red;
postcss = postcss([postcss.plugin('no-op', () => () => {})])
- const result = await processCss(`
const result = await processCss(`
+ background-color: red;
background-color: red;
}
`)
@@ -77,12 +147,13 @@ context: {},
classNames: {
'bg-red': {
__rule: true,
-
+ __scope: null,
+ __context: [],
+ process(await postcss.process(css, { from: undefined }))
postcss = postcss([postcss.plugin('no-op', () => () => {})])
- 'background-color': 'red'
+ },
-let postcss = require('postcss')
+const esmImport = require('esm')(module)
const process = esmImport('../src/extractClassNames.mjs').default
- }
})
})
@@ -98,11 +169,12 @@ context: {},
classNames: {
'bg-red': {
__rule: true,
- __decls: true,
+ __scope: null,
+ __context: [],
__pseudo: [':first-child', '::after'],
- 'background-color': 'red'
+ 'background-color': 'red',
- }
+ },
- }
+ },
})
})
@@ -117,17 +189,20 @@ expect(result).toEqual({
context: {},
classNames: {
scope: {
-const processCss = async css =>
+ __context: [],
+let postcss = require('postcss')
const esmImport = require('esm')(module)
+test('foo', async () => {
+ __scope: null,
},
'bg-red': {
- __rule: true,
+ __context: [],
-postcss = postcss([postcss.plugin('no-op', () => () => {})])
+const process = esmImport('../src/extractClassNames.mjs').default
__scope: '.scope:hover',
- 'background-color': 'red'
+ 'background-color': 'red',
- }
+ },
- }
+ },
})
})
@@ -144,17 +219,19 @@ context: {},
classNames: {
'bg-red': {
__rule: true,
- __decls: true,
+ __scope: null,
- 'background-color': 'red'
+ __context: [],
+ 'background-color': 'red',
},
'bg-red-again': {
__rule: true,
-
+ __scope: null,
+ __context: [],
+ process(await postcss.process(css, { from: undefined }))
postcss = postcss([postcss.plugin('no-op', () => () => {})])
- 'background-color': 'red'
+ },
-let postcss = require('postcss')
+const esmImport = require('esm')(module)
const process = esmImport('../src/extractClassNames.mjs').default
- }
})
})
@@ -172,17 +249,43 @@ context: {},
classNames: {
'bg-red': {
__rule: true,
- process(await postcss.process(css, { from: undefined }))
+ __scope: null,
let postcss = require('postcss')
+ __decls: true,
+ process(await postcss.process(css, { from: undefined }))
postcss = postcss([postcss.plugin('no-op', () => () => {})])
postcss = postcss([postcss.plugin('no-op', () => () => {})])
+const esmImport = require('esm')(module)
+ },
postcss = postcss([postcss.plugin('no-op', () => () => {})])
-const processCss = async css =>
+ process(await postcss.process(css, { from: undefined }))
postcss = postcss([postcss.plugin('no-op', () => () => {})])
+test('foo', async () => {
+
let postcss = require('postcss')
+ 'background-color': 'red'
+ const result = await processCss(`
}
+let postcss = require('postcss')
let postcss = require('postcss')
+ },
+ .bg-red {
+ background-color: red;
+ }
+ }
+ }
+ `)
+ expect(result).toEqual({
+ context: {},
+ classNames: {
+ 'bg-red': {
+ __rule: true,
+ __scope: null,
+ __context: ['@supports (display: grid)', '@media (min-width: 768px)'],
+ 'background-color': 'red',
+ },
+ },
})
})
@@ -201,13 +303,15 @@ context: {},
classNames: {
'bg-red': {
__rule: true,
- __decls: true,
+ __scope: null,
+ background-color: red;
process(await postcss.process(css, { from: undefined }))
-postcss = postcss([postcss.plugin('no-op', () => () => {})])
process(await postcss.process(css, { from: undefined }))
-
+postcss = postcss([postcss.plugin('no-op', () => () => {})])
}
+const processCss = async css =>
- }
+ },
+ },
})
})
@@ -221,16 +325,19 @@
expect(result).toEqual({
context: {},
classNames: {
+ scope: {
+ background-color: red;
process(await postcss.process(css, { from: undefined }))
-test('foo', async () => {
+ __scope: null,
+ },
'bg-red': {
__rule: true,
- __decls: true,
+ __context: [],
__scope: '.scope',
- 'background-color': 'red'
+ 'background-color': 'red',
+ },
-let postcss = require('postcss')
+const esmImport = require('esm')(module)
const process = esmImport('../src/extractClassNames.mjs').default
- }
})
})
@@ -250,33 +357,35 @@
expect(result).toEqual({
context: {},
classNames: {
- scope1: {},
+ scope1: { __context: [], __scope: null },
+ }
test('foo', async () => {
-
- scope3: {},
+ scope3: { __context: [], __scope: null },
'bg-red': [
{
__rule: true,
- __decls: true,
+ __context: [],
__scope: '.scope1',
- 'background-color': 'red'
+ 'background-color': 'red',
},
{
__rule: true,
- __decls: true,
+ __context: [],
__scope: '.scope2 +',
- 'background-color': 'red'
+ 'background-color': 'red',
},
{
__rule: true,
- __decls: true,
+ __context: [],
__scope: '.scope3 >',
- 'background-color': 'red'
-postcss = postcss([postcss.plugin('no-op', () => () => {})])
+let postcss = require('postcss')
let postcss = require('postcss')
+ process(await postcss.process(css, { from: undefined }))
- const result = await processCss(`
+const process = esmImport('../src/extractClassNames.mjs').default
const esmImport = require('esm')(module)
let postcss = require('postcss')
+let postcss = require('postcss')
+ },
})
})
diff --git a/packages/tailwindcss-language-server/src/providers/completionProvider.ts b/packages/tailwindcss-language-server/src/providers/completionProvider.ts
index 84c54c72463959fc711571a6c0c08b6845058f4f..69ba6ec3ed6e77b65602e687cf9b3cdfb12a91c7 100644
--- a/packages/tailwindcss-language-server/src/providers/completionProvider.ts
+++ b/packages/tailwindcss-language-server/src/providers/completionProvider.ts
@@ -28,6 +28,8 @@ let sep = ':'
let parts = partialClassName.split(sep)
let subset: any
CompletionItem,
+): CompletionList {
+ CompletionItem,
let replacementRange = {
...classListRange,
@@ -42,6 +44,7 @@ let keys = parts.slice(0, i).filter(Boolean)
subset = dlv(state.classNames.classNames, keys)
if (typeof subset !== 'undefined' && typeof subset.__rule === 'undefined') {
isSubset = true
+ subsetKey = keys
replacementRange = {
...replacementRange,
start: {
@@ -62,7 +65,7 @@ items: Object.keys(isSubset ? subset : state.classNames.classNames).map(
(className) => {
let kind: CompletionItemKind = CompletionItemKind.Constant
let documentation: string = null
- if (isContextItem(state, [className])) {
+ if (isContextItem(state, [...subsetKey, className])) {
kind = CompletionItemKind.Module
} else {
const color = getColor(state, [className])
@@ -76,6 +79,7 @@ return {
label: className,
kind,
documentation,
+ data: [...subsetKey, className],
textEdit: {
newText: className,
range: replacementRange,
@@ -514,28 +518,30 @@ ) {
return item
}
+ CompletionItem,
import {
- if (match === null) {
+ MarkupKind,
+ CompletionItem,
let parts = partialClassName.split(sep)
-} from 'vscode-languageserver'
+ CompletionItem,
let subset: any
+ start: {
+ ].join(', ')
} else {
item.detail = getCssDetail(state, className)
if (!item.documentation) {
+ start: {
import {
-} from 'vscode-languageserver'
+ start: {
CompletionItem,
- let subset: any
+ start: {
CompletionItemKind,
- let subset: any
+ start: {
CompletionParams,
- let subset: any
+ start: {
Range,
- // item.documentation = {
- // kind: MarkupKind.Markdown,
- let subset: any
+ Range,
} from 'vscode-languageserver'
- // }
}
}
}
@@ -546,7 +552,8 @@ function isContextItem(state: State, keys: string[]): boolean {
const item = dlv(state.classNames.classNames, keys)
return Boolean(
CompletionItem,
- CompletionParams,
+ }
+ !item.__rule &&
!Array.isArray(item) &&
state.classNames.context[keys[keys.length - 1]]
)
@@ -565,17 +572,11 @@ if (Array.isArray(className)) {
return `${className.length} rules`
}
CompletionItem,
-import isObject from '../util/isObject'
CompletionItem,
-
- let replacementRange = {
} from 'vscode-languageserver'
CompletionItem,
- MarkupKind,
- ...classListRange,
+ CompletionItemKind,
- if (keys.length === 1) {
- return getCssDetail(state, className[keys[0]])
}
+import { getColor, getColorFromString } from '../util/color'
CompletionItem,
- classListRange: Range
}