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 [![MIT License](https://flat.badgen.net/github/license/tw-in-js/typescript-plugin)](https://github.com/tw-in-js/typescript-plugin/blob/main/LICENSE) [![Latest Release](https://flat.badgen.net/npm/v/@twind/typescript-plugin?icon=npm&label)](https://www.npmjs.com/package/@twind/typescript-plugin) [![Github](https://flat.badgen.net/badge/icon/tw-in-js%2Ftypescript-plugin?icon=github&label)](https://github.com/tw-in-js/typescript-plugin) +![Demo](https://raw.githubusercontent.com/tw-in-js/typescript-plugin/main/assets/demo.gif) + +
+ --- @@ -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==