initial refactor
|
@ -1,7 +1,2 @@
|
|||
dist
|
||||
node_modules
|
||||
.vscode-test/
|
||||
.vsix
|
||||
*.vsix
|
||||
.DS_Store
|
||||
.rts2_cache_cjs
|
||||
dist
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"version": "0.1.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": ["--extensionDevelopmentPath=${workspaceRoot}"],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outFiles": ["${workspaceRoot}/dist/**/*.js"]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
*
|
||||
*/**
|
||||
**/.DS_Store
|
||||
|
||||
!package.json
|
||||
!README.md
|
||||
!dist/index.js
|
||||
!dist/server/index.js
|
||||
!resources/**/*
|
31
CHANGELOG.md
|
@ -1,31 +0,0 @@
|
|||
# Changelog
|
||||
|
||||
## 0.2.0
|
||||
|
||||
- Support for Tailwind v1 via LSP 🎉
|
||||
- Support for multi-root workspaces
|
||||
- Support for reason, slim, edge, njk, svelte files (thanks [@nhducit](https://github.com/nhducit), [@wayness](https://github.com/wayness), [@mattwaler](https://github.com/mattwaler), [@guillaumebriday](https://github.com/guillaumebriday))
|
||||
- Support for non-default Tailwind separators
|
||||
- Add `@variants` completions
|
||||
- Better support for dynamic class(Name) values in JSX
|
||||
- Disables Emmet support by default. This can be enabled via the `tailwindCSS.emmetCompletions` setting
|
||||
|
||||
## 0.1.16
|
||||
|
||||
- add support for [EEx templates](https://hexdocs.pm/phoenix/templates.html), via [vscode-elixir](https://marketplace.visualstudio.com/items?itemName=mjmcloug.vscode-elixir) – thanks [@dhc02](https://github.com/dhc02)
|
||||
|
||||
## 0.1.15
|
||||
|
||||
- add support for [leaf](https://github.com/vapor/leaf) files (#16)
|
||||
|
||||
## 0.1.10
|
||||
|
||||
- add syntax definitions for `@apply` and `config()`:
|
||||
|
||||
**Before:**
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/2615508/44740655-ed02ee80-aaf2-11e8-8d3e-1075e0801fd7.png" alt="Syntax highlighting before update" width="345" />
|
||||
|
||||
**After:**
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/2615508/44740606-cba20280-aaf2-11e8-92b8-42adbfe54c61.png" alt="Syntax highlighting after update" width="345" />
|
50
README.md
|
@ -1,50 +0,0 @@
|
|||
# Tailwind CSS IntelliSense
|
||||
|
||||
> [Tailwind CSS](https://tailwindcss.com/) class name completion for VS Code
|
||||
|
||||
**[Get it from the VS Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
|
||||
|
||||
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/img/html.gif" alt="HTML autocompletion" width="750">
|
||||
|
||||
## Features
|
||||
|
||||
Tailwind CSS IntelliSense uses your projects Tailwind installation and configuration to provide suggestions as you type.
|
||||
|
||||
It also includes features that improve the overall Tailwind experience, including improved syntax highlighting, and CSS previews.
|
||||
|
||||
### HTML (including Vue, JSX, PHP etc.)
|
||||
|
||||
- [Class name suggestions, including support for Emmet syntax](#class-name-suggestions-including-support-for-emmet-syntax)
|
||||
- Suggestions include color previews where applicable, for example for text and background colors
|
||||
- They also include a preview of the actual CSS for that class name
|
||||
- [CSS preview when hovering over class names](#css-preview-when-hovering-over-class-names)
|
||||
|
||||
### CSS
|
||||
|
||||
- [Suggestions when using `@apply` and `config()`](#suggestions-when-using-apply-and-config)
|
||||
- Suggestions when using the `@screen` directive
|
||||
- [Improves syntax highlighting when using `@apply` and `config()`](#improves-syntax-highlighting-when-using-apply-and-config)
|
||||
|
||||
## Examples
|
||||
|
||||
#### Class name suggestions, including support for Emmet syntax
|
||||
|
||||
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/img/html.gif" alt="HTML autocompletion" width="750">
|
||||
|
||||
#### CSS preview when hovering over class names
|
||||
|
||||
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/img/html-hover.gif" alt="HTML hover preview" width="750">
|
||||
|
||||
#### Suggestions when using `@apply` and `config()`
|
||||
|
||||
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/img/css.gif" alt="CSS autocompletion" width="750">
|
||||
|
||||
#### Improves syntax highlighting when using `@apply` and `config()`
|
||||
|
||||
Before:
|
||||
|
||||
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/img/css-highlighting-before.png" alt="CSS syntax highlighting before" width="400">
|
||||
|
||||
After:
|
||||
|
||||
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/img/css-highlighting-after.png" alt="CSS syntax highlighting after" width="400">
|
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 32 KiB |
BIN
img/css.gif
Before Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 592 KiB |
BIN
img/html.gif
Before Width: | Height: | Size: 2.8 MiB |
Before Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 1.3 MiB |
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "independent"
|
||||
}
|
83
package.json
|
@ -1,84 +1,11 @@
|
|||
{
|
||||
"name": "vscode-tailwindcss",
|
||||
"displayName": "Tailwind CSS IntelliSense",
|
||||
"description": "Tailwind CSS class name completion",
|
||||
"version": "0.2.0",
|
||||
"publisher": "bradlc",
|
||||
"engines": {
|
||||
"vscode": "^1.30.0"
|
||||
},
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"galleryBanner": {
|
||||
"color": "#f1f5f8"
|
||||
},
|
||||
"icon": "resources/icon.png",
|
||||
"keywords": [
|
||||
"tailwind",
|
||||
"tailwindcss",
|
||||
"css",
|
||||
"intellisense",
|
||||
"autocomplete",
|
||||
"vscode"
|
||||
],
|
||||
"activationEvents": [
|
||||
"workspaceContains:**/{tailwind,tailwind.config,tailwind-config,.tailwindrc}.js"
|
||||
],
|
||||
"main": "./dist/index.js",
|
||||
"contributes": {
|
||||
"grammars": [
|
||||
{
|
||||
"scopeName": "source.css.tailwind",
|
||||
"path": "./resources/syntaxes/tailwind.tmLanguage.json",
|
||||
"injectTo": [
|
||||
"source.css",
|
||||
"source.css.scss",
|
||||
"source.css.less",
|
||||
"source.css.postcss"
|
||||
]
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
"type": "object",
|
||||
"title": "Tailwind CSS IntelliSense configuration",
|
||||
"properties": {
|
||||
"tailwindCSS.emmetCompletions": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable class name completions for Emmet-style syntax"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"preview": true,
|
||||
"name": "root",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run build",
|
||||
"build": "ncc build src/index.ts --out dist --minify --external vscode && ncc build src/server.ts --out dist/server --minify",
|
||||
"watch": "ncc build src/index.ts --out dist --watch --external vscode",
|
||||
"start": "npm run watch",
|
||||
"postinstall": "node ./node_modules/vscode/bin/install",
|
||||
"test": "npm run build && node ./node_modules/vscode/bin/test"
|
||||
},
|
||||
"author": "Brad Cornes <hello@bradley.dev>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/bradlc/vscode-tailwindcss/blob/master/README.md",
|
||||
"bugs": {
|
||||
"url": "https://github.com/bradlc/vscode-tailwindcss/issues",
|
||||
"email": "hello@bradley.dev"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bradlc/vscode-tailwindcss.git"
|
||||
"bootstrap": "lerna bootstrap",
|
||||
"dev": "lerna run --parallel dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^11.13.5",
|
||||
"@zeit/ncc": "^0.17.4",
|
||||
"color": "^3.1.0",
|
||||
"dlv": "^1.1.2",
|
||||
"tailwindcss-language-server": "0.0.1",
|
||||
"tmp": "0.0.33",
|
||||
"vscode": "^1.1.26",
|
||||
"vscode-languageclient": "^5.2.1"
|
||||
"lerna": "^3.20.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "tailwindcss-class-names",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"dev": "ncc build src/index.js --watch",
|
||||
"build": "ncc build src/index.js --minify"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Brad Cornes <hello@bradley.dev>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chokidar": "^3.3.1",
|
||||
"dlv": "^1.1.3",
|
||||
"dset": "^2.0.1",
|
||||
"glob": "^7.1.6",
|
||||
"import-from": "^3.0.0",
|
||||
"pkg-up": "^3.1.0",
|
||||
"postcss-selector-parser": "^6.0.2",
|
||||
"semver": "^7.1.3",
|
||||
"stack-trace": "0.0.10",
|
||||
"tiny-invariant": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@zeit/ncc": "^0.21.1",
|
||||
"esm": "^3.2.25",
|
||||
"jest": "^25.1.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
import selectorParser from 'postcss-selector-parser'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import dset from 'dset'
|
||||
import dlv from 'dlv'
|
||||
|
||||
function createSelectorFromNodes(nodes) {
|
||||
if (nodes.length === 0) return null
|
||||
const selector = selectorParser.selector()
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
selector.append(nodes[i])
|
||||
}
|
||||
return String(selector).trim()
|
||||
}
|
||||
|
||||
function getClassNamesFromSelector(selector) {
|
||||
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]
|
||||
let pseudo = []
|
||||
|
||||
if (node.type === 'class') {
|
||||
let next = subSelectors[i].nodes[j + 1]
|
||||
|
||||
while (next && next.type === 'pseudo') {
|
||||
pseudo.push(next)
|
||||
j++
|
||||
next = subSelectors[i].nodes[j + 1]
|
||||
}
|
||||
|
||||
classNames.push({
|
||||
className: String(node)
|
||||
.trim()
|
||||
.substr(1),
|
||||
scope: createSelectorFromNodes(scope),
|
||||
__rule: j === subSelectors[i].nodes.length - 1,
|
||||
// __pseudo: createSelectorFromNodes(pseudo)
|
||||
__pseudo: pseudo.length === 0 ? null : pseudo.map(String)
|
||||
})
|
||||
}
|
||||
scope.push(node, ...pseudo)
|
||||
}
|
||||
}
|
||||
|
||||
// console.log(classNames)
|
||||
|
||||
return classNames
|
||||
}
|
||||
|
||||
// console.log(getClassNamesFromSelector('h1, h2, h3, .foo .bar, .baz'))
|
||||
|
||||
// const css = fs.readFileSync(path.resolve(__dirname, 'tailwind.css'), 'utf8')
|
||||
|
||||
async function process(ast) {
|
||||
const start = new Date()
|
||||
|
||||
const tree = {}
|
||||
const commonContext = {}
|
||||
|
||||
ast.root.walkRules(rule => {
|
||||
const classNames = getClassNamesFromSelector(rule.selector)
|
||||
|
||||
const decls = { __decls: true }
|
||||
rule.walkDecls(decl => {
|
||||
decls[decl.prop] = decl.value
|
||||
})
|
||||
|
||||
let p = rule
|
||||
const keys = []
|
||||
while (p.parent.type !== 'root') {
|
||||
p = p.parent
|
||||
if (p.type === 'atrule') {
|
||||
keys.push(`@${p.name} ${p.params}`)
|
||||
}
|
||||
}
|
||||
|
||||
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 (Array.isArray(existing)) {
|
||||
const scopeIndex = existing.findIndex(
|
||||
x => x.__scope === classNames[i].scope
|
||||
)
|
||||
if (scopeIndex > -1) {
|
||||
keys.unshift(scopeIndex)
|
||||
index.push(scopeIndex)
|
||||
} else {
|
||||
keys.unshift(existing.length)
|
||||
index.push(existing.length)
|
||||
}
|
||||
} else {
|
||||
if (existing.__scope !== classNames[i].scope) {
|
||||
dset(tree, baseKeys, [existing])
|
||||
keys.unshift(1)
|
||||
index.push(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (classNames[i].__rule) {
|
||||
dset(tree, [...baseKeys, ...index, '__rule'], true)
|
||||
dsetEach(tree, [...baseKeys, ...keys], decls)
|
||||
}
|
||||
if (classNames[i].__pseudo) {
|
||||
dset(tree, [...baseKeys, ...keys, '__pseudo'], classNames[i].__pseudo)
|
||||
}
|
||||
dset(tree, [...baseKeys, ...index, '__scope'], classNames[i].scope)
|
||||
} else {
|
||||
if (classNames[i].__rule) {
|
||||
dset(tree, [...baseKeys, '__rule'], true)
|
||||
dsetEach(tree, [...baseKeys, ...keys], decls)
|
||||
} else {
|
||||
dset(tree, [...baseKeys, ...keys], {})
|
||||
}
|
||||
if (classNames[i].__pseudo) {
|
||||
dset(tree, [...baseKeys, ...keys, '__pseudo'], classNames[i].__pseudo)
|
||||
}
|
||||
}
|
||||
|
||||
// common context
|
||||
if (classNames[i].__pseudo) {
|
||||
context.push(...classNames[i].__pseudo)
|
||||
}
|
||||
|
||||
for (let i = 0; i < contextKeys.length; i++) {
|
||||
if (typeof commonContext[contextKeys[i]] === 'undefined') {
|
||||
commonContext[contextKeys[i]] = context
|
||||
} else {
|
||||
commonContext[contextKeys[i]] = intersection(
|
||||
commonContext[contextKeys[i]],
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
// console.log(`${new Date() - start}ms`)
|
||||
// console.log(tree)
|
||||
// console.log(commonContext)
|
||||
|
||||
return { classNames: tree, context: commonContext }
|
||||
}
|
||||
|
||||
function intersection(arr1, arr2) {
|
||||
return arr1.filter(value => arr2.indexOf(value) !== -1)
|
||||
}
|
||||
|
||||
function dsetEach(obj, keys, values) {
|
||||
const k = Object.keys(values)
|
||||
for (let i = 0; i < k.length; i++) {
|
||||
dset(obj, [...keys, k[i]], values[k[i]])
|
||||
}
|
||||
}
|
||||
|
||||
export default process
|
||||
|
||||
// process(`
|
||||
// .bg-red {
|
||||
// background-color: red;
|
||||
// }
|
||||
// .bg-red {
|
||||
// color: white;
|
||||
// }`).then(x => {
|
||||
// console.log(x)
|
||||
// })
|
|
@ -0,0 +1,71 @@
|
|||
import * as path from 'path'
|
||||
import stackTrace from 'stack-trace'
|
||||
import pkgUp from 'pkg-up'
|
||||
|
||||
function isObject(variable) {
|
||||
return Object.prototype.toString.call(variable) === '[object Object]'
|
||||
}
|
||||
|
||||
export default function getPlugins(config) {
|
||||
let plugins = config.plugins
|
||||
|
||||
if (!Array.isArray(plugins)) {
|
||||
return []
|
||||
}
|
||||
|
||||
return plugins.map(plugin => {
|
||||
let pluginConfig = plugin.config
|
||||
if (!isObject(pluginConfig)) {
|
||||
pluginConfig = {}
|
||||
}
|
||||
|
||||
let contributes = {
|
||||
theme: isObject(pluginConfig.theme)
|
||||
? Object.keys(pluginConfig.theme)
|
||||
: [],
|
||||
variants: isObject(pluginConfig.variants)
|
||||
? Object.keys(pluginConfig.variants)
|
||||
: []
|
||||
}
|
||||
|
||||
const fn = plugin.handler || plugin
|
||||
const fnName =
|
||||
typeof fn.name === 'string' && fn.name !== 'handler' && fn.name !== ''
|
||||
? fn.name
|
||||
: null
|
||||
|
||||
try {
|
||||
fn()
|
||||
} catch (e) {
|
||||
const trace = stackTrace.parse(e)
|
||||
if (trace.length === 0)
|
||||
return {
|
||||
name: fnName
|
||||
}
|
||||
const file = trace[0].fileName
|
||||
const dir = path.dirname(file)
|
||||
let pkg = pkgUp.sync({ cwd: dir })
|
||||
if (!pkg)
|
||||
return {
|
||||
name: fnName
|
||||
}
|
||||
try {
|
||||
pkg = __non_webpack_require__(pkg)
|
||||
} catch (_) {
|
||||
return {
|
||||
name: fnName
|
||||
}
|
||||
}
|
||||
if (pkg.name && path.resolve(dir, pkg.main || 'index.js') === file) {
|
||||
return {
|
||||
name: pkg.name,
|
||||
homepage: pkg.homepage,
|
||||
contributes
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: fnName
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import semver from 'semver'
|
||||
import dlv from 'dlv'
|
||||
|
||||
export default function getVariants({ config, version, postcss }) {
|
||||
let variants = ['responsive', 'hover']
|
||||
semver.gte(version, '0.3.0') && variants.push('focus', 'group-hover')
|
||||
semver.gte(version, '0.5.0') && variants.push('active')
|
||||
semver.gte(version, '0.7.0') && variants.push('focus-within')
|
||||
semver.gte(version, '1.1.0') &&
|
||||
variants.push('first', 'last', 'odd', 'even', 'disabled', 'visited')
|
||||
|
||||
let plugins = config.plugins
|
||||
if (!Array.isArray(plugins)) {
|
||||
plugins = []
|
||||
}
|
||||
plugins.forEach(plugin => {
|
||||
try {
|
||||
;(plugin.handler || plugin)({
|
||||
addUtilities: () => {},
|
||||
addComponents: () => {},
|
||||
addBase: () => {},
|
||||
addVariant: name => {
|
||||
variants.push(name)
|
||||
},
|
||||
e: x => x,
|
||||
prefix: x => x,
|
||||
theme: (path, defaultValue) =>
|
||||
dlv(config, `theme.${path}`, defaultValue),
|
||||
variants: () => [],
|
||||
config: (path, defaultValue) => dlv(config, path, defaultValue),
|
||||
postcss
|
||||
})
|
||||
} catch (_) {
|
||||
console.error(_)
|
||||
}
|
||||
})
|
||||
|
||||
return variants
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* Adapted from: https://github.com/elastic/require-in-the-middle
|
||||
*/
|
||||
import Module from 'module'
|
||||
|
||||
export default function Hook(find, onrequire) {
|
||||
if (!(this instanceof Hook)) return new Hook(find, onrequire)
|
||||
|
||||
if (typeof Module._resolveFilename !== 'function') {
|
||||
throw new Error(
|
||||
`Error: Expected Module._resolveFilename to be a function (was: ${typeof Module._resolveFilename}) - aborting!`
|
||||
)
|
||||
}
|
||||
|
||||
this.cache = {}
|
||||
this.deps = []
|
||||
this._unhooked = false
|
||||
this._origRequire = Module.prototype.require
|
||||
|
||||
let self = this
|
||||
let patching = {}
|
||||
|
||||
this._require = Module.prototype.require = function(request) {
|
||||
if (self._unhooked) {
|
||||
// if the patched require function could not be removed because
|
||||
// someone else patched it after it was patched here, we just
|
||||
// abort and pass the request onwards to the original require
|
||||
return self._origRequire.apply(this, arguments)
|
||||
}
|
||||
|
||||
let filename = Module._resolveFilename(request, this)
|
||||
|
||||
// return known patched modules immediately
|
||||
if (self.cache.hasOwnProperty(filename)) {
|
||||
return self.cache[filename]
|
||||
}
|
||||
|
||||
// Check if this module has a patcher in-progress already.
|
||||
// Otherwise, mark this module as patching in-progress.
|
||||
let patched = patching[filename]
|
||||
if (!patched) {
|
||||
patching[filename] = true
|
||||
}
|
||||
|
||||
let exports = self._origRequire.apply(this, arguments)
|
||||
|
||||
if (filename !== find) {
|
||||
if (self._watching) {
|
||||
self.deps.push(filename)
|
||||
}
|
||||
return exports
|
||||
}
|
||||
|
||||
// If it's already patched, just return it as-is.
|
||||
if (patched) return exports
|
||||
|
||||
// The module has already been loaded,
|
||||
// so the patching mark can be cleaned up.
|
||||
delete patching[filename]
|
||||
|
||||
// only call onrequire the first time a module is loaded
|
||||
if (!self.cache.hasOwnProperty(filename)) {
|
||||
// ensure that the cache entry is assigned a value before calling
|
||||
// onrequire, in case calling onrequire requires the same module.
|
||||
self.cache[filename] = exports
|
||||
self.cache[filename] = onrequire(exports)
|
||||
}
|
||||
|
||||
return self.cache[filename]
|
||||
}
|
||||
}
|
||||
|
||||
Hook.prototype.unhook = function() {
|
||||
this._unhooked = true
|
||||
if (this._require === Module.prototype.require) {
|
||||
Module.prototype.require = this._origRequire
|
||||
}
|
||||
}
|
||||
|
||||
Hook.prototype.watch = function() {
|
||||
this._watching = true
|
||||
}
|
||||
|
||||
Hook.prototype.unwatch = function() {
|
||||
this._watching = false
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
import extractClassNames from './extractClassNames.mjs'
|
||||
import Hook from './hook.mjs'
|
||||
import dlv from 'dlv'
|
||||
import dset from 'dset'
|
||||
import importFrom from 'import-from'
|
||||
import nodeGlob from 'glob'
|
||||
import * as path from 'path'
|
||||
import chokidar from 'chokidar'
|
||||
import semver from 'semver'
|
||||
import invariant from 'tiny-invariant'
|
||||
import getPlugins from './getPlugins'
|
||||
import getVariants from './getVariants'
|
||||
import resolveConfig from './resolveConfig'
|
||||
|
||||
function glob(pattern, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let g = new nodeGlob.Glob(pattern, options)
|
||||
let matches = []
|
||||
let max = dlv(options, 'max', Infinity)
|
||||
g.on('match', match => {
|
||||
matches.push(path.resolve(options.cwd || process.cwd(), match))
|
||||
if (matches.length === max) {
|
||||
g.abort()
|
||||
resolve(matches)
|
||||
}
|
||||
})
|
||||
g.on('end', () => {
|
||||
resolve(matches)
|
||||
})
|
||||
g.on('error', reject)
|
||||
})
|
||||
}
|
||||
|
||||
function arraysEqual(arr1, arr2) {
|
||||
return JSON.stringify(arr1.sort()) === JSON.stringify(arr2.sort())
|
||||
}
|
||||
|
||||
export default async function getClassNames(
|
||||
cwd = process.cwd(),
|
||||
{ onChange = () => {} } = {}
|
||||
) {
|
||||
let configPath
|
||||
let postcss
|
||||
let tailwindcss
|
||||
let version
|
||||
|
||||
try {
|
||||
configPath = await glob(
|
||||
'**/{tailwind,tailwind.config,tailwind-config,.tailwindrc}.js',
|
||||
{
|
||||
cwd,
|
||||
ignore: '**/node_modules/**',
|
||||
max: 1
|
||||
}
|
||||
)
|
||||
invariant(configPath.length === 1, 'No Tailwind CSS config found.')
|
||||
configPath = configPath[0]
|
||||
postcss = importFrom(cwd, 'postcss')
|
||||
tailwindcss = importFrom(cwd, 'tailwindcss')
|
||||
version = importFrom(cwd, 'tailwindcss/package.json').version
|
||||
} catch (_) {
|
||||
return null
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const sepLocation = semver.gte(version, '0.99.0')
|
||||
? ['separator']
|
||||
: ['options', 'separator']
|
||||
let userSeperator
|
||||
let hook = Hook(configPath, exports => {
|
||||
userSeperator = dlv(exports, sepLocation)
|
||||
dset(exports, sepLocation, '__TAILWIND_SEPARATOR__')
|
||||
return exports
|
||||
})
|
||||
|
||||
hook.watch()
|
||||
const config = __non_webpack_require__(configPath)
|
||||
hook.unwatch()
|
||||
|
||||
const ast = await postcss([tailwindcss(configPath)]).process(
|
||||
`
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
`,
|
||||
{ from: undefined }
|
||||
)
|
||||
|
||||
hook.unhook()
|
||||
|
||||
if (typeof userSeperator !== 'undefined') {
|
||||
dset(config, sepLocation, userSeperator)
|
||||
} else {
|
||||
delete config[sepLocation]
|
||||
}
|
||||
|
||||
return {
|
||||
config: resolveConfig({ cwd, config }),
|
||||
separator: typeof userSeperator === 'undefined' ? ':' : userSeperator,
|
||||
classNames: await extractClassNames(ast),
|
||||
dependencies: [configPath, ...hook.deps],
|
||||
plugins: getPlugins(config),
|
||||
variants: getVariants({ config, version, postcss })
|
||||
}
|
||||
}
|
||||
|
||||
let watcher
|
||||
function watch(files) {
|
||||
if (watcher) watcher.close()
|
||||
watcher = chokidar
|
||||
.watch(files)
|
||||
.on('change', handleChange)
|
||||
.on('unlink', handleChange)
|
||||
}
|
||||
|
||||
let result = await run()
|
||||
watch(result.dependencies)
|
||||
|
||||
async function handleChange() {
|
||||
const prevDeps = result.dependencies
|
||||
result = await run()
|
||||
if (!arraysEqual(prevDeps, result.dependencies)) {
|
||||
watch(result.dependencies)
|
||||
}
|
||||
onChange(result)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
import importFrom from 'import-from'
|
||||
import * as path from 'path'
|
||||
|
||||
export default function resolveConfig({ cwd, config }) {
|
||||
let resolve = x => x
|
||||
|
||||
if (typeof config === 'string') {
|
||||
if (!cwd) {
|
||||
cwd = path.dirname(config)
|
||||
}
|
||||
config = __non_webpack_require__(config)
|
||||
}
|
||||
|
||||
try {
|
||||
resolve = importFrom(cwd, 'tailwindcss/resolveConfig.js')
|
||||
} catch (_) {
|
||||
try {
|
||||
const resolveConfig = importFrom(
|
||||
cwd,
|
||||
'tailwindcss/lib/util/resolveConfig.js'
|
||||
)
|
||||
const defaultConfig = importFrom(
|
||||
cwd,
|
||||
'tailwindcss/stubs/defaultConfig.stub.js'
|
||||
)
|
||||
resolve = config => resolveConfig([config, defaultConfig])
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return resolve(config)
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
let postcss = require('postcss')
|
||||
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('foo', async () => {
|
||||
const result = await processCss(`
|
||||
@media (min-width: 640px) {
|
||||
.sm__TAILWIND_SEPARATOR__bg-red {
|
||||
background-color: red;
|
||||
}
|
||||
.sm__TAILWIND_SEPARATOR__hover__TAILWIND_SEPARATOR__bg-red:hover {
|
||||
background-color: red;
|
||||
}
|
||||
}
|
||||
.hover__TAILWIND_SEPARATOR__bg-red:hover {
|
||||
background-color: red;
|
||||
}
|
||||
`)
|
||||
|
||||
expect(result).toEqual({
|
||||
context: {
|
||||
sm: ['@media (min-width: 640px)'],
|
||||
hover: [':hover']
|
||||
},
|
||||
classNames: {
|
||||
sm: {
|
||||
'bg-red': {
|
||||
__rule: true,
|
||||
'@media (min-width: 640px)': {
|
||||
__decls: true,
|
||||
'background-color': 'red'
|
||||
}
|
||||
},
|
||||
hover: {
|
||||
'bg-red': {
|
||||
__rule: true,
|
||||
'@media (min-width: 640px)': {
|
||||
__decls: true,
|
||||
__pseudo: [':hover'],
|
||||
'background-color': 'red'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
hover: {
|
||||
'bg-red': {
|
||||
__rule: true,
|
||||
__decls: true,
|
||||
__pseudo: [':hover'],
|
||||
'background-color': 'red'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('processes basic css', async () => {
|
||||
const result = await processCss(`
|
||||
.bg-red {
|
||||
background-color: red;
|
||||
}
|
||||
`)
|
||||
|
||||
expect(result).toEqual({
|
||||
context: {},
|
||||
classNames: {
|
||||
'bg-red': {
|
||||
__rule: true,
|
||||
__decls: true,
|
||||
'background-color': 'red'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('processes pseudo selectors', async () => {
|
||||
const result = await processCss(`
|
||||
.bg-red:first-child::after {
|
||||
background-color: red;
|
||||
}
|
||||
`)
|
||||
|
||||
expect(result).toEqual({
|
||||
context: {},
|
||||
classNames: {
|
||||
'bg-red': {
|
||||
__rule: true,
|
||||
__decls: true,
|
||||
__pseudo: [':first-child', '::after'],
|
||||
'background-color': 'red'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('processes pseudo selectors in scope', async () => {
|
||||
const result = await processCss(`
|
||||
.scope:hover .bg-red {
|
||||
background-color: red;
|
||||
}
|
||||
`)
|
||||
|
||||
expect(result).toEqual({
|
||||
context: {},
|
||||
classNames: {
|
||||
scope: {
|
||||
__pseudo: [':hover']
|
||||
},
|
||||
'bg-red': {
|
||||
__rule: true,
|
||||
__decls: true,
|
||||
__scope: '.scope:hover',
|
||||
'background-color': 'red'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('processes multiple class names in the same rule', async () => {
|
||||
const result = await processCss(`
|
||||
.bg-red,
|
||||
.bg-red-again {
|
||||
background-color: red;
|
||||
}
|
||||
`)
|
||||
|
||||
expect(result).toEqual({
|
||||
context: {},
|
||||
classNames: {
|
||||
'bg-red': {
|
||||
__rule: true,
|
||||
__decls: true,
|
||||
'background-color': 'red'
|
||||
},
|
||||
'bg-red-again': {
|
||||
__rule: true,
|
||||
__decls: true,
|
||||
'background-color': 'red'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('processes media queries', async () => {
|
||||
const result = await processCss(`
|
||||
@media (min-width: 768px) {
|
||||
.bg-red {
|
||||
background-color: red;
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
expect(result).toEqual({
|
||||
context: {},
|
||||
classNames: {
|
||||
'bg-red': {
|
||||
__rule: true,
|
||||
'@media (min-width: 768px)': {
|
||||
__decls: true,
|
||||
'background-color': 'red'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('merges declarations', async () => {
|
||||
const result = await processCss(`
|
||||
.bg-red {
|
||||
background-color: red;
|
||||
}
|
||||
.bg-red {
|
||||
color: white;
|
||||
}
|
||||
`)
|
||||
|
||||
expect(result).toEqual({
|
||||
context: {},
|
||||
classNames: {
|
||||
'bg-red': {
|
||||
__rule: true,
|
||||
__decls: true,
|
||||
'background-color': 'red',
|
||||
color: 'white'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('processes class name scope', async () => {
|
||||
const result = await processCss(`
|
||||
.scope .bg-red {
|
||||
background-color: red;
|
||||
}
|
||||
`)
|
||||
|
||||
expect(result).toEqual({
|
||||
context: {},
|
||||
classNames: {
|
||||
scope: {},
|
||||
'bg-red': {
|
||||
__rule: true,
|
||||
__decls: true,
|
||||
__scope: '.scope',
|
||||
'background-color': 'red'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('processes multiple scopes for the same class name', async () => {
|
||||
const result = await processCss(`
|
||||
.scope1 .bg-red {
|
||||
background-color: red;
|
||||
}
|
||||
.scope2 + .bg-red {
|
||||
background-color: red;
|
||||
}
|
||||
.scope3 > .bg-red {
|
||||
background-color: red;
|
||||
}
|
||||
`)
|
||||
|
||||
expect(result).toEqual({
|
||||
context: {},
|
||||
classNames: {
|
||||
scope1: {},
|
||||
scope2: {},
|
||||
scope3: {},
|
||||
'bg-red': [
|
||||
{
|
||||
__rule: true,
|
||||
__decls: true,
|
||||
__scope: '.scope1',
|
||||
'background-color': 'red'
|
||||
},
|
||||
{
|
||||
__rule: true,
|
||||
__decls: true,
|
||||
__scope: '.scope2 +',
|
||||
'background-color': 'red'
|
||||
},
|
||||
{
|
||||
__rule: true,
|
||||
__decls: true,
|
||||
__scope: '.scope3 >',
|
||||
'background-color': 'red'
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
})
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "tailwindcss-language-server",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"main": "dist/src/server/index.js",
|
||||
"scripts": {
|
||||
"dev1": "ncc build src/server.ts --watch -o dist/foo.js",
|
||||
"dev": "glob-exec --foreach --parallel \"src/*.ts\" -- \"ncc build {{file}} --watch -o dist/{{file.toString().replace(/\\.ts$/, '')}}\"",
|
||||
"build": "ncc build src/server.ts --minify"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Brad Cornes <hello@bradley.dev",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.9.0",
|
||||
"@babel/register": "^7.9.0",
|
||||
"@types/node": "^13.9.3",
|
||||
"@zeit/ncc": "^0.22.0",
|
||||
"dlv": "^1.1.3",
|
||||
"glob-exec": "^0.1.1",
|
||||
"tailwindcss-class-names": "0.0.1",
|
||||
"typescript": "^3.8.3",
|
||||
"vscode-languageserver": "^5.2.1",
|
||||
"vscode-uri": "^2.1.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,378 @@
|
|||
import { State } from '../util/state'
|
||||
import {
|
||||
CompletionItem,
|
||||
CompletionItemKind,
|
||||
CompletionParams,
|
||||
Range,
|
||||
MarkupKind,
|
||||
CompletionList,
|
||||
} from 'vscode-languageserver'
|
||||
const dlv = require('dlv')
|
||||
import removeMeta from '../util/removeMeta'
|
||||
import { getColor, getColorFromString } from '../util/color'
|
||||
import { isHtmlDoc } from '../util/html'
|
||||
import { isCssDoc } from '../util/css'
|
||||
import { findLast, findJsxStrings, arrFindLast } from '../util/find'
|
||||
import { stringifyConfigValue } from '../util/stringify'
|
||||
import isObject from '../util/isObject'
|
||||
|
||||
function completionsFromClassList(
|
||||
state: State,
|
||||
classList: string,
|
||||
classListRange: Range
|
||||
): CompletionList {
|
||||
let classNames = classList.split(/[\s+]/)
|
||||
const partialClassName = classNames[classNames.length - 1]
|
||||
// TODO
|
||||
let sep = ':'
|
||||
let parts = partialClassName.split(sep)
|
||||
let subset: any
|
||||
let isSubset: boolean = false
|
||||
|
||||
let replacementRange = {
|
||||
...classListRange,
|
||||
start: {
|
||||
...classListRange.start,
|
||||
character: classListRange.end.character - partialClassName.length,
|
||||
},
|
||||
}
|
||||
|
||||
for (let i = parts.length - 1; i > 0; i--) {
|
||||
let keys = parts.slice(0, i).filter(Boolean)
|
||||
subset = dlv(state.classNames.classNames, keys)
|
||||
if (typeof subset !== 'undefined' && typeof subset.__rule === 'undefined') {
|
||||
isSubset = true
|
||||
replacementRange = {
|
||||
...replacementRange,
|
||||
start: {
|
||||
...replacementRange.start,
|
||||
character:
|
||||
replacementRange.start.character +
|
||||
keys.join(sep).length +
|
||||
sep.length,
|
||||
},
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isIncomplete: false,
|
||||
items: Object.keys(isSubset ? subset : state.classNames.classNames).map(
|
||||
(className) => {
|
||||
let kind: CompletionItemKind = CompletionItemKind.Constant
|
||||
let documentation: string = null
|
||||
if (isContextItem(state, [className])) {
|
||||
kind = CompletionItemKind.Module
|
||||
} else {
|
||||
const color = getColor(state, [className])
|
||||
if (color) {
|
||||
kind = CompletionItemKind.Color
|
||||
documentation = color
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
label: className,
|
||||
kind,
|
||||
documentation,
|
||||
textEdit: {
|
||||
newText: className,
|
||||
range: replacementRange,
|
||||
},
|
||||
}
|
||||
}
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
function provideClassAttributeCompletions(
|
||||
state: State,
|
||||
{ context, position, textDocument }: CompletionParams
|
||||
): CompletionList {
|
||||
let doc = state.editor.documents.get(textDocument.uri)
|
||||
let str = doc.getText({
|
||||
start: { line: Math.max(position.line - 10, 0), character: 0 },
|
||||
end: position,
|
||||
})
|
||||
|
||||
const match = findLast(/\bclass(?:Name)?=(?<initial>['"`{])/gi, str)
|
||||
|
||||
if (match === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
const rest = str.substr(match.index + match[0].length)
|
||||
|
||||
if (match.groups.initial === '{') {
|
||||
const strings = findJsxStrings('{' + rest)
|
||||
const lastOpenString = arrFindLast(
|
||||
strings,
|
||||
(string) => typeof string.end === 'undefined'
|
||||
)
|
||||
if (lastOpenString) {
|
||||
const classList = str.substr(
|
||||
str.length - rest.length + lastOpenString.start - 1
|
||||
)
|
||||
return completionsFromClassList(state, classList, {
|
||||
start: {
|
||||
line: position.line,
|
||||
character: position.character - classList.length,
|
||||
},
|
||||
end: position,
|
||||
})
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
if (rest.indexOf(match.groups.initial) !== -1) {
|
||||
return null
|
||||
}
|
||||
|
||||
return completionsFromClassList(state, rest, {
|
||||
start: {
|
||||
line: position.line,
|
||||
character: position.character - rest.length,
|
||||
},
|
||||
end: position,
|
||||
})
|
||||
}
|
||||
|
||||
function provideAtApplyCompletions(
|
||||
state: State,
|
||||
{ context, position, textDocument }: CompletionParams
|
||||
): CompletionList {
|
||||
let doc = state.editor.documents.get(textDocument.uri)
|
||||
let str = doc.getText({
|
||||
start: { line: Math.max(position.line - 30, 0), character: 0 },
|
||||
end: position,
|
||||
})
|
||||
|
||||
const match = findLast(/@apply\s+(?<classList>[^;}]*)$/gi, str)
|
||||
|
||||
if (match === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
const classList = match.groups.classList
|
||||
|
||||
return completionsFromClassList(state, classList, {
|
||||
start: {
|
||||
line: position.line,
|
||||
character: position.character - classList.length,
|
||||
},
|
||||
end: position,
|
||||
})
|
||||
}
|
||||
|
||||
function provideClassNameCompletions(
|
||||
state: State,
|
||||
params: CompletionParams
|
||||
): CompletionList {
|
||||
let doc = state.editor.documents.get(params.textDocument.uri)
|
||||
|
||||
if (isHtmlDoc(doc)) {
|
||||
return provideClassAttributeCompletions(state, params)
|
||||
}
|
||||
|
||||
if (isCssDoc(doc)) {
|
||||
return provideAtApplyCompletions(state, params)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function provideCssHelperCompletions(
|
||||
state: State,
|
||||
{ position, textDocument }: CompletionParams
|
||||
): CompletionList {
|
||||
let doc = state.editor.documents.get(textDocument.uri)
|
||||
|
||||
if (!isCssDoc(doc)) {
|
||||
return null
|
||||
}
|
||||
|
||||
let text = doc.getText({
|
||||
start: { line: position.line, character: 0 },
|
||||
// read one extra character so we can see if it's a ] later
|
||||
end: { line: position.line, character: position.character + 1 },
|
||||
})
|
||||
|
||||
const match = text
|
||||
.substr(0, text.length - 1) // don't include that extra character from earlier
|
||||
.match(/\b(?<helper>config|theme)\(['"](?<keys>[^'"]*)$/)
|
||||
|
||||
if (match === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
let base =
|
||||
match.groups.helper === 'config'
|
||||
? state.config
|
||||
: dlv(state.config, 'theme', {})
|
||||
let parts = match.groups.keys.split(/([\[\].]+)/)
|
||||
let keys = parts.filter((_, i) => i % 2 === 0)
|
||||
let separators = parts.filter((_, i) => i % 2 !== 0)
|
||||
// let obj =
|
||||
// keys.length === 1 ? base : dlv(base, keys.slice(0, keys.length - 1), {})
|
||||
|
||||
// if (!isObject(obj)) return null
|
||||
|
||||
function totalLength(arr: string[]): number {
|
||||
return arr.reduce((acc, cur) => acc + cur.length, 0)
|
||||
}
|
||||
|
||||
let obj: any
|
||||
let offset: number = 0
|
||||
let separator: string = separators.length
|
||||
? separators[separators.length - 1]
|
||||
: null
|
||||
|
||||
if (keys.length === 1) {
|
||||
obj = base
|
||||
} else {
|
||||
for (let i = keys.length - 1; i > 0; i--) {
|
||||
let o = dlv(base, keys.slice(0, i))
|
||||
if (isObject(o)) {
|
||||
obj = o
|
||||
offset = totalLength(parts.slice(i * 2))
|
||||
separator = separators[i - 1]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!obj) return null
|
||||
|
||||
return {
|
||||
isIncomplete: false,
|
||||
items: Object.keys(obj).map((item) => {
|
||||
let color = getColorFromString(obj[item])
|
||||
const replaceDot: boolean =
|
||||
item.indexOf('.') !== -1 && separator && separator.endsWith('.')
|
||||
const insertClosingBrace: boolean =
|
||||
text.charAt(text.length - 1) !== ']' &&
|
||||
(replaceDot || (separator && separator.endsWith('[')))
|
||||
|
||||
return {
|
||||
label: item,
|
||||
filterText: `${replaceDot ? '.' : ''}${item}`,
|
||||
kind: color
|
||||
? CompletionItemKind.Color
|
||||
: isObject(obj[item])
|
||||
? CompletionItemKind.Module
|
||||
: CompletionItemKind.Property,
|
||||
detail: stringifyConfigValue(obj[item]),
|
||||
documentation: color,
|
||||
textEdit: {
|
||||
newText: `${replaceDot ? '[' : ''}${item}${
|
||||
insertClosingBrace ? ']' : ''
|
||||
}`,
|
||||
range: {
|
||||
start: {
|
||||
line: position.line,
|
||||
character:
|
||||
position.character -
|
||||
keys[keys.length - 1].length -
|
||||
(replaceDot ? 1 : 0) -
|
||||
offset,
|
||||
},
|
||||
end: position,
|
||||
},
|
||||
},
|
||||
data: 'helper',
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
export function provideCompletions(
|
||||
state: State,
|
||||
params: CompletionParams
|
||||
): CompletionList {
|
||||
if (state === null) return { items: [], isIncomplete: false }
|
||||
|
||||
return (
|
||||
provideClassNameCompletions(state, params) ||
|
||||
provideCssHelperCompletions(state, params)
|
||||
)
|
||||
}
|
||||
|
||||
export function resolveCompletionItem(
|
||||
state: State,
|
||||
item: CompletionItem
|
||||
): CompletionItem {
|
||||
if (item.data === 'helper') {
|
||||
return item
|
||||
}
|
||||
|
||||
const className = state.classNames.classNames[item.label]
|
||||
if (isContextItem(state, [item.label])) {
|
||||
item.detail = state.classNames.context[item.label].join(', ')
|
||||
} else {
|
||||
item.detail = getCssDetail(state, className)
|
||||
if (!item.documentation) {
|
||||
item.documentation = stringifyCss(className)
|
||||
if (item.detail === item.documentation) {
|
||||
item.documentation = null
|
||||
} else {
|
||||
// item.documentation = {
|
||||
// kind: MarkupKind.Markdown,
|
||||
// value: ['```css', item.documentation, '```'].join('\n')
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
function isContextItem(state: State, keys: string[]): boolean {
|
||||
const item = dlv(state.classNames.classNames, keys)
|
||||
return Boolean(
|
||||
!item.__rule &&
|
||||
!Array.isArray(item) &&
|
||||
state.classNames.context[keys[keys.length - 1]]
|
||||
)
|
||||
}
|
||||
|
||||
function stringifyDecls(obj: any): string {
|
||||
return Object.keys(obj)
|
||||
.map((prop) => {
|
||||
return `${prop}: ${obj[prop]};`
|
||||
})
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
function stringifyCss(obj: any, indent: number = 0): string {
|
||||
let indentStr = ' '.repeat(indent)
|
||||
if (obj.__decls === true) {
|
||||
return Object.keys(removeMeta(obj))
|
||||
.reduce((acc, curr, i) => {
|
||||
return `${acc}${i === 0 ? '' : '\n'}${indentStr}${curr}: ${obj[curr]};`
|
||||
}, '')
|
||||
.trim()
|
||||
}
|
||||
return Object.keys(removeMeta(obj))
|
||||
.reduce((acc, curr, i) => {
|
||||
return `${acc}${i === 0 ? '' : '\n'}${indentStr}${curr} {\n${stringifyCss(
|
||||
obj[curr],
|
||||
indent + 2
|
||||
)}\n${indentStr}}`
|
||||
}, '')
|
||||
.trim()
|
||||
}
|
||||
|
||||
function getCssDetail(state: State, className: any): string {
|
||||
if (Array.isArray(className)) {
|
||||
return `${className.length} rules`
|
||||
}
|
||||
let withoutMeta = removeMeta(className)
|
||||
if (className.__decls === true) {
|
||||
return stringifyDecls(withoutMeta)
|
||||
}
|
||||
let keys = Object.keys(withoutMeta)
|
||||
if (keys.length === 1) {
|
||||
return getCssDetail(state, className[keys[0]])
|
||||
}
|
||||
return `${keys.length} rules`
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import {
|
||||
createConnection,
|
||||
TextDocuments,
|
||||
ProposedFeatures,
|
||||
TextDocumentSyncKind,
|
||||
CompletionItem,
|
||||
InitializeParams,
|
||||
InitializeResult,
|
||||
CompletionParams,
|
||||
CompletionList,
|
||||
} from 'vscode-languageserver'
|
||||
import getTailwindState from 'tailwindcss-class-names'
|
||||
import { State } from './util/state'
|
||||
import {
|
||||
provideCompletions,
|
||||
resolveCompletionItem,
|
||||
} from './providers/completionProvider'
|
||||
import { URI } from 'vscode-uri'
|
||||
|
||||
let state: State = null
|
||||
let connection = createConnection(ProposedFeatures.all)
|
||||
let documents = new TextDocuments()
|
||||
let workspaceFolder: string | null
|
||||
|
||||
documents.onDidOpen((event) => {
|
||||
connection.console.log(
|
||||
`[Server(${process.pid}) ${workspaceFolder}] Document opened: ${event.document.uri}`
|
||||
)
|
||||
})
|
||||
documents.listen(connection)
|
||||
|
||||
connection.onInitialize(
|
||||
async (params: InitializeParams): Promise<InitializeResult> => {
|
||||
state = await getTailwindState(
|
||||
params.rootPath || URI.parse(params.rootUri).path,
|
||||
{
|
||||
onChange: (newState: State): void => {
|
||||
state = { ...newState, editor: state.editor }
|
||||
connection.sendNotification('tailwindcss/configUpdated', [
|
||||
state.dependencies[0],
|
||||
state.config,
|
||||
state.plugins,
|
||||
])
|
||||
},
|
||||
}
|
||||
)
|
||||
state.editor = { connection, documents }
|
||||
|
||||
return {
|
||||
capabilities: {
|
||||
// textDocumentSync: {
|
||||
// openClose: true,
|
||||
// change: TextDocumentSyncKind.None
|
||||
// },
|
||||
textDocumentSync: documents.syncKind,
|
||||
completionProvider: {
|
||||
resolveProvider: true,
|
||||
triggerCharacters: ['"', "'", '`', ' ', '.', '[', state.separator],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
connection.onInitialized &&
|
||||
connection.onInitialized(async () => {
|
||||
connection.sendNotification('tailwindcss/configUpdated', [
|
||||
state.dependencies[0],
|
||||
state.config,
|
||||
state.plugins,
|
||||
])
|
||||
})
|
||||
|
||||
connection.onCompletion(
|
||||
(params: CompletionParams): CompletionList => {
|
||||
return provideCompletions(state, params)
|
||||
}
|
||||
)
|
||||
|
||||
connection.onCompletionResolve(
|
||||
(item: CompletionItem): CompletionItem => {
|
||||
return resolveCompletionItem(state, item)
|
||||
}
|
||||
)
|
||||
|
||||
connection.listen()
|
|
@ -0,0 +1,199 @@
|
|||
const dlv = require('dlv')
|
||||
import { State } from './state'
|
||||
import removeMeta from './removeMeta'
|
||||
|
||||
const COLOR_PROPS = [
|
||||
'caret-color',
|
||||
'color',
|
||||
'column-rule-color',
|
||||
'background-color',
|
||||
'border-color',
|
||||
'border-top-color',
|
||||
'border-right-color',
|
||||
'border-bottom-color',
|
||||
'border-left-color',
|
||||
'fill',
|
||||
'outline-color',
|
||||
'stop-color',
|
||||
'stroke',
|
||||
'text-decoration-color'
|
||||
]
|
||||
|
||||
const COLOR_NAMES = {
|
||||
transparent: 'rgba(0, 0, 0, 0.01)',
|
||||
aliceblue: '#f0f8ff',
|
||||
antiquewhite: '#faebd7',
|
||||
aqua: '#0ff',
|
||||
aquamarine: '#7fffd4',
|
||||
azure: '#f0ffff',
|
||||
beige: '#f5f5dc',
|
||||
bisque: '#ffe4c4',
|
||||
black: '#000',
|
||||
blanchedalmond: '#ffebcd',
|
||||
blue: '#00f',
|
||||
blueviolet: '#8a2be2',
|
||||
brown: '#a52a2a',
|
||||
burlywood: '#deb887',
|
||||
burntsienna: '#ea7e5d',
|
||||
cadetblue: '#5f9ea0',
|
||||
chartreuse: '#7fff00',
|
||||
chocolate: '#d2691e',
|
||||
coral: '#ff7f50',
|
||||
cornflowerblue: '#6495ed',
|
||||
cornsilk: '#fff8dc',
|
||||
crimson: '#dc143c',
|
||||
cyan: '#0ff',
|
||||
darkblue: '#00008b',
|
||||
darkcyan: '#008b8b',
|
||||
darkgoldenrod: '#b8860b',
|
||||
darkgray: '#a9a9a9',
|
||||
darkgreen: '#006400',
|
||||
darkgrey: '#a9a9a9',
|
||||
darkkhaki: '#bdb76b',
|
||||
darkmagenta: '#8b008b',
|
||||
darkolivegreen: '#556b2f',
|
||||
darkorange: '#ff8c00',
|
||||
darkorchid: '#9932cc',
|
||||
darkred: '#8b0000',
|
||||
darksalmon: '#e9967a',
|
||||
darkseagreen: '#8fbc8f',
|
||||
darkslateblue: '#483d8b',
|
||||
darkslategray: '#2f4f4f',
|
||||
darkslategrey: '#2f4f4f',
|
||||
darkturquoise: '#00ced1',
|
||||
darkviolet: '#9400d3',
|
||||
deeppink: '#ff1493',
|
||||
deepskyblue: '#00bfff',
|
||||
dimgray: '#696969',
|
||||
dimgrey: '#696969',
|
||||
dodgerblue: '#1e90ff',
|
||||
firebrick: '#b22222',
|
||||
floralwhite: '#fffaf0',
|
||||
forestgreen: '#228b22',
|
||||
fuchsia: '#f0f',
|
||||
gainsboro: '#dcdcdc',
|
||||
ghostwhite: '#f8f8ff',
|
||||
gold: '#ffd700',
|
||||
goldenrod: '#daa520',
|
||||
gray: '#808080',
|
||||
green: '#008000',
|
||||
greenyellow: '#adff2f',
|
||||
grey: '#808080',
|
||||
honeydew: '#f0fff0',
|
||||
hotpink: '#ff69b4',
|
||||
indianred: '#cd5c5c',
|
||||
indigo: '#4b0082',
|
||||
ivory: '#fffff0',
|
||||
khaki: '#f0e68c',
|
||||
lavender: '#e6e6fa',
|
||||
lavenderblush: '#fff0f5',
|
||||
lawngreen: '#7cfc00',
|
||||
lemonchiffon: '#fffacd',
|
||||
lightblue: '#add8e6',
|
||||
lightcoral: '#f08080',
|
||||
lightcyan: '#e0ffff',
|
||||
lightgoldenrodyellow: '#fafad2',
|
||||
lightgray: '#d3d3d3',
|
||||
lightgreen: '#90ee90',
|
||||
lightgrey: '#d3d3d3',
|
||||
lightpink: '#ffb6c1',
|
||||
lightsalmon: '#ffa07a',
|
||||
lightseagreen: '#20b2aa',
|
||||
lightskyblue: '#87cefa',
|
||||
lightslategray: '#789',
|
||||
lightslategrey: '#789',
|
||||
lightsteelblue: '#b0c4de',
|
||||
lightyellow: '#ffffe0',
|
||||
lime: '#0f0',
|
||||
limegreen: '#32cd32',
|
||||
linen: '#faf0e6',
|
||||
magenta: '#f0f',
|
||||
maroon: '#800000',
|
||||
mediumaquamarine: '#66cdaa',
|
||||
mediumblue: '#0000cd',
|
||||
mediumorchid: '#ba55d3',
|
||||
mediumpurple: '#9370db',
|
||||
mediumseagreen: '#3cb371',
|
||||
mediumslateblue: '#7b68ee',
|
||||
mediumspringgreen: '#00fa9a',
|
||||
mediumturquoise: '#48d1cc',
|
||||
mediumvioletred: '#c71585',
|
||||
midnightblue: '#191970',
|
||||
mintcream: '#f5fffa',
|
||||
mistyrose: '#ffe4e1',
|
||||
moccasin: '#ffe4b5',
|
||||
navajowhite: '#ffdead',
|
||||
navy: '#000080',
|
||||
oldlace: '#fdf5e6',
|
||||
olive: '#808000',
|
||||
olivedrab: '#6b8e23',
|
||||
orange: '#ffa500',
|
||||
orangered: '#ff4500',
|
||||
orchid: '#da70d6',
|
||||
palegoldenrod: '#eee8aa',
|
||||
palegreen: '#98fb98',
|
||||
paleturquoise: '#afeeee',
|
||||
palevioletred: '#db7093',
|
||||
papayawhip: '#ffefd5',
|
||||
peachpuff: '#ffdab9',
|
||||
peru: '#cd853f',
|
||||
pink: '#ffc0cb',
|
||||
plum: '#dda0dd',
|
||||
powderblue: '#b0e0e6',
|
||||
purple: '#800080',
|
||||
rebeccapurple: '#663399',
|
||||
red: '#f00',
|
||||
rosybrown: '#bc8f8f',
|
||||
royalblue: '#4169e1',
|
||||
saddlebrown: '#8b4513',
|
||||
salmon: '#fa8072',
|
||||
sandybrown: '#f4a460',
|
||||
seagreen: '#2e8b57',
|
||||
seashell: '#fff5ee',
|
||||
sienna: '#a0522d',
|
||||
silver: '#c0c0c0',
|
||||
skyblue: '#87ceeb',
|
||||
slateblue: '#6a5acd',
|
||||
slategray: '#708090',
|
||||
slategrey: '#708090',
|
||||
snow: '#fffafa',
|
||||
springgreen: '#00ff7f',
|
||||
steelblue: '#4682b4',
|
||||
tan: '#d2b48c',
|
||||
teal: '#008080',
|
||||
thistle: '#d8bfd8',
|
||||
tomato: '#ff6347',
|
||||
turquoise: '#40e0d0',
|
||||
violet: '#ee82ee',
|
||||
wheat: '#f5deb3',
|
||||
white: '#fff',
|
||||
whitesmoke: '#f5f5f5',
|
||||
yellow: '#ff0',
|
||||
yellowgreen: '#9acd32'
|
||||
}
|
||||
|
||||
export function getColor(state: State, keys: string[]): string {
|
||||
const item = dlv(state.classNames.classNames, keys)
|
||||
if (!item.__decls) return null
|
||||
const props = Object.keys(removeMeta(item))
|
||||
if (props.length === 0 || props.length > 1) return null
|
||||
const prop = props[0]
|
||||
if (COLOR_PROPS.indexOf(prop) === -1) return null
|
||||
return COLOR_NAMES[item[prop].toLowerCase()] || item[prop]
|
||||
}
|
||||
|
||||
export function isColor(str: any): boolean {
|
||||
return (
|
||||
typeof str === 'string' &&
|
||||
/^(?:#|0x)(?:[a-f0-9]{3,4}|[a-f0-9]{6}|[a-f0-9]{8})\b|(?:rgb|hsl)a?\([^\)]*\)$/.test(
|
||||
str.trim()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export function getColorFromString(str: string): string {
|
||||
if (isColor(str)) {
|
||||
return str
|
||||
}
|
||||
return COLOR_NAMES[str] || null
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import { TextDocument } from 'vscode-languageserver'
|
||||
|
||||
export const CSS_LANGUAGES = [
|
||||
'css',
|
||||
'less',
|
||||
'postcss',
|
||||
'sass',
|
||||
'scss',
|
||||
'stylus',
|
||||
'svelte',
|
||||
'vue'
|
||||
]
|
||||
|
||||
export function isCssDoc(doc: TextDocument): boolean {
|
||||
return CSS_LANGUAGES.indexOf(doc.languageId) !== -1
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
export function findAll(re: RegExp, str: string): RegExpMatchArray[] {
|
||||
let match: RegExpMatchArray
|
||||
let matches: RegExpMatchArray[] = []
|
||||
while ((match = re.exec(str)) !== null) {
|
||||
matches.push({ ...match })
|
||||
}
|
||||
return matches
|
||||
}
|
||||
|
||||
export function findLast(re: RegExp, str: string): RegExpMatchArray {
|
||||
const matches = findAll(re, str)
|
||||
if (matches.length === 0) {
|
||||
return null
|
||||
}
|
||||
return matches[matches.length - 1]
|
||||
}
|
||||
|
||||
export function arrFindLast<T>(arr: T[], predicate: (item: T) => boolean): T {
|
||||
for (let i = arr.length - 1; i >= 0; --i) {
|
||||
const x = arr[i]
|
||||
if (predicate(x)) {
|
||||
return x
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
enum Quote {
|
||||
SINGLE = "'",
|
||||
DOUBLE = '"',
|
||||
TICK = '`',
|
||||
}
|
||||
type StringInfo = {
|
||||
start: number
|
||||
end?: number
|
||||
char: Quote
|
||||
}
|
||||
|
||||
export function findJsxStrings(str: string): StringInfo[] {
|
||||
const chars = str.split('')
|
||||
const strings: StringInfo[] = []
|
||||
let bracketCount = 0
|
||||
for (let i = 0; i < chars.length; i++) {
|
||||
const char = chars[i]
|
||||
if (char === '{') {
|
||||
bracketCount += 1
|
||||
} else if (char === '}') {
|
||||
bracketCount -= 1
|
||||
} else if (
|
||||
char === Quote.SINGLE ||
|
||||
char === Quote.DOUBLE ||
|
||||
char === Quote.TICK
|
||||
) {
|
||||
let open = arrFindLast(strings, (string) => string.char === char)
|
||||
if (strings.length === 0 || !open || (open && open.end)) {
|
||||
strings.push({ start: i + 1, char })
|
||||
} else {
|
||||
open.end = i
|
||||
}
|
||||
}
|
||||
if (i !== 0 && bracketCount === 0) {
|
||||
// end
|
||||
break
|
||||
}
|
||||
}
|
||||
return strings
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import { TextDocument } from 'vscode-languageserver'
|
||||
import { JS_LANGUAGES } from './js'
|
||||
|
||||
export const HTML_LANGUAGES = [
|
||||
'blade',
|
||||
'django-html',
|
||||
'edge',
|
||||
'ejs',
|
||||
'erb',
|
||||
'haml',
|
||||
'handlebars',
|
||||
'html',
|
||||
'HTML (Eex)',
|
||||
'jade',
|
||||
'leaf',
|
||||
'markdown',
|
||||
'njk',
|
||||
'nunjucks',
|
||||
'php',
|
||||
'razor',
|
||||
'slim',
|
||||
'svelte',
|
||||
'twig',
|
||||
'vue',
|
||||
...JS_LANGUAGES
|
||||
]
|
||||
|
||||
export function isHtmlDoc(doc: TextDocument): boolean {
|
||||
return HTML_LANGUAGES.indexOf(doc.languageId) !== -1
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export default function isObject(variable: any): boolean {
|
||||
return Object.prototype.toString.call(variable) === '[object Object]'
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { TextDocument } from 'vscode-languageserver'
|
||||
|
||||
export const JS_LANGUAGES = [
|
||||
'javascript',
|
||||
'javascriptreact',
|
||||
'reason',
|
||||
'svelte',
|
||||
'typescriptreact'
|
||||
]
|
||||
|
||||
export function isJsDoc(doc: TextDocument): boolean {
|
||||
return JS_LANGUAGES.indexOf(doc.languageId) !== -1
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import isObject from './isObject'
|
||||
|
||||
export default function removeMeta(obj: any): any {
|
||||
let result = {}
|
||||
for (let key in obj) {
|
||||
if (isObject(obj[key])) {
|
||||
result[key] = removeMeta(obj[key])
|
||||
} else if (key.substr(0, 2) !== '__') {
|
||||
result[key] = obj[key]
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import { TextDocuments, Connection } from 'vscode-languageserver'
|
||||
|
||||
export type ClassNamesTree = {
|
||||
[key: string]: ClassNamesTree
|
||||
}
|
||||
|
||||
export type ClassNamesContext = {
|
||||
[key: string]: string[]
|
||||
}
|
||||
|
||||
export type ClassNames = {
|
||||
context: ClassNamesContext
|
||||
classNames: ClassNamesTree
|
||||
}
|
||||
|
||||
export type EditorState = {
|
||||
connection: Connection
|
||||
documents: TextDocuments
|
||||
}
|
||||
|
||||
export type State = null | {
|
||||
config: any
|
||||
separator: string
|
||||
plugins: any[]
|
||||
variants: string[]
|
||||
classNames: ClassNames
|
||||
dependencies: string[]
|
||||
editor: EditorState
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
export function stringifyConfigValue(x: any): string {
|
||||
if (typeof x === 'string') return x
|
||||
if (typeof x === 'number') return x.toString()
|
||||
if (Array.isArray(x)) {
|
||||
return x
|
||||
.filter(y => typeof y === 'string')
|
||||
.filter(Boolean)
|
||||
.join(', ')
|
||||
}
|
||||
return ''
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"outDir": "out",
|
||||
"rootDir": "src",
|
||||
"sourceMap": true,
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", ".vscode-test"]
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
.vscode/**
|
||||
**/*.ts
|
||||
**/*.map
|
||||
.gitignore
|
||||
**/tsconfig.json
|
||||
**/tsconfig.base.json
|
||||
contributing.md
|
||||
.travis.yml
|
||||
node_modules/**
|
||||
!node_modules/vscode-jsonrpc/**
|
||||
!node_modules/vscode-languageclient/**
|
||||
!node_modules/vscode-languageserver-protocol/**
|
||||
!node_modules/vscode-languageserver-types/**
|
|
@ -0,0 +1,754 @@
|
|||
{
|
||||
"name": "tailwindcss-vscode",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
|
||||
"integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"@babel/highlight": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
|
||||
"integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.0.0",
|
||||
"esutils": "^2.0.2",
|
||||
"js-tokens": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@types/mocha": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.1.tgz",
|
||||
"integrity": "sha512-dOrgprHnkDaj1pmrwdcMAf0QRNQzqTB5rxJph+iIQshSmIvtgRqJ0nim8u1vvXU8iOXZrH96+M46JDFTPLingA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "8.10.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.18.tgz",
|
||||
"integrity": "sha512-WoepSz+wJlU5Bjq5oK6cO1oXe2FgPcjMtQPgKPS8fVaTAD0lxkScMCCbMimdkVCsykqaA4lvHWz3cmj28yimhA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/vscode": {
|
||||
"version": "1.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.43.0.tgz",
|
||||
"integrity": "sha512-kIaR9qzd80rJOxePKpCB/mdy00mz8Apt2QA5Y6rdrKFn13QNFNeP3Hzmsf37Bwh/3cS7QjtAeGSK7wSqAU0sYQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@zeit/ncc": {
|
||||
"version": "0.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@zeit/ncc/-/ncc-0.22.0.tgz",
|
||||
"integrity": "sha512-zaS6chwztGSLSEzsTJw9sLTYxQt57bPFBtsYlVtbqGvmDUsfW7xgXPYofzFa1kB9ur2dRop6IxCwPnWLBVCrbQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"builtin-modules": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
|
||||
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
|
||||
"dev": true
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
|
||||
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"string-width": "^3.1.0",
|
||||
"strip-ansi": "^5.2.0",
|
||||
"wrap-ansi": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
|
||||
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true
|
||||
},
|
||||
"concurrently": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-5.1.0.tgz",
|
||||
"integrity": "sha512-9ViZMu3OOCID3rBgU31mjBftro2chOop0G2u1olq1OuwRBVRw/GxHTg80TVJBUTJfoswMmEUeuOg1g1yu1X2dA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"date-fns": "^2.0.1",
|
||||
"lodash": "^4.17.15",
|
||||
"read-pkg": "^4.0.1",
|
||||
"rxjs": "^6.5.2",
|
||||
"spawn-command": "^0.0.2-1",
|
||||
"supports-color": "^6.1.0",
|
||||
"tree-kill": "^1.2.2",
|
||||
"yargs": "^13.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"date-fns": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.11.0.tgz",
|
||||
"integrity": "sha512-8P1cDi8ebZyDxUyUprBXwidoEtiQAawYPGvpfb+Dg0G6JrQ+VozwOmm91xYC0vAv1+0VmLehEPb+isg4BGUFfA==",
|
||||
"dev": true
|
||||
},
|
||||
"decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
|
||||
"dev": true
|
||||
},
|
||||
"diff": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
|
||||
"dev": true
|
||||
},
|
||||
"dlv": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
|
||||
"dev": true
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
|
||||
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
|
||||
"dev": true
|
||||
},
|
||||
"error-ex": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"dev": true
|
||||
},
|
||||
"esutils": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
|
||||
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
|
||||
"dev": true
|
||||
},
|
||||
"find-up": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
|
||||
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"locate-path": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true
|
||||
},
|
||||
"get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
|
||||
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"glob-exec": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/glob-exec/-/glob-exec-0.1.1.tgz",
|
||||
"integrity": "sha1-172HjoZ9a5JeoFa67MVicbpeZxM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "7.1.X",
|
||||
"subarg": "1.0.X"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"hosted-git-info": {
|
||||
"version": "2.8.8",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
|
||||
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
|
||||
"dev": true
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"dev": true
|
||||
},
|
||||
"is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.13.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
|
||||
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"json-parse-better-errors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
|
||||
"dev": true
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
|
||||
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-locate": "^3.0.0",
|
||||
"path-exists": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.3.tgz",
|
||||
"integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==",
|
||||
"dev": true
|
||||
},
|
||||
"normalize-package-data": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
|
||||
"integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"hosted-git-info": "^2.1.4",
|
||||
"resolve": "^1.10.0",
|
||||
"semver": "2 || 3 || 4 || 5",
|
||||
"validate-npm-package-license": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
|
||||
"integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-try": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
|
||||
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-limit": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"p-try": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||
"dev": true
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"error-ex": "^1.3.1",
|
||||
"json-parse-better-errors": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
|
||||
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
|
||||
"dev": true
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
||||
"dev": true
|
||||
},
|
||||
"pify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||
"dev": true
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz",
|
||||
"integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"normalize-package-data": "^2.3.2",
|
||||
"parse-json": "^4.0.0",
|
||||
"pify": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
|
||||
"dev": true
|
||||
},
|
||||
"require-main-filename": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
||||
"dev": true
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz",
|
||||
"integrity": "sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-parse": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "6.5.4",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz",
|
||||
"integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true
|
||||
},
|
||||
"set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
||||
"dev": true
|
||||
},
|
||||
"spawn-command": {
|
||||
"version": "0.0.2-1",
|
||||
"resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz",
|
||||
"integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=",
|
||||
"dev": true
|
||||
},
|
||||
"spdx-correct": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
|
||||
"integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"spdx-expression-parse": "^3.0.0",
|
||||
"spdx-license-ids": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"spdx-exceptions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
|
||||
"integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
|
||||
"dev": true
|
||||
},
|
||||
"spdx-expression-parse": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
|
||||
"integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"spdx-exceptions": "^2.1.0",
|
||||
"spdx-license-ids": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"spdx-license-ids": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
|
||||
"integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^7.0.1",
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"subarg": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
|
||||
"integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"tree-kill": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
|
||||
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
|
||||
"dev": true
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
|
||||
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
|
||||
"dev": true
|
||||
},
|
||||
"tslint": {
|
||||
"version": "5.16.0",
|
||||
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.16.0.tgz",
|
||||
"integrity": "sha512-UxG2yNxJ5pgGwmMzPMYh/CCnCnh0HfPgtlVRDs1ykZklufFBL1ZoTlWFRz2NQjcoEiDoRp+JyT0lhBbbH/obyA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"builtin-modules": "^1.1.1",
|
||||
"chalk": "^2.3.0",
|
||||
"commander": "^2.12.1",
|
||||
"diff": "^3.2.0",
|
||||
"glob": "^7.1.1",
|
||||
"js-yaml": "^3.13.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"resolve": "^1.3.2",
|
||||
"semver": "^5.3.0",
|
||||
"tslib": "^1.8.0",
|
||||
"tsutils": "^2.29.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz",
|
||||
"integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tsutils": {
|
||||
"version": "2.29.0",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
|
||||
"integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.8.1"
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.8.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
|
||||
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
|
||||
"dev": true
|
||||
},
|
||||
"validate-npm-package-license": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
||||
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"spdx-correct": "^3.0.0",
|
||||
"spdx-expression-parse": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"vscode-jsonrpc": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz",
|
||||
"integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==",
|
||||
"dev": true
|
||||
},
|
||||
"vscode-languageclient": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.2.1.tgz",
|
||||
"integrity": "sha512-7jrS/9WnV0ruqPamN1nE7qCxn0phkH5LjSgSp9h6qoJGoeAKzwKz/PF6M+iGA/aklx4GLZg1prddhEPQtuXI1Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "^5.5.0",
|
||||
"vscode-languageserver-protocol": "3.14.1"
|
||||
}
|
||||
},
|
||||
"vscode-languageserver-protocol": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz",
|
||||
"integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"vscode-jsonrpc": "^4.0.0",
|
||||
"vscode-languageserver-types": "3.14.0"
|
||||
}
|
||||
},
|
||||
"vscode-languageserver-types": {
|
||||
"version": "3.14.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz",
|
||||
"integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==",
|
||||
"dev": true
|
||||
},
|
||||
"which-module": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
|
||||
"dev": true
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
|
||||
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.0",
|
||||
"string-width": "^3.0.0",
|
||||
"strip-ansi": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs": {
|
||||
"version": "13.3.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
|
||||
"integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cliui": "^5.0.0",
|
||||
"find-up": "^3.0.0",
|
||||
"get-caller-file": "^2.0.1",
|
||||
"require-directory": "^2.1.1",
|
||||
"require-main-filename": "^2.0.0",
|
||||
"set-blocking": "^2.0.0",
|
||||
"string-width": "^3.0.0",
|
||||
"which-module": "^2.0.0",
|
||||
"y18n": "^4.0.0",
|
||||
"yargs-parser": "^13.1.2"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "13.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
|
||||
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"name": "tailwindcss-vscode",
|
||||
"description": "",
|
||||
"author": "Brad Cornes <hello@bradley.dev>",
|
||||
"license": "MIT",
|
||||
"version": "0.0.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bradlc/"
|
||||
},
|
||||
"publisher": "bradlc",
|
||||
"categories": [],
|
||||
"keywords": [
|
||||
"multi-root ready"
|
||||
],
|
||||
"engines": {
|
||||
"vscode": "^1.33.0"
|
||||
},
|
||||
"activationEvents": [
|
||||
"onLanguage:plaintext"
|
||||
],
|
||||
"main": "dist/src/extension/index.js",
|
||||
"contributes": {
|
||||
"grammars": [
|
||||
{
|
||||
"scopeName": "source.css.tailwind",
|
||||
"path": "./syntaxes/tailwind.tmLanguage.json",
|
||||
"injectTo": [
|
||||
"source.css",
|
||||
"source.css.scss",
|
||||
"source.css.less",
|
||||
"source.css.postcss"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run build",
|
||||
"devOld": "concurrently \"npm:devOld:*\"",
|
||||
"devOld:client": "ncc build src/extension.ts --watch -o dist/client",
|
||||
"devOld:server": "ncc build src/server.ts --watch -o dist/server",
|
||||
"dev": "glob-exec --foreach --parallel \"src/*.ts\" -- \"ncc build {{file}} --watch -o dist/{{file.toString().replace(/\\.ts$/, '')}}\"",
|
||||
"build": "npm run build:client && npm run build:server",
|
||||
"build:client": "ncc build src/extension.ts --minify -o dist/client",
|
||||
"build:server": "ncc build src/server.ts --minify -o dist/server"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^5.2.0",
|
||||
"@types/node": "^8.0.0",
|
||||
"@types/vscode": "^1.32.0",
|
||||
"@zeit/ncc": "^0.22.0",
|
||||
"concurrently": "^5.1.0",
|
||||
"dlv": "^1.1.3",
|
||||
"glob-exec": "^0.1.1",
|
||||
"mkdirp": "^1.0.3",
|
||||
"tailwindcss-language-server": "0.0.1",
|
||||
"tslint": "^5.16.0",
|
||||
"typescript": "^3.8.3",
|
||||
"vscode-languageclient": "^5.2.1"
|
||||
}
|
||||
}
|
|
@ -1,200 +1,168 @@
|
|||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
import {
|
||||
workspace as Workspace,
|
||||
window as Window,
|
||||
ExtensionContext,
|
||||
TextDocument,
|
||||
OutputChannel,
|
||||
WorkspaceFolder,
|
||||
Uri
|
||||
} from 'vscode'
|
||||
|
||||
import {
|
||||
LanguageClient,
|
||||
LanguageClientOptions,
|
||||
TransportKind
|
||||
} from 'vscode-languageclient'
|
||||
|
||||
import * as path from 'path'
|
||||
|
||||
const CONFIG_GLOB =
|
||||
'**/{tailwind,tailwind.config,tailwind-config,.tailwindrc}.js'
|
||||
export const CSS_LANGUAGES: string[] = [
|
||||
'css',
|
||||
'less',
|
||||
'postcss',
|
||||
'sass',
|
||||
'scss',
|
||||
'stylus',
|
||||
'vue'
|
||||
]
|
||||
export const JS_LANGUAGES: string[] = [
|
||||
'javascript',
|
||||
'javascriptreact',
|
||||
'reason',
|
||||
'typescriptreact'
|
||||
]
|
||||
export const HTML_LANGUAGES: string[] = [
|
||||
'blade',
|
||||
'django-html',
|
||||
'edge',
|
||||
'ejs',
|
||||
'erb',
|
||||
'haml',
|
||||
'handlebars',
|
||||
'html',
|
||||
'HTML (Eex)',
|
||||
'HTML (EEx)',
|
||||
'jade',
|
||||
'leaf',
|
||||
'markdown',
|
||||
'njk',
|
||||
'nunjucks',
|
||||
'php',
|
||||
'razor',
|
||||
'slim',
|
||||
'svelte',
|
||||
'twig',
|
||||
'vue',
|
||||
...JS_LANGUAGES
|
||||
]
|
||||
export const LANGUAGES: string[] = [...CSS_LANGUAGES, ...HTML_LANGUAGES].filter(
|
||||
(val, index, arr) => arr.indexOf(val) === index
|
||||
)
|
||||
|
||||
let defaultClient: LanguageClient
|
||||
let clients: Map<string, LanguageClient> = new Map()
|
||||
|
||||
let _sortedWorkspaceFolders: string[] | undefined
|
||||
function sortedWorkspaceFolders(): string[] {
|
||||
if (_sortedWorkspaceFolders === void 0) {
|
||||
_sortedWorkspaceFolders = Workspace.workspaceFolders
|
||||
? Workspace.workspaceFolders
|
||||
.map(folder => {
|
||||
let result = folder.uri.toString()
|
||||
if (result.charAt(result.length - 1) !== '/') {
|
||||
result = result + '/'
|
||||
}
|
||||
return result
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return a.length - b.length
|
||||
})
|
||||
: []
|
||||
}
|
||||
return _sortedWorkspaceFolders
|
||||
}
|
||||
Workspace.onDidChangeWorkspaceFolders(
|
||||
() => (_sortedWorkspaceFolders = undefined)
|
||||
)
|
||||
|
||||
function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder {
|
||||
let sorted = sortedWorkspaceFolders()
|
||||
for (let element of sorted) {
|
||||
let uri = folder.uri.toString()
|
||||
if (uri.charAt(uri.length - 1) !== '/') {
|
||||
uri = uri + '/'
|
||||
}
|
||||
if (uri.startsWith(element)) {
|
||||
return Workspace.getWorkspaceFolder(Uri.parse(element))!
|
||||
}
|
||||
}
|
||||
return folder
|
||||
}
|
||||
|
||||
export async function activate(context: ExtensionContext) {
|
||||
let module = context.asAbsolutePath(path.join('dist', 'server', 'index.js'))
|
||||
let outputChannel: OutputChannel = Window.createOutputChannel(
|
||||
'tailwindcss-language-server'
|
||||
)
|
||||
|
||||
async function didOpenTextDocument(document: TextDocument): Promise<void> {
|
||||
if (
|
||||
document.uri.scheme !== 'file' ||
|
||||
LANGUAGES.indexOf(document.languageId) === -1
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
let uri = document.uri
|
||||
let folder = Workspace.getWorkspaceFolder(uri)
|
||||
// Files outside a folder can't be handled. This might depend on the language.
|
||||
// Single file languages like JSON might handle files outside the workspace folders.
|
||||
if (!folder) {
|
||||
return
|
||||
}
|
||||
|
||||
// If we have nested workspace folders we only start a server on the outer most workspace folder.
|
||||
folder = getOuterMostWorkspaceFolder(folder)
|
||||
|
||||
if (!clients.has(folder.uri.toString())) {
|
||||
// placeholder
|
||||
clients.set(folder.uri.toString(), null)
|
||||
|
||||
let files = await Workspace.findFiles(
|
||||
CONFIG_GLOB,
|
||||
'**/node_modules/**',
|
||||
1
|
||||
)
|
||||
if (!files.length) return
|
||||
|
||||
let debugOptions = {
|
||||
execArgv: ['--nolazy', `--inspect=${6011 + clients.size}`]
|
||||
}
|
||||
let serverOptions = {
|
||||
run: { module, transport: TransportKind.ipc },
|
||||
debug: { module, transport: TransportKind.ipc, options: debugOptions }
|
||||
}
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
documentSelector: LANGUAGES.map(language => ({
|
||||
scheme: 'file',
|
||||
language,
|
||||
pattern: `${folder.uri.fsPath}/**/*`
|
||||
})),
|
||||
diagnosticCollectionName: 'tailwindcss-language-server',
|
||||
workspaceFolder: folder,
|
||||
outputChannel: outputChannel,
|
||||
synchronize: {
|
||||
fileEvents: Workspace.createFileSystemWatcher(CONFIG_GLOB)
|
||||
}
|
||||
}
|
||||
let client = new LanguageClient(
|
||||
'tailwindcss-language-server',
|
||||
'Tailwind CSS Language Server',
|
||||
serverOptions,
|
||||
clientOptions
|
||||
)
|
||||
|
||||
client.start()
|
||||
clients.set(folder.uri.toString(), client)
|
||||
}
|
||||
}
|
||||
|
||||
Workspace.onDidOpenTextDocument(didOpenTextDocument)
|
||||
Workspace.textDocuments.forEach(didOpenTextDocument)
|
||||
Workspace.onDidChangeWorkspaceFolders(event => {
|
||||
for (let folder of event.removed) {
|
||||
let client = clients.get(folder.uri.toString())
|
||||
if (client) {
|
||||
clients.delete(folder.uri.toString())
|
||||
client.stop()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deactivate(): Thenable<void> {
|
||||
let promises: Thenable<void>[] = []
|
||||
if (defaultClient) {
|
||||
promises.push(defaultClient.stop())
|
||||
}
|
||||
for (let client of clients.values()) {
|
||||
if (client) {
|
||||
promises.push(client.stop())
|
||||
}
|
||||
}
|
||||
return Promise.all(promises).then(() => undefined)
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
import * as path from 'path'
|
||||
import {
|
||||
workspace as Workspace,
|
||||
window as Window,
|
||||
ExtensionContext,
|
||||
TextDocument,
|
||||
OutputChannel,
|
||||
WorkspaceFolder,
|
||||
Uri,
|
||||
} from 'vscode'
|
||||
|
||||
import {
|
||||
LanguageClient,
|
||||
LanguageClientOptions,
|
||||
TransportKind,
|
||||
} from 'vscode-languageclient'
|
||||
|
||||
let defaultClient: LanguageClient
|
||||
let clients: Map<string, LanguageClient> = new Map()
|
||||
|
||||
const LANGS = ['css', 'javascript', 'html']
|
||||
|
||||
let _sortedWorkspaceFolders: string[] | undefined
|
||||
function sortedWorkspaceFolders(): string[] {
|
||||
if (_sortedWorkspaceFolders === void 0) {
|
||||
_sortedWorkspaceFolders = Workspace.workspaceFolders
|
||||
? Workspace.workspaceFolders
|
||||
.map((folder) => {
|
||||
let result = folder.uri.toString()
|
||||
if (result.charAt(result.length - 1) !== '/') {
|
||||
result = result + '/'
|
||||
}
|
||||
return result
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return a.length - b.length
|
||||
})
|
||||
: []
|
||||
}
|
||||
return _sortedWorkspaceFolders
|
||||
}
|
||||
Workspace.onDidChangeWorkspaceFolders(
|
||||
() => (_sortedWorkspaceFolders = undefined)
|
||||
)
|
||||
|
||||
function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder {
|
||||
let sorted = sortedWorkspaceFolders()
|
||||
for (let element of sorted) {
|
||||
let uri = folder.uri.toString()
|
||||
if (uri.charAt(uri.length - 1) !== '/') {
|
||||
uri = uri + '/'
|
||||
}
|
||||
if (uri.startsWith(element)) {
|
||||
return Workspace.getWorkspaceFolder(Uri.parse(element))!
|
||||
}
|
||||
}
|
||||
return folder
|
||||
}
|
||||
|
||||
export function activate(context: ExtensionContext) {
|
||||
let module = context.asAbsolutePath(
|
||||
path.join('dist', 'src', 'server', 'index.js')
|
||||
)
|
||||
let outputChannel: OutputChannel = Window.createOutputChannel(
|
||||
'lsp-multi-server-example'
|
||||
)
|
||||
|
||||
function didOpenTextDocument(document: TextDocument): void {
|
||||
// We are only interested in language mode text
|
||||
if (
|
||||
LANGS.indexOf(document.languageId) === -1 ||
|
||||
(document.uri.scheme !== 'file' && document.uri.scheme !== 'untitled')
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
let uri = document.uri
|
||||
// Untitled files go to a default client.
|
||||
if (uri.scheme === 'untitled' && !defaultClient) {
|
||||
let debugOptions = { execArgv: ['--nolazy', '--inspect=6010'] }
|
||||
let serverOptions = {
|
||||
run: { module, transport: TransportKind.ipc },
|
||||
debug: { module, transport: TransportKind.ipc, options: debugOptions },
|
||||
}
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
documentSelector: LANGS.map((language) => ({
|
||||
scheme: 'untitled',
|
||||
language,
|
||||
})),
|
||||
diagnosticCollectionName: 'lsp-multi-server-example',
|
||||
outputChannel: outputChannel,
|
||||
}
|
||||
defaultClient = new LanguageClient(
|
||||
'lsp-multi-server-example',
|
||||
'LSP Multi Server Example',
|
||||
serverOptions,
|
||||
clientOptions
|
||||
)
|
||||
defaultClient.start()
|
||||
return
|
||||
}
|
||||
let folder = Workspace.getWorkspaceFolder(uri)
|
||||
// Files outside a folder can't be handled. This might depend on the language.
|
||||
// Single file languages like JSON might handle files outside the workspace folders.
|
||||
if (!folder) {
|
||||
return
|
||||
}
|
||||
// If we have nested workspace folders we only start a server on the outer most workspace folder.
|
||||
folder = getOuterMostWorkspaceFolder(folder)
|
||||
|
||||
if (!clients.has(folder.uri.toString())) {
|
||||
let debugOptions = {
|
||||
execArgv: ['--nolazy', `--inspect=${6011 + clients.size}`],
|
||||
}
|
||||
let serverOptions = {
|
||||
run: { module, transport: TransportKind.ipc },
|
||||
debug: { module, transport: TransportKind.ipc, options: debugOptions },
|
||||
}
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
documentSelector: LANGS.map((language) => ({
|
||||
scheme: 'file',
|
||||
language,
|
||||
pattern: `${folder.uri.fsPath}/**/*`,
|
||||
})),
|
||||
diagnosticCollectionName: 'lsp-multi-server-example',
|
||||
workspaceFolder: folder,
|
||||
outputChannel: outputChannel,
|
||||
middleware: {},
|
||||
}
|
||||
let client = new LanguageClient(
|
||||
'lsp-multi-server-example',
|
||||
'LSP Multi Server Example',
|
||||
serverOptions,
|
||||
clientOptions
|
||||
)
|
||||
|
||||
client.start()
|
||||
clients.set(folder.uri.toString(), client)
|
||||
}
|
||||
}
|
||||
|
||||
Workspace.onDidOpenTextDocument(didOpenTextDocument)
|
||||
Workspace.textDocuments.forEach(didOpenTextDocument)
|
||||
Workspace.onDidChangeWorkspaceFolders((event) => {
|
||||
for (let folder of event.removed) {
|
||||
let client = clients.get(folder.uri.toString())
|
||||
if (client) {
|
||||
clients.delete(folder.uri.toString())
|
||||
client.stop()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deactivate(): Thenable<void> {
|
||||
let promises: Thenable<void>[] = []
|
||||
if (defaultClient) {
|
||||
promises.push(defaultClient.stop())
|
||||
}
|
||||
for (let client of clients.values()) {
|
||||
promises.push(client.stop())
|
||||
}
|
||||
return Promise.all(promises).then(() => undefined)
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
"name": "TailwindCSS",
|
||||
"patterns": [
|
||||
{
|
||||
"begin": "^\\s*(@)apply\\b",
|
||||
"begin": "(@)apply\\b",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "keyword.control.at-rule.apply.tailwind"
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"outDir": "out",
|
||||
"rootDir": "src",
|
||||
"sourceMap": true,
|
||||
"moduleResolution": "node"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", ".vscode-test"]
|
||||
}
|
Before Width: | Height: | Size: 19 KiB |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M3 3v18h18V3H3zm8 16H5v-6h6v6zm0-8H5V5h6v6zm8 8h-6v-6h6v6zm0-8h-6V5h6v6z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
|
Before Width: | Height: | Size: 226 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M4 6h18V4H4c-1.1 0-2 .9-2 2v11H0v3h14v-3H4V6zm19 2h-6c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h6c.55 0 1-.45 1-1V9c0-.55-.45-1-1-1zm-1 9h-4v-7h4v7z"/></svg>
|
Before Width: | Height: | Size: 258 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/></svg>
|
Before Width: | Height: | Size: 409 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><g transform="translate(24,0) scale(-1,1)"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm2 4v-2H3c0 1.1.89 2 2 2zM3 9h2V7H3v2zm12 12h2v-2h-2v2zm4-18H9c-1.11 0-2 .9-2 2v10c0 1.1.89 2 2 2h10c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 12H9V5h10v10zm-8 6h2v-2h-2v2zm-4 0h2v-2H7v2z"/></g></svg>
|
Before Width: | Height: | Size: 410 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
|
Before Width: | Height: | Size: 383 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M6 7h2.5L5 3.5 1.5 7H4v10H1.5L5 20.5 8.5 17H6V7zm4-2v2h12V5H10zm0 14h12v-2H10v2zm0-6h12v-2H10v2z"/></svg>
|
Before Width: | Height: | Size: 213 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 4v3h5v12h3V7h5V4H9zm-6 8h3v7h3v-7h3V9H3v3z"/></svg>
|
Before Width: | Height: | Size: 199 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M11.99 18.54l-7.37-5.73L3 14.07l9 7 9-7-1.63-1.27-7.38 5.74zM12 16l7.36-5.73L21 9l-9-7-9 7 1.63 1.27L12 16z"/></svg>
|
Before Width: | Height: | Size: 224 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M17.66 8L12 2.35 6.34 8C4.78 9.56 4 11.64 4 13.64s.78 4.11 2.34 5.67 3.61 2.35 5.66 2.35 4.1-.79 5.66-2.35S20 15.64 20 13.64 19.22 9.56 17.66 8zM6 14c.01-2 .62-3.27 1.76-4.4L12 5.27l4.24 4.38C17.38 10.77 17.99 12 18 14H6z"/></svg>
|
Before Width: | Height: | Size: 338 B |
|
@ -1,11 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 9H7C7 7.9 7.9 7 9 7V9Z"/>
|
||||
<path d="M15 9L15 7C16.1 7 17 7.9 17 9L15 9Z"/>
|
||||
<path d="M9 15L9 17C7.9 17 7 16.1 7 15L9 15Z"/>
|
||||
<path d="M15 15L17 15C17 16.1 16.1 17 15 17L15 15Z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M21 3H3V21H21V3ZM19 5H5V19H19V5Z"/>
|
||||
<rect x="11" y="7" width="2" height="2"/>
|
||||
<rect x="7" y="11" width="2" height="2"/>
|
||||
<rect x="11" y="15" width="2" height="2"/>
|
||||
<rect x="15" y="11" width="2" height="2"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 567 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></svg>
|
Before Width: | Height: | Size: 569 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M21 15h2v2h-2v-2zm0-4h2v2h-2v-2zm2 8h-2v2c1 0 2-1 2-2zM13 3h2v2h-2V3zm8 4h2v2h-2V7zm0-4v2h2c0-1-1-2-2-2zM1 7h2v2H1V7zm16-4h2v2h-2V3zm0 16h2v2h-2v-2zM3 3C2 3 1 4 1 5h2V3zm6 0h2v2H9V3zM5 3h2v2H5V3zm-4 8v8c0 1.1.9 2 2 2h12V11H1zm2 8l2.5-3.21 1.79 2.15 2.5-3.22L13 19H3z"/></svg>
|
Before Width: | Height: | Size: 383 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><defs><path id="a" d="M0 0h24v24H0V0z"/></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"/></clipPath><path clip-path="url(#b)" d="M19 19h2v2h-2v-2zm0-2h2v-2h-2v2zM3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm0-4h2V3H3v2zm4 0h2V3H7v2zm8 16h2v-2h-2v2zm-4 0h2v-2h-2v2zm4 0h2v-2h-2v2zm-8 0h2v-2H7v2zm-4 0h2v-2H3v2zM21 8c0-2.76-2.24-5-5-5h-5v2h5c1.65 0 3 1.35 3 3v5h2V8z"/></svg>
|
Before Width: | Height: | Size: 528 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M3 5h2V3c-1.1 0-2 .9-2 2zm0 8h2v-2H3v2zm4 8h2v-2H7v2zM3 9h2V7H3v2zm10-6h-2v2h2V3zm6 0v2h2c0-1.1-.9-2-2-2zM5 21v-2H3c0 1.1.9 2 2 2zm-2-4h2v-2H3v2zM9 3H7v2h2V3zm2 18h2v-2h-2v2zm8-8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zm0-12h2V7h-2v2zm0 8h2v-2h-2v2zm-4 4h2v-2h-2v2zm0-16h2V3h-2v2zM7 17h10V7H7v10zm2-8h6v6H9V9z"/></svg>
|
Before Width: | Height: | Size: 421 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="#44a8b3"><path d="M15.95 10.78c.03-.25.05-.51.05-.78s-.02-.53-.06-.78l1.69-1.32c.15-.12.19-.34.1-.51l-1.6-2.77c-.1-.18-.31-.24-.49-.18l-1.99.8c-.42-.32-.86-.58-1.35-.78L12 2.34c-.03-.2-.2-.34-.4-.34H8.4c-.2 0-.36.14-.39.34l-.3 2.12c-.49.2-.94.47-1.35.78l-1.99-.8c-.18-.07-.39 0-.49.18l-1.6 2.77c-.1.18-.06.39.1.51l1.69 1.32c-.04.25-.07.52-.07.78s.02.53.06.78L2.37 12.1c-.15.12-.19.34-.1.51l1.6 2.77c.1.18.31.24.49.18l1.99-.8c.42.32.86.58 1.35.78l.3 2.12c.04.2.2.34.4.34h3.2c.2 0 .37-.14.39-.34l.3-2.12c.49-.2.94-.47 1.35-.78l1.99.8c.18.07.39 0 .49-.18l1.6-2.77c.1-.18.06-.39-.1-.51l-1.67-1.32zM10 13c-1.65 0-3-1.35-3-3s1.35-3 3-3 3 1.35 3 3-1.35 3-3 3z"/></svg>
|
Before Width: | Height: | Size: 751 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 10H3V8h2v4h2V8h2v4h2V8h2v4h2V8h2v4h2V8h2v8z"/></svg>
|
Before Width: | Height: | Size: 238 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3"><path d="M5 4v3h5.5v12h3V7H19V4z"/></svg>
|
Before Width: | Height: | Size: 140 B |
|
@ -1,4 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="#44a8b3" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11 2L5.5 16H7.75L8.87 13H15.12L16.24 16H18.49L13 2H11ZM9.62 11L12 4.67L14.38 11H9.62V11Z"/>
|
||||
<path d="M17.5 24L17.5 21.5L6.5 21.5L6.5 24L3 20.5L6.5 17L6.5 19.5L17.5 19.5L17.5 17L21 20.5L17.5 24Z"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 313 B |
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "packages/tailwindcss-vscode"
|
||||
},
|
||||
{
|
||||
"path": "packages/tailwindcss-language-server"
|
||||
},
|
||||
{
|
||||
"path": "packages/tailwindcss-class-names"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"typescript.tsc.autoDetect": "off"
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "**/*.spec.ts"]
|
||||
}
|