Skip to content

Commit 568e078

Browse files
author
Brad Cornes
committed
prevent crash on config error
1 parent 850ad5c commit 568e078

File tree

3 files changed

+96
-54
lines changed

3 files changed

+96
-54
lines changed

packages/tailwindcss-class-names/src/index.js

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function glob(pattern, options = {}) {
1717
let g = new nodeGlob.Glob(pattern, options)
1818
let matches = []
1919
let max = dlv(options, 'max', Infinity)
20-
g.on('match', match => {
20+
g.on('match', (match) => {
2121
matches.push(path.resolve(options.cwd || process.cwd(), match))
2222
if (matches.length === max) {
2323
g.abort()
@@ -38,39 +38,35 @@ function arraysEqual(arr1, arr2) {
3838
)
3939
}
4040

41+
const CONFIG_GLOB =
42+
'**/{tailwind,tailwind.config,tailwind-config,.tailwindrc}.js'
43+
4144
export default async function getClassNames(
4245
cwd = process.cwd(),
4346
{ onChange = () => {} } = {}
4447
) {
45-
let configPath
46-
let postcss
47-
let tailwindcss
48-
let version
48+
async function run() {
49+
let configPath
50+
let postcss
51+
let tailwindcss
52+
let version
4953

50-
try {
51-
configPath = await glob(
52-
'**/{tailwind,tailwind.config,tailwind-config,.tailwindrc}.js',
53-
{
54-
cwd,
55-
ignore: '**/node_modules/**',
56-
max: 1
57-
}
58-
)
54+
configPath = await glob(CONFIG_GLOB, {
55+
cwd,
56+
ignore: '**/node_modules/**',
57+
max: 1,
58+
})
5959
invariant(configPath.length === 1, 'No Tailwind CSS config found.')
6060
configPath = configPath[0]
6161
postcss = importFrom(cwd, 'postcss')
6262
tailwindcss = importFrom(cwd, 'tailwindcss')
6363
version = importFrom(cwd, 'tailwindcss/package.json').version
64-
} catch (_) {
65-
return null
66-
}
6764

68-
async function run() {
6965
const sepLocation = semver.gte(version, '0.99.0')
7066
? ['separator']
7167
: ['options', 'separator']
7268
let userSeperator
73-
let hook = Hook(configPath, exports => {
69+
let hook = Hook(configPath, (exports) => {
7470
userSeperator = dlv(exports, sepLocation)
7571
dset(exports, sepLocation, '__TAILWIND_SEPARATOR__')
7672
return exports
@@ -97,35 +93,48 @@ export default async function getClassNames(
9793
}
9894

9995
return {
96+
configPath,
10097
config: resolveConfig({ cwd, config }),
10198
separator: typeof userSeperator === 'undefined' ? ':' : userSeperator,
10299
classNames: await extractClassNames(ast),
103-
dependencies: [configPath, ...hook.deps],
100+
dependencies: hook.deps,
104101
plugins: getPlugins(config),
105-
variants: getVariants({ config, version, postcss })
102+
variants: getVariants({ config, version, postcss }),
106103
}
107104
}
108105

109106
let watcher
110-
function watch(files) {
107+
function watch(files = []) {
111108
if (watcher) watcher.close()
112109
watcher = chokidar
113-
.watch(files)
110+
.watch([CONFIG_GLOB, ...files])
114111
.on('change', handleChange)
115112
.on('unlink', handleChange)
116113
}
117114

118-
let result = await run()
119-
watch(result.dependencies)
120-
121115
async function handleChange() {
122-
const prevDeps = result.dependencies
123-
result = await run()
116+
const prevDeps = result ? result.dependencies : []
117+
try {
118+
result = await run()
119+
} catch (_) {
120+
onChange(null)
121+
return
122+
}
124123
if (!arraysEqual(prevDeps, result.dependencies)) {
125124
watch(result.dependencies)
126125
}
127126
onChange(result)
128127
}
129128

129+
let result
130+
try {
131+
result = await run()
132+
} catch (_) {
133+
watch()
134+
return null
135+
}
136+
137+
watch(result.dependencies)
138+
130139
return result
131140
}

packages/tailwindcss-language-server/src/server.ts

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
DidChangeConfigurationNotification,
1919
} from 'vscode-languageserver'
2020
import getTailwindState from 'tailwindcss-class-names'
21-
import { State, Settings } from './util/state'
21+
import { State, Settings, EditorState } from './util/state'
2222
import {
2323
provideCompletions,
2424
resolveCompletionItem,
@@ -27,7 +27,7 @@ import { provideHover } from './providers/hoverProvider'
2727
import { URI } from 'vscode-uri'
2828
import { getDocumentSettings } from './util/getDocumentSettings'
2929

30-
let state: State = null
30+
let state: State = { enabled: false }
3131
let connection = createConnection(ProposedFeatures.all)
3232
let documents = new TextDocuments()
3333
let workspaceFolder: string | null
@@ -46,28 +46,43 @@ documents.listen(connection)
4646

4747
connection.onInitialize(
4848
async (params: InitializeParams): Promise<InitializeResult> => {
49-
state = await getTailwindState(
49+
const capabilities = params.capabilities
50+
51+
const editorState: EditorState = {
52+
connection,
53+
documents,
54+
documentSettings,
55+
globalSettings,
56+
capabilities: {
57+
configuration:
58+
capabilities.workspace && !!capabilities.workspace.configuration,
59+
},
60+
}
61+
62+
const tailwindState = await getTailwindState(
5063
params.rootPath || URI.parse(params.rootUri).path,
5164
{
5265
onChange: (newState: State): void => {
53-
state = { ...newState, editor: state.editor }
54-
connection.sendNotification('tailwindcss/configUpdated', [
55-
state.dependencies[0],
56-
state.config,
57-
state.plugins,
58-
])
66+
if (newState) {
67+
state = { ...newState, enabled: true, editor: editorState }
68+
connection.sendNotification('tailwindcss/configUpdated', [
69+
state.configPath,
70+
state.config,
71+
state.plugins,
72+
])
73+
} else {
74+
state = { enabled: false, editor: editorState }
75+
// TODO
76+
// connection.sendNotification('tailwindcss/configUpdated', [null])
77+
}
5978
},
6079
}
6180
)
6281

63-
const capabilities = params.capabilities
64-
65-
state.editor = {
66-
connection,
67-
documents,
68-
documentSettings,
69-
globalSettings,
70-
capabilities: { configuration: capabilities.workspace && !!capabilities.workspace.configuration },
82+
if (tailwindState) {
83+
state = { enabled: true, editor: editorState, ...tailwindState }
84+
} else {
85+
state = { enabled: false, editor: editorState }
7186
}
7287

7388
return {
@@ -79,7 +94,20 @@ connection.onInitialize(
7994
textDocumentSync: documents.syncKind,
8095
completionProvider: {
8196
resolveProvider: true,
82-
triggerCharacters: ['"', "'", '`', ' ', '.', '[', state.separator],
97+
triggerCharacters: [
98+
// class attributes
99+
'"',
100+
"'",
101+
'`',
102+
// between class names
103+
' ',
104+
// @apply and emmet-style
105+
'.',
106+
// config/theme helper
107+
'[',
108+
// TODO: restart server if separater changes?
109+
typeof state.separator === 'undefined' ? ':' : state.separator,
110+
],
83111
},
84112
hoverProvider: true,
85113
},
@@ -97,7 +125,7 @@ connection.onInitialized &&
97125
}
98126

99127
connection.sendNotification('tailwindcss/configUpdated', [
100-
state.dependencies[0],
128+
state.configPath,
101129
state.config,
102130
state.plugins,
103131
])
@@ -120,18 +148,21 @@ connection.onDidChangeConfiguration((change) => {
120148

121149
connection.onCompletion(
122150
(params: CompletionParams): Promise<CompletionList> => {
151+
if (!state.enabled) return null
123152
return provideCompletions(state, params)
124153
}
125154
)
126155

127156
connection.onCompletionResolve(
128157
(item: CompletionItem): CompletionItem => {
158+
if (!state.enabled) return null
129159
return resolveCompletionItem(state, item)
130160
}
131161
)
132162

133163
connection.onHover(
134164
(params: TextDocumentPositionParams): Hover => {
165+
if (!state.enabled) return null
135166
return provideHover(state, params)
136167
}
137168
)

packages/tailwindcss-language-server/src/util/state.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ export type Settings = {
2828
}
2929

3030
export type State = null | {
31-
config: any
32-
separator: string
33-
plugins: any[]
34-
variants: string[]
35-
classNames: ClassNames
36-
dependencies: string[]
37-
editor: EditorState
31+
enabled: boolean
32+
configPath?: string
33+
config?: any
34+
separator?: string
35+
plugins?: any[]
36+
variants?: string[]
37+
classNames?: ClassNames
38+
dependencies?: string[]
39+
editor?: EditorState
3840
}
3941

4042
export type DocumentClassList = {

0 commit comments

Comments
 (0)