From c7a1632250201e91002a9a11fc458e7c1cd9314c Mon Sep 17 00:00:00 2001 From: Brad Cornes Date: Fri, 29 Jan 2021 16:37:39 +0000 Subject: [PATCH] =?UTF-8?q?fix=20error=20when=20using=20@=E2=80=8Bapply=20?= =?UTF-8?q?in=20plugins=20(#255)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 35 ++-- .../package-lock.json | 14 ++ .../tailwindcss-intellisense/package.json | 1 + .../src/class-names/extractClassNames.js | 163 +++++++++--------- .../src/class-names/index.js | 102 ++++++++--- 5 files changed, 200 insertions(+), 115 deletions(-) diff --git a/package-lock.json b/package-lock.json index 10a5306..e3f10cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6295,6 +6295,14 @@ "node": ">=6" } }, + "node_modules/klona": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", + "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", + "engines": { + "node": ">= 8" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.20", "license": "ODC-By-1.0" @@ -12158,7 +12166,7 @@ }, "packages/tailwindcss-intellisense": { "name": "vscode-tailwindcss", - "version": "0.5.6", + "version": "0.5.7", "license": "MIT", "dependencies": { "@types/debounce": "^1.2.0", @@ -12179,6 +12187,7 @@ "glob-exec": "^0.1.1", "import-from": "^3.0.0", "jest": "^25.5.4", + "klona": "^2.0.4", "mitt": "^1.2.0", "normalize-path": "^3.0.0", "pkg-up": "^3.1.0", @@ -12188,7 +12197,7 @@ "rimraf": "^3.0.2", "semver": "^7.3.2", "stack-trace": "0.0.10", - "tailwindcss-language-service": "0.0.10", + "tailwindcss-language-service": "0.0.11", "terser": "^4.6.12", "tiny-invariant": "^1.1.0", "tslint": "^5.16.0", @@ -12262,9 +12271,9 @@ } }, "packages/tailwindcss-intellisense/node_modules/tailwindcss-language-service": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/tailwindcss-language-service/-/tailwindcss-language-service-0.0.10.tgz", - "integrity": "sha512-qE2blv1x8wxSUN+PH1kjvN28UjNKhrZeZcAFHL4X35jtTbGZ2X//b1Ya+NOK5hLOFWinHPxR9PB/WeNuOSn/sQ==", + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/tailwindcss-language-service/-/tailwindcss-language-service-0.0.11.tgz", + "integrity": "sha512-dIOvB4CveOkz6DPYz0lqMbQHz4pEBiuTQcBMi86e+xoyW6OwosEj3k3ds6+pwra+ZN4SScxHdru63bGjWM5fiQ==", "dependencies": { "@ctrl/tinycolor": "^3.1.4", "@types/moo": "^0.5.3", @@ -12304,7 +12313,7 @@ } }, "packages/tailwindcss-language-service": { - "version": "0.0.10", + "version": "0.0.11", "dependencies": { "@ctrl/tinycolor": "^3.1.4", "@types/moo": "^0.5.3", @@ -16490,6 +16499,11 @@ "kleur": { "version": "3.0.3" }, + "klona": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", + "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==" + }, "language-subtag-registry": { "version": "0.3.20" }, @@ -20269,6 +20283,7 @@ "glob-exec": "^0.1.1", "import-from": "^3.0.0", "jest": "^25.5.4", + "klona": "^2.0.4", "mitt": "^1.2.0", "normalize-path": "^3.0.0", "pkg-up": "^3.1.0", @@ -20278,7 +20293,7 @@ "rimraf": "^3.0.2", "semver": "^7.3.2", "stack-trace": "0.0.10", - "tailwindcss-language-service": "0.0.10", + "tailwindcss-language-service": "0.0.11", "terser": "^4.6.12", "tiny-invariant": "^1.1.0", "tslint": "^5.16.0", @@ -20325,9 +20340,9 @@ } }, "tailwindcss-language-service": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/tailwindcss-language-service/-/tailwindcss-language-service-0.0.10.tgz", - "integrity": "sha512-qE2blv1x8wxSUN+PH1kjvN28UjNKhrZeZcAFHL4X35jtTbGZ2X//b1Ya+NOK5hLOFWinHPxR9PB/WeNuOSn/sQ==", + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/tailwindcss-language-service/-/tailwindcss-language-service-0.0.11.tgz", + "integrity": "sha512-dIOvB4CveOkz6DPYz0lqMbQHz4pEBiuTQcBMi86e+xoyW6OwosEj3k3ds6+pwra+ZN4SScxHdru63bGjWM5fiQ==", "requires": { "@ctrl/tinycolor": "^3.1.4", "@types/moo": "^0.5.3", diff --git a/packages/tailwindcss-intellisense/package-lock.json b/packages/tailwindcss-intellisense/package-lock.json index 814b166..4fee91b 100644 --- a/packages/tailwindcss-intellisense/package-lock.json +++ b/packages/tailwindcss-intellisense/package-lock.json @@ -27,6 +27,7 @@ "glob-exec": "^0.1.1", "import-from": "^3.0.0", "jest": "^25.5.4", + "klona": "^2.0.4", "mitt": "^1.2.0", "normalize-path": "^3.0.0", "pkg-up": "^3.1.0", @@ -7107,6 +7108,14 @@ "node": ">=6" } }, + "node_modules/klona": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", + "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", + "engines": { + "node": ">= 8" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.21", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", @@ -19307,6 +19316,11 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" }, + "klona": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", + "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==" + }, "language-subtag-registry": { "version": "0.3.21", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", diff --git a/packages/tailwindcss-intellisense/package.json b/packages/tailwindcss-intellisense/package.json index 5e917bc..80a129f 100755 --- a/packages/tailwindcss-intellisense/package.json +++ b/packages/tailwindcss-intellisense/package.json @@ -197,6 +197,7 @@ "glob-exec": "^0.1.1", "import-from": "^3.0.0", "jest": "^25.5.4", + "klona": "^2.0.4", "mitt": "^1.2.0", "normalize-path": "^3.0.0", "pkg-up": "^3.1.0", diff --git a/packages/tailwindcss-intellisense/src/class-names/extractClassNames.js b/packages/tailwindcss-intellisense/src/class-names/extractClassNames.js index 35e14eb..6079ca3 100644 --- a/packages/tailwindcss-intellisense/src/class-names/extractClassNames.js +++ b/packages/tailwindcss-intellisense/src/class-names/extractClassNames.js @@ -44,93 +44,100 @@ function getClassNamesFromSelector(selector) { return classNames } -async function process(groups) { +async function process(root) { const tree = {} const commonContext = {} - groups.forEach((group) => { - group.root.walkRules((rule) => { - const classNames = getClassNamesFromSelector(rule.selector) + let layer - const decls = {} - rule.walkDecls((decl) => { - if (decls[decl.prop]) { - decls[decl.prop] = [ - ...(Array.isArray(decls[decl.prop]) - ? decls[decl.prop] - : [decls[decl.prop]]), - decl.value, - ] - } else { - decls[decl.prop] = decl.value - } - }) + root.walk((node) => { + if (node.type === 'comment') { + let match = node.text.trim().match(/^__tw_intellisense_layer_([a-z]+)__$/) + if (match === null) return + layer = match[1] + node.remove() + return + } - let p = rule - const keys = [] - while (p.parent.type !== 'root') { - p = p.parent - if (p.type === 'atrule') { - keys.push(`@${p.name} ${p.params}`) - } - } + if (node.type !== 'rule') return - for (let i = 0; i < classNames.length; i++) { - const context = keys.concat([]) - const baseKeys = classNames[i].className.split('__TAILWIND_SEPARATOR__') - const contextKeys = baseKeys.slice(0, baseKeys.length - 1) - const index = [] + const rule = node + const classNames = getClassNamesFromSelector(rule.selector) - const existing = dlv(tree, [...baseKeys, '__info']) - if (typeof existing !== 'undefined') { - if (Array.isArray(existing)) { - index.push(existing.length) - } else { - dset(tree, [...baseKeys, '__info'], [existing]) - index.push(1) - } - } - if (classNames[i].__rule) { - dset(tree, [...baseKeys, '__info', ...index, '__rule'], true) - dset( - tree, - [...baseKeys, '__info', ...index, '__source'], - group.source - ) - - dsetEach(tree, [...baseKeys, '__info', ...index], decls) - } - dset( - tree, - [...baseKeys, '__info', ...index, '__pseudo'], - classNames[i].__pseudo - ) - dset( - tree, - [...baseKeys, '__info', ...index, '__scope'], - classNames[i].scope - ) - dset( - tree, - [...baseKeys, '__info', ...index, '__context'], - context.concat([]).reverse() - ) - - // common context - context.push(...classNames[i].__pseudo.map((x) => `&${x}`)) - - for (let i = 0; i < contextKeys.length; i++) { - if (typeof commonContext[contextKeys[i]] === 'undefined') { - commonContext[contextKeys[i]] = context - } else { - commonContext[contextKeys[i]] = intersection( - commonContext[contextKeys[i]], - context - ) - } - } + const decls = {} + rule.walkDecls((decl) => { + if (decls[decl.prop]) { + decls[decl.prop] = [ + ...(Array.isArray(decls[decl.prop]) + ? decls[decl.prop] + : [decls[decl.prop]]), + decl.value, + ] + } else { + decls[decl.prop] = decl.value } }) + + let p = rule + const keys = [] + while (p.parent.type !== 'root') { + p = p.parent + if (p.type === 'atrule') { + keys.push(`@${p.name} ${p.params}`) + } + } + + for (let i = 0; i < classNames.length; i++) { + const context = keys.concat([]) + const baseKeys = classNames[i].className.split(/__TWSEP__.*?__TWSEP__/) + const contextKeys = baseKeys.slice(0, baseKeys.length - 1) + const index = [] + + const existing = dlv(tree, [...baseKeys, '__info']) + if (typeof existing !== 'undefined') { + if (Array.isArray(existing)) { + index.push(existing.length) + } else { + dset(tree, [...baseKeys, '__info'], [existing]) + index.push(1) + } + } + if (classNames[i].__rule) { + dset(tree, [...baseKeys, '__info', ...index, '__rule'], true) + dset(tree, [...baseKeys, '__info', ...index, '__source'], layer) + + dsetEach(tree, [...baseKeys, '__info', ...index], decls) + } + dset( + tree, + [...baseKeys, '__info', ...index, '__pseudo'], + classNames[i].__pseudo + ) + dset( + tree, + [...baseKeys, '__info', ...index, '__scope'], + classNames[i].scope + ) + dset( + tree, + [...baseKeys, '__info', ...index, '__context'], + context.concat([]).reverse() + ) + + // common context + context.push(...classNames[i].__pseudo.map((x) => `&${x}`)) + + for (let i = 0; i < contextKeys.length; i++) { + if (typeof commonContext[contextKeys[i]] === 'undefined') { + commonContext[contextKeys[i]] = context + } else { + commonContext[contextKeys[i]] = intersection( + commonContext[contextKeys[i]], + context + ) + } + } + } }) return { classNames: tree, context: commonContext } diff --git a/packages/tailwindcss-intellisense/src/class-names/index.js b/packages/tailwindcss-intellisense/src/class-names/index.js index e8034c4..06177bd 100644 --- a/packages/tailwindcss-intellisense/src/class-names/index.js +++ b/packages/tailwindcss-intellisense/src/class-names/index.js @@ -16,6 +16,7 @@ import glob from 'fast-glob' import normalizePath from 'normalize-path' import { withUserEnvironment } from './environment' import execa from 'execa' +import { klona } from 'klona/full' function arraysEqual(arr1, arr2) { return ( @@ -71,7 +72,13 @@ export default async function getClassNames( let hook = Hook(fs.realpathSync(configPath), (exports) => { userSeperator = dlv(exports, sepLocation) userPurge = exports.purge - dset(exports, sepLocation, '__TAILWIND_SEPARATOR__') + dset( + exports, + sepLocation, + `__TWSEP__${ + typeof userSeperator === 'undefined' ? ':' : userSeperator + }__TWSEP__` + ) exports.purge = {} return exports }) @@ -89,15 +96,17 @@ export default async function getClassNames( hook.unwatch() const { - base, - components, - utilities, + postcssResult, resolvedConfig, browserslist, postcss, } = await withPackages( - configDir, - cwd, + { + configDir, + cwd, + userSeperator, + version, + }, async ({ postcss, tailwindcss, @@ -106,19 +115,17 @@ export default async function getClassNames( }) => { let postcssResult try { - postcssResult = await Promise.all( + postcssResult = await postcss([tailwindcss(configPath)]).process( [ semver.gte(version, '0.99.0') ? 'base' : 'preflight', 'components', 'utilities', - ].map((group) => - postcss([tailwindcss(configPath)]).process( - `@tailwind ${group};`, - { - from: undefined, - } - ) - ) + ] + .map((x) => `/*__tw_intellisense_layer_${x}__*/\n@tailwind ${x};`) + .join('\n'), + { + from: undefined, + } ) } catch (error) { throw error @@ -126,8 +133,6 @@ export default async function getClassNames( hook.unhook() } - const [base, components, utilities] = postcssResult - if (typeof userSeperator !== 'undefined') { dset(config, sepLocation, userSeperator) } else { @@ -168,9 +173,7 @@ export default async function getClassNames( } return { - base, - components, - utilities, + postcssResult, resolvedConfig, postcss, browserslist, @@ -183,11 +186,7 @@ export default async function getClassNames( configPath, config: resolvedConfig, separator: typeof userSeperator === 'undefined' ? ':' : userSeperator, - classNames: await extractClassNames([ - { root: base.root, source: 'base' }, - { root: components.root, source: 'components' }, - { root: utilities.root, source: 'utilities' }, - ]), + classNames: await extractClassNames(postcssResult.root), dependencies: hook.deps, plugins: getPlugins(config), variants: getVariants({ config, version, postcss, browserslist }), @@ -262,10 +261,10 @@ function loadMeta(configDir, root) { }) } -function withPackages(configDir, root, cb) { +function withPackages({ configDir, cwd, userSeperator, version }, cb) { return withUserEnvironment( configDir, - root, + cwd, async ({ isPnp, require, resolve }) => { const tailwindBase = path.dirname(resolve('tailwindcss/package.json')) const postcss = require('postcss', tailwindBase) @@ -290,6 +289,55 @@ function withPackages(configDir, root, cb) { } } catch (_) {} + if (semver.gte(version, '1.7.0')) { + const applyComplexClasses = semver.gte(version, '1.99.0') + ? require('./lib/lib/substituteClassApplyAtRules', tailwindBase) + : require('./lib/flagged/applyComplexClasses', tailwindBase) + + if (!applyComplexClasses.default.__patched) { + let _applyComplexClasses = applyComplexClasses.default + applyComplexClasses.default = (config, ...args) => { + let configClone = klona(config) + configClone.separator = + typeof userSeperator === 'undefined' ? ':' : userSeperator + + let fn = _applyComplexClasses(configClone, ...args) + + return async (css) => { + css.walkRules((rule) => { + const newSelector = rule.selector.replace( + /__TWSEP__(.*?)__TWSEP__/g, + '$1' + ) + if (newSelector !== rule.selector) { + rule.before( + postcss.comment({ + text: '__ORIGINAL_SELECTOR__:' + rule.selector, + }) + ) + rule.selector = newSelector + } + }) + + await fn(css) + + css.walkComments((comment) => { + if (comment.text.startsWith('__ORIGINAL_SELECTOR__:')) { + comment.next().selector = comment.text.replace( + /^__ORIGINAL_SELECTOR__:/, + '' + ) + comment.remove() + } + }) + + return css + } + } + applyComplexClasses.default.__patched = true + } + } + return cb({ postcss, tailwindcss, browserslistCommand, browserslistArgs }) } )