diff --git a/README.md b/README.md
index 5a665ba..3ccfa4a 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,17 @@
# @twind/typescript-plugin
+
+
> TypeScript language service plugin that adds IntelliSense for tailwindjs
[](https://github.com/tw-in-js/typescript-plugin/blob/main/LICENSE)
[](https://www.npmjs.com/package/@twind/typescript-plugin)
[](https://github.com/tw-in-js/typescript-plugin)
+
+
+
+
---
@@ -27,25 +33,23 @@
Provides editor support for ```tw`...```` tagged template syntax including:
-- Autocomplete for tailwind, beamwind and oceanwin classes
+- Autocomplete for [twind](https://github.com/tw-in-js/twind) classes
- Warnings on unknown classes
-- Quick fixes for misspelled property names.
+- Warnings on unknown theme values
## Installation
```sh
-npm install --save-dev @twind/typescript-plugin
+npm install --save-dev typescript @twind/typescript-plugin
```
## Usage
-This plugin requires TypeScript 2.4 or later. It can provide intellisense in both JavaScript and TypeScript files within any editor that uses TypeScript to power their language features. This includes [VS Code](https://code.visualstudio.com), [Sublime with the TypeScript plugin](https://github.com/Microsoft/TypeScript-Sublime-Plugin), [Atom with the TypeScript plugin](https://atom.io/packages/atom-typescript), [Visual Studio](https://www.visualstudio.com), and others.
+This plugin requires TypeScript 4.1 or later. It can provide intellisense in both JavaScript and TypeScript files within any editor that uses TypeScript to power their language features. This includes [VS Code](https://code.visualstudio.com), [Sublime with the TypeScript plugin](https://github.com/Microsoft/TypeScript-Sublime-Plugin), [Atom with the TypeScript plugin](https://atom.io/packages/atom-typescript), [Visual Studio](https://www.visualstudio.com), and others.
### With VS Code
-Just install the [VS Code tailwindjs extension](https://github.com/tw-in-js/core/packages/vscode). This extension adds syntax highlighting and IntelliSense for styled components in JavaScript and TypeScript files.
-
-If you are using a [workspace version of TypeScript](<(https://code.visualstudio.com/Docs/languages/typescript#_using-newer-typescript-versions)>) however, you must manually install the plugin along side the version of TypeScript in your workspace.
+Currently you must manually install the plugin along side TypeScript in your workspace.
Then add a `plugins` section to your [`tsconfig.json`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html) or [`jsconfig.json`](https://code.visualstudio.com/Docs/languages/javascript#_javascript-project-jsconfigjson)
@@ -61,7 +65,17 @@ Then add a `plugins` section to your [`tsconfig.json`](http://www.typescriptlang
}
```
-Finally, run the `Select TypeScript version` command in VS Code to switch to use the workspace version of TypeScript for VS Code's JavaScript and TypeScript language support. You can find more information about managing typescript versions [in the VS Code documentation](https://code.visualstudio.com/Docs/languages/typescript#_using-newer-typescript-versions).
+Finally, run the `Select TypeScript version` command in VS Code to switch to use the workspace version of TypeScript for VS Code's JavaScript and TypeScript language support. You can find more information about managing typescript versions [in the VS Code documentation](https://code.visualstudio.com/docs/typescript/typescript-compiling#_using-the-workspace-version-of-typescript).
+
+By default VS Code will not trigger completions when editing "string" content, for example within JSX attribute values. Updating the `editor.quickSuggestions` setting may improve your experience, particularly when editing Tailwind classes within JSX:
+
+```json
+{
+ "editor.quickSuggestions": {
+ "strings": true
+ }
+}
+```
### With Sublime
@@ -168,7 +182,7 @@ Now strings tagged with either `tw` and `cx` will have IntelliSense.
Thanks for being willing to contribute!
-> This project is free and open-source, so if you think this project can help you or anyone else, you may [star it on GitHub](https://github.com/tw-in-js/core). Feel free to [open an issue](https://github.com/tw-in-js/core/issues) if you have any idea, question, or you've found a bug.
+> This project is free and open-source, so if you think this project can help you or anyone else, you may [star it on GitHub](https://github.com/tw-in-js/typescript-plugin). Feel free to [open an issue](https://github.com/tw-in-js/typescript-plugin/issues) if you have any idea, question, or you've found a bug.
**Working on your first Pull Request?** You can learn how from this _free_ series [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github)
@@ -201,7 +215,9 @@ yarn link @twind/typescript-plugin
code . # Or launch editor/IDE what you like
```
-Of course, you can use other editor which communicates with tsserver .
+Of course, you can use other editor which communicates with tsserver.
+
+> To see typescript debug logs start your editor with `TSS_LOG="-logToFile true -file /path/to/tss.log -level verbose"`.
## License
diff --git a/assets/demo.gif b/assets/demo.gif
new file mode 100644
index 0000000..2f9970f
Binary files /dev/null and b/assets/demo.gif differ
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..b164b52
--- /dev/null
+++ b/index.js
@@ -0,0 +1,2 @@
+/* eslint-env node */
+module.exports = require('./typescript-plugin.cjs')
diff --git a/package.json b/package.json
index 41e2c84..a2615d0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@twind/typescript-plugin",
- "version": "0.1.0",
+ "version": "0.2.0",
"description": "TypeScript language service plugin that adds IntelliSense for twind",
"//": "mark as private to prevent accidental publish - use 'yarn release'",
"private": true,
@@ -14,15 +14,20 @@
"bugs": "https://github.com/tw-in-js/typescript-plugin/issues",
"repository": "github:tw-in-js/typescript-plugin",
"license": "MIT",
- "contributors": [
- "Luke Jackson (lukejacksonn.github.io)",
- "Sascha Tandel (https://github.com/sastan)"
+ "author": "Sascha Tandel (https://github.com/sastan)",
+ "files": [
+ "index.js"
],
- "main": "dist/node/twind_typescript-plugin.js",
- "source": "src/index.ts",
+ "// The 'module', 'unpkg' and 'types' fields are added by distilt": "",
+ "main": "src/index.ts",
+ "// Each entry is expanded into several bundles (module, script, types, require, node, and default)": "",
+ "exports": {
+ ".": "./src/index.ts",
+ "./package.json": "./package.json"
+ },
"browser": false,
"scripts": {
- "build": "./scripts/esbundle.js",
+ "build": "distilt",
"format": "prettier --write --ignore-path .gitignore .",
"lint": "eslint --ext .js,.ts --ignore-path .gitignore .",
"lint:fix": "yarn lint -- --fix",
@@ -77,17 +82,32 @@
}
]
},
+ "sideEffects": false,
+ "peerDependencies": {
+ "twind": ">=0.15.9 <2"
+ },
+ "peerDependenciesMeta": {
+ "twind": {
+ "optional": true
+ }
+ },
"dependencies": {
- "dlv": "^1.1.3",
- "tailwindcss": "^2.0.1",
+ "cssbeautify": "^0.3.1",
+ "esbuild": "^0.9.1",
+ "import-from": "^3.0.0",
+ "match-sorter": "^6.3.0",
+ "resolve-from": "^5.0.0",
+ "twind": "^0.16.0",
"typescript": "^4.1.0",
"typescript-template-language-service-decorator": "^2.2.0",
"vscode-languageserver-types": "^3.13.0"
},
"devDependencies": {
+ "@types/cssbeautify": "^0.3.1",
+ "@types/node": "^14.14.34",
"@typescript-eslint/eslint-plugin": "^4.9.1",
"@typescript-eslint/parser": "^4.9.1",
- "esbuild": "^0.8.23",
+ "distilt": "^0.10.1",
"eslint": "^7.15.0",
"eslint-config-prettier": "^7.0.0",
"eslint-plugin-prettier": "^3.2.0",
diff --git a/scripts/esbundle.js b/scripts/esbundle.js
deleted file mode 100755
index bf3d956..0000000
--- a/scripts/esbundle.js
+++ /dev/null
@@ -1,259 +0,0 @@
-#!/usr/bin/env node
-
-const { existsSync, promises: fs } = require('fs')
-const path = require('path')
-
-const paths = {
- root: path.resolve(__dirname, '..'),
- dist: path.resolve(__dirname, '..', 'dist'),
-}
-
-const manifest = require(path.resolve(paths.root, 'package.json'))
-
-const packageName = manifest.name.replace('@', '').replace('/', '_')
-const globalName = manifest.globalName || manifest.name.replace('@', '').replace('/', '.')
-
-const inputFile = path.resolve(paths.root, manifest.source || manifest.main)
-const tsconfig = path.resolve(paths.root, 'tsconfig.json')
-
-const useTypescript = existsSync(tsconfig)
-
-const targets = {
- node: 'node10.13',
- browser: ['chrome79', 'firefox78', 'safari13.1', 'edge79'],
-}
-
-const external = Object.keys({
- ...manifest.dependencies,
- ...manifest.peerDependencies,
- ...manifest.devDependencies,
- ...manifest.optinonalDependencies,
-})
-
-main().catch((error) => {
- console.error(error)
- process.exit(1)
-})
-
-async function main() {
- console.log(`Building bundle for ${path.relative(process.cwd(), inputFile)} ...`)
-
- await prepare()
- await Promise.all([
- copyFiles(),
- useTypescript && generateTypescriptDeclarations(),
- generateBundles(),
- ])
-
- if (manifest['size-limit']) {
- await require('size-limit/run')(process)
- }
-}
-
-async function prepare() {
- // Cleanup old build
- await fs.rmdir(paths.dist, { recursive: true, force: true })
-
- // Copy files
- await fs.mkdir(paths.dist)
-}
-
-async function copyFiles() {
- console.time('Copied common files')
-
- await Promise.all(
- ['LICENSE', 'README.md'].map((file) =>
- fs.copyFile(path.resolve(paths.root, file), path.resolve(paths.dist, file)),
- ),
- )
-
- console.timeEnd('Copied common files')
-}
-
-async function generateTypescriptDeclarations() {
- // generate typescript definitions
- const execa = require('execa')
-
- console.time('Generated typescript declarations')
-
- const config = path.resolve(path.dirname(tsconfig), 'tsconfig.dist.json')
-
- await fs.writeFile(
- config,
- JSON.stringify(
- {
- extends: './' + path.basename(tsconfig),
- exclude: ['**/__fixtures__/**', '**/__tests__/**'],
- compilerOptions: {
- target: 'ESNext',
- module: manifest.browser === false ? 'CommonJS' : 'ESNext',
- emitDeclarationOnly: true,
- noEmit: false,
- outDir: path.resolve(paths.dist, 'types'),
- },
- },
- null,
- 2,
- ),
- )
-
- try {
- // tsc --project tsconfig.dist.json
- await execa('tsc', ['--project', config], {
- cwd: paths.root,
- extendEnv: true,
- stdout: 'inherit',
- stderr: 'inherit',
- })
- } finally {
- await fs.unlink(config)
- }
-
- console.timeEnd('Generated typescript declarations')
-}
-
-async function generateBundles() {
- const outputs = {}
-
- if (manifest.browser !== true) {
- Object.assign(outputs, {
- // Used by nodejs
- node: {
- outfile: `./node/${packageName}.js`,
- platform: 'node',
- target: targets.node,
- format: 'cjs',
- },
- })
- }
-
- if (manifest.browser !== false) {
- Object.assign(outputs, {
- esnext: {
- outfile: `./esnext/${packageName}.js`,
- platform: 'browser',
- target: 'esnext',
- format: 'esm',
- },
- // Can be used from a normal script tag without module system.
- script: {
- outfile: `./script/${packageName}.js`,
- platform: 'browser',
- target: 'es2017',
- format: 'iife',
- globalName,
- minify: true,
- external: false,
- },
- // Used by bundlers like rollup and cdn
- default: {
- outfile: `./module/${packageName}.js`,
- platform: 'browser',
- target: targets.browser,
- format: 'esm',
- minify: true,
- },
- })
- }
-
- const publishManifest = {
- ...manifest,
-
- // Define package loading
- // https://gist.github.com/sokra/e032a0f17c1721c71cfced6f14516c62
- exports: {
- ...manifest.exports,
- '.': {
- node: outputs.node && outputs.node.outfile,
- esnext: outputs.esnext && outputs.esnext.outfile,
- default: outputs.default ? outputs.default.outfile : outputs.node.outfile,
- },
-
- // Allow access to all files (including package.json, ...)
- './': './',
- },
-
- // Used by nodejs
- main: outputs.node ? outputs.node.outfile : outputs.default.outfile,
-
- // Used by carv cdn
- esnext: outputs.esnext && outputs.esnext.outfile,
-
- // Used by bundlers like rollup and cdns
- module: outputs.default && outputs.default.outfile,
-
- unpkg: outputs.script && outputs.script.outfile,
-
- types: useTypescript ? './types/index.d.ts' : undefined,
-
- // Some defaults
- sideEffects: false,
-
- // Allow publish
- private: undefined,
-
- // Include all files in the dist folder
- files: undefined,
-
- // Default to cjs
- type: undefined,
-
- // These are not needed any more
- source: undefined,
- scripts: undefined,
- devDependencies: undefined,
- optionalDependencies: undefined,
-
- // Reset bundledDependencies as esbuild includes those into the bundle
- bundledDependencies: undefined,
- bundleDependencies: undefined,
-
- // Reset config sections
- eslintConfig: undefined,
- prettier: undefined,
- np: undefined,
- 'size-limit': undefined,
-
- // Resets comments
- '//': undefined,
- }
-
- await fs.writeFile(
- path.join(paths.dist, 'package.json'),
- JSON.stringify(publishManifest, null, 2),
- )
-
- const service = await require('esbuild').startService()
-
- try {
- await Promise.all(
- Object.entries(outputs)
- .filter(([, output]) => output)
- .map(async ([, output]) => {
- const outfile = path.resolve(paths.dist, output.outfile)
-
- const logKey = `Bundled ${path.relative(process.cwd(), outfile)} (${output.format} - ${
- output.target
- })`
- console.time(logKey)
-
- await service.build({
- ...output,
- outfile,
- entryPoints: [inputFile],
- charset: 'utf8',
- resolveExtensions: ['.tsx', '.ts', '.jsx', '.mjs', '.js', '.cjs', '.css', '.json'],
- bundle: true,
- external: output.external === false ? undefined : external,
- mainFields: ['esnext', 'es2015', 'module', 'main'],
- sourcemap: 'external',
- tsconfig,
- })
-
- console.timeEnd(logKey)
- }),
- )
- } finally {
- service.stop()
- }
-}
diff --git a/src/colors.ts b/src/colors.ts
new file mode 100644
index 0000000..557ed34
--- /dev/null
+++ b/src/colors.ts
@@ -0,0 +1,198 @@
+const NAMED_COLORS = new Set([
+ 'transparent',
+ 'currentColor',
+ 'aliceblue',
+ 'antiquewhite',
+ 'aqua',
+ 'aquamarine',
+ 'azure',
+ 'beige',
+ 'bisque',
+ 'black',
+ 'blanchedalmond',
+ 'blue',
+ 'blueviolet',
+ 'brown',
+ 'burlywood',
+ 'cadetblue',
+ 'chartreuse',
+ 'chocolate',
+ 'coral',
+ 'cornflowerblue',
+ 'cornsilk',
+ 'crimson',
+ 'cyan',
+ 'darkblue',
+ 'darkcyan',
+ 'darkgoldenrod',
+ 'darkgray',
+ 'darkgreen',
+ 'darkgrey',
+ 'darkkhaki',
+ 'darkmagenta',
+ 'darkolivegreen',
+ 'darkorange',
+ 'darkorchid',
+ 'darkred',
+ 'darksalmon',
+ 'darkseagreen',
+ 'darkslateblue',
+ 'darkslategray',
+ 'darkslategrey',
+ 'darkturquoise',
+ 'darkviolet',
+ 'deeppink',
+ 'deepskyblue',
+ 'dimgray',
+ 'dimgrey',
+ 'dodgerblue',
+ 'firebrick',
+ 'floralwhite',
+ 'forestgreen',
+ 'fuchsia',
+ 'gainsboro',
+ 'ghostwhite',
+ 'gold',
+ 'goldenrod',
+ 'gray',
+ 'green',
+ 'greenyellow',
+ 'grey',
+ 'honeydew',
+ 'hotpink',
+ 'indianred',
+ 'indigo',
+ 'ivory',
+ 'khaki',
+ 'lavender',
+ 'lavenderblush',
+ 'lawngreen',
+ 'lemonchiffon',
+ 'lightblue',
+ 'lightcoral',
+ 'lightcyan',
+ 'lightgoldenrodyellow',
+ 'lightgray',
+ 'lightgreen',
+ 'lightgrey',
+ 'lightpink',
+ 'lightsalmon',
+ 'lightseagreen',
+ 'lightskyblue',
+ 'lightslategray',
+ 'lightslategrey',
+ 'lightsteelblue',
+ 'lightyellow',
+ 'lime',
+ 'limegreen',
+ 'linen',
+ 'magenta',
+ 'maroon',
+ 'mediumaquamarine',
+ 'mediumblue',
+ 'mediumorchid',
+ 'mediumpurple',
+ 'mediumseagreen',
+ 'mediumslateblue',
+ 'mediumspringgreen',
+ 'mediumturquoise',
+ 'mediumvioletred',
+ 'midnightblue',
+ 'mintcream',
+ 'mistyrose',
+ 'moccasin',
+ 'navajowhite',
+ 'navy',
+ 'oldlace',
+ 'olive',
+ 'olivedrab',
+ 'orange',
+ 'orangered',
+ 'orchid',
+ 'palegoldenrod',
+ 'palegreen',
+ 'paleturquoise',
+ 'palevioletred',
+ 'papayawhip',
+ 'peachpuff',
+ 'peru',
+ 'pink',
+ 'plum',
+ 'powderblue',
+ 'purple',
+ 'rebeccapurple',
+ 'red',
+ 'rosybrown',
+ 'royalblue',
+ 'saddlebrown',
+ 'salmon',
+ 'sandybrown',
+ 'seagreen',
+ 'seashell',
+ 'sienna',
+ 'silver',
+ 'skyblue',
+ 'slateblue',
+ 'slategray',
+ 'slategrey',
+ 'snow',
+ 'springgreen',
+ 'steelblue',
+ 'tan',
+ 'teal',
+ 'thistle',
+ 'tomato',
+ 'transparent',
+ 'turquoise',
+ 'violet',
+ 'wheat',
+ 'white',
+ 'whitesmoke',
+ 'yellow',
+ 'yellowgreen',
+])
+
+const DEPRECATED_SYSTEM_COLORS = new Set([
+ 'ActiveBorder',
+ 'ActiveCaption',
+ 'AppWorkspace',
+ 'Background',
+ 'ButtonFace',
+ 'ButtonHighlight',
+ 'ButtonShadow',
+ 'ButtonText',
+ 'CaptionText',
+ 'GrayText',
+ 'Highlight',
+ 'HighlightText',
+ 'InactiveBorder',
+ 'InactiveCaption',
+ 'InactiveCaptionText',
+ 'InfoBackground',
+ 'InfoText',
+ 'Menu',
+ 'MenuText',
+ 'Scrollbar',
+ 'ThreeDDarkShadow',
+ 'ThreeDFace',
+ 'ThreeDHighlight',
+ 'ThreeDLightShadow',
+ 'ThreeDShadow',
+ 'Window',
+ 'WindowFrame',
+ 'WindowText',
+])
+
+const COLORS = new Set([...NAMED_COLORS, ...DEPRECATED_SYSTEM_COLORS])
+
+const isColorLike = (value: string): boolean =>
+ /^((#[\da-f]{3,8})|(((rgb|hsl)[a]?)\(?([\d]?\.?[\d]+%?,?\s?){3,4}\)?))$/i.test(value)
+
+// TODO function with opacityValue
+export const getColor = (value: unknown): string | undefined => {
+ if (typeof value == 'string' && (COLORS.has(value) || isColorLike(value))) {
+ return value
+ }
+
+ return undefined
+}
diff --git a/src/configuration.ts b/src/configuration.ts
index db80ba9..5bab385 100644
--- a/src/configuration.ts
+++ b/src/configuration.ts
@@ -1,13 +1,15 @@
-export interface TailwindjsPluginConfiguration {
+export interface TwindPluginConfiguration {
readonly tags: ReadonlyArray
+ readonly debug: boolean
// Readonly validate: boolean;
// readonly lint: { [key: string]: any };
// readonly emmet: { [key: string]: any };
}
export class ConfigurationManager {
- private static readonly defaultConfiguration: TailwindjsPluginConfiguration = {
- tags: ['tw'],
+ private static readonly defaultConfiguration: TwindPluginConfiguration = {
+ tags: ['tw', 'apply'],
+ debug: false,
// Validate: true,
// lint: {
// emptyRules: 'ignore',
@@ -17,18 +19,23 @@ export class ConfigurationManager {
private readonly _configUpdatedListeners = new Set<() => void>()
- public get config(): TailwindjsPluginConfiguration {
+ public get config(): TwindPluginConfiguration {
return this._configuration
}
- private _configuration: TailwindjsPluginConfiguration = ConfigurationManager.defaultConfiguration
+ private _configuration: TwindPluginConfiguration = ConfigurationManager.defaultConfiguration
- public updateFromPluginConfig(config: TailwindjsPluginConfiguration): void {
- this._configuration = {
+ public updateFromPluginConfig(config: Partial = {}): void {
+ const mergedConfig = {
...ConfigurationManager.defaultConfiguration,
...config,
}
+ this._configuration = {
+ ...mergedConfig,
+ debug: 'true' == String(mergedConfig.debug),
+ }
+
for (const listener of this._configUpdatedListeners) {
listener()
}
diff --git a/src/index.ts b/src/index.ts
index a418fe4..65c327a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -4,7 +4,6 @@
// https://github.com/tailwindlabs/tailwindcss-intellisense/tree/master/packages/tailwindcss-language-service
import type * as ts from 'typescript/lib/tsserverlibrary'
-import { TailwindjsPlugin } from './plugin'
+import { TwindPlugin } from './plugin'
-export = (config: { typescript: typeof ts }): TailwindjsPlugin =>
- new TailwindjsPlugin(config.typescript)
+export = (config: { typescript: typeof ts }): TwindPlugin => new TwindPlugin(config.typescript)
diff --git a/src/language-service.ts b/src/language-service.ts
index 4b0a80b..d6976fc 100644
--- a/src/language-service.ts
+++ b/src/language-service.ts
@@ -7,13 +7,14 @@ import type {
TemplateLanguageService,
} from 'typescript-template-language-service-decorator'
import type * as ts from 'typescript/lib/tsserverlibrary'
+import * as vscode from 'vscode-languageserver-types'
import type { ConfigurationManager } from './configuration'
-import * as vscode from 'vscode-languageserver-types'
+import { defaultBaseSortFn, matchSorter } from 'match-sorter'
-import { processPlugins } from './process-plugins'
-import { parse } from './parse'
+import { parse, ParsedRule } from './parse'
+import { CompletionToken, Twind } from './twind'
function arePositionsEqual(left: ts.LineAndCharacter, right: ts.LineAndCharacter): boolean {
return left.line === right.line && left.character === right.character
@@ -27,20 +28,29 @@ function arePositionsEqual(left: ts.LineAndCharacter, right: ts.LineAndCharacter
// return !isAfter(a.end, b.start) && !isAfter(b.end, a.start)
// }
-function pad(n: string): string {
- return ('00000000' + n).slice(-8)
-}
-
-function naturalExpand(value: number | string): string {
- const string = typeof value === 'string' ? value : value.toString()
- return string.replace(/\d+/g, pad)
-}
-
// !const emptyCompletionList: vscode.CompletionList = {
// items: [],
// isIncomplete: false,
// }
+const enum ErrorCodes {
+ UNKNOWN_DIRECTIVE = -2020,
+ UNKNOWN_THEME_VALUE = -2021,
+}
+
+const pad = (n: string): string => n.padStart(8, '0')
+
+const naturalExpand = (value: number | string): string => ('' + value).replace(/\d+/g, pad)
+
+// By default, match-sorter assumes spaces to be the word separator.
+// Lets split the text into whitespace spearated words
+const prepareText = (value: string): string =>
+ value
+ .replace(/[A-Z]/g, ' $&')
+ .replace(/(?
-
- constructor(typescript: typeof ts, configurationManager: ConfigurationManager, logger: Logger) {
+ private readonly _twind: Twind
+
+ constructor(
+ typescript: typeof ts,
+ info: ts.server.PluginCreateInfo,
+ configurationManager: ConfigurationManager,
+ logger: Logger,
+ ) {
this.typescript = typescript
+ this.info = info
this.configurationManager = configurationManager
this.logger = logger
- this.state = processPlugins()
+ this._twind = new Twind(typescript, info, configurationManager, logger)
}
public getCompletionsAtPosition(
@@ -119,59 +135,114 @@ export class TailwindjsTemplateLanguageService implements TemplateLanguageServic
return translateCompletionItemsToCompletionEntryDetails(this.typescript, item)
}
- // Public getQuickInfoAtPosition(
- // context: TemplateContext,
- // position: ts.LineAndCharacter,
- // ): ts.QuickInfo | undefined {
- // const doc = this.virtualDocumentFactory.createVirtualDocument(context)
- // const stylesheet = this.scssLanguageService.parseStylesheet(doc)
- // const hover = this.scssLanguageService.doHover(
- // doc,
- // this.virtualDocumentFactory.toVirtualDocPosition(position),
- // stylesheet,
- // )
- // if (hover) {
- // return this.translateHover(
- // hover,
- // this.virtualDocumentFactory.toVirtualDocPosition(position),
- // context,
- // )
- // }
- // }
+ public getQuickInfoAtPosition(
+ context: TemplateContext,
+ position: ts.LineAndCharacter,
+ ): ts.QuickInfo | undefined {
+ const offset = context.toOffset(position)
- // public getSemanticDiagnostics(context: TemplateContext): ts.Diagnostic[] {
- // const diagnostics: ts.Diagnostic[] = []
-
- // // for (const match of regexExec(/[^:\s]+:?/g, templateContext.text)) {
- // // const className = match[0]
- // // const start = match.index
- // // const length = match[0].length
-
- // // if (!languageServiceContext.completionEntries.has(className)) {
- // // diagnostics.push({
- // // messageText: `unknown tailwind class or variant "${className}"`,
- // // start: start,
- // // length: length,
- // // file: templateContext.node.getSourceFile(),
- // // category: ts.DiagnosticCategory.Warning,
- // // code: 0, // ???
- // // })
- // // }
- // // }
-
- // return diagnostics
- // // const doc = this.virtualDocumentFactory.createVirtualDocument(context)
- // // const stylesheet = this.scssLanguageService.parseStylesheet(doc)
- // // return this.translateDiagnostics(
- // // this.scssLanguageService.doValidation(doc, stylesheet),
- // // doc,
- // // context,
- // // context.text,
- // // ).filter((x) => !!x) as ts.Diagnostic[]
- // }
+ const find = (char: string): number => {
+ const index = context.text.indexOf(char, offset)
+ return index >= offset ? index : context.text.length
+ }
+
+ const nextBoundary = Math.min(find(')'), find(' '), find('\t'), find('\n'), find('\r'))
+
+ if (nextBoundary == offset) {
+ return undefined
+ }
+
+ const parsed = parse(context.text, nextBoundary)
+
+ const end = parsed.tokenStartOffset + (parsed.token == '&' ? -1 : 0)
+ const start = Math.max(0, end - parsed.token.length)
+ const rule = parsed.prefix ? parsed.rule.replace('&', parsed.prefix) : parsed.rule
+
+ const css = this._twind.css(rule)
+
+ if (css) {
+ return {
+ kind: translateCompletionItemKind(this.typescript, vscode.CompletionItemKind.Property),
+ kindModifiers: '',
+ textSpan: {
+ start,
+ length: end - start,
+ },
+ displayParts: toDisplayParts(rule),
+ // displayParts: [],
+ documentation: toDisplayParts({
+ kind: 'markdown',
+ value: '```css\n' + css + '\n```',
+ }),
+ tags: [],
+ }
+ }
+
+ return undefined
+ }
+
+ public getSemanticDiagnostics(context: TemplateContext): ts.Diagnostic[] {
+ const diagnostics: ts.Diagnostic[] = []
+
+ const { text } = context
+
+ for (let offset = 0; offset <= text.length; offset++) {
+ if (') \t\n\r'.includes(text[offset]) || offset == text.length) {
+ const parsed = parse(context.text, offset)
+
+ const rule = parsed.prefix ? parsed.rule.replace('&', parsed.prefix) : parsed.rule
+
+ if (rule) {
+ const end = offset
+ const start = Math.max(0, end - parsed.token.length)
+
+ this.logger.log(
+ `getDiagnostics: ${rule} ${parsed.token} - ${parsed.tokenStartOffset} ${start}:${end}`,
+ )
+
+ this._twind.getDiagnostics(rule)?.some((info) => {
+ switch (info.id) {
+ case 'UNKNOWN_DIRECTIVE': {
+ diagnostics.push({
+ messageText: `Unknown utility "${
+ parsed.prefix ? parsed.directive.replace('&', parsed.prefix) : parsed.directive
+ }"`,
+ start: start,
+ length: end - start,
+ file: context.node.getSourceFile(),
+ category: this.typescript.DiagnosticCategory.Warning,
+ code: ErrorCodes.UNKNOWN_DIRECTIVE,
+ })
+ return true
+ }
+ case 'UNKNOWN_THEME_VALUE': {
+ if (info.key) {
+ const [section, ...key] = info.key?.split('.')
+
+ diagnostics.push({
+ messageText: `Unknown theme value "${section}[${key.join('.')}]"`,
+ start: start,
+ length: end - start,
+ file: context.node.getSourceFile(),
+ category: this.typescript.DiagnosticCategory.Warning,
+ code: ErrorCodes.UNKNOWN_THEME_VALUE,
+ })
+ return true
+ }
+ }
+ }
+
+ return false
+ })
+ }
+ }
+ }
+
+ return diagnostics
+ }
// public getSupportedCodeFixes(): number[] {
- // return [cssErrorCode]
+ // return [ErrorCodes.UNKNOWN_DIRECTIVE, ErrorCodes.UNKNOWN_THEME_VALUE]
// }
// public getCodeFixesAtPosition(
@@ -209,6 +280,84 @@ export class TailwindjsTemplateLanguageService implements TemplateLanguageServic
// .map((range) => this.translateOutliningSpan(context, range))
// }
+ private getCompletionItem(
+ context: TemplateContext,
+ position: ts.LineAndCharacter,
+ completion: CompletionToken,
+ parsed: ParsedRule,
+ sortedIndex: number,
+ ): vscode.CompletionItem {
+ const label =
+ parsed.prefix && completion.kind == 'utility'
+ ? completion.label.slice(parsed.prefix.length + 1)
+ : completion.label
+
+ const newText =
+ parsed.prefix && completion.kind == 'utility'
+ ? completion.value.slice(parsed.prefix.length + 1)
+ : completion.value
+
+ const textEdit = {
+ newText,
+ range: {
+ start: context.toPosition(Math.max(0, parsed.tokenStartOffset - parsed.token.length)),
+ end: context.toPosition(parsed.tokenStartOffset),
+ },
+ }
+
+ return {
+ kind: completion.color
+ ? vscode.CompletionItemKind.Color
+ : completion.kind == 'screen'
+ ? vscode.CompletionItemKind.EnumMember
+ : completion.kind == 'variant'
+ ? vscode.CompletionItemKind.Module
+ : vscode.CompletionItemKind.Property,
+ data: completion.kind,
+ label,
+ preselect: false,
+ filterText: parsed.rule,
+ sortText: sortedIndex.toString().padStart(8, '0'),
+ detail: completion.detail,
+ documentation: {
+ kind: vscode.MarkupKind.Markdown,
+ value: [
+ completion.css && '```css\n' + completion.css + '\n```',
+ completion.theme &&
+ '**Theme**\n\n```json\n' +
+ JSON.stringify(
+ {
+ [completion.theme.section]: {
+ [completion.theme.key]: completion.theme.value,
+ },
+ },
+ null,
+ 2,
+ ) +
+ '\n```',
+ this.configurationManager.config.debug &&
+ '**Parsed**\n\n```json\n' +
+ JSON.stringify(
+ {
+ ...parsed,
+ sortedIndex,
+ textEdit,
+ },
+ null,
+ 2,
+ ) +
+ '\n```',
+ this.configurationManager.config.debug &&
+ '**Completion**\n\n```json\n' + JSON.stringify(completion, null, 2) + '\n```',
+ ]
+ .filter(Boolean)
+ .join('\n\n'),
+ },
+
+ textEdit,
+ }
+ }
+
private getCompletionItems(
context: TemplateContext,
position: ts.LineAndCharacter,
@@ -219,159 +368,208 @@ export class TailwindjsTemplateLanguageService implements TemplateLanguageServic
}] ${JSON.stringify(context.text)}`,
)
- // Const cached = this._completionsCache.getCached(context, position)
+ const cached = this._completionsCache.getCached(context, position)
- // if (cached) {
- // return cached
- // }
-
- const { token, variants, prefix, directive, tokenStartOffset } = parse(
- context.text,
- context.toOffset(position),
- )
+ if (cached) {
+ return cached
+ }
const completions: vscode.CompletionList = {
- isIncomplete: false,
+ isIncomplete: true,
items: [],
}
- // Sort order
- // 1. ! - best guess
- // 2. # - directive group
- // 3. $ - directive
- // 4. & - prefix self
- // 5. : - variant
- // 6. @ - screen
- completions.items = [
- ...Object.keys(this.state.screens)
- .filter((screen) => variants.length === 0 && screen.startsWith(token))
- .map((screen) => ({
- kind: vscode.CompletionItemKind.EnumMember,
- data: 'screen',
- label: `${screen}:`,
- sortText: `@${screen}`,
- detail: `breakpoint @ ${this.state.screens[screen]}`,
- documentation: {
- kind: vscode.MarkupKind.PlainText,
- value: `@media (min-width: ${this.state.screens[screen]})`,
- },
- textEdit: {
- newText: `${screen}:`.slice(token.length),
- range: {
- start: context.toPosition(tokenStartOffset + token.length),
- end: position,
- },
- },
- })),
- ...this.state.variants
- .filter((variant) => !variants.includes(':' + variant) && variant.startsWith(token))
- .map((variant) => ({
- kind: vscode.CompletionItemKind.Unit,
- data: 'variant',
- label: `${variant}:`,
- detail: `pseudo-class ${variant}`,
- documentation: { kind: vscode.MarkupKind.PlainText, value: `Add ${variant} variant` },
- textEdit: {
- newText: `${variant}:`.slice(token.length),
- range: {
- start: context.toPosition(tokenStartOffset + token.length),
- end: position,
- },
- },
- })),
- // Start a new directive group
- ...Object.keys(this.state.directives)
- .filter((key) => key.startsWith(directive))
- // Tex
- // text-current
- // => text
- // ring-off
- // ring-offset-70
- // => ring-offset
- .map((key) => {
- const nextDash = key.indexOf('-', directive.length)
- return nextDash >= 0 ? key.slice(0, nextDash) : ''
- })
- .filter((group, index, groups) => group && groups.indexOf(group) === index)
- .map((key) => ({
- kind: vscode.CompletionItemKind.Module,
- data: 'directive-group',
- label: prefix ? key.slice(prefix.length + 1) : key,
- sortText: `#${key}`,
- detail: `${key}(...)`,
- documentation: { kind: vscode.MarkupKind.PlainText, value: `Start a new ${key} group` },
- textEdit: {
- newText: (prefix ? key.slice(prefix.length + 1) : key).slice(token.length),
- range: {
- start: context.toPosition(tokenStartOffset + token.length),
- end: position,
- },
- },
- })),
- // Insert directive
- // tex
- // text-current
- // => text
- // ring-off
- // ring-offset-70
- // => ring-offset
- ...Object.keys(this.state.directives)
- .filter((key) => key.startsWith(directive))
- .map((key) => ({
- kind:
- key === 'text-black'
- ? vscode.CompletionItemKind.Color
- : vscode.CompletionItemKind.Property,
- data: 'directive',
- label: prefix ? key.slice(prefix.length + 1) : key,
- sortText: `$${naturalExpand(key)}`,
- // VS Code bug causes '0' to not display in some cases
- detail: key === '0' ? '0 ' : key,
- // TODO https://github.com/tailwindlabs/tailwindcss-intellisense/blob/264cdc0c5e6fdbe1fee3c2dc338354235277ed08/packages/tailwindcss-language-service/src/util/color.ts#L28
- documentation:
- key === 'text-black'
- ? '#ff0000'
- : {
- kind: vscode.MarkupKind.Markdown,
- value: [
- '```css',
- '.' +
- (variants.length === 0 ? '' : variants.join('').slice(1) + ':') +
- this.state.directives[key].selector.slice(1) +
- ' {',
- ...Object.entries(this.state.directives[key].properties).map(
- ([property, value]) => ` ${property}: ${value};`,
- ),
- '}',
- '```',
- ].join('\n'),
- },
- textEdit: {
- newText: (prefix ? key.slice(prefix.length + 1) : key).slice(token.length),
- range: {
- start: context.toPosition(tokenStartOffset + token.length),
- end: position,
- },
- },
- })),
+ const { completions: twindCompletions } = this._twind
+
+ const parsed = parse(context.text, context.toOffset(position))
+
+ const hasScreenVariant = parsed.variants.some((x) => twindCompletions.screens.includes(x))
+
+ const screens = hasScreenVariant
+ ? []
+ : twindCompletions.tokens.filter((completion) => completion.kind == 'screen')
+
+ const variants = twindCompletions.tokens.filter(
+ (completion) => completion.kind == 'variant' && !parsed.variants.includes(completion.value),
+ )
+
+ const utilities = twindCompletions.tokens.filter(
+ (completion) =>
+ (completion.kind == 'utility' && !parsed.prefix) ||
+ completion.value.startsWith(parsed.prefix + '-'),
+ )
+
+ // TODO Start a new directive group
+ const matched = [
+ ...matchSorter(screens, prepareText(parsed.token), {
+ threshold: matchSorter.rankings.MATCHES,
+ keys: [
+ (completion) => prepareText(naturalExpand(completion.detail) + ' ' + completion.value),
+ ],
+ }),
+ ...matchSorter(utilities, prepareText(parsed.directive), {
+ threshold: matchSorter.rankings.ACRONYM,
+ keys: [(completion) => prepareText(naturalExpand(completion.value))],
+ sorter: (items) =>
+ items.sort((a, b) => {
+ if (a.rankedValue[0] == '-' && b.rankedValue[0] != '-') {
+ return 1
+ }
+
+ if (a.rankedValue[0] != '-' && b.rankedValue[0] == '-') {
+ return -1
+ }
+
+ return defaultBaseSortFn(a, b)
+ }),
+ }),
+ ...matchSorter(variants, prepareText(parsed.token), {
+ threshold: matchSorter.rankings.ACRONYM,
+ keys: [(completion) => prepareText(completion.value)],
+ }),
]
- if (prefix && (!token || token === '&')) {
- completions.items.push({
- kind: vscode.CompletionItemKind.Snippet,
+ completions.items = matched.map((completion, index) =>
+ this.getCompletionItem(context, position, completion, parsed, index),
+ )
+
+ // this._completions.tokens.forEach((completion) => {
+ // if (completion.kind != 'utility' && !completion.value.startsWith(parsed.token)) {
+ // return
+ // }
+
+ // if (completion.kind == 'utility' && !completion.value.startsWith(parsed.directive)) {
+ // return
+ // }
+
+ // if (completion.kind == 'screen' && hasScreenVariant) {
+ // return
+ // }
+
+ // if (completion.kind == 'variant' && parsed.variants.includes(completion.value)) {
+ // return
+ // }
+
+ // completions.items.push(this.getCompletionItem(context, position, completion, parsed))
+ // })
+
+ // completions.items = [
+ // // Start a new directive group
+ // ...Object.keys(this.state.directives)
+ // .filter((key) => key.startsWith(directive))
+ // // Tex
+ // // text-current
+ // // => text
+ // // ring-off
+ // // ring-offset-70
+ // // => ring-offset
+ // .map((key) => {
+ // const nextDash = key.indexOf('-', directive.length)
+ // return nextDash >= 0 ? key.slice(0, nextDash) : ''
+ // })
+ // .filter((group, index, groups) => group && groups.indexOf(group) === index)
+ // .map((key) => ({
+ // kind: vscode.CompletionItemKind.Module,
+ // data: 'directive-group',
+ // label: prefix ? key.slice(prefix.length + 1) : key,
+ // sortText: `#${key}`,
+ // detail: `${key}(...)`,
+ // documentation: { kind: vscode.MarkupKind.PlainText, value: `Start a new ${key} group` },
+ // textEdit: {
+ // newText: (prefix ? key.slice(prefix.length + 1) : key).slice(token.length),
+ // range: {
+ // start: context.toPosition(tokenStartOffset + token.length),
+ // end: position,
+ // },
+ // },
+ // })),
+ // ]
+
+ if (parsed.prefix && (!parsed.token || parsed.token === '&')) {
+ completions.items.unshift({
+ kind: vscode.CompletionItemKind.Constant,
label: `&`,
- detail: prefix,
- sortText: `&`,
+ detail: `${parsed.prefix}`,
+ sortText: `&${parsed.prefix}`,
+ documentation: this.configurationManager.config.debug
+ ? {
+ kind: vscode.MarkupKind.Markdown,
+ value: [
+ '**Parsed**\n\n```json\n' +
+ JSON.stringify(
+ {
+ ...parsed,
+ items: completions.items.map(({ label, filterText, sortText, textEdit }) => ({
+ label,
+ filterText,
+ sortText,
+ textEdit,
+ })),
+ matched: matched.map((x) => x.value),
+ // utilities: utilities.map((x) => x.value),
+ },
+ null,
+ 2,
+ ) +
+ '\n```',
+ ]
+ .filter(Boolean)
+ .join('\n\n'),
+ }
+ : undefined,
textEdit: {
- newText: `&`.slice(token.length),
+ newText: `&`.slice(parsed.token.length),
range: {
- start: context.toPosition(tokenStartOffset + token.length),
- end: position,
+ start: context.toPosition(Math.max(0, parsed.tokenStartOffset - parsed.token.length)),
+ end: context.toPosition(parsed.tokenStartOffset),
},
},
})
}
+ // if (this.configurationManager.config.debug) {
+ // completions.items.unshift({
+ // kind: vscode.CompletionItemKind.Constant,
+ // label: `----`,
+ // filterText: parsed.token,
+ // preselect: true,
+ // detail: parsed.directive,
+ // sortText: `&${parsed.prefix}`,
+ // documentation: {
+ // kind: vscode.MarkupKind.Markdown,
+ // value: [
+ // this.configurationManager.config.debug &&
+ // '**Parsed**\n\n```json\n' +
+ // JSON.stringify(
+ // {
+ // ...parsed,
+ // items: completions.items.map(({ label, filterText, sortText, textEdit }) => ({
+ // label,
+ // filterText,
+ // sortText,
+ // textEdit,
+ // })),
+ // matched: matched.map((x) => x.value),
+ // // utilities: utilities.map((x) => x.value),
+ // },
+ // null,
+ // 2,
+ // ) +
+ // '\n```',
+ // ]
+ // .filter(Boolean)
+ // .join('\n\n'),
+ // },
+ // textEdit: {
+ // newText: `&`.slice(parsed.token.length),
+ // range: {
+ // start: context.toPosition(parsed.tokenStartOffset + parsed.token.length),
+ // end: position,
+ // },
+ // },
+ // })
+ // }
+
this._completionsCache.updateCached(context, position, completions)
return completions
diff --git a/src/load-twind-config.ts b/src/load-twind-config.ts
new file mode 100644
index 0000000..02e4e6f
--- /dev/null
+++ b/src/load-twind-config.ts
@@ -0,0 +1,89 @@
+import * as Path from 'path'
+import Module from 'module'
+
+import { buildSync } from 'esbuild'
+import findUp from 'find-up'
+
+import type { Configuration } from 'twind'
+
+export const findConfig = (cwd = process.cwd()): string | undefined =>
+ findUp.sync(['twind.config.ts', 'twind.config.mjs', 'twind.config.js', 'twind.config.cjs'], {
+ cwd,
+ })
+
+export const loadConfig = (configFile: string): Configuration => {
+ const result = buildSync({
+ bundle: true,
+ entryPoints: [configFile],
+ format: 'cjs',
+ platform: 'node',
+ target: `node${process.versions.node}`,
+ external: Module.builtinModules,
+ sourcemap: 'inline',
+ minify: false,
+ splitting: false,
+ write: false,
+ })
+
+ const module = { exports: {} as { default?: Configuration } & Configuration }
+
+ new Function(
+ 'exports',
+ 'require',
+ 'module',
+ '__filename',
+ '__dirname',
+ result.outputFiles[0].text,
+ )(
+ module.exports,
+ Module.createRequire?.(configFile) || Module.createRequireFromPath(configFile),
+ module,
+ configFile,
+ Path.dirname(configFile),
+ )
+
+ const config = module.exports.default || module.exports || {}
+
+ // could be tailwind config
+ if (
+ (Array.isArray(config.plugins) ||
+ // Twind has variants as {key: string}; Tailwind array or object
+ Object.values(config.variants || {}).some((value) => typeof value == 'object') ||
+ typeof config.prefix == 'string',
+ 'presets' in config ||
+ 'important' in config ||
+ 'separator' in config ||
+ 'variantOrder' in config ||
+ 'corePlugins' in config ||
+ 'purge' in config)
+ ) {
+ // console.error(
+ // kleur.red(
+ // `${kleur.bold(
+ // Path.relative(process.cwd(), configFile),
+ // )} is a tailwindcss configuration file – ${kleur.bold(
+ // 'only',
+ // )} the theme, darkMode, purge files are used`,
+ // ),
+ // )
+
+ return {
+ theme: config.theme,
+ darkMode: config.darkMode,
+ }
+ }
+
+ return config
+}
+
+export const getConfig = (
+ cwd = process.cwd(),
+ configFile?: string,
+): Configuration & { configFile: string | undefined } => {
+ configFile ??= findConfig(cwd)
+
+ return {
+ ...(configFile ? loadConfig(Path.resolve(cwd, configFile)) : {}),
+ configFile,
+ }
+}
diff --git a/src/parse.ts b/src/parse.ts
index 2220063..24a7a81 100644
--- a/src/parse.ts
+++ b/src/parse.ts
@@ -10,6 +10,8 @@ export interface ParsedRule {
/** [":sm", ":dark", ":hover"] */
variants: string[]
+ important: boolean
+
prefix: string
/** "text-sm", "rotate-45" */
@@ -34,14 +36,7 @@ const endGrouping = (isWhitespace?: boolean): void => {
// ['', ':sm', ':hover'] => ['']
// ['', ':sm', ':hover', ''] => ['', ':sm', ':hover', '']
- const index = groupings.lastIndexOf('')
-
- if (~index) {
- groupings.splice(
- index + ~~(isWhitespace as boolean),
- groupings.length - index + ~~(isWhitespace as boolean),
- )
- }
+ groupings.length = Math.max(groupings.lastIndexOf('') + ~~(isWhitespace as boolean), 0)
}
const onlyPrefixes = (s: string): '' | boolean => s && s[0] !== ':'
@@ -59,7 +54,7 @@ export const parse = (text: string, offset = text.length): ParsedRule => {
case ':':
if (token) {
tokenStartOffset = offset
- token = startGrouping(':' + token)
+ token = startGrouping(':' + (text[position + 1] == char ? text[position++] : '') + token)
}
break
@@ -91,7 +86,13 @@ export const parse = (text: string, offset = text.length): ParsedRule => {
}
}
- const variants = groupings.filter(onlyVariants)
+ const variants = groupings.filter(onlyVariants).map((variant) => {
+ if (variant.startsWith('::')) {
+ return variant.slice(2) + '::'
+ }
+
+ return variant.slice(1) + ':'
+ })
const prefix = groupings.filter(onlyPrefixes).join('-')
const directive = token === '&' ? token : (prefix && prefix + '-') + token
@@ -99,12 +100,19 @@ export const parse = (text: string, offset = text.length): ParsedRule => {
tokenStartOffset += 1
}
+ const important = token[token.length - 1] == '!'
+
+ if (important) {
+ token = token.slice(0, -1)
+ }
+
return {
token,
variants,
+ important,
prefix,
directive,
- rule: (variants.length === 0 ? '' : variants.join('').slice(1) + ':') + directive,
+ rule: variants.join('') + directive,
tokenStartOffset,
}
}
diff --git a/src/plugin.ts b/src/plugin.ts
index 8677e83..337e7f8 100644
--- a/src/plugin.ts
+++ b/src/plugin.ts
@@ -2,13 +2,12 @@ import type * as ts from 'typescript/lib/tsserverlibrary'
import type { TemplateSettings } from 'typescript-template-language-service-decorator'
import { decorateWithTemplateLanguageService } from 'typescript-template-language-service-decorator'
-import { ConfigurationManager, TailwindjsPluginConfiguration } from './configuration'
-import { TailwindjsTemplateLanguageService } from './language-service'
+import { ConfigurationManager, TwindPluginConfiguration } from './configuration'
+import { TwindTemplateLanguageService } from './language-service'
import { LanguageServiceLogger } from './logger'
import { getSubstitutions } from './substituter'
-// Import { StyledVirtualDocumentFactory } from './_virtual-document-provider'
-export class TailwindjsPlugin {
+export class TwindPlugin {
private readonly typescript: typeof ts
private _logger?: LanguageServiceLogger
private readonly _configManager = new ConfigurationManager()
@@ -26,21 +25,37 @@ export class TailwindjsPlugin {
this._logger.log('config: ' + JSON.stringify(this._configManager.config))
if (!isValidTypeScriptVersion(this.typescript)) {
- this._logger.log('Invalid typescript version detected. TypeScript 3.x required.')
+ this._logger.log('Invalid typescript version detected. TypeScript 4.1 required.')
return info.languageService
}
+ // Set up decorator
+ // const proxy: ts.LanguageService = {
+ // ...info.languageService,
+ // getCompletionsAtPosition: (fileName, position, options) => {
+ // // emmetCompletions: false
+ // const prior = info.languageService.getCompletionsAtPosition(fileName, position, options)
+
+ // logger.log(
+ // 'getCompletionsAtPosition: ' + JSON.stringify({ fileName, position, prior }, null, 2),
+ // )
+
+ // // prior.entries = prior.entries.filter((e) => e.name !== 'caller')
+ // return prior
+ // },
+ // }
+
return decorateWithTemplateLanguageService(
this.typescript,
info.languageService,
info.project,
- new TailwindjsTemplateLanguageService(this.typescript, this._configManager, this._logger),
+ new TwindTemplateLanguageService(this.typescript, info, this._configManager, this._logger),
getTemplateSettings(this._configManager, this._logger),
{ logger: this._logger },
)
}
- public onConfigurationChanged(config: TailwindjsPluginConfiguration): void {
+ public onConfigurationChanged(config: TwindPluginConfiguration): void {
if (this._logger) {
this._logger.log('onConfigurationChanged')
}
@@ -60,13 +75,13 @@ export function getTemplateSettings(
enableForStringWithSubstitutions: true,
getSubstitutions(templateString, spans): string {
logger.log(`getSubstitutions: ${JSON.stringify(templateString)} (${JSON.stringify(spans)})`)
- return getSubstitutions(templateString, spans)
+ return getSubstitutions(/* templateString, spans */)
},
}
}
function isValidTypeScriptVersion(typescript: typeof ts): boolean {
- const [major] = typescript.version.split('.')
+ const [major, minor] = typescript.version.split('.')
- return Number(major) >= 3
+ return Number(major) > 4 || (Number(major) == 4 && Number(minor) >= 1)
}
diff --git a/src/process-plugins.d.ts b/src/process-plugins.d.ts
deleted file mode 100644
index ec92b5b..0000000
--- a/src/process-plugins.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export declare function processPlugins(): {
- screens: Record
- variants: string[]
- directives: Record }>
- darkMode: false | 'media' | 'class'
- prefix: string
- separator: string
-}
diff --git a/src/process-plugins.mjs b/src/process-plugins.mjs
deleted file mode 100644
index 1ff74f7..0000000
--- a/src/process-plugins.mjs
+++ /dev/null
@@ -1,145 +0,0 @@
-import dlv from 'dlv'
-
-import corePlugins from 'tailwindcss/lib/corePlugins.js'
-import resolveConfig from 'tailwindcss/lib/util/resolveConfig.js'
-import defaultConfig from 'tailwindcss/stubs/defaultConfig.stub.js'
-import transformThemeValue from 'tailwindcss/lib/util/transformThemeValue.js'
-
-export function processPlugins() {
- const config = resolveConfig([defaultConfig])
-
- const plugins = [...corePlugins(config), ...dlv(config, 'plugins', [])]
-
- const {
- theme: { screens },
- variantOrder: variants,
- darkMode,
- prefix,
- separator,
- } = config
-
- // eslint-disable-next-line unicorn/consistent-function-scoping
- const applyConfiguredPrefix = (selector) => selector
-
- const getConfigValue = (path, defaultValue) => (path ? dlv(config, path, defaultValue) : config)
-
- const utilities = {}
-
- plugins.forEach((plugin) => {
- if (plugin.__isOptionsFunction) {
- plugin = plugin()
- }
-
- const handler = typeof plugin === 'function' ? plugin : dlv(plugin, 'handler', () => {})
-
- handler({
- // Postcss,
- config: getConfigValue,
-
- theme: (path, defaultValue) => {
- const [pathRoot, ...subPaths] = path.split('.')
-
- const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue)
-
- return transformThemeValue(pathRoot)(value)
- },
-
- corePlugins: (path) => {
- if (Array.isArray(config.corePlugins)) {
- return config.corePlugins.includes(path)
- }
-
- return getConfigValue(`corePlugins.${path}`, true)
- },
-
- variants: (path, defaultValue) => {
- if (Array.isArray(config.variants)) {
- return config.variants
- }
-
- return getConfigValue(`variants.${path}`, defaultValue)
- },
-
- // No escaping of class names as we use theme as directives
- e: (className) => className,
-
- prefix: applyConfiguredPrefix,
-
- addUtilities: (newUtilities) => {
- // => const defaultOptions = { variants: [], respectPrefix: true, respectImportant: true }
-
- // options = Array.isArray(options)
- // ? { ...defaultOptions, variants: options }
- // : { ...defaultOptions, ...options }
-
- // .directive => CSS rule
- Object.assign(utilities, ...(Array.isArray(newUtilities) ? newUtilities : [newUtilities]))
-
- // =>pluginUtilities.push(
- // wrapWithLayer(wrapWithVariants(styles.nodes, options.variants), 'utilities'),
- // )
- },
-
- addComponents: (newComponents, _options) => {
- // => const defaultOptions = { variants: [], respectPrefix: true }
- // options = Array.isArray(options)
- // ? { ...defaultOptions, variants: options }
- // : { ...defaultOptions, ...options }
- // pluginComponents.push(
- // wrapWithLayer(wrapWithVariants(styles.nodes, options.variants), 'components'),
- // )
- Object.assign(
- utilities,
- ...(Array.isArray(newComponents) ? newComponents : [newComponents]),
- )
- },
-
- addBase: (_baseStyles) => {
- // => pluginBaseStyles.push(wrapWithLayer(parseStyles(baseStyles), 'base'))
- },
-
- addVariant: (_name, _generator, _options = {}) => {
- // =>pluginVariantGenerators[name] = generateVariantFunction(generator, options)
- },
- })
- })
-
- const directives = {
- group: { selector: '.group', properties: {} },
- }
-
- for (const selector of Object.keys(utilities)) {
- // '@keyframes spin'
- if (selector[0] === '@') {
- continue
- }
-
- // '.ordinal, .slashed-zero, .lining-nums, .oldstyle-nums'
- if (selector.includes(',')) {
- continue
- }
-
- // '.placeholder-black::placeholder'
- // '.divide-pink-50 > :not([hidden]) ~ :not([hidden])'
- const [_, directive] = /^\.([^\s:]+)/.exec(selector) || []
-
- if (directive) {
- // Unescape
- // '.w-4\\/5'
- // '.space-x-2\\.5'
- directives[directive.replace(/\\/g, '')] = {
- selector,
- properties: utilities[selector],
- }
- }
- }
-
- return {
- screens,
- variants,
- directives,
- darkMode,
- prefix,
- separator,
- }
-}
diff --git a/src/substituter.ts b/src/substituter.ts
index ec58d17..8fbfa28 100644
--- a/src/substituter.ts
+++ b/src/substituter.ts
@@ -1,7 +1,6 @@
-export function getSubstitutions(
- _contents: string,
- _spans: ReadonlyArray<{ start: number; end: number }>,
-): string {
+export function getSubstitutions(): string {
+ // _contents: string,
+ // _spans: ReadonlyArray<{ start: number; end: number }>,
const parts: string[] = []
return parts.join('')
diff --git a/src/twind.ts b/src/twind.ts
new file mode 100644
index 0000000..c7c6a27
--- /dev/null
+++ b/src/twind.ts
@@ -0,0 +1,569 @@
+import * as path from 'path'
+
+import type { Logger } from 'typescript-template-language-service-decorator'
+import type * as TS from 'typescript/lib/tsserverlibrary'
+
+import resolveFrom from 'resolve-from'
+import cssbeautify from 'cssbeautify'
+
+import type {
+ Context,
+ Theme,
+ ThemeSectionType,
+ CSSRules,
+ CSSRuleValue,
+ ThemeScreenValue,
+ TW,
+ Configuration,
+ ReportInfo,
+ Token,
+} from 'twind'
+import { theme, create, silent } from 'twind'
+import { VirtualSheet, virtualSheet } from 'twind/sheets'
+import { getConfig } from './load-twind-config'
+import { getColor } from './colors'
+
+import type { ConfigurationManager } from './configuration'
+
+const isCSSProperty = (key: string, value: CSSRuleValue): boolean =>
+ !'@:&'.includes(key[0]) && ('rg'.includes((typeof value)[5]) || Array.isArray(value))
+
+const detectKind = (directive: string): CompletionToken['kind'] => {
+ return directive.endsWith(':') ? 'variant' : 'utility'
+}
+
+const sameValueToUndefined = (ref: string, value: string | undefined): string | undefined =>
+ ref === value ? undefined : value
+
+const convertRem = (value: string | undefined): string | undefined => {
+ const replaced = value?.replace(/((?:\d+\.)\d+)rem/g, (_, number) => `${Number(number) * 16}px`)
+
+ return value === replaced ? value : `${value} (${replaced})`
+}
+
+const detailsFromThemeValue = (
+ section: Section,
+ value: ThemeSectionType,
+): string | undefined => {
+ if (value == null) return
+
+ switch (section) {
+ case 'screens': {
+ // | string
+ // | [size: string, lineHeight: string]
+ // | [size: string, options: { lineHeight?: string; letterSpacing?: string }]
+ const screen = value as ThemeSectionType
+
+ // >=726px, (display-mode:standalone), >=500px & <=700px
+ return typeof screen == 'string'
+ ? '≥' + screen
+ : ((Array.isArray(screen)
+ ? (screen as ThemeScreenValue[])
+ : [screen as undefined]) as ThemeScreenValue[])
+ .filter(Boolean)
+ .map((value) => {
+ if (typeof value == 'string') {
+ return '≥' + value
+ }
+
+ return (
+ (value as { raw?: string }).raw ||
+ // >=500px & <=700px
+ Object.keys(value)
+ .map(
+ (feature) => (
+ { min: '≥', max: '≤' }[feature as 'min'],
+ (value as Record)[feature as 'min']
+ ),
+ )
+ .join(' & ')
+ )
+ })
+ .filter(Boolean)
+ .join(', ')
+ }
+
+ case 'fontSize': {
+ // | string
+ // | [size: string, lineHeight: string]
+ // | [size: string, options: { lineHeight?: string; letterSpacing?: string }]
+ const fontSize = value as ThemeSectionType
+
+ // 1rem/2rem - ignoring the letterSpacing
+ return typeof fontSize == 'string'
+ ? fontSize
+ : [fontSize[0], typeof fontSize[1] == 'string' ? fontSize[1] : fontSize[1].lineHeight]
+ .filter(Boolean)
+ .join('/')
+ }
+ }
+
+ if (typeof value == 'string') return value
+ if (typeof value == 'number') return '' + value
+
+ // https://github.com/tailwindlabs/tailwindcss/blob/master/src/util/transformThemeValue.js
+ // only testing for sections that uses an array for values
+ if (
+ Array.isArray(value) &&
+ !['fontSize', 'outline'].includes(section) &&
+ value.every((x) => x == null || typeof x == 'string' || typeof x == 'number')
+ ) {
+ return value.filter(Boolean).join(', ')
+ }
+
+ return undefined
+}
+
+const getSampleInterpolation = (interpolation: CompletionToken['interpolation']): string => {
+ switch (interpolation) {
+ case 'nonzero':
+ return '1'
+ case 'number':
+ return '1'
+ case 'string':
+ return 'xyz'
+ }
+
+ return ''
+}
+
+export interface CompletionToken {
+ readonly kind: 'screen' | 'variant' | 'utility'
+ readonly raw: string
+ // dark:, sm:, after::, bg-black, row-span-
+ /**
+ * A string that should be inserted into a document when selecting
+ * this completion.
+ */
+ readonly value: string
+ // row-span-{{nonzero}}
+ /**
+ * The label of this completion item.
+ */
+ readonly label: string
+ /**
+ * A human-readable string with additional information
+ * about this item, like type or symbol information.
+ *
+ * The extract important info from the theme or CSS.
+ * - theme(...) and value != key
+ * - screen: => theme value – ...
+ * - my-6 => 1.5rem – ...
+ * - text-red-600 => #DC2626 – ...
+ * - text-2xl => 1.5rem/2rem – ...
+ * - bg-opacity-40 => 0.4 – ...
+ * - translate-x-2 => 0.5rem – ...
+ * - {{string}} => NonEmptyString
+ * - {{number}} => NonNegativeNumber
+ * - {{nonzero}} => positive number
+ * - if several rules: x rules
+ * - if at-rule use at rule
+ * - if variant: use &:hover, &>*
+ * - fallback to stringify declartions (order: props, custom)
+ */
+ readonly detail: string
+ readonly color?: string
+ readonly theme?: {
+ section: keyof Theme
+ key: string
+ value: ThemeSectionType
+ }
+ readonly interpolation?:
+ | `string` // NonEmptyString
+ | `number` // NonNegativeNumber
+ | `nonzero` // PositiveNumber
+
+ /**
+ * ```css
+ * /** spacing[0.5]: 0.125rem *\/
+ * .py-0.5 {
+ * padding-top: 0.125rem;
+ * padding-bottom: 0.125rem;
+ * }
+ * ```
+ */
+ readonly css: string
+}
+
+export interface Completions {
+ tokens: CompletionToken[]
+ screens: string[]
+}
+
+export class Twind {
+ private readonly typescript: typeof TS
+ private readonly info: ts.server.PluginCreateInfo
+ private readonly configurationManager: ConfigurationManager
+ private readonly logger: Logger
+ private _completions: Completions | undefined
+ private _configFile: string | undefined
+ private _state:
+ | {
+ program: TS.Program
+ sheet: VirtualSheet
+ reports: ReportInfo[]
+ tw: TW
+ context: Context
+ config: Configuration
+ }
+ | undefined
+
+ constructor(
+ typescript: typeof TS,
+ info: ts.server.PluginCreateInfo,
+ configurationManager: ConfigurationManager,
+ logger: Logger,
+ ) {
+ this.typescript = typescript
+ this.info = info
+ this.configurationManager = configurationManager
+ this.logger = logger
+ }
+
+ private get state() {
+ if (this._state) {
+ return this._state
+ }
+
+ const program = this.info.languageService.getProgram()
+
+ if (!program) {
+ return undefined
+ }
+
+ const { configFile, ...config } = getConfig(program.getCurrentDirectory())
+
+ this._configFile = configFile
+
+ const sheet = virtualSheet()
+ const reports: ReportInfo[] = []
+ sheet.init(() => {
+ reports.length = 0
+ })
+
+ const { tw } = create({
+ ...config,
+ sheet,
+ mode: {
+ ...silent,
+ report: (info) => {
+ reports.push(info)
+ },
+ },
+ preflight: false,
+ prefix: false,
+ plugins: {
+ ...config.plugins,
+ // Used to generate CSS for variants
+ TYPESCRIPT_PLUGIN_PLACEHOLDER: { '--typescript_plugin_placeholder': 'none' },
+ },
+ })
+
+ let context: Context
+ tw((_) => {
+ context = _
+ return ''
+ })
+
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this._state = { program, sheet, tw, reports, context: context!, config }
+
+ return this._state
+ }
+
+ css(rule: string): string | undefined {
+ const { state } = this
+
+ return state && generateCSS(state.sheet, state.tw, rule)
+ }
+
+ getDiagnostics(...tokens: Token[]): ReportInfo[] | undefined {
+ const { state } = this
+
+ if (!state) {
+ return undefined
+ }
+
+ state.sheet.reset()
+ state.tw(...tokens)
+ return [...state.reports]
+ }
+
+ get completions(): Completions {
+ return this._completions || (this._completions = this._getCompletions())
+ }
+
+ private _getCompletions(): Completions {
+ const { state } = this
+
+ if (!state) {
+ return { screens: [], tokens: [] }
+ }
+
+ const { program, config, sheet, tw, context } = state
+
+ const checker = program.getTypeChecker()
+
+ let tokens: string[] = []
+
+ // TODO use resolveFrom.silent and warn
+ const twindPackageFile = resolveFrom(program.getCurrentDirectory(), 'twind/package.json')
+ const twindDTSFileName = path.resolve(path.dirname(twindPackageFile), 'twind.d.ts')
+ const twindDTSSourceFile = program.getSourceFile(twindDTSFileName)
+
+ if (twindDTSSourceFile) {
+ const { typescript: ts } = this
+ const visit = (node: TS.Node) => {
+ if (tokens.length) return
+
+ if (
+ ts.isTypeAliasDeclaration(node) &&
+ ts.isIdentifier(node.name) &&
+ node.name.escapedText == 'CompletionTokens'
+ ) {
+ const type = checker.getTypeAtLocation(node)
+
+ // (type.flags & ts.TypeFlags.Union) | (type.flags & ts.TypeFlags.Intersection)
+ const { types } = type as ts.UnionOrIntersectionType
+
+ // (type.flags & ts.TypeFlags.StringLiteral)
+ tokens = types.map((type) => (type as ts.StringLiteralType).value)
+ } else {
+ ts.forEachChild(node, visit)
+ }
+ }
+
+ // Walk the tree to search for classes
+ this.typescript.forEachChild(twindDTSSourceFile, visit)
+ }
+
+ // Add plugins and variants from loaded config
+ // as first to be overwritten by specific types
+ tokens.unshift(...Object.keys(config.plugins || {}))
+ tokens.unshift(...Object.keys(config.variants || {}).map((x) => x + ':'))
+
+ const createCompletionToken = (
+ directive: string,
+ {
+ kind = detectKind(directive),
+ raw = directive,
+ value = directive,
+ label = value,
+ theme,
+ color = getColor(theme?.value),
+ detail,
+ css,
+ interpolation,
+ ...options
+ }: Partial = {},
+ ): CompletionToken => {
+ return {
+ ...options,
+ kind,
+ raw,
+ value,
+ label,
+ color,
+ theme,
+ get detail() {
+ return (
+ detail ??
+ (detail =
+ (theme &&
+ convertRem(
+ sameValueToUndefined(
+ theme.key,
+ detailsFromThemeValue(theme.section, theme.value),
+ ),
+ )) ||
+ interpolation ||
+ detailFromCSS(sheet, tw, value, interpolation))
+ )
+ },
+ get css() {
+ return css ?? (css = generateCSS(sheet, tw, value, interpolation))
+ },
+ }
+ }
+
+ // Assume there can only be one interpolation
+ const INTERPOLATION_RE = /{{([^}]+)}}/
+
+ const completionTokens = new Map()
+ const screens = Object.keys(theme('screens')(context)).map((x) => x + ':')
+
+ tokens.forEach((directive): void => {
+ const match = INTERPOLATION_RE.exec(directive)
+
+ if (!match) {
+ completionTokens.set(directive, createCompletionToken(directive))
+ return
+ }
+
+ const prefix = directive.slice(0, match.index)
+ const suffix = directive.slice(match.index + match[0].length)
+ const value = match[1]
+
+ // | `theme(${keyof Theme})`
+ // | `range(${number},${number},${number})`
+ // | `string` // NonEmptyString
+ // | `number` // NonNegativeNumber
+ // | `nonzero` // PositiveNumber
+ if (value.startsWith('theme(') && value.endsWith(')')) {
+ const sectionKey = value.slice(6, -1)
+ const section = theme(sectionKey as keyof Theme)(context)
+
+ Object.keys(section)
+ .filter((key, _index, keys) => {
+ // Remove flattened values
+ if (key.includes('.') && keys.includes(key.replace(/\./g, '-'))) {
+ return false
+ }
+
+ // Is this the base object for nested values
+ const value = section[key]
+ if (
+ typeof value === 'object' &&
+ Object.keys(value).every((nestedKey) => keys.includes(`${key}-${nestedKey}`))
+ ) {
+ return false
+ }
+
+ return true
+ })
+ .forEach((key) => {
+ let className = prefix
+ if (key && key != 'DEFAULT') {
+ className += key
+ }
+ if (className.endsWith('-')) {
+ className = className.slice(0, -1)
+ }
+ className += suffix
+
+ completionTokens.set(
+ className,
+ createCompletionToken(className, {
+ kind: screens.includes(className) ? 'screen' : undefined,
+ raw: directive,
+ theme: { section: sectionKey as keyof Theme, key, value: section[key] },
+ }),
+ )
+ })
+ } else if (value.startsWith('range(') && value.endsWith(')')) {
+ const [start, end, step = 1] = value.slice(6, -1).split(',').map(Number)
+
+ for (let n = start; n <= end; n += step) {
+ const className = prefix + n + suffix
+ completionTokens.set(
+ className,
+ createCompletionToken(className, {
+ raw: directive,
+ }),
+ )
+ }
+ } else {
+ completionTokens.set(
+ prefix,
+ createCompletionToken(prefix, {
+ raw: directive,
+ label: directive,
+ interpolation: value as CompletionToken['interpolation'],
+ }),
+ )
+ }
+ })
+
+ return {
+ tokens: [...completionTokens.values()],
+ screens,
+ }
+ }
+}
+
+function generateCSS(
+ sheet: VirtualSheet,
+ tw: TW,
+ value: string,
+ interpolation?: CompletionToken['interpolation'],
+): string {
+ sheet.reset()
+
+ if (interpolation) {
+ value += getSampleInterpolation(interpolation)
+ }
+
+ if (value.endsWith(':')) {
+ tw(value + 'TYPESCRIPT_PLUGIN_PLACEHOLDER')
+ } else {
+ tw(value)
+ }
+
+ return cssbeautify(
+ sheet.target
+ // remove * { } rules
+ .filter((rule) => !/^\s*\*\s*{/.test(rule))
+ .join('\n')
+ // Add whitespace after ,
+ .replace(/(,)(\S)/g, '$1 $2'),
+
+ {
+ autosemicolon: true,
+ indent: ' ',
+ openbrace: 'end-of-line',
+ },
+ )
+ .replace(/TYPESCRIPT_PLUGIN_PLACEHOLDER/g, '<...>')
+ .replace(/^(\s*)--typescript_plugin_placeholder:\s*none\s*;$/gm, '$1/* ... */')
+ .trim()
+}
+
+function detailFromCSS(
+ sheet: VirtualSheet,
+ tw: TW,
+ value: string,
+ interpolation?: CompletionToken['interpolation'],
+): string {
+ if (interpolation) {
+ value += getSampleInterpolation(interpolation)
+ }
+
+ let style: CSSRules = {}
+ tw(({ css }) => {
+ style = value.endsWith(':') ? css(value + 'TYPESCRIPT_PLUGIN_PLACEHOLDER') : css(value)
+ return ''
+ })
+
+ const { 0: key, length } = Object.keys(style).filter(
+ (key) => !(/^([@:]global)/.test(key) || isCSSProperty(key, style[key])),
+ )
+
+ // - if several rules: x rules
+ if (length > 1) {
+ return `${length} rules`
+ }
+
+ // - if at-rule use at rule
+ // - if variant: use &:hover, &>*
+ if (key && /^@|&/.test(key)) {
+ // TODO beautify children: siblings
+ // TODO order of suggestions
+ // TODO grouping prefix is ommited
+ return key.replace(/([,+><*]|&(?!:))(\S)/g, '$1 $2')
+ }
+
+ // fallback to stringify declarations – interpolation has already been added to the value
+ const css = generateCSS(sheet, tw, value)
+
+ let result = ''
+ for (const [, property, value] of css.matchAll(/[{;]\s*([A-Z\d-]+)\s*:\s*([^;}]+)/gi)) {
+ if (result.length < 30) {
+ result += (result && '; ') + `${property}: ${value}`
+ } else {
+ result += '; …'
+ break
+ }
+ }
+
+ return result
+}
diff --git a/tsconfig.json b/tsconfig.json
index 822bc97..89afd90 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -5,7 +5,7 @@
// During development for Node v10.8 support
"target": "es2018",
"module": "CommonJS",
- "lib": ["ESNext", "DOM"],
+ "lib": ["ESNext"],
// ensure that nobody can accidentally use this config for a build
"noEmit": true,
"declaration": true,
diff --git a/yarn.lock b/yarn.lock
index 278b216..9a9a147 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9,6 +9,13 @@
dependencies:
"@babel/highlight" "^7.10.4"
+"@babel/code-frame@^7.10.4":
+ version "7.12.11"
+ resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
+ integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
+ dependencies:
+ "@babel/highlight" "^7.10.4"
+
"@babel/helper-validator-identifier@^7.10.4":
version "7.10.4"
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
@@ -23,6 +30,13 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
+"@babel/runtime@^7.12.5":
+ version "7.13.10"
+ resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
+ integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
+ dependencies:
+ regenerator-runtime "^0.13.4"
+
"@eslint/eslintrc@^0.2.2":
version "0.2.2"
resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz#d01fc791e2fc33e88a29d6f3dc7e93d0cd784b76"
@@ -39,14 +53,6 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
-"@fullhuman/postcss-purgecss@^3.0.0":
- version "3.0.0"
- resolved "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-3.0.0.tgz#e39bf7a7d2a2c664ed151b639785b2efcbca33ff"
- integrity sha512-cvuOgMwIVlfgWcUMqg5p33NbGUxLwMrKtDKkm3QRfOo4PRVNR6+y/xd9OyXTVZiB1bIpKNJ0ZObYPWD3DRQDtw==
- dependencies:
- postcss "7.0.32"
- purgecss "^3.0.0"
-
"@nodelib/fs.scandir@2.1.3":
version "2.1.3"
resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b"
@@ -68,11 +74,21 @@
"@nodelib/fs.scandir" "2.1.3"
fastq "^1.6.0"
+"@types/cssbeautify@^0.3.1":
+ version "0.3.1"
+ resolved "https://registry.npmjs.org/@types/cssbeautify/-/cssbeautify-0.3.1.tgz#8e0bee8f7decb952250da0caebe05e30591c17ef"
+ integrity sha1-jgvuj33suVIlDaDK6+BeMFkcF+8=
+
"@types/json-schema@^7.0.3":
version "7.0.6"
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==
+"@types/node@^14.14.34":
+ version "14.14.34"
+ resolved "https://registry.npmjs.org/@types/node/-/node-14.14.34.tgz#07935194fc049069a1c56c0c274265abeddf88da"
+ integrity sha512-dBPaxocOK6UVyvhbnpFIj2W+S+1cBTkHQbFQfeeJhoKFbzYcVUGHvddeWPSucKATb3F0+pgDq0i6ghEaZjsugA==
+
"@typescript-eslint/eslint-plugin@^4.9.1":
version "4.10.0"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.10.0.tgz#19ed3baf4bc4232c5a7fcd32eaca75c3a5baf9f3"
@@ -148,21 +164,7 @@ acorn-jsx@^5.3.1:
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"
integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==
-acorn-node@^1.6.1:
- version "1.8.2"
- resolved "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8"
- integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==
- dependencies:
- acorn "^7.0.0"
- acorn-walk "^7.0.0"
- xtend "^4.0.2"
-
-acorn-walk@^7.0.0:
- version "7.2.0"
- resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
- integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
-
-acorn@^7.0.0, acorn@^7.4.0:
+acorn@^7.4.0:
version "7.4.1"
resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
@@ -223,11 +225,6 @@ astral-regex@^1.0.0:
resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
-at-least-node@^1.0.0:
- version "1.0.0"
- resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
- integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
-
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
@@ -248,22 +245,12 @@ braces@^3.0.1:
dependencies:
fill-range "^7.0.1"
-bytes@^3.0.0:
- version "3.1.0"
- resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
- integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
-
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-camelcase-css@^2.0.1:
- version "2.0.1"
- resolved "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
- integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
-
-chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
+chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -272,7 +259,7 @@ chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
-chalk@^4.0.0, chalk@^4.1.0:
+chalk@^4.0.0:
version "4.1.0"
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
@@ -280,7 +267,7 @@ chalk@^4.0.0, chalk@^4.1.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
-color-convert@^1.9.0, color-convert@^1.9.1:
+color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
@@ -299,37 +286,11 @@ color-name@1.1.3:
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
-color-name@^1.0.0, color-name@~1.1.4:
+color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-color-string@^1.5.4:
- version "1.5.4"
- resolved "https://registry.npmjs.org/color-string/-/color-string-1.5.4.tgz#dd51cd25cfee953d138fe4002372cc3d0e504cb6"
- integrity sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==
- dependencies:
- color-name "^1.0.0"
- simple-swizzle "^0.2.2"
-
-color@^3.1.3:
- version "3.1.3"
- resolved "https://registry.npmjs.org/color/-/color-3.1.3.tgz#ca67fb4e7b97d611dcde39eceed422067d91596e"
- integrity sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==
- dependencies:
- color-convert "^1.9.1"
- color-string "^1.5.4"
-
-colorette@^1.2.1:
- version "1.2.1"
- resolved "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b"
- integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==
-
-commander@^6.0.0:
- version "6.2.0"
- resolved "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz#b990bfb8ac030aedc6d11bc04d1488ffef56db75"
- integrity sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==
-
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -344,15 +305,15 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3:
shebang-command "^2.0.0"
which "^2.0.1"
-css-unit-converter@^1.1.1:
- version "1.1.2"
- resolved "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz#4c77f5a1954e6dbff60695ecb214e3270436ab21"
- integrity sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==
+cssbeautify@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.npmjs.org/cssbeautify/-/cssbeautify-0.3.1.tgz#12dd1f734035c2e6faca67dcbdcef74e42811397"
+ integrity sha1-Et0fc0A1wub6ymfcvc73TkKBE5c=
-cssesc@^3.0.0:
- version "3.0.0"
- resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
- integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+csstype@^3.0.5:
+ version "3.0.7"
+ resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b"
+ integrity sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==
debug@^4.0.1, debug@^4.1.1:
version "4.3.1"
@@ -366,25 +327,6 @@ deep-is@^0.1.3:
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
-defined@^1.0.0:
- version "1.0.0"
- resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
- integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
-
-detective@^5.2.0:
- version "5.2.0"
- resolved "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b"
- integrity sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==
- dependencies:
- acorn-node "^1.6.1"
- defined "^1.0.0"
- minimist "^1.1.1"
-
-didyoumean@^1.2.1:
- version "1.2.1"
- resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.1.tgz#e92edfdada6537d484d73c0172fd1eba0c4976ff"
- integrity sha1-6S7f2tplN9SE1zwBcv0eugxJdv8=
-
dir-glob@^3.0.1:
version "3.0.1"
resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@@ -392,10 +334,20 @@ dir-glob@^3.0.1:
dependencies:
path-type "^4.0.0"
-dlv@^1.1.3:
- version "1.1.3"
- resolved "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
- integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
+distilt@^0.10.1:
+ version "0.10.1"
+ resolved "https://registry.npmjs.org/distilt/-/distilt-0.10.1.tgz#7603f8f3b64c24e7ed66a696ee0ec85dbb2d4dc4"
+ integrity sha512-JZSjKlpXMDBunrwlpDZW3+L+UlnjaSP1egOfEPix7anPXG24Mq3d9SRghpQkoZs8jeCq76Gnp3/VL2uM1NXtSA==
+ dependencies:
+ es-module-lexer "^0.3.26"
+ esbuild "^0.8.28"
+ execa "^5.0.0"
+ find-up "^5.0.0"
+ globby "^11.0.1"
+ pkg-dir "^5.0.0"
+ project-root-directory "^1.0.3"
+ rollup "^2.35.1"
+ rollup-plugin-dts "^2.0.1"
doctrine@^3.0.0:
version "3.0.0"
@@ -404,6 +356,36 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
+dom-serializer@^1.0.1:
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz#3433d9136aeb3c627981daa385fc7f32d27c48f1"
+ integrity sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^4.0.0"
+ entities "^2.0.0"
+
+domelementtype@^2.0.1, domelementtype@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz#a851c080a6d1c3d94344aed151d99f669edf585e"
+ integrity sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==
+
+domhandler@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz#01ea7821de996d85f69029e81fa873c21833098e"
+ integrity sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==
+ dependencies:
+ domelementtype "^2.1.0"
+
+domutils@^2.4.4:
+ version "2.5.0"
+ resolved "https://registry.npmjs.org/domutils/-/domutils-2.5.0.tgz#42f49cffdabb92ad243278b331fd761c1c2d3039"
+ integrity sha512-Ho16rzNMOFk2fPwChGh3D2D9OEHAfG19HgmRR2l+WLSsIstNsAYBzePH412bL0y5T44ejABIVfTHQ8nqi/tBCg==
+ dependencies:
+ dom-serializer "^1.0.1"
+ domelementtype "^2.0.1"
+ domhandler "^4.0.0"
+
emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
@@ -416,10 +398,25 @@ enquirer@^2.3.5:
dependencies:
ansi-colors "^4.1.1"
-esbuild@^0.8.23:
- version "0.8.23"
- resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.8.23.tgz#8c4ccd3abb5f7b4ae9f31c571971517be4ae60d2"
- integrity sha512-LkgCmotGnhVgRGxjDkTBBYrnJ5stcxK+40cEJGtXUS16hcAWy90cn1qjxKCogzLPJ75gW/L6ejly7VKrMstVGQ==
+entities@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
+ integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
+
+es-module-lexer@^0.3.26:
+ version "0.3.26"
+ resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.3.26.tgz#7b507044e97d5b03b01d4392c74ffeb9c177a83b"
+ integrity sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==
+
+esbuild@^0.8.28:
+ version "0.8.57"
+ resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.8.57.tgz#a42d02bc2b57c70bcd0ef897fe244766bb6dd926"
+ integrity sha512-j02SFrUwFTRUqiY0Kjplwjm1psuzO1d6AjaXKuOR9hrY0HuPsT6sV42B6myW34h1q4CRy+Y3g4RU/cGJeI/nNA==
+
+esbuild@^0.9.1:
+ version "0.9.2"
+ resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.9.2.tgz#7e9fde247c913ed8ee059e2648b0c53f7d00abe5"
+ integrity sha512-xE3oOILjnmN8PSjkG3lT9NBbd1DbxNqolJ5qNyrLhDWsFef3yTp/KTQz1C/x7BYFKbtrr9foYtKA6KA1zuNAUQ==
escape-string-regexp@^1.0.5:
version "1.0.5"
@@ -617,6 +614,14 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
+find-up@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+ integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+ dependencies:
+ locate-path "^6.0.0"
+ path-exists "^4.0.0"
+
flat-cache@^3.0.4:
version "3.0.4"
resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
@@ -630,25 +635,15 @@ flatted@^3.1.0:
resolved "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz#a5d06b4a8b01e3a63771daa5cb7a1903e2e57067"
integrity sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==
-fs-extra@^9.0.1:
- version "9.0.1"
- resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc"
- integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==
- dependencies:
- at-least-node "^1.0.0"
- graceful-fs "^4.2.0"
- jsonfile "^6.0.1"
- universalify "^1.0.0"
-
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
-function-bind@^1.1.1:
- version "1.1.1"
- resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
- integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+fsevents@~2.1.2:
+ version "2.1.3"
+ resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
+ integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
functional-red-black-tree@^1.0.1:
version "1.0.1"
@@ -667,7 +662,7 @@ glob-parent@^5.0.0, glob-parent@^5.1.0:
dependencies:
is-glob "^4.0.1"
-glob@^7.0.0, glob@^7.1.2, glob@^7.1.3:
+glob@^7.1.3:
version "7.1.6"
resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -698,11 +693,6 @@ globby@^11.0.1:
merge2 "^1.3.0"
slash "^3.0.0"
-graceful-fs@^4.1.6, graceful-fs@^4.2.0:
- version "4.2.4"
- resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
- integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
-
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -713,17 +703,15 @@ has-flag@^4.0.0:
resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-has@^1.0.3:
- version "1.0.3"
- resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
- integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+htmlparser2@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.0.1.tgz#422521231ef6d42e56bd411da8ba40aa36e91446"
+ integrity sha512-GDKPd+vk4jvSuvCbyuzx/unmXkk090Azec7LovXP8as1Hn8q9p3hbjmDGbUqqhknw0ajwit6LiiWqfiTUPMK7w==
dependencies:
- function-bind "^1.1.1"
-
-html-tags@^3.1.0:
- version "3.1.0"
- resolved "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140"
- integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==
+ domelementtype "^2.0.1"
+ domhandler "^4.0.0"
+ domutils "^2.4.4"
+ entities "^2.0.0"
human-signals@^2.1.0:
version "2.1.0"
@@ -748,16 +736,18 @@ import-fresh@^3.0.0, import-fresh@^3.2.1:
parent-module "^1.0.0"
resolve-from "^4.0.0"
+import-from@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz#055cfec38cd5a27d8057ca51376d7d3bf0891966"
+ integrity sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==
+ dependencies:
+ resolve-from "^5.0.0"
+
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
-indexes-of@^1.0.1:
- version "1.0.1"
- resolved "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
- integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc=
-
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@@ -771,18 +761,6 @@ inherits@2:
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-is-arrayish@^0.3.1:
- version "0.3.2"
- resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
- integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
-
-is-core-module@^2.1.0:
- version "2.2.0"
- resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a"
- integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==
- dependencies:
- has "^1.0.3"
-
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
@@ -838,15 +816,6 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
-jsonfile@^6.0.1:
- version "6.1.0"
- resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
- integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
- dependencies:
- universalify "^2.0.0"
- optionalDependencies:
- graceful-fs "^4.1.6"
-
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
@@ -855,12 +824,14 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"
-lodash.toarray@^4.4.0:
- version "4.4.0"
- resolved "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
- integrity sha1-JMS/zWsvuji/0FlNsRedjptlZWE=
+locate-path@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+ integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+ dependencies:
+ p-locate "^5.0.0"
-lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20:
+lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19:
version "4.17.20"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
@@ -872,6 +843,21 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
+magic-string@^0.25.7:
+ version "0.25.7"
+ resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
+ integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
+ dependencies:
+ sourcemap-codec "^1.4.4"
+
+match-sorter@^6.3.0:
+ version "6.3.0"
+ resolved "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.0.tgz#454a1b31ed218cddbce6231a0ecb5fdc549fed01"
+ integrity sha512-efYOf/wUpNb8FgNY+cOD2EIJI1S5I7YPKsw0LBp7wqPh5pmMS6i/wr3ZWwfwrAw1NvqTA2KUReVRWDX84lUcOQ==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ remove-accents "0.4.2"
+
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@@ -902,38 +888,16 @@ minimatch@^3.0.4:
dependencies:
brace-expansion "^1.1.7"
-minimist@^1.1.1:
- version "1.2.5"
- resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
-
-modern-normalize@^1.0.0:
- version "1.0.0"
- resolved "https://registry.npmjs.org/modern-normalize/-/modern-normalize-1.0.0.tgz#539d84a1e141338b01b346f3e27396d0ed17601e"
- integrity sha512-1lM+BMLGuDfsdwf3rsgBSrxJwAZHFIrQ8YR61xIqdHo0uNKI9M52wNpHSrliZATJp51On6JD0AfRxd4YGSU0lw==
-
ms@2.1.2:
version "2.1.2"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-nanoid@^3.1.20:
- version "3.1.20"
- resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"
- integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==
-
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
-node-emoji@^1.8.1:
- version "1.10.0"
- resolved "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da"
- integrity sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==
- dependencies:
- lodash.toarray "^4.4.0"
-
npm-run-path@^4.0.1:
version "4.0.1"
resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
@@ -941,16 +905,6 @@ npm-run-path@^4.0.1:
dependencies:
path-key "^3.0.0"
-object-assign@^4.1.1:
- version "4.1.1"
- resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
- integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
-
-object-hash@^2.0.3:
- version "2.0.3"
- resolved "https://registry.npmjs.org/object-hash/-/object-hash-2.0.3.tgz#d12db044e03cd2ca3d77c0570d87225b02e1e6ea"
- integrity sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg==
-
once@^1.3.0:
version "1.4.0"
resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@@ -977,6 +931,20 @@ optionator@^0.9.1:
type-check "^0.4.0"
word-wrap "^1.2.3"
+p-limit@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+ integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+ dependencies:
+ yocto-queue "^0.1.0"
+
+p-locate@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+ integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+ dependencies:
+ p-limit "^3.0.2"
+
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@@ -984,6 +952,11 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
+path-exists@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
@@ -994,11 +967,6 @@ path-key@^3.0.0, path-key@^3.1.0:
resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
-path-parse@^1.0.6:
- version "1.0.6"
- resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
- integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
-
path-type@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
@@ -1009,77 +977,12 @@ picomatch@^2.0.5, picomatch@^2.2.1:
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
-postcss-functions@^3:
- version "3.0.0"
- resolved "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz#0e94d01444700a481de20de4d55fb2640564250e"
- integrity sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4=
- dependencies:
- glob "^7.1.2"
- object-assign "^4.1.1"
- postcss "^6.0.9"
- postcss-value-parser "^3.3.0"
-
-postcss-js@^3.0.3:
- version "3.0.3"
- resolved "https://registry.npmjs.org/postcss-js/-/postcss-js-3.0.3.tgz#2f0bd370a2e8599d45439f6970403b5873abda33"
- integrity sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw==
- dependencies:
- camelcase-css "^2.0.1"
- postcss "^8.1.6"
-
-postcss-nested@^5.0.1:
- version "5.0.3"
- resolved "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.3.tgz#2f46d77a06fc98d9c22344fd097396f5431386db"
- integrity sha512-R2LHPw+u5hFfDgJG748KpGbJyTv7Yr33/2tIMWxquYuHTd9EXu27PYnKi7BxMXLtzKC0a0WVsqHtd7qIluQu/g==
- dependencies:
- postcss-selector-parser "^6.0.4"
-
-postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
- version "6.0.4"
- resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz#56075a1380a04604c38b063ea7767a129af5c2b3"
- integrity sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==
- dependencies:
- cssesc "^3.0.0"
- indexes-of "^1.0.1"
- uniq "^1.0.1"
- util-deprecate "^1.0.2"
-
-postcss-value-parser@^3.3.0:
- version "3.3.1"
- resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
- integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
-
-postcss-value-parser@^4.1.0:
- version "4.1.0"
- resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
- integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
-
-postcss@7.0.32:
- version "7.0.32"
- resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d"
- integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==
- dependencies:
- chalk "^2.4.2"
- source-map "^0.6.1"
- supports-color "^6.1.0"
-
-postcss@^6.0.9:
- version "6.0.23"
- resolved "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324"
- integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==
- dependencies:
- chalk "^2.4.1"
- source-map "^0.6.1"
- supports-color "^5.4.0"
-
-postcss@^8.1.6:
- version "8.2.1"
- resolved "https://registry.npmjs.org/postcss/-/postcss-8.2.1.tgz#eabc5557c4558059b9d9e5b15bce7ffa9089c2a8"
- integrity sha512-RhsqOOAQzTgh1UB/IZdca7F9WDb7SUCR2Vnv1x7DbvuuggQIpoDwjK+q0rzoPffhYvWNKX5JSwS4so4K3UC6vA==
+pkg-dir@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760"
+ integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==
dependencies:
- colorette "^1.2.1"
- nanoid "^3.1.20"
- source-map "^0.6.1"
+ find-up "^5.0.0"
prelude-ls@^1.2.1:
version "1.2.1"
@@ -1098,56 +1001,47 @@ prettier@^2.0.5:
resolved "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5"
integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==
-pretty-hrtime@^1.0.3:
- version "1.0.3"
- resolved "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
- integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
-
progress@^2.0.0:
version "2.0.3"
resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
+project-root-directory@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/project-root-directory/-/project-root-directory-1.0.3.tgz#b83f25a76fa4aeb64f69a95cc9c83035c96ee045"
+ integrity sha512-GVRoyflCe4VYlGwtEVcQngm1FMuu9q9KJfEK85g5OWGUTxc+iYvnMT64ixvxEgN48chvBWe2fc2ZGATSJMRyqQ==
+ dependencies:
+ resolve-from "^5.0.0"
+
punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-purgecss@^3.0.0:
- version "3.0.0"
- resolved "https://registry.npmjs.org/purgecss/-/purgecss-3.0.0.tgz#039c191871bb999894222a00c4c8b179fccdb043"
- integrity sha512-t3FGCwyX9XWV3ffvnAXTw6Y3Z9kNlcgm14VImNK66xKi5sdqxSA2I0SFYxtmZbAKuIZVckPdazw5iKL/oY/2TA==
- dependencies:
- commander "^6.0.0"
- glob "^7.0.0"
- postcss "7.0.32"
- postcss-selector-parser "^6.0.2"
-
-reduce-css-calc@^2.1.6:
- version "2.1.7"
- resolved "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.7.tgz#1ace2e02c286d78abcd01fd92bfe8097ab0602c2"
- integrity sha512-fDnlZ+AybAS3C7Q9xDq5y8A2z+lT63zLbynew/lur/IR24OQF5x98tfNwf79mzEdfywZ0a2wpM860FhFfMxZlA==
- dependencies:
- css-unit-converter "^1.1.1"
- postcss-value-parser "^3.3.0"
+regenerator-runtime@^0.13.4:
+ version "0.13.7"
+ resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
+ integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
regexpp@^3.0.0, regexpp@^3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
+remove-accents@0.4.2:
+ version "0.4.2"
+ resolved "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5"
+ integrity sha1-CkPTqq4egNuRngeuJUsoXZ4ce7U=
+
resolve-from@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
-resolve@^1.19.0:
- version "1.19.0"
- resolved "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c"
- integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==
- dependencies:
- is-core-module "^2.1.0"
- path-parse "^1.0.6"
+resolve-from@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
+ integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
reusify@^1.0.4:
version "1.0.4"
@@ -1161,6 +1055,22 @@ rimraf@^3.0.2:
dependencies:
glob "^7.1.3"
+rollup-plugin-dts@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-2.0.1.tgz#333f50a637e199a073d490b198746f3c6bd07701"
+ integrity sha512-y38NSXIY37YExCumbGBTL5dXg7pL7XD+Kbe98iEHWFN9yiKJf7t4kKBOkml5ylUDjQIXBnNClGDeRktc1T5dmA==
+ dependencies:
+ magic-string "^0.25.7"
+ optionalDependencies:
+ "@babel/code-frame" "^7.10.4"
+
+rollup@^2.35.1:
+ version "2.35.1"
+ resolved "https://registry.npmjs.org/rollup/-/rollup-2.35.1.tgz#e6bc8d10893556a638066f89e8c97f422d03968c"
+ integrity sha512-q5KxEyWpprAIcainhVy6HfRttD9kutQpHbeqDTWnqAFNJotiojetK6uqmcydNMymBEtC4I8bCYR+J3mTMqeaUA==
+ optionalDependencies:
+ fsevents "~2.1.2"
+
run-parallel@^1.1.9:
version "1.1.10"
resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz#60a51b2ae836636c81377df16cb107351bcd13ef"
@@ -1190,13 +1100,6 @@ signal-exit@^3.0.3:
resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
-simple-swizzle@^0.2.2:
- version "0.2.2"
- resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
- integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=
- dependencies:
- is-arrayish "^0.3.1"
-
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
@@ -1211,10 +1114,10 @@ slice-ansi@^2.1.0:
astral-regex "^1.0.0"
is-fullwidth-code-point "^2.0.0"
-source-map@^0.6.1:
- version "0.6.1"
- resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
- integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+sourcemap-codec@^1.4.4:
+ version "1.4.8"
+ resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
+ integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
sprintf-js@~1.0.2:
version "1.0.3"
@@ -1254,20 +1157,18 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
-supports-color@^5.3.0, supports-color@^5.4.0:
+style-vendorizer@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/style-vendorizer/-/style-vendorizer-2.0.0.tgz#0c46cec94069f1c768d31c3d307ed045646f503c"
+ integrity sha512-CeqwnrtXd/DKIadVNdJDtHnpCmsc28rWVWLmgpF2HdzTiWFVCE1F1OzWWwskOEtWpOpgm6NrjccfkNGo8qW4MA==
+
+supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
-supports-color@^6.1.0:
- version "6.1.0"
- resolved "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3"
- integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==
- dependencies:
- has-flag "^3.0.0"
-
supports-color@^7.1.0:
version "7.2.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
@@ -1285,32 +1186,6 @@ table@^5.2.3:
slice-ansi "^2.1.0"
string-width "^3.0.0"
-tailwindcss@^2.0.1:
- version "2.0.1"
- resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-2.0.1.tgz#8d336917819341d1018208e8b3ed8cbc46e6b643"
- integrity sha512-57G3jdcVBWTPkHCNSAfDAo1Qp2Nkr4H6WnLD0luNFh1td+KwQp9FOVcqj0SYBH6qwVQJawzT+0/zLxzKmyznGw==
- dependencies:
- "@fullhuman/postcss-purgecss" "^3.0.0"
- bytes "^3.0.0"
- chalk "^4.1.0"
- color "^3.1.3"
- detective "^5.2.0"
- didyoumean "^1.2.1"
- fs-extra "^9.0.1"
- html-tags "^3.1.0"
- lodash "^4.17.20"
- modern-normalize "^1.0.0"
- node-emoji "^1.8.1"
- object-hash "^2.0.3"
- postcss-functions "^3"
- postcss-js "^3.0.3"
- postcss-nested "^5.0.1"
- postcss-selector-parser "^6.0.4"
- postcss-value-parser "^4.1.0"
- pretty-hrtime "^1.0.3"
- reduce-css-calc "^2.1.6"
- resolve "^1.19.0"
-
text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -1335,6 +1210,15 @@ tsutils@^3.17.1:
dependencies:
tslib "^1.8.1"
+twind@^0.16.0:
+ version "0.16.0"
+ resolved "https://registry.npmjs.org/twind/-/twind-0.16.0.tgz#8045ae7178149aaa94669669ea98c1f129a0ef82"
+ integrity sha512-dAslmdmPi8N9dmEB2ZgZewqTHnkC2K39WaPQSWAqon+oKhn7sh4wd5R0zkxvPpbB8QGLdGxeEOZJjQt5RgS57Q==
+ dependencies:
+ csstype "^3.0.5"
+ htmlparser2 "^6.0.0"
+ style-vendorizer "^2.0.0"
+
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
@@ -1357,21 +1241,6 @@ typescript@^4.1.0:
resolved "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz#6369ef22516fe5e10304aae5a5c4862db55380e9"
integrity sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==
-uniq@^1.0.1:
- version "1.0.1"
- resolved "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
- integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=
-
-universalify@^1.0.0:
- version "1.0.0"
- resolved "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d"
- integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==
-
-universalify@^2.0.0:
- version "2.0.0"
- resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
- integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
-
uri-js@^4.2.2:
version "4.4.0"
resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602"
@@ -1379,11 +1248,6 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
-util-deprecate@^1.0.2:
- version "1.0.2"
- resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
- integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
-
v8-compile-cache@^2.0.3:
version "2.2.0"
resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132"
@@ -1411,12 +1275,12 @@ wrappy@1:
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
-xtend@^4.0.2:
- version "4.0.2"
- resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
- integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
-
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yocto-queue@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+ integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==