From 9f003fecd52144f20b38329d3f22cf0924b2eacd Mon Sep 17 00:00:00 2001 From: Brad Cornes Date: Wed, 24 Jun 2020 11:55:17 +0100 Subject: [PATCH] rejig config finder (#130) --- package-lock.json | 67 ++++++++++++++++++++++ package.json | 2 + src/class-names/glob.js | 22 ------- src/class-names/globSingle.js | 105 ---------------------------------- src/class-names/index.js | 26 +++++---- 5 files changed, 85 insertions(+), 137 deletions(-) delete mode 100644 src/class-names/glob.js delete mode 100644 src/class-names/globSingle.js diff --git a/package-lock.json b/package-lock.json index fed8018..10c6a8c 100755 --- a/package-lock.json +++ b/package-lock.json @@ -937,6 +937,32 @@ } } }, + "@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + } + }, "@sinonjs/commons": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz", @@ -2411,6 +2437,20 @@ "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", "dev": true }, + "fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2423,6 +2463,15 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, "fb-watchman": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", @@ -4870,6 +4919,12 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", @@ -5832,6 +5887,12 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -5847,6 +5908,12 @@ "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", "dev": true }, + "run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, "rxjs": { "version": "6.5.4", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", diff --git a/package.json b/package.json index 275d490..5f51520 100755 --- a/package.json +++ b/package.json @@ -170,6 +170,7 @@ "dlv": "^1.1.3", "dset": "^2.0.1", "esm": "^3.2.25", + "fast-glob": "^3.2.4", "glob-exec": "^0.1.1", "globalyzer": "^0.1.4", "globrex": "^0.1.2", @@ -179,6 +180,7 @@ "mitt": "^1.2.0", "mkdirp": "^1.0.3", "moo": "^0.5.1", + "normalize-path": "^3.0.0", "pkg-up": "^3.1.0", "postcss": "^7.0.27", "postcss-selector-parser": "^6.0.2", diff --git a/src/class-names/glob.js b/src/class-names/glob.js deleted file mode 100644 index 22e3eb8..0000000 --- a/src/class-names/glob.js +++ /dev/null @@ -1,22 +0,0 @@ -import nodeGlob from 'glob' -import dlv from 'dlv' -import * as path from 'path' - -export function glob(pattern, options = {}) { - return new Promise((resolve, reject) => { - let g = new nodeGlob.Glob(pattern, options) - let matches = [] - let max = dlv(options, 'max', Infinity) - g.on('match', (match) => { - matches.push(path.resolve(options.cwd || process.cwd(), match)) - if (matches.length === max) { - g.abort() - resolve(matches) - } - }) - g.on('end', () => { - resolve(matches) - }) - g.on('error', reject) - }) -} diff --git a/src/class-names/globSingle.js b/src/class-names/globSingle.js deleted file mode 100644 index 91d10fb..0000000 --- a/src/class-names/globSingle.js +++ /dev/null @@ -1,105 +0,0 @@ -const fs = require('fs') -const globrex = require('globrex') -const { promisify } = require('util') -const globalyzer = require('globalyzer') -const { join, resolve, relative } = require('path') -const isHidden = /(^|[\\\/])\.[^\\\/\.]/g -const readdir = promisify(fs.readdir) -const stat = promisify(fs.stat) -let CACHE = {} - -async function walk(output, prefix, lexer, opts, dirname = '', level = 0) { - if (output.length === 1) return - const rgx = lexer.segments[level] - const dir = join(opts.cwd, prefix, dirname) - const files = await readdir(dir) - const { dot, filesOnly } = opts - - let i = 0, - len = files.length, - file - let fullpath, relpath, stats, isMatch - - for (; i < len; i++) { - file = files[i] - if (file === 'node_modules') continue - fullpath = join(dir, file) - relpath = dirname ? join(dirname, file) : file - if (!dot && isHidden.test(relpath)) continue - isMatch = lexer.regex.test(relpath) - - if ((stats = CACHE[relpath]) === void 0) { - CACHE[relpath] = stats = fs.lstatSync(fullpath) - } - - if (!stats.isDirectory()) { - if (isMatch) { - output.push(relative(opts.cwd, fullpath)) - return - } - continue - } - - if (rgx && !rgx.test(file)) continue - if (!filesOnly && isMatch) { - output.push(join(prefix, relpath)) - return - } - - await walk( - output, - prefix, - lexer, - opts, - relpath, - rgx && rgx.toString() !== lexer.globstar && ++level - ) - } -} - -/** - * Find files using bash-like globbing. - * All paths are normalized compared to node-glob. - * @param {String} str Glob string - * @param {String} [options.cwd='.'] Current working directory - * @param {Boolean} [options.dot=false] Include dotfile matches - * @param {Boolean} [options.absolute=false] Return absolute paths - * @param {Boolean} [options.filesOnly=false] Do not include folders if true - * @param {Boolean} [options.flush=false] Reset cache object - * @returns {Array} array containing matching files - */ -export async function globSingle(str, opts = {}) { - if (!str) return [] - - let glob = globalyzer(str) - - opts.cwd = opts.cwd || '.' - - if (!glob.isGlob) { - try { - let resolved = resolve(opts.cwd, str) - let dirent = await stat(resolved) - if (opts.filesOnly && !dirent.isFile()) return [] - - return opts.absolute ? [resolved] : [str] - } catch (err) { - if (err.code != 'ENOENT') throw err - - return [] - } - } - - if (opts.flush) CACHE = {} - - let matches = [] - const { path } = globrex(glob.glob, { - filepath: true, - globstar: true, - extended: true, - }) - - path.globstar = path.globstar.toString() - await walk(matches, glob.base, path, opts, '.', 0) - - return opts.absolute ? matches.map((x) => resolve(opts.cwd, x)) : matches -} diff --git a/src/class-names/index.js b/src/class-names/index.js index 0ddd81c..b1d3794 100644 --- a/src/class-names/index.js +++ b/src/class-names/index.js @@ -12,8 +12,9 @@ import getVariants from './getVariants' import resolveConfig from './resolveConfig' import * as util from 'util' import * as path from 'path' -import { globSingle } from './globSingle' import { getUtilityConfigMap } from './getUtilityConfigMap' +import glob from 'fast-glob' +import normalizePath from 'normalize-path' function TailwindConfigError(error) { Error.call(this) @@ -41,20 +42,25 @@ export default async function getClassNames( { onChange = () => {} } = {} ) { async function run() { - let configPath let postcss let tailwindcss let browserslistModule let version - configPath = await globSingle(CONFIG_GLOB, { - cwd, - filesOnly: true, - absolute: true, - flush: true, - }) - invariant(configPath.length === 1, 'No Tailwind CSS config found.') - configPath = configPath[0] + const configPaths = ( + await glob(CONFIG_GLOB, { + cwd, + ignore: ['**/node_modules'], + onlyFiles: true, + absolute: true, + }) + ) + .map(normalizePath) + .sort((a, b) => a.split('/').length - b.split('/').length) + .map(path.normalize) + + invariant(configPaths.length > 0, 'No Tailwind CSS config found.') + const configPath = configPaths[0] const configDir = path.dirname(configPath) const tailwindBase = path.dirname( resolveFrom(configDir, 'tailwindcss/package.json')