tailwindcss
Advanced tools
Comparing version 3.2.4 to 3.3.6
@@ -12,6 +12,14 @@ "use strict"; | ||
_export(exports, { | ||
lazyPostcss: ()=>lazyPostcss, | ||
lazyPostcssImport: ()=>lazyPostcssImport, | ||
lazyAutoprefixer: ()=>lazyAutoprefixer, | ||
lazyCssnano: ()=>lazyCssnano | ||
lazyPostcss: function() { | ||
return lazyPostcss; | ||
}, | ||
lazyPostcssImport: function() { | ||
return lazyPostcssImport; | ||
}, | ||
lazyAutoprefixer: function() { | ||
return lazyAutoprefixer; | ||
}, | ||
lazyCssnano: function() { | ||
return lazyCssnano; | ||
} | ||
}); | ||
@@ -18,0 +26,0 @@ function lazyPostcss() { |
230
lib/cli.js
#!/usr/bin/env node | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
const _path = /*#__PURE__*/ _interopRequireDefault(require("path")); | ||
const _arg = /*#__PURE__*/ _interopRequireDefault(require("arg")); | ||
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs")); | ||
const _build = require("./cli/build"); | ||
const _help = require("./cli/help"); | ||
const _init = require("./cli/init"); | ||
function _interopRequireDefault(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
default: obj | ||
}; | ||
if (false) { | ||
module.exports = require("./oxide/cli"); | ||
} else { | ||
module.exports = require("./cli/index"); | ||
} | ||
function isESM() { | ||
const pkgPath = _path.default.resolve("./package.json"); | ||
try { | ||
let pkg = JSON.parse(_fs.default.readFileSync(pkgPath, "utf8")); | ||
return pkg.type && pkg.type === "module"; | ||
} catch (err) { | ||
return false; | ||
} | ||
} | ||
let configs = isESM() ? { | ||
tailwind: "tailwind.config.cjs", | ||
postcss: "postcss.config.cjs" | ||
} : { | ||
tailwind: "tailwind.config.js", | ||
postcss: "postcss.config.js" | ||
}; | ||
// --- | ||
function oneOf(...options) { | ||
return Object.assign((value = true)=>{ | ||
for (let option of options){ | ||
let parsed = option(value); | ||
if (parsed === value) { | ||
return parsed; | ||
} | ||
} | ||
throw new Error("..."); | ||
}, { | ||
manualParsing: true | ||
}); | ||
} | ||
let commands = { | ||
init: { | ||
run: _init.init, | ||
args: { | ||
"--full": { | ||
type: Boolean, | ||
description: `Initialize a full \`${configs.tailwind}\` file` | ||
}, | ||
"--postcss": { | ||
type: Boolean, | ||
description: `Initialize a \`${configs.postcss}\` file` | ||
}, | ||
"-f": "--full", | ||
"-p": "--postcss" | ||
} | ||
}, | ||
build: { | ||
run: _build.build, | ||
args: { | ||
"--input": { | ||
type: String, | ||
description: "Input file" | ||
}, | ||
"--output": { | ||
type: String, | ||
description: "Output file" | ||
}, | ||
"--watch": { | ||
type: Boolean, | ||
description: "Watch for changes and rebuild as needed" | ||
}, | ||
"--poll": { | ||
type: Boolean, | ||
description: "Use polling instead of filesystem events when watching" | ||
}, | ||
"--content": { | ||
type: String, | ||
description: "Content paths to use for removing unused classes" | ||
}, | ||
"--purge": { | ||
type: String, | ||
deprecated: true | ||
}, | ||
"--postcss": { | ||
type: oneOf(String, Boolean), | ||
description: "Load custom PostCSS configuration" | ||
}, | ||
"--minify": { | ||
type: Boolean, | ||
description: "Minify the output" | ||
}, | ||
"--config": { | ||
type: String, | ||
description: "Path to a custom config file" | ||
}, | ||
"--no-autoprefixer": { | ||
type: Boolean, | ||
description: "Disable autoprefixer" | ||
}, | ||
"-c": "--config", | ||
"-i": "--input", | ||
"-o": "--output", | ||
"-m": "--minify", | ||
"-w": "--watch", | ||
"-p": "--poll" | ||
} | ||
} | ||
}; | ||
let sharedFlags = { | ||
"--help": { | ||
type: Boolean, | ||
description: "Display usage information" | ||
}, | ||
"-h": "--help" | ||
}; | ||
if (process.stdout.isTTY /* Detect redirecting output to a file */ && (process.argv[2] === undefined || process.argv.slice(2).every((flag)=>sharedFlags[flag] !== undefined))) { | ||
(0, _help.help)({ | ||
usage: [ | ||
"tailwindcss [--input input.css] [--output output.css] [--watch] [options...]", | ||
"tailwindcss init [--full] [--postcss] [options...]" | ||
], | ||
commands: Object.keys(commands).filter((command)=>command !== "build").map((command)=>`${command} [options]`), | ||
options: { | ||
...commands.build.args, | ||
...sharedFlags | ||
} | ||
}); | ||
process.exit(0); | ||
} | ||
let command = ((arg = "")=>arg.startsWith("-") ? undefined : arg)(process.argv[2]) || "build"; | ||
if (commands[command] === undefined) { | ||
if (_fs.default.existsSync(_path.default.resolve(command))) { | ||
// TODO: Deprecate this in future versions | ||
// Check if non-existing command, might be a file. | ||
command = "build"; | ||
} else { | ||
(0, _help.help)({ | ||
message: `Invalid command: ${command}`, | ||
usage: [ | ||
"tailwindcss <command> [options]" | ||
], | ||
commands: Object.keys(commands).filter((command)=>command !== "build").map((command)=>`${command} [options]`), | ||
options: sharedFlags | ||
}); | ||
process.exit(1); | ||
} | ||
} | ||
// Execute command | ||
let { args: flags , run } = commands[command]; | ||
let args = (()=>{ | ||
try { | ||
let result = (0, _arg.default)(Object.fromEntries(Object.entries({ | ||
...flags, | ||
...sharedFlags | ||
}).filter(([_key, value])=>{ | ||
var ref; | ||
return !(value === null || value === void 0 ? void 0 : (ref = value.type) === null || ref === void 0 ? void 0 : ref.manualParsing); | ||
}).map(([key, value])=>[ | ||
key, | ||
typeof value === "object" ? value.type : value | ||
])), { | ||
permissive: true | ||
}); | ||
// Manual parsing of flags to allow for special flags like oneOf(Boolean, String) | ||
for(let i = result["_"].length - 1; i >= 0; --i){ | ||
let flag = result["_"][i]; | ||
if (!flag.startsWith("-")) continue; | ||
let flagName = flag; | ||
let handler = flags[flag]; | ||
// Resolve flagName & handler | ||
while(typeof handler === "string"){ | ||
flagName = handler; | ||
handler = flags[handler]; | ||
} | ||
if (!handler) continue; | ||
let args = []; | ||
let offset = i + 1; | ||
// Parse args for current flag | ||
while(result["_"][offset] && !result["_"][offset].startsWith("-")){ | ||
args.push(result["_"][offset++]); | ||
} | ||
// Cleanup manually parsed flags + args | ||
result["_"].splice(i, 1 + args.length); | ||
// Set the resolved value in the `result` object | ||
result[flagName] = handler.type(args.length === 0 ? undefined : args.length === 1 ? args[0] : args, flagName); | ||
} | ||
// Ensure that the `command` is always the first argument in the `args`. | ||
// This is important so that we don't have to check if a default command | ||
// (build) was used or not from within each plugin. | ||
// | ||
// E.g.: tailwindcss input.css -> _: ['build', 'input.css'] | ||
// E.g.: tailwindcss build input.css -> _: ['build', 'input.css'] | ||
if (result["_"][0] !== command) { | ||
result["_"].unshift(command); | ||
} | ||
return result; | ||
} catch (err) { | ||
if (err.code === "ARG_UNKNOWN_OPTION") { | ||
(0, _help.help)({ | ||
message: err.message, | ||
usage: [ | ||
"tailwindcss <command> [options]" | ||
], | ||
options: sharedFlags | ||
}); | ||
process.exit(1); | ||
} | ||
throw err; | ||
} | ||
})(); | ||
if (args["--help"]) { | ||
(0, _help.help)({ | ||
options: { | ||
...flags, | ||
...sharedFlags | ||
}, | ||
usage: [ | ||
`tailwindcss ${command} [options]` | ||
] | ||
}); | ||
process.exit(0); | ||
} | ||
run(args, configs); |
@@ -13,8 +13,16 @@ // @ts-check | ||
_export(exports, { | ||
loadPostcss: ()=>loadPostcss, | ||
loadPostcssImport: ()=>loadPostcssImport, | ||
loadCssNano: ()=>loadCssNano, | ||
loadAutoprefixer: ()=>loadAutoprefixer | ||
loadPostcss: function() { | ||
return loadPostcss; | ||
}, | ||
loadPostcssImport: function() { | ||
return loadPostcssImport; | ||
}, | ||
loadCssNano: function() { | ||
return loadCssNano; | ||
}, | ||
loadAutoprefixer: function() { | ||
return loadAutoprefixer; | ||
} | ||
}); | ||
const _indexJs = require("../../../peers/index.js"); | ||
const _index = require("../../../peers/index.js"); | ||
function loadPostcss() { | ||
@@ -25,3 +33,3 @@ // Try to load a local `postcss` version first | ||
} catch {} | ||
return (0, _indexJs.lazyPostcss)(); | ||
return (0, _index.lazyPostcss)(); | ||
} | ||
@@ -33,3 +41,3 @@ function loadPostcssImport() { | ||
} catch {} | ||
return (0, _indexJs.lazyPostcssImport)(); | ||
return (0, _index.lazyPostcssImport)(); | ||
} | ||
@@ -49,3 +57,3 @@ function loadCssNano() { | ||
} catch {} | ||
return (0, _indexJs.lazyCssnano)()(options); | ||
return (0, _index.lazyCssnano)()(options); | ||
} | ||
@@ -57,3 +65,3 @@ function loadAutoprefixer() { | ||
} catch {} | ||
return (0, _indexJs.lazyAutoprefixer)(); | ||
return (0, _index.lazyAutoprefixer)(); | ||
} |
@@ -8,8 +8,11 @@ // @ts-check | ||
enumerable: true, | ||
get: ()=>build | ||
get: function() { | ||
return build; | ||
} | ||
}); | ||
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs")); | ||
const _path = /*#__PURE__*/ _interopRequireDefault(require("path")); | ||
const _pluginJs = require("./plugin.js"); | ||
function _interopRequireDefault(obj) { | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _path = /*#__PURE__*/ _interop_require_default(require("path")); | ||
const _resolveConfigPath = require("../../util/resolveConfigPath.js"); | ||
const _plugin = require("./plugin.js"); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -19,3 +22,3 @@ default: obj | ||
} | ||
async function build(args, configs) { | ||
async function build(args) { | ||
let input = args["--input"]; | ||
@@ -37,11 +40,18 @@ let shouldWatch = args["--watch"]; | ||
// TODO: Reference the @config path here if exists | ||
let configPath = args["--config"] ? args["--config"] : ((defaultPath)=>_fs.default.existsSync(defaultPath) ? defaultPath : null)(_path.default.resolve(`./${configs.tailwind}`)); | ||
let processor = await (0, _pluginJs.createProcessor)(args, configPath); | ||
let configPath = args["--config"] ? args["--config"] : (0, _resolveConfigPath.resolveDefaultConfigPath)(); | ||
let processor = await (0, _plugin.createProcessor)(args, configPath); | ||
if (shouldWatch) { | ||
/* Abort the watcher if stdin is closed to avoid zombie processes */ process.stdin.on("end", ()=>process.exit(0)); | ||
// Abort the watcher if stdin is closed to avoid zombie processes | ||
// You can disable this behavior with --watch=always | ||
if (args["--watch"] !== "always") { | ||
process.stdin.on("end", ()=>process.exit(0)); | ||
} | ||
process.stdin.resume(); | ||
await processor.watch(); | ||
} else { | ||
await processor.build(); | ||
await processor.build().catch((e)=>{ | ||
console.error(e); | ||
process.exit(1); | ||
}); | ||
} | ||
} |
@@ -8,24 +8,27 @@ // @ts-check | ||
enumerable: true, | ||
get: ()=>createProcessor | ||
get: function() { | ||
return createProcessor; | ||
} | ||
}); | ||
const _path = /*#__PURE__*/ _interopRequireDefault(require("path")); | ||
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs")); | ||
const _postcssLoadConfig = /*#__PURE__*/ _interopRequireDefault(require("postcss-load-config")); | ||
const _path = /*#__PURE__*/ _interop_require_default(require("path")); | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _postcssloadconfig = /*#__PURE__*/ _interop_require_default(require("postcss-load-config")); | ||
const _lilconfig = require("lilconfig"); | ||
const _plugins = /*#__PURE__*/ _interopRequireDefault(require("postcss-load-config/src/plugins" // Little bit scary, looking at private/internal API | ||
const _plugins = /*#__PURE__*/ _interop_require_default(require("postcss-load-config/src/plugins" // Little bit scary, looking at private/internal API | ||
)); | ||
const _options = /*#__PURE__*/ _interopRequireDefault(require("postcss-load-config/src/options" // Little bit scary, looking at private/internal API | ||
const _options = /*#__PURE__*/ _interop_require_default(require("postcss-load-config/src/options" // Little bit scary, looking at private/internal API | ||
)); | ||
const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("../../processTailwindFeatures")); | ||
const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("../../processTailwindFeatures")); | ||
const _deps = require("./deps"); | ||
const _utils = require("./utils"); | ||
const _shared = require("../shared"); | ||
const _resolveConfigJs = /*#__PURE__*/ _interopRequireDefault(require("../../../resolveConfig.js")); | ||
const _getModuleDependenciesJs = /*#__PURE__*/ _interopRequireDefault(require("../../lib/getModuleDependencies.js")); | ||
const _contentJs = require("../../lib/content.js"); | ||
const _watchingJs = require("./watching.js"); | ||
const _fastGlob = /*#__PURE__*/ _interopRequireDefault(require("fast-glob")); | ||
const _findAtConfigPathJs = require("../../lib/findAtConfigPath.js"); | ||
const _log = /*#__PURE__*/ _interopRequireDefault(require("../../util/log")); | ||
function _interopRequireDefault(obj) { | ||
const _sharedState = require("../../lib/sharedState"); | ||
const _resolveConfig = /*#__PURE__*/ _interop_require_default(require("../../../resolveConfig.js")); | ||
const _content = require("../../lib/content.js"); | ||
const _watching = require("./watching.js"); | ||
const _fastglob = /*#__PURE__*/ _interop_require_default(require("fast-glob")); | ||
const _findAtConfigPath = require("../../lib/findAtConfigPath.js"); | ||
const _log = /*#__PURE__*/ _interop_require_default(require("../../util/log")); | ||
const _loadconfig = require("../../lib/load-config"); | ||
const _getModuleDependencies = /*#__PURE__*/ _interop_require_default(require("../../lib/getModuleDependencies")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -58,3 +61,3 @@ default: obj | ||
}; | ||
})() : await (0, _postcssLoadConfig.default)(); | ||
})() : await (0, _postcssloadconfig.default)(); | ||
let configPlugins = config.plugins; | ||
@@ -114,8 +117,8 @@ let configPluginTailwindIdx = configPlugins.findIndex((plugin)=>{ | ||
/** @type {{content: string, extension: string}[]} */ changedContent: [], | ||
configDependencies: new Set(), | ||
/** @type {ReturnType<typeof load> | null} */ configBag: null, | ||
contextDependencies: new Set(), | ||
/** @type {import('../../lib/content.js').ContentPath[]} */ contentPaths: [], | ||
refreshContentPaths () { | ||
var ref; | ||
this.contentPaths = (0, _contentJs.parseCandidateFiles)(this.context, (ref = this.context) === null || ref === void 0 ? void 0 : ref.tailwindConfig); | ||
var _this_context; | ||
this.contentPaths = (0, _content.parseCandidateFiles)(this.context, (_this_context = this.context) === null || _this_context === void 0 ? void 0 : _this_context.tailwindConfig); | ||
}, | ||
@@ -133,7 +136,17 @@ get config () { | ||
if (this.watcher && configPath) { | ||
this.refreshConfigDependencies(configPath); | ||
this.refreshConfigDependencies(); | ||
} | ||
let config = configPath ? require(configPath) : {}; | ||
let config = (0, _loadconfig.loadConfig)(configPath); | ||
let dependencies = (0, _getModuleDependencies.default)(configPath); | ||
this.configBag = { | ||
config, | ||
dependencies, | ||
dispose () { | ||
for (let file of dependencies){ | ||
delete require.cache[require.resolve(file)]; | ||
} | ||
} | ||
}; | ||
// @ts-ignore | ||
config = (0, _resolveConfigJs.default)(config, { | ||
this.configBag.config = (0, _resolveConfig.default)(this.configBag.config, { | ||
content: { | ||
@@ -145,18 +158,11 @@ files: [] | ||
if ((content === null || content === void 0 ? void 0 : content.length) > 0) { | ||
config.content.files = content; | ||
this.configBag.config.content.files = content; | ||
} | ||
return config; | ||
return this.configBag.config; | ||
}, | ||
refreshConfigDependencies (configPath) { | ||
_shared.env.DEBUG && console.time("Module dependencies"); | ||
for (let file of this.configDependencies){ | ||
delete require.cache[require.resolve(file)]; | ||
} | ||
if (configPath) { | ||
let deps = (0, _getModuleDependenciesJs.default)(configPath).map(({ file })=>file); | ||
for (let dependency of deps){ | ||
this.configDependencies.add(dependency); | ||
} | ||
} | ||
_shared.env.DEBUG && console.timeEnd("Module dependencies"); | ||
refreshConfigDependencies () { | ||
var _this_configBag; | ||
_sharedState.env.DEBUG && console.time("Module dependencies"); | ||
(_this_configBag = this.configBag) === null || _this_configBag === void 0 ? void 0 : _this_configBag.dispose(); | ||
_sharedState.env.DEBUG && console.timeEnd("Module dependencies"); | ||
}, | ||
@@ -167,8 +173,15 @@ readContentPaths () { | ||
// TODO: When we make the postcss plugin async-capable this can become async | ||
let files = _fastGlob.default.sync(this.contentPatterns.all); | ||
let files = _fastglob.default.sync(this.contentPatterns.all); | ||
for (let file of files){ | ||
content.push({ | ||
content: _fs.default.readFileSync(_path.default.resolve(file), "utf8"), | ||
extension: _path.default.extname(file).slice(1) | ||
}); | ||
if (false) { | ||
content.push({ | ||
file, | ||
extension: _path.default.extname(file).slice(1) | ||
}); | ||
} else { | ||
content.push({ | ||
content: _fs.default.readFileSync(_path.default.resolve(file), "utf8"), | ||
extension: _path.default.extname(file).slice(1) | ||
}); | ||
} | ||
} | ||
@@ -188,2 +201,6 @@ // Resolve raw content in the tailwind config | ||
getContext ({ createContext , cliConfigPath , root , result , content }) { | ||
_sharedState.env.DEBUG && console.time("Searching for config"); | ||
var _findAtConfigPath1; | ||
let configPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : cliConfigPath; | ||
_sharedState.env.DEBUG && console.timeEnd("Searching for config"); | ||
if (this.context) { | ||
@@ -193,10 +210,6 @@ this.context.changedContent = this.changedContent.splice(0); | ||
} | ||
_shared.env.DEBUG && console.time("Searching for config"); | ||
var ref; | ||
let configPath = (ref = (0, _findAtConfigPathJs.findAtConfigPath)(root, result)) !== null && ref !== void 0 ? ref : cliConfigPath; | ||
_shared.env.DEBUG && console.timeEnd("Searching for config"); | ||
_shared.env.DEBUG && console.time("Loading config"); | ||
_sharedState.env.DEBUG && console.time("Loading config"); | ||
let config = this.loadConfig(configPath, content); | ||
_shared.env.DEBUG && console.timeEnd("Loading config"); | ||
_shared.env.DEBUG && console.time("Creating context"); | ||
_sharedState.env.DEBUG && console.timeEnd("Loading config"); | ||
_sharedState.env.DEBUG && console.time("Creating context"); | ||
this.context = createContext(config, []); | ||
@@ -206,16 +219,14 @@ Object.assign(this.context, { | ||
}); | ||
_shared.env.DEBUG && console.timeEnd("Creating context"); | ||
_shared.env.DEBUG && console.time("Resolving content paths"); | ||
_sharedState.env.DEBUG && console.timeEnd("Creating context"); | ||
_sharedState.env.DEBUG && console.time("Resolving content paths"); | ||
this.refreshContentPaths(); | ||
_shared.env.DEBUG && console.timeEnd("Resolving content paths"); | ||
_sharedState.env.DEBUG && console.timeEnd("Resolving content paths"); | ||
if (this.watcher) { | ||
_shared.env.DEBUG && console.time("Watch new files"); | ||
_sharedState.env.DEBUG && console.time("Watch new files"); | ||
this.watcher.refreshWatchedFiles(); | ||
_shared.env.DEBUG && console.timeEnd("Watch new files"); | ||
_sharedState.env.DEBUG && console.timeEnd("Watch new files"); | ||
} | ||
_shared.env.DEBUG && console.time("Reading content files"); | ||
for (let file of this.readContentPaths()){ | ||
this.context.changedContent.push(file); | ||
} | ||
_shared.env.DEBUG && console.timeEnd("Reading content files"); | ||
return this.context; | ||
@@ -225,3 +236,3 @@ } | ||
async function createProcessor(args, cliConfigPath) { | ||
var ref; | ||
var _args_content; | ||
let postcss = (0, _deps.loadPostcss)(); | ||
@@ -242,10 +253,10 @@ let input = args["--input"]; | ||
} | ||
var ref1; | ||
let content = (ref1 = (ref = args["--content"]) === null || ref === void 0 ? void 0 : ref.split(/(?<!{[^}]+),/)) !== null && ref1 !== void 0 ? ref1 : []; | ||
var _args_content_split; | ||
let content = (_args_content_split = (_args_content = args["--content"]) === null || _args_content === void 0 ? void 0 : _args_content.split(/(?<!{[^}]+),/)) !== null && _args_content_split !== void 0 ? _args_content_split : []; | ||
let tailwindPlugin = ()=>{ | ||
return { | ||
postcssPlugin: "tailwindcss", | ||
Once (root, { result }) { | ||
_shared.env.DEBUG && console.time("Compiling CSS"); | ||
(0, _processTailwindFeatures.default)(({ createContext })=>{ | ||
async Once (root, { result }) { | ||
_sharedState.env.DEBUG && console.time("Compiling CSS"); | ||
await (0, _processTailwindFeatures.default)(({ createContext })=>{ | ||
console.error(); | ||
@@ -263,3 +274,3 @@ console.error("Rebuilding..."); | ||
})(root, result); | ||
_shared.env.DEBUG && console.timeEnd("Compiling CSS"); | ||
_sharedState.env.DEBUG && console.timeEnd("Compiling CSS"); | ||
} | ||
@@ -301,3 +312,3 @@ }; | ||
} | ||
_shared.env.DEBUG && console.time("Recording PostCSS dependencies"); | ||
_sharedState.env.DEBUG && console.time("Recording PostCSS dependencies"); | ||
for (let message of result.messages){ | ||
@@ -308,7 +319,7 @@ if (message.type === "dependency") { | ||
} | ||
_shared.env.DEBUG && console.timeEnd("Recording PostCSS dependencies"); | ||
_sharedState.env.DEBUG && console.timeEnd("Recording PostCSS dependencies"); | ||
// TODO: This needs to be in a different spot | ||
_shared.env.DEBUG && console.time("Watch new files"); | ||
_sharedState.env.DEBUG && console.time("Watch new files"); | ||
state.watcher.refreshWatchedFiles(); | ||
_shared.env.DEBUG && console.timeEnd("Watch new files"); | ||
_sharedState.env.DEBUG && console.timeEnd("Watch new files"); | ||
return result; | ||
@@ -321,4 +332,4 @@ }).then((result)=>{ | ||
return Promise.all([ | ||
(0, _utils.outputFile)(output, result.css), | ||
result.map && (0, _utils.outputFile)(output + ".map", result.map.toString()) | ||
(0, _utils.outputFile)(result.opts.to, result.css), | ||
result.map && (0, _utils.outputFile)(result.opts.to + ".map", result.map.toString()) | ||
]); | ||
@@ -339,3 +350,7 @@ }).then(()=>{ | ||
// resilient to future errors. | ||
console.error(err); | ||
if (state.watcher) { | ||
console.error(err); | ||
} else { | ||
return Promise.reject(err); | ||
} | ||
}); | ||
@@ -357,3 +372,3 @@ } | ||
watch: async ()=>{ | ||
state.watcher = (0, _watchingJs.createWatcher)(args, { | ||
state.watcher = (0, _watching.createWatcher)(args, { | ||
state, | ||
@@ -364,3 +379,4 @@ /** | ||
let needsNewContext = changes.some((change)=>{ | ||
return state.configDependencies.has(change.file) || state.contextDependencies.has(change.file); | ||
var _state_configBag; | ||
return ((_state_configBag = state.configBag) === null || _state_configBag === void 0 ? void 0 : _state_configBag.dependencies.has(change.file)) || state.contextDependencies.has(change.file); | ||
}); | ||
@@ -367,0 +383,0 @@ if (needsNewContext) { |
@@ -13,11 +13,21 @@ // @ts-check | ||
_export(exports, { | ||
indentRecursive: ()=>indentRecursive, | ||
formatNodes: ()=>formatNodes, | ||
readFileWithRetries: ()=>readFileWithRetries, | ||
drainStdin: ()=>drainStdin, | ||
outputFile: ()=>outputFile | ||
indentRecursive: function() { | ||
return indentRecursive; | ||
}, | ||
formatNodes: function() { | ||
return formatNodes; | ||
}, | ||
readFileWithRetries: function() { | ||
return readFileWithRetries; | ||
}, | ||
drainStdin: function() { | ||
return drainStdin; | ||
}, | ||
outputFile: function() { | ||
return outputFile; | ||
} | ||
}); | ||
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs")); | ||
const _path = /*#__PURE__*/ _interopRequireDefault(require("path")); | ||
function _interopRequireDefault(obj) { | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _path = /*#__PURE__*/ _interop_require_default(require("path")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -24,0 +34,0 @@ default: obj |
@@ -8,11 +8,13 @@ // @ts-check | ||
enumerable: true, | ||
get: ()=>createWatcher | ||
get: function() { | ||
return createWatcher; | ||
} | ||
}); | ||
const _chokidar = /*#__PURE__*/ _interopRequireDefault(require("chokidar")); | ||
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs")); | ||
const _micromatch = /*#__PURE__*/ _interopRequireDefault(require("micromatch")); | ||
const _normalizePath = /*#__PURE__*/ _interopRequireDefault(require("normalize-path")); | ||
const _path = /*#__PURE__*/ _interopRequireDefault(require("path")); | ||
const _utilsJs = require("./utils.js"); | ||
function _interopRequireDefault(obj) { | ||
const _chokidar = /*#__PURE__*/ _interop_require_default(require("chokidar")); | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _micromatch = /*#__PURE__*/ _interop_require_default(require("micromatch")); | ||
const _normalizepath = /*#__PURE__*/ _interop_require_default(require("normalize-path")); | ||
const _path = /*#__PURE__*/ _interop_require_default(require("path")); | ||
const _utils = require("./utils.js"); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -68,3 +70,5 @@ default: obj | ||
// Resolve the promise even when the rebuild fails | ||
return rebuild(changes).then(()=>{}, ()=>{}); | ||
return rebuild(changes).then(()=>{}, (e)=>{ | ||
console.error(e.toString()); | ||
}); | ||
} | ||
@@ -114,3 +118,3 @@ /** | ||
watcher.on("unlink", (file)=>{ | ||
file = (0, _normalizePath.default)(file); | ||
file = (0, _normalizepath.default)(file); | ||
// Only re-add the file if it's not covered by a dynamic pattern | ||
@@ -128,3 +132,3 @@ if (!_micromatch.default.some([ | ||
watcher.on("raw", (evt, filePath, meta)=>{ | ||
if (evt !== "rename") { | ||
if (evt !== "rename" || filePath === null) { | ||
return; | ||
@@ -155,3 +159,3 @@ } | ||
// immediately increases the chance that the file is still there | ||
let content = await (0, _utilsJs.readFileWithRetries)(_path.default.resolve(filePath)); | ||
let content = await (0, _utils.readFileWithRetries)(_path.default.resolve(filePath)); | ||
if (content === undefined) { | ||
@@ -179,3 +183,3 @@ return; | ||
watcher.add(Array.from(state.contextDependencies)); | ||
watcher.add(Array.from(state.configDependencies)); | ||
watcher.add(Array.from(state.configBag.dependencies)); | ||
watcher.add(state.contentPatterns.all); | ||
@@ -182,0 +186,0 @@ } |
@@ -8,6 +8,8 @@ // @ts-check | ||
enumerable: true, | ||
get: ()=>help | ||
get: function() { | ||
return help; | ||
} | ||
}); | ||
const _packageJson = /*#__PURE__*/ _interopRequireDefault(require("../../../package.json")); | ||
function _interopRequireDefault(obj) { | ||
const _packagejson = /*#__PURE__*/ _interop_require_default(require("../../../package.json")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -21,3 +23,3 @@ default: obj | ||
console.log(); | ||
console.log(`${_packageJson.default.name} v${_packageJson.default.version}`); | ||
console.log(`${_packagejson.default.name} v${_packagejson.default.version}`); | ||
// Render message | ||
@@ -24,0 +26,0 @@ if (message) { |
@@ -0,1 +1,2 @@ | ||
#!/usr/bin/env node | ||
"use strict"; | ||
@@ -5,15 +6,226 @@ Object.defineProperty(exports, "__esModule", { | ||
}); | ||
_exportStar(require("./build"), exports); | ||
_exportStar(require("./config"), exports); | ||
_exportStar(require("./content"), exports); | ||
function _exportStar(from, to) { | ||
Object.keys(from).forEach(function(k) { | ||
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) Object.defineProperty(to, k, { | ||
enumerable: true, | ||
get: function() { | ||
return from[k]; | ||
const _path = /*#__PURE__*/ _interop_require_default(require("path")); | ||
const _arg = /*#__PURE__*/ _interop_require_default(require("arg")); | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _build = require("./build"); | ||
const _help = require("./help"); | ||
const _init = require("./init"); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
default: obj | ||
}; | ||
} | ||
function oneOf(...options) { | ||
return Object.assign((value = true)=>{ | ||
for (let option of options){ | ||
let parsed = option(value); | ||
if (parsed === value) { | ||
return parsed; | ||
} | ||
} | ||
throw new Error("..."); | ||
}, { | ||
manualParsing: true | ||
}); | ||
} | ||
let commands = { | ||
init: { | ||
run: _init.init, | ||
args: { | ||
"--esm": { | ||
type: Boolean, | ||
description: `Initialize configuration file as ESM` | ||
}, | ||
"--ts": { | ||
type: Boolean, | ||
description: `Initialize configuration file as TypeScript` | ||
}, | ||
"--postcss": { | ||
type: Boolean, | ||
description: `Initialize a \`postcss.config.js\` file` | ||
}, | ||
"--full": { | ||
type: Boolean, | ||
description: `Include the default values for all options in the generated configuration file` | ||
}, | ||
"-f": "--full", | ||
"-p": "--postcss" | ||
} | ||
}, | ||
build: { | ||
run: _build.build, | ||
args: { | ||
"--input": { | ||
type: String, | ||
description: "Input file" | ||
}, | ||
"--output": { | ||
type: String, | ||
description: "Output file" | ||
}, | ||
"--watch": { | ||
type: oneOf(String, Boolean), | ||
description: "Watch for changes and rebuild as needed" | ||
}, | ||
"--poll": { | ||
type: Boolean, | ||
description: "Use polling instead of filesystem events when watching" | ||
}, | ||
"--content": { | ||
type: String, | ||
description: "Content paths to use for removing unused classes" | ||
}, | ||
"--purge": { | ||
type: String, | ||
deprecated: true | ||
}, | ||
"--postcss": { | ||
type: oneOf(String, Boolean), | ||
description: "Load custom PostCSS configuration" | ||
}, | ||
"--minify": { | ||
type: Boolean, | ||
description: "Minify the output" | ||
}, | ||
"--config": { | ||
type: String, | ||
description: "Path to a custom config file" | ||
}, | ||
"--no-autoprefixer": { | ||
type: Boolean, | ||
description: "Disable autoprefixer" | ||
}, | ||
"-c": "--config", | ||
"-i": "--input", | ||
"-o": "--output", | ||
"-m": "--minify", | ||
"-w": "--watch", | ||
"-p": "--poll" | ||
} | ||
} | ||
}; | ||
let sharedFlags = { | ||
"--help": { | ||
type: Boolean, | ||
description: "Display usage information" | ||
}, | ||
"-h": "--help" | ||
}; | ||
if (process.stdout.isTTY /* Detect redirecting output to a file */ && (process.argv[2] === undefined || process.argv.slice(2).every((flag)=>sharedFlags[flag] !== undefined))) { | ||
(0, _help.help)({ | ||
usage: [ | ||
"tailwindcss [--input input.css] [--output output.css] [--watch] [options...]", | ||
"tailwindcss init [--full] [--postcss] [options...]" | ||
], | ||
commands: Object.keys(commands).filter((command)=>command !== "build").map((command)=>`${command} [options]`), | ||
options: { | ||
...commands.build.args, | ||
...sharedFlags | ||
} | ||
}); | ||
process.exit(0); | ||
} | ||
let command = ((arg = "")=>arg.startsWith("-") ? undefined : arg)(process.argv[2]) || "build"; | ||
if (commands[command] === undefined) { | ||
if (_fs.default.existsSync(_path.default.resolve(command))) { | ||
// TODO: Deprecate this in future versions | ||
// Check if non-existing command, might be a file. | ||
command = "build"; | ||
} else { | ||
(0, _help.help)({ | ||
message: `Invalid command: ${command}`, | ||
usage: [ | ||
"tailwindcss <command> [options]" | ||
], | ||
commands: Object.keys(commands).filter((command)=>command !== "build").map((command)=>`${command} [options]`), | ||
options: sharedFlags | ||
}); | ||
process.exit(1); | ||
} | ||
} | ||
// Execute command | ||
let { args: flags , run } = commands[command]; | ||
let args = (()=>{ | ||
try { | ||
let result = (0, _arg.default)(Object.fromEntries(Object.entries({ | ||
...flags, | ||
...sharedFlags | ||
}).filter(([_key, value])=>{ | ||
var _value_type; | ||
return !(value === null || value === void 0 ? void 0 : (_value_type = value.type) === null || _value_type === void 0 ? void 0 : _value_type.manualParsing); | ||
}).map(([key, value])=>[ | ||
key, | ||
typeof value === "object" ? value.type : value | ||
])), { | ||
permissive: true | ||
}); | ||
// Manual parsing of flags to allow for special flags like oneOf(Boolean, String) | ||
for(let i = result["_"].length - 1; i >= 0; --i){ | ||
let flag = result["_"][i]; | ||
if (!flag.startsWith("-")) continue; | ||
let [flagName, flagValue] = flag.split("="); | ||
let handler = flags[flagName]; | ||
// Resolve flagName & handler | ||
while(typeof handler === "string"){ | ||
flagName = handler; | ||
handler = flags[handler]; | ||
} | ||
if (!handler) continue; | ||
let args = []; | ||
let offset = i + 1; | ||
// --flag value syntax was used so we need to pull `value` from `args` | ||
if (flagValue === undefined) { | ||
// Parse args for current flag | ||
while(result["_"][offset] && !result["_"][offset].startsWith("-")){ | ||
args.push(result["_"][offset++]); | ||
} | ||
// Cleanup manually parsed flags + args | ||
result["_"].splice(i, 1 + args.length); | ||
// No args were provided, use default value defined in handler | ||
// One arg was provided, use that directly | ||
// Multiple args were provided so pass them all in an array | ||
flagValue = args.length === 0 ? undefined : args.length === 1 ? args[0] : args; | ||
} else { | ||
// Remove the whole flag from the args array | ||
result["_"].splice(i, 1); | ||
} | ||
// Set the resolved value in the `result` object | ||
result[flagName] = handler.type(flagValue, flagName); | ||
} | ||
// Ensure that the `command` is always the first argument in the `args`. | ||
// This is important so that we don't have to check if a default command | ||
// (build) was used or not from within each plugin. | ||
// | ||
// E.g.: tailwindcss input.css -> _: ['build', 'input.css'] | ||
// E.g.: tailwindcss build input.css -> _: ['build', 'input.css'] | ||
if (result["_"][0] !== command) { | ||
result["_"].unshift(command); | ||
} | ||
return result; | ||
} catch (err) { | ||
if (err.code === "ARG_UNKNOWN_OPTION") { | ||
(0, _help.help)({ | ||
message: err.message, | ||
usage: [ | ||
"tailwindcss <command> [options]" | ||
], | ||
options: sharedFlags | ||
}); | ||
process.exit(1); | ||
} | ||
throw err; | ||
} | ||
})(); | ||
if (args["--help"]) { | ||
(0, _help.help)({ | ||
options: { | ||
...flags, | ||
...sharedFlags | ||
}, | ||
usage: [ | ||
`tailwindcss ${command} [options]` | ||
] | ||
}); | ||
return from; | ||
process.exit(0); | ||
} | ||
run(args); |
@@ -8,7 +8,9 @@ // @ts-check | ||
enumerable: true, | ||
get: ()=>init | ||
get: function() { | ||
return init; | ||
} | ||
}); | ||
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs")); | ||
const _path = /*#__PURE__*/ _interopRequireDefault(require("path")); | ||
function _interopRequireDefault(obj) { | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _path = /*#__PURE__*/ _interop_require_default(require("path")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -18,12 +20,27 @@ default: obj | ||
} | ||
function init(args, configs) { | ||
function isESM() { | ||
const pkgPath = _path.default.resolve("./package.json"); | ||
try { | ||
let pkg = JSON.parse(_fs.default.readFileSync(pkgPath, "utf8")); | ||
return pkg.type && pkg.type === "module"; | ||
} catch (err) { | ||
return false; | ||
} | ||
} | ||
function init(args) { | ||
let messages = []; | ||
var ref; | ||
let tailwindConfigLocation = _path.default.resolve((ref = args["_"][1]) !== null && ref !== void 0 ? ref : `./${configs.tailwind}`); | ||
let isProjectESM = args["--ts"] || args["--esm"] || isESM(); | ||
let syntax = args["--ts"] ? "ts" : isProjectESM ? "js" : "cjs"; | ||
let extension = args["--ts"] ? "ts" : "js"; | ||
var _args___; | ||
let tailwindConfigLocation = _path.default.resolve((_args___ = args["_"][1]) !== null && _args___ !== void 0 ? _args___ : `./tailwind.config.${extension}`); | ||
if (_fs.default.existsSync(tailwindConfigLocation)) { | ||
messages.push(`${_path.default.basename(tailwindConfigLocation)} already exists.`); | ||
} else { | ||
let stubFile = _fs.default.readFileSync(args["--full"] ? _path.default.resolve(__dirname, "../../../stubs/defaultConfig.stub.js") : _path.default.resolve(__dirname, "../../../stubs/simpleConfig.stub.js"), "utf8"); | ||
let stubContentsFile = _fs.default.readFileSync(args["--full"] ? _path.default.resolve(__dirname, "../../../stubs/config.full.js") : _path.default.resolve(__dirname, "../../../stubs/config.simple.js"), "utf8"); | ||
let stubFile = _fs.default.readFileSync(_path.default.resolve(__dirname, `../../../stubs/tailwind.config.${syntax}`), "utf8"); | ||
// Change colors import | ||
stubFile = stubFile.replace("../colors", "tailwindcss/colors"); | ||
stubContentsFile = stubContentsFile.replace("../colors", "tailwindcss/colors"); | ||
// Replace contents of {ts,js,cjs} file with the stub {simple,full}. | ||
stubFile = stubFile.replace("__CONFIG__", stubContentsFile.replace("module.exports =", "").trim()).trim() + "\n\n"; | ||
_fs.default.writeFileSync(tailwindConfigLocation, stubFile, "utf8"); | ||
@@ -33,8 +50,8 @@ messages.push(`Created Tailwind CSS config file: ${_path.default.basename(tailwindConfigLocation)}`); | ||
if (args["--postcss"]) { | ||
let postcssConfigLocation = _path.default.resolve(`./${configs.postcss}`); | ||
let postcssConfigLocation = _path.default.resolve("./postcss.config.js"); | ||
if (_fs.default.existsSync(postcssConfigLocation)) { | ||
messages.push(`${_path.default.basename(postcssConfigLocation)} already exists.`); | ||
} else { | ||
let stubFile1 = _fs.default.readFileSync(_path.default.resolve(__dirname, "../../../stubs/defaultPostCssConfig.stub.js"), "utf8"); | ||
_fs.default.writeFileSync(postcssConfigLocation, stubFile1, "utf8"); | ||
let stubFile = _fs.default.readFileSync(isProjectESM ? _path.default.resolve(__dirname, "../../../stubs/postcss.config.js") : _path.default.resolve(__dirname, "../../../stubs/postcss.config.cjs"), "utf8"); | ||
_fs.default.writeFileSync(postcssConfigLocation, stubFile, "utf8"); | ||
messages.push(`Created PostCSS config file: ${_path.default.basename(postcssConfigLocation)}`); | ||
@@ -41,0 +58,0 @@ } |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
@@ -31,2 +33,3 @@ const _default = [ | ||
"boxSizing", | ||
"lineClamp", | ||
"display", | ||
@@ -45,2 +48,3 @@ "aspectRatio", | ||
"tableLayout", | ||
"captionSide", | ||
"borderCollapse", | ||
@@ -66,2 +70,3 @@ "borderSpacing", | ||
"listStyleType", | ||
"listStyleImage", | ||
"appearance", | ||
@@ -98,2 +103,3 @@ "columns", | ||
"textOverflow", | ||
"hyphens", | ||
"whitespace", | ||
@@ -100,0 +106,0 @@ "wordBreak", |
@@ -12,9 +12,15 @@ "use strict"; | ||
_export(exports, { | ||
flagEnabled: ()=>flagEnabled, | ||
issueFlagNotices: ()=>issueFlagNotices, | ||
default: ()=>_default | ||
flagEnabled: function() { | ||
return flagEnabled; | ||
}, | ||
issueFlagNotices: function() { | ||
return issueFlagNotices; | ||
}, | ||
default: function() { | ||
return _default; | ||
} | ||
}); | ||
const _picocolors = /*#__PURE__*/ _interopRequireDefault(require("picocolors")); | ||
const _log = /*#__PURE__*/ _interopRequireDefault(require("./util/log")); | ||
function _interopRequireDefault(obj) { | ||
const _picocolors = /*#__PURE__*/ _interop_require_default(require("picocolors")); | ||
const _log = /*#__PURE__*/ _interop_require_default(require("./util/log")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -26,3 +32,9 @@ default: obj | ||
optimizeUniversalDefaults: false, | ||
generalizedModifiers: true | ||
generalizedModifiers: true, | ||
get disableColorOpacityUtilitiesByDefault () { | ||
return false; | ||
}, | ||
get relativeContentPathsByDefault () { | ||
return false; | ||
} | ||
}; | ||
@@ -43,10 +55,10 @@ let featureFlags = { | ||
if (featureFlags.future.includes(flag)) { | ||
var ref; | ||
var ref1, ref2; | ||
return config.future === "all" || ((ref2 = (ref1 = config === null || config === void 0 ? void 0 : (ref = config.future) === null || ref === void 0 ? void 0 : ref[flag]) !== null && ref1 !== void 0 ? ref1 : defaults[flag]) !== null && ref2 !== void 0 ? ref2 : false); | ||
var _config_future; | ||
var _config_future_flag, _ref; | ||
return config.future === "all" || ((_ref = (_config_future_flag = config === null || config === void 0 ? void 0 : (_config_future = config.future) === null || _config_future === void 0 ? void 0 : _config_future[flag]) !== null && _config_future_flag !== void 0 ? _config_future_flag : defaults[flag]) !== null && _ref !== void 0 ? _ref : false); | ||
} | ||
if (featureFlags.experimental.includes(flag)) { | ||
var ref3; | ||
var ref4, ref5; | ||
return config.experimental === "all" || ((ref5 = (ref4 = config === null || config === void 0 ? void 0 : (ref3 = config.experimental) === null || ref3 === void 0 ? void 0 : ref3[flag]) !== null && ref4 !== void 0 ? ref4 : defaults[flag]) !== null && ref5 !== void 0 ? ref5 : false); | ||
var _config_experimental; | ||
var _config_experimental_flag, _ref1; | ||
return config.experimental === "all" || ((_ref1 = (_config_experimental_flag = config === null || config === void 0 ? void 0 : (_config_experimental = config.experimental) === null || _config_experimental === void 0 ? void 0 : _config_experimental[flag]) !== null && _config_experimental_flag !== void 0 ? _config_experimental_flag : defaults[flag]) !== null && _ref1 !== void 0 ? _ref1 : false); | ||
} | ||
@@ -59,4 +71,4 @@ return false; | ||
} | ||
var ref; | ||
return Object.keys((ref = config === null || config === void 0 ? void 0 : config.experimental) !== null && ref !== void 0 ? ref : {}).filter((flag)=>featureFlags.experimental.includes(flag) && config.experimental[flag]); | ||
var _config_experimental; | ||
return Object.keys((_config_experimental = config === null || config === void 0 ? void 0 : config.experimental) !== null && _config_experimental !== void 0 ? _config_experimental : {}).filter((flag)=>featureFlags.experimental.includes(flag) && config.experimental[flag]); | ||
} | ||
@@ -63,0 +75,0 @@ function issueFlagNotices(config) { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
const _setupTrackingContext = /*#__PURE__*/ _interopRequireDefault(require("./lib/setupTrackingContext")); | ||
const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("./processTailwindFeatures")); | ||
const _sharedState = require("./lib/sharedState"); | ||
const _findAtConfigPath = require("./lib/findAtConfigPath"); | ||
function _interopRequireDefault(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
default: obj | ||
}; | ||
} | ||
module.exports = function tailwindcss(configOrPath) { | ||
return { | ||
postcssPlugin: "tailwindcss", | ||
plugins: [ | ||
_sharedState.env.DEBUG && function(root) { | ||
console.log("\n"); | ||
console.time("JIT TOTAL"); | ||
return root; | ||
}, | ||
function(root, result) { | ||
var ref; | ||
// Use the path for the `@config` directive if it exists, otherwise use the | ||
// path for the file being processed | ||
configOrPath = (ref = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && ref !== void 0 ? ref : configOrPath; | ||
let context = (0, _setupTrackingContext.default)(configOrPath); | ||
if (root.type === "document") { | ||
let roots = root.nodes.filter((node)=>node.type === "root"); | ||
for (const root1 of roots){ | ||
if (root1.type === "root") { | ||
(0, _processTailwindFeatures.default)(context)(root1, result); | ||
} | ||
} | ||
return; | ||
} | ||
(0, _processTailwindFeatures.default)(context)(root, result); | ||
}, | ||
_sharedState.env.DEBUG && function(root) { | ||
console.timeEnd("JIT TOTAL"); | ||
console.log("\n"); | ||
return root; | ||
} | ||
].filter(Boolean) | ||
}; | ||
}; | ||
module.exports.postcss = true; | ||
module.exports = require("./plugin"); |
@@ -7,7 +7,9 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>hasContentChanged | ||
get: function() { | ||
return hasContentChanged; | ||
} | ||
}); | ||
const _crypto = /*#__PURE__*/ _interopRequireDefault(require("crypto")); | ||
const _sharedState = /*#__PURE__*/ _interopRequireWildcard(require("./sharedState")); | ||
function _interopRequireDefault(obj) { | ||
const _crypto = /*#__PURE__*/ _interop_require_default(require("crypto")); | ||
const _sharedState = /*#__PURE__*/ _interop_require_wildcard(require("./sharedState")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -25,3 +27,3 @@ default: obj | ||
} | ||
function _interopRequireWildcard(obj, nodeInterop) { | ||
function _interop_require_wildcard(obj, nodeInterop) { | ||
if (!nodeInterop && obj && obj.__esModule) { | ||
@@ -28,0 +30,0 @@ return obj; |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>collapseAdjacentRules | ||
get: function() { | ||
return collapseAdjacentRules; | ||
} | ||
}); | ||
@@ -33,6 +35,6 @@ let comparisonMap = { | ||
let properties = comparisonMap[node.type]; | ||
var _property, _property1; | ||
var _node_property, _currentRule_property; | ||
if (node.type === "atrule" && node.name === "font-face") { | ||
currentRule = node; | ||
} else if (properties.every((property)=>((_property = node[property]) !== null && _property !== void 0 ? _property : "").replace(/\s+/g, " ") === ((_property1 = currentRule[property]) !== null && _property1 !== void 0 ? _property1 : "").replace(/\s+/g, " "))) { | ||
} else if (properties.every((property)=>((_node_property = node[property]) !== null && _node_property !== void 0 ? _node_property : "").replace(/\s+/g, " ") === ((_currentRule_property = currentRule[property]) !== null && _currentRule_property !== void 0 ? _currentRule_property : "").replace(/\s+/g, " "))) { | ||
// An AtRule may not have children (for example if we encounter duplicate @import url(…) rules) | ||
@@ -39,0 +41,0 @@ if (node.nodes) { |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>collapseDuplicateDeclarations | ||
get: function() { | ||
return collapseDuplicateDeclarations; | ||
} | ||
}); | ||
@@ -55,4 +57,4 @@ function collapseDuplicateDeclarations() { | ||
let byUnit = new Map(); | ||
for (let decl1 of declarations){ | ||
let unit = resolveUnit(decl1.value); | ||
for (let decl of declarations){ | ||
let unit = resolveUnit(decl.value); | ||
if (unit === null) { | ||
@@ -64,9 +66,9 @@ continue; | ||
} | ||
byUnit.get(unit).add(decl1); | ||
byUnit.get(unit).add(decl); | ||
} | ||
for (let declarations1 of byUnit.values()){ | ||
for (let declarations of byUnit.values()){ | ||
// Get all but the last one | ||
let removableDeclarations = Array.from(declarations1).slice(0, -1); | ||
for (let decl2 of removableDeclarations){ | ||
decl2.remove(); | ||
let removableDeclarations = Array.from(declarations).slice(0, -1); | ||
for (let decl of removableDeclarations){ | ||
decl.remove(); | ||
} | ||
@@ -82,6 +84,6 @@ } | ||
if (result) { | ||
var ref; | ||
return (ref = result[1]) !== null && ref !== void 0 ? ref : UNITLESS_NUMBER; | ||
var _result_; | ||
return (_result_ = result[1]) !== null && _result_ !== void 0 ? _result_ : UNITLESS_NUMBER; | ||
} | ||
return null; | ||
} |
@@ -13,13 +13,17 @@ // @ts-check | ||
_export(exports, { | ||
parseCandidateFiles: ()=>parseCandidateFiles, | ||
resolvedChangedContent: ()=>resolvedChangedContent | ||
parseCandidateFiles: function() { | ||
return parseCandidateFiles; | ||
}, | ||
resolvedChangedContent: function() { | ||
return resolvedChangedContent; | ||
} | ||
}); | ||
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs")); | ||
const _path = /*#__PURE__*/ _interopRequireDefault(require("path")); | ||
const _isGlob = /*#__PURE__*/ _interopRequireDefault(require("is-glob")); | ||
const _fastGlob = /*#__PURE__*/ _interopRequireDefault(require("fast-glob")); | ||
const _normalizePath = /*#__PURE__*/ _interopRequireDefault(require("normalize-path")); | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _path = /*#__PURE__*/ _interop_require_default(require("path")); | ||
const _isglob = /*#__PURE__*/ _interop_require_default(require("is-glob")); | ||
const _fastglob = /*#__PURE__*/ _interop_require_default(require("fast-glob")); | ||
const _normalizepath = /*#__PURE__*/ _interop_require_default(require("normalize-path")); | ||
const _parseGlob = require("../util/parseGlob"); | ||
const _sharedState = require("./sharedState"); | ||
function _interopRequireDefault(obj) { | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -33,5 +37,5 @@ default: obj | ||
files = files.filter((filePath)=>typeof filePath === "string"); | ||
files = files.map(_normalizePath.default); | ||
files = files.map(_normalizepath.default); | ||
// Split into included and excluded globs | ||
let tasks = _fastGlob.default.generateTasks(files); | ||
let tasks = _fastglob.default.generateTasks(files); | ||
/** @type {ContentPath[]} */ let included = []; | ||
@@ -68,3 +72,3 @@ /** @type {ContentPath[]} */ let excluded = []; | ||
}; | ||
if ((0, _isGlob.default)(filePath)) { | ||
if ((0, _isglob.default)(filePath)) { | ||
Object.assign(contentPath, (0, _parseGlob.parseGlob)(filePath)); | ||
@@ -83,6 +87,6 @@ } | ||
// a package which can't handle mixed directory separators | ||
let base = (0, _normalizePath.default)(contentPath.base); | ||
let base = (0, _normalizepath.default)(contentPath.base); | ||
// If the user's file path contains any special characters (like parens) for instance fast-glob | ||
// is like "OOOH SHINY" and treats them as such. So we have to escape the base path to fix this | ||
base = _fastGlob.default.escapePath(base); | ||
base = _fastglob.default.escapePath(base); | ||
contentPath.pattern = contentPath.glob ? `${base}/${contentPath.glob}` : base; | ||
@@ -142,11 +146,14 @@ contentPath.pattern = contentPath.ignore ? `!${contentPath.pattern}` : contentPath.pattern; | ||
})); | ||
for (let changedFile of resolveChangedFiles(candidateFiles, fileModifiedMap)){ | ||
let content = _fs.default.readFileSync(changedFile, "utf8"); | ||
let [changedFiles, mTimesToCommit] = resolveChangedFiles(candidateFiles, fileModifiedMap); | ||
for (let changedFile of changedFiles){ | ||
let extension = _path.default.extname(changedFile).slice(1); | ||
changedContent.push({ | ||
content, | ||
file: changedFile, | ||
extension | ||
}); | ||
} | ||
return changedContent; | ||
return [ | ||
changedContent, | ||
mTimesToCommit | ||
]; | ||
} | ||
@@ -157,27 +164,24 @@ /** | ||
* @param {Map<string, number>} fileModifiedMap | ||
* @returns {Set<string>} | ||
* @returns {[Set<string>, Map<string, number>]} | ||
*/ function resolveChangedFiles(candidateFiles, fileModifiedMap) { | ||
let paths = candidateFiles.map((contentPath)=>contentPath.pattern); | ||
let mTimesToCommit = new Map(); | ||
let changedFiles = new Set(); | ||
_sharedState.env.DEBUG && console.time("Finding changed files"); | ||
let files = _fastGlob.default.sync(paths, { | ||
let files = _fastglob.default.sync(paths, { | ||
absolute: true | ||
}); | ||
for (let file of files){ | ||
let prevModified = fileModifiedMap.has(file) ? fileModifiedMap.get(file) : -Infinity; | ||
let prevModified = fileModifiedMap.get(file) || -Infinity; | ||
let modified = _fs.default.statSync(file).mtimeMs; | ||
// This check is intentionally >= because we track the last modified time of context dependencies | ||
// earier in the process and we want to make sure we don't miss any changes that happen | ||
// when a context dependency is also a content dependency | ||
// Ideally, we'd do all this tracking at one time but that is a larger refactor | ||
// than we want to commit to right now, so this is a decent compromise. | ||
// This should be sufficient because file modification times will be off by at least | ||
// 1ms (the precision of fstat in Node) in most cases if they exist and were changed. | ||
if (modified >= prevModified) { | ||
if (modified > prevModified) { | ||
changedFiles.add(file); | ||
fileModifiedMap.set(file, modified); | ||
mTimesToCommit.set(file, modified); | ||
} | ||
} | ||
_sharedState.env.DEBUG && console.timeEnd("Finding changed files"); | ||
return changedFiles; | ||
return [ | ||
changedFiles, | ||
mTimesToCommit | ||
]; | ||
} |
@@ -7,6 +7,7 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>defaultExtractor | ||
get: function() { | ||
return defaultExtractor; | ||
} | ||
}); | ||
const _featureFlags = require("../featureFlags"); | ||
const _regex = /*#__PURE__*/ _interopRequireWildcard(require("./regex")); | ||
const _regex = /*#__PURE__*/ _interop_require_wildcard(require("./regex")); | ||
function _getRequireWildcardCache(nodeInterop) { | ||
@@ -20,3 +21,3 @@ if (typeof WeakMap !== "function") return null; | ||
} | ||
function _interopRequireWildcard(obj, nodeInterop) { | ||
function _interop_require_wildcard(obj, nodeInterop) { | ||
if (!nodeInterop && obj && obj.__esModule) { | ||
@@ -59,9 +60,8 @@ return obj; | ||
for (let pattern of patterns){ | ||
var ref; | ||
results = [ | ||
...results, | ||
...(ref = content.match(pattern)) !== null && ref !== void 0 ? ref : [] | ||
]; | ||
var _content_match; | ||
for (let result of (_content_match = content.match(pattern)) !== null && _content_match !== void 0 ? _content_match : []){ | ||
results.push(clipAtBalancedParens(result)); | ||
} | ||
} | ||
return results.filter((v)=>v !== undefined).map(clipAtBalancedParens); | ||
return results; | ||
}; | ||
@@ -71,3 +71,2 @@ } | ||
let separator = context.tailwindConfig.separator; | ||
let variantGroupingEnabled = (0, _featureFlags.flagEnabled)(context.tailwindConfig, "variantGrouping"); | ||
let prefix = context.tailwindConfig.prefix !== "" ? _regex.optional(_regex.pattern([ | ||
@@ -78,4 +77,9 @@ /-?/, | ||
let utility = _regex.any([ | ||
// Arbitrary properties | ||
/\[[^\s:'"`]+:[^\s]+\]/, | ||
// Arbitrary properties (without square brackets) | ||
/\[[^\s:'"`]+:[^\s\[\]]+\]/, | ||
// Arbitrary properties with balanced square brackets | ||
// This is a targeted fix to continue to allow theme() | ||
// with square brackets to work in arbitrary properties | ||
// while fixing a problem with the regex matching too much | ||
/\[[^\s:'"`\]]+:[^\s]+?\[[^\s]+\][^\s]+?\]/, | ||
// Utilities | ||
@@ -89,3 +93,8 @@ _regex.pattern([ | ||
// Arbitrary values | ||
/-(?:\w+-)*\[[^\s:]+\]/, | ||
_regex.any([ | ||
/-(?:\w+-)*\['[^\s]+'\]/, | ||
/-(?:\w+-)*\["[^\s]+"\]/, | ||
/-(?:\w+-)*\[`[^\s]+`\]/, | ||
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s:\[\]]+\]/ | ||
]), | ||
// Not immediately followed by an `{[(` | ||
@@ -98,3 +107,8 @@ /(?![{([]])/, | ||
// Arbitrary values | ||
/-(?:\w+-)*\[[^\s]+\]/, | ||
_regex.any([ | ||
/-(?:\w+-)*\['[^\s]+'\]/, | ||
/-(?:\w+-)*\["[^\s]+"\]/, | ||
/-(?:\w+-)*\[`[^\s]+`\]/, | ||
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s\[\]]+\]/ | ||
]), | ||
// Not immediately followed by an `{[(` | ||
@@ -118,3 +132,8 @@ /(?![{([]])/, | ||
]), | ||
// With variant modifier (e.g.: group-[..]/modifier) | ||
_regex.pattern([ | ||
/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]\/\w+/, | ||
separator | ||
]), | ||
_regex.pattern([ | ||
/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]/, | ||
@@ -130,3 +149,8 @@ separator | ||
_regex.any([ | ||
// With variant modifier (e.g.: group-[..]/modifier) | ||
_regex.pattern([ | ||
/([^\s"'`\[\\]+-)?\[[^\s`]+\]\/\w+/, | ||
separator | ||
]), | ||
_regex.pattern([ | ||
/([^\s"'`\[\\]+-)?\[[^\s`]+\]/, | ||
@@ -150,16 +174,3 @@ separator | ||
prefix, | ||
variantGroupingEnabled ? _regex.any([ | ||
// Or any of those things but grouped separated by commas | ||
_regex.pattern([ | ||
/\(/, | ||
utility, | ||
_regex.zeroOrMore([ | ||
/,/, | ||
utility | ||
]), | ||
/\)/ | ||
]), | ||
// Arbitrary properties, constrained utilities, arbitrary values, etc… | ||
utility | ||
]) : utility | ||
utility | ||
]); | ||
@@ -229,3 +240,3 @@ } | ||
if (depth < 0) { | ||
return input.substring(0, match.index); | ||
return input.substring(0, match.index - 1); | ||
} | ||
@@ -232,0 +243,0 @@ // We've finished balancing the brackets but there still may be characters that can be included |
@@ -7,4 +7,12 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
function isRoot(node) { | ||
return node.type === "root"; | ||
} | ||
function isAtLayer(node) { | ||
return node.type === "atrule" && node.name === "layer"; | ||
} | ||
function _default(_context) { | ||
@@ -15,3 +23,3 @@ return (root, result)=>{ | ||
if (found) return false; | ||
if (node.parent && node.parent.type !== "root") { | ||
if (node.parent && !(isRoot(node.parent) || isAtLayer(node.parent))) { | ||
found = true; | ||
@@ -18,0 +26,0 @@ node.warn(result, [ |
@@ -7,15 +7,17 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
const _dlv = /*#__PURE__*/ _interopRequireDefault(require("dlv")); | ||
const _didyoumean = /*#__PURE__*/ _interopRequireDefault(require("didyoumean")); | ||
const _transformThemeValue = /*#__PURE__*/ _interopRequireDefault(require("../util/transformThemeValue")); | ||
const _postcssValueParser = /*#__PURE__*/ _interopRequireDefault(require("postcss-value-parser")); | ||
const _dlv = /*#__PURE__*/ _interop_require_default(require("dlv")); | ||
const _didyoumean = /*#__PURE__*/ _interop_require_default(require("didyoumean")); | ||
const _transformThemeValue = /*#__PURE__*/ _interop_require_default(require("../util/transformThemeValue")); | ||
const _index = /*#__PURE__*/ _interop_require_default(require("../value-parser/index")); | ||
const _normalizeScreens = require("../util/normalizeScreens"); | ||
const _buildMediaQuery = /*#__PURE__*/ _interopRequireDefault(require("../util/buildMediaQuery")); | ||
const _buildMediaQuery = /*#__PURE__*/ _interop_require_default(require("../util/buildMediaQuery")); | ||
const _toPath = require("../util/toPath"); | ||
const _withAlphaVariable = require("../util/withAlphaVariable"); | ||
const _pluginUtils = require("../util/pluginUtils"); | ||
const _log = /*#__PURE__*/ _interopRequireDefault(require("../util/log")); | ||
function _interopRequireDefault(obj) { | ||
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -90,12 +92,12 @@ default: obj | ||
if (!(typeof value === "string" || typeof value === "number" || typeof value === "function" || value instanceof String || value instanceof Number || Array.isArray(value))) { | ||
let error1 = `'${pathString}' was found but does not resolve to a string.`; | ||
let error = `'${pathString}' was found but does not resolve to a string.`; | ||
if (isObject(value)) { | ||
let validKeys1 = Object.keys(value).filter((key)=>validatePath(config, [ | ||
let validKeys = Object.keys(value).filter((key)=>validatePath(config, [ | ||
...pathSegments, | ||
key | ||
]).isValid); | ||
if (validKeys1.length) { | ||
error1 += ` Did you mean something like '${pathToString([ | ||
if (validKeys.length) { | ||
error += ` Did you mean something like '${pathToString([ | ||
...pathSegments, | ||
validKeys1[0] | ||
validKeys[0] | ||
])}'?`; | ||
@@ -106,3 +108,3 @@ } | ||
isValid: false, | ||
error: error1 | ||
error | ||
}; | ||
@@ -125,3 +127,3 @@ } | ||
} else { | ||
args[args.length - 1] += _postcssValueParser.default.stringify(vNode); | ||
args[args.length - 1] += _index.default.stringify(vNode); | ||
} | ||
@@ -140,3 +142,5 @@ } | ||
function resolveFunctions(node, input, functions) { | ||
return (0, _postcssValueParser.default)(input).walk((vNode)=>{ | ||
let hasAnyFn = Object.keys(functions).some((fn)=>input.includes(`${fn}(`)); | ||
if (!hasAnyFn) return input; | ||
return (0, _index.default)(input).walk((vNode)=>{ | ||
resolveVNode(node, vNode, functions); | ||
@@ -185,4 +189,4 @@ }).toString(); | ||
}); | ||
var ref; | ||
return (ref = results.find((result)=>result.isValid)) !== null && ref !== void 0 ? ref : results[0]; | ||
var _results_find; | ||
return (_results_find = results.find((result)=>result.isValid)) !== null && _results_find !== void 0 ? _results_find : results[0]; | ||
} | ||
@@ -195,5 +199,5 @@ function _default(context) { | ||
if (!isValid) { | ||
var ref; | ||
var _parentNode_raws_tailwind; | ||
let parentNode = node.parent; | ||
let candidate = (ref = parentNode === null || parentNode === void 0 ? void 0 : parentNode.raws.tailwind) === null || ref === void 0 ? void 0 : ref.candidate; | ||
let candidate = (_parentNode_raws_tailwind = parentNode === null || parentNode === void 0 ? void 0 : parentNode.raws.tailwind) === null || _parentNode_raws_tailwind === void 0 ? void 0 : _parentNode_raws_tailwind.candidate; | ||
if (parentNode && candidate !== undefined) { | ||
@@ -200,0 +204,0 @@ // Remove this utility from any caches |
@@ -7,9 +7,13 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>expandApplyAtRules | ||
get: function() { | ||
return expandApplyAtRules; | ||
} | ||
}); | ||
const _postcss = /*#__PURE__*/ _interopRequireDefault(require("postcss")); | ||
const _postcssSelectorParser = /*#__PURE__*/ _interopRequireDefault(require("postcss-selector-parser")); | ||
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss")); | ||
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser")); | ||
const _generateRules = require("./generateRules"); | ||
const _escapeClassName = /*#__PURE__*/ _interopRequireDefault(require("../util/escapeClassName")); | ||
function _interopRequireDefault(obj) { | ||
const _escapeClassName = /*#__PURE__*/ _interop_require_default(require("../util/escapeClassName")); | ||
const _applyImportantSelector = require("../util/applyImportantSelector"); | ||
const _pseudoElements = require("../util/pseudoElements"); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -27,3 +31,3 @@ default: obj | ||
container.walkRules((rule)=>{ | ||
(0, _postcssSelectorParser.default)((selectors)=>{ | ||
(0, _postcssselectorparser.default)((selectors)=>{ | ||
selectors.walkClasses((classSelector)=>{ | ||
@@ -45,3 +49,3 @@ let parentSelector = classSelector.parent.toString(); | ||
} | ||
let selectorExtractor = (0, _postcssSelectorParser.default)(); | ||
let selectorExtractor = (0, _postcssselectorparser.default)(); | ||
/** | ||
@@ -145,4 +149,4 @@ * @param {string} ruleSelectors | ||
for (let node of pathToRoot(rule)){ | ||
var ref; | ||
if (((ref = node.raws.tailwind) === null || ref === void 0 ? void 0 : ref.layer) !== undefined) { | ||
var _node_raws_tailwind; | ||
if (((_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.layer) !== undefined) { | ||
return; | ||
@@ -316,7 +320,7 @@ } | ||
// This happens when replacing `.bar` in `.foo.bar` with a tag like `section` | ||
for (let sel1 of replaced){ | ||
for (let sel of replaced){ | ||
let groups = [ | ||
[] | ||
]; | ||
for (let node of sel1.nodes){ | ||
for (let node of sel.nodes){ | ||
if (node.type === "combinator") { | ||
@@ -330,3 +334,3 @@ groups.push(node); | ||
} | ||
sel1.nodes = []; | ||
sel.nodes = []; | ||
for (let group of groups){ | ||
@@ -347,3 +351,3 @@ if (Array.isArray(group)) { | ||
} | ||
sel1.nodes = sel1.nodes.concat(group); | ||
sel.nodes = sel.nodes.concat(group); | ||
} | ||
@@ -366,11 +370,11 @@ } | ||
]); | ||
let [applyCandidates1, important] = extractApplyCandidates(apply.params); | ||
let [applyCandidates, important] = extractApplyCandidates(apply.params); | ||
if (apply.parent.type === "atrule") { | ||
if (apply.parent.name === "screen") { | ||
let screenType = apply.parent.params; | ||
throw apply.error(`@apply is not supported within nested at-rules like @screen. We suggest you write this as @apply ${applyCandidates1.map((c)=>`${screenType}:${c}`).join(" ")} instead.`); | ||
throw apply.error(`@apply is not supported within nested at-rules like @screen. We suggest you write this as @apply ${applyCandidates.map((c)=>`${screenType}:${c}`).join(" ")} instead.`); | ||
} | ||
throw apply.error(`@apply is not supported within nested at-rules like @${apply.parent.name}. You can fix this by un-nesting @${apply.parent.name}.`); | ||
} | ||
for (let applyCandidate of applyCandidates1){ | ||
for (let applyCandidate of applyCandidates){ | ||
if ([ | ||
@@ -394,12 +398,12 @@ prefix(context, "group"), | ||
} | ||
for (let [parent, [candidates1, atApplySource]] of perParentApplies){ | ||
for (let [parent, [candidates, atApplySource]] of perParentApplies){ | ||
let siblings = []; | ||
for (let [applyCandidate1, important1, rules1] of candidates1){ | ||
for (let [applyCandidate, important, rules] of candidates){ | ||
let potentialApplyCandidates = [ | ||
applyCandidate1, | ||
applyCandidate, | ||
...extractBaseCandidates([ | ||
applyCandidate1 | ||
applyCandidate | ||
], context.tailwindConfig.separator) | ||
]; | ||
for (let [meta, node] of rules1){ | ||
for (let [meta, node] of rules){ | ||
let parentClasses = extractClasses(parent); | ||
@@ -435,5 +439,5 @@ let nodeClasses = extractClasses(node); | ||
if (intersects) { | ||
throw node.error(`You cannot \`@apply\` the \`${applyCandidate1}\` utility here because it creates a circular dependency.`); | ||
throw node.error(`You cannot \`@apply\` the \`${applyCandidate}\` utility here because it creates a circular dependency.`); | ||
} | ||
let root1 = _postcss.default.root({ | ||
let root = _postcss.default.root({ | ||
nodes: [ | ||
@@ -444,3 +448,3 @@ node.clone() | ||
// Make sure every node in the entire tree points back at the @apply rule that generated it | ||
root1.walk((node)=>{ | ||
root.walk((node)=>{ | ||
node.source = atApplySource; | ||
@@ -450,3 +454,3 @@ }); | ||
if (canRewriteSelector) { | ||
root1.walkRules((rule)=>{ | ||
root.walkRules((rule)=>{ | ||
// Let's imagine you have the following structure: | ||
@@ -483,3 +487,3 @@ // | ||
// case it would result in `{}` instead of `.something-unrelated {}` | ||
if (!extractClasses(rule).some((candidate)=>candidate === applyCandidate1)) { | ||
if (!extractClasses(rule).some((candidate)=>candidate === applyCandidate)) { | ||
rule.remove(); | ||
@@ -494,10 +498,20 @@ return; | ||
let parentSelector = isGenerated && importantSelector && parent.selector.indexOf(importantSelector) === 0 ? parent.selector.slice(importantSelector.length) : parent.selector; | ||
rule.selector = replaceSelector(parentSelector, rule.selector, applyCandidate1); | ||
// If the selector becomes empty after replacing the important selector | ||
// This means that it's the same as the parent selector and we don't want to replace it | ||
// Otherwise we'll crash | ||
if (parentSelector === "") { | ||
parentSelector = parent.selector; | ||
} | ||
rule.selector = replaceSelector(parentSelector, rule.selector, applyCandidate); | ||
// And then re-add it if it was removed | ||
if (importantSelector && parentSelector !== parent.selector) { | ||
rule.selector = `${importantSelector} ${rule.selector}`; | ||
rule.selector = (0, _applyImportantSelector.applyImportantSelector)(rule.selector, importantSelector); | ||
} | ||
rule.walkDecls((d)=>{ | ||
d.important = meta.important || important1; | ||
d.important = meta.important || important; | ||
}); | ||
// Move pseudo elements to the end of the selector (if necessary) | ||
let selector = (0, _postcssselectorparser.default)().astSync(rule.selector); | ||
selector.each((sel)=>(0, _pseudoElements.movePseudos)(sel)); | ||
rule.selector = selector.toString(); | ||
}); | ||
@@ -507,3 +521,3 @@ } | ||
// If that was the *only* rule in the parent, then we have nothing add so we skip it | ||
if (!root1.nodes[0]) { | ||
if (!root.nodes[0]) { | ||
continue; | ||
@@ -514,3 +528,3 @@ } | ||
meta.sort, | ||
root1.nodes[0] | ||
root.nodes[0] | ||
]); | ||
@@ -524,9 +538,9 @@ } | ||
} | ||
for (let apply1 of applies){ | ||
for (let apply of applies){ | ||
// If there are left-over declarations, just remove the @apply | ||
if (apply1.parent.nodes.length > 1) { | ||
apply1.remove(); | ||
if (apply.parent.nodes.length > 1) { | ||
apply.remove(); | ||
} else { | ||
// The node is empty, drop the full node | ||
apply1.parent.remove(); | ||
apply.parent.remove(); | ||
} | ||
@@ -533,0 +547,0 @@ } |
@@ -7,11 +7,14 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>expandTailwindAtRules | ||
get: function() { | ||
return expandTailwindAtRules; | ||
} | ||
}); | ||
const _quickLru = /*#__PURE__*/ _interopRequireDefault(require("quick-lru")); | ||
const _sharedState = /*#__PURE__*/ _interopRequireWildcard(require("./sharedState")); | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _quicklru = /*#__PURE__*/ _interop_require_default(require("@alloc/quick-lru")); | ||
const _sharedState = /*#__PURE__*/ _interop_require_wildcard(require("./sharedState")); | ||
const _generateRules = require("./generateRules"); | ||
const _log = /*#__PURE__*/ _interopRequireDefault(require("../util/log")); | ||
const _cloneNodes = /*#__PURE__*/ _interopRequireDefault(require("../util/cloneNodes")); | ||
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log")); | ||
const _cloneNodes = /*#__PURE__*/ _interop_require_default(require("../util/cloneNodes")); | ||
const _defaultExtractor = require("./defaultExtractor"); | ||
function _interopRequireDefault(obj) { | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -29,3 +32,3 @@ default: obj | ||
} | ||
function _interopRequireWildcard(obj, nodeInterop) { | ||
function _interop_require_wildcard(obj, nodeInterop) { | ||
if (!nodeInterop && obj && obj.__esModule) { | ||
@@ -83,3 +86,3 @@ return obj; | ||
if (!extractorCache.has(extractor)) { | ||
extractorCache.set(extractor, new _quickLru.default({ | ||
extractorCache.set(extractor, new _quicklru.default({ | ||
maxSize: 25000 | ||
@@ -101,4 +104,4 @@ })); | ||
let lineMatchesSet = new Set(extractorMatches); | ||
for (let match1 of lineMatchesSet){ | ||
candidates.add(match1); | ||
for (let match of lineMatchesSet){ | ||
candidates.add(match); | ||
} | ||
@@ -128,3 +131,3 @@ extractorCache.get(extractor).set(line, lineMatchesSet); | ||
function expandTailwindAtRules(context) { | ||
return (root)=>{ | ||
return async (root)=>{ | ||
let layerNodes = { | ||
@@ -150,5 +153,7 @@ base: null, | ||
} | ||
var _context_candidates; | ||
// --- | ||
// Find potential rules in changed files | ||
let candidates = new Set([ | ||
...(_context_candidates = context.candidates) !== null && _context_candidates !== void 0 ? _context_candidates : [], | ||
_sharedState.NOT_ON_DEMAND | ||
@@ -158,6 +163,33 @@ ]); | ||
env.DEBUG && console.time("Reading changed files"); | ||
for (let { content , extension } of context.changedContent){ | ||
let transformer = getTransformer(context.tailwindConfig, extension); | ||
let extractor = getExtractor(context, extension); | ||
getClassCandidates(transformer(content), extractor, candidates, seen); | ||
if (false) { | ||
// TODO: Pass through or implement `extractor` | ||
for (let candidate of require("@tailwindcss/oxide").parseCandidateStringsFromFiles(context.changedContent)){ | ||
candidates.add(candidate); | ||
} | ||
// for (let { file, content, extension } of context.changedContent) { | ||
// let transformer = getTransformer(context.tailwindConfig, extension) | ||
// let extractor = getExtractor(context, extension) | ||
// getClassCandidatesOxide(file, transformer(content), extractor, candidates, seen) | ||
// } | ||
} else { | ||
/** @type {[item: {file?: string, content?: string}, meta: {transformer: any, extractor: any}][]} */ let regexParserContent = []; | ||
for (let item of context.changedContent){ | ||
let transformer = getTransformer(context.tailwindConfig, item.extension); | ||
let extractor = getExtractor(context, item.extension); | ||
regexParserContent.push([ | ||
item, | ||
{ | ||
transformer, | ||
extractor | ||
} | ||
]); | ||
} | ||
const BATCH_SIZE = 500; | ||
for(let i = 0; i < regexParserContent.length; i += BATCH_SIZE){ | ||
let batch = regexParserContent.slice(i, i + BATCH_SIZE); | ||
await Promise.all(batch.map(async ([{ file , content }, { transformer , extractor }])=>{ | ||
content = file ? await _fs.default.promises.readFile(file, "utf8") : content; | ||
getClassCandidates(transformer(content), extractor, candidates, seen); | ||
})); | ||
} | ||
} | ||
@@ -169,3 +201,12 @@ env.DEBUG && console.timeEnd("Reading changed files"); | ||
env.DEBUG && console.time("Generate rules"); | ||
(0, _generateRules.generateRules)(candidates, context); | ||
env.DEBUG && console.time("Sorting candidates"); | ||
let sortedCandidates = false ? candidates : new Set([ | ||
...candidates | ||
].sort((a, z)=>{ | ||
if (a === z) return 0; | ||
if (a < z) return -1; | ||
return 1; | ||
})); | ||
env.DEBUG && console.timeEnd("Sorting candidates"); | ||
(0, _generateRules.generateRules)(sortedCandidates, context); | ||
env.DEBUG && console.timeEnd("Generate rules"); | ||
@@ -210,4 +251,4 @@ // We only ever add to the classCache, so if it didn't grow, there is nothing new. | ||
const variantNodes = Array.from(screenNodes).filter((node)=>{ | ||
var ref; | ||
const parentLayer = (ref = node.raws.tailwind) === null || ref === void 0 ? void 0 : ref.parentLayer; | ||
var _node_raws_tailwind; | ||
const parentLayer = (_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.parentLayer; | ||
if (parentLayer === "components") { | ||
@@ -231,6 +272,9 @@ return layerNodes.components !== null; | ||
} | ||
var _root_source_end; | ||
// TODO: Why is the root node having no source location for `end` possible? | ||
root.source.end = (_root_source_end = root.source.end) !== null && _root_source_end !== void 0 ? _root_source_end : root.source.start; | ||
// If we've got a utility layer and no utilities are generated there's likely something wrong | ||
const hasUtilityVariants = variantNodes.some((node)=>{ | ||
var ref; | ||
return ((ref = node.raws.tailwind) === null || ref === void 0 ? void 0 : ref.parentLayer) === "utilities"; | ||
var _node_raws_tailwind; | ||
return ((_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.parentLayer) === "utilities"; | ||
}); | ||
@@ -237,0 +281,0 @@ if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) { |
@@ -7,7 +7,9 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>findAtConfigPath | ||
get: function() { | ||
return findAtConfigPath; | ||
} | ||
}); | ||
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs")); | ||
const _path = /*#__PURE__*/ _interopRequireDefault(require("path")); | ||
function _interopRequireDefault(obj) { | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _path = /*#__PURE__*/ _interop_require_default(require("path")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -21,5 +23,5 @@ default: obj | ||
root.walkAtRules("config", (rule)=>{ | ||
var ref; | ||
var _file, ref1; | ||
relativeTo = (ref1 = (_file = (ref = rule.source) === null || ref === void 0 ? void 0 : ref.input.file) !== null && _file !== void 0 ? _file : result.opts.from) !== null && ref1 !== void 0 ? ref1 : null; | ||
var _rule_source; | ||
var _rule_source_input_file, _ref; | ||
relativeTo = (_ref = (_rule_source_input_file = (_rule_source = rule.source) === null || _rule_source === void 0 ? void 0 : _rule_source.input.file) !== null && _rule_source_input_file !== void 0 ? _rule_source_input_file : result.opts.from) !== null && _ref !== void 0 ? _ref : null; | ||
if (relativeTo === null) { | ||
@@ -26,0 +28,0 @@ throw rule.error("The `@config` directive cannot be used without setting `from` in your PostCSS config."); |
@@ -12,14 +12,20 @@ "use strict"; | ||
_export(exports, { | ||
getClassNameFromSelector: ()=>getClassNameFromSelector, | ||
resolveMatches: ()=>resolveMatches, | ||
generateRules: ()=>generateRules | ||
getClassNameFromSelector: function() { | ||
return getClassNameFromSelector; | ||
}, | ||
resolveMatches: function() { | ||
return resolveMatches; | ||
}, | ||
generateRules: function() { | ||
return generateRules; | ||
} | ||
}); | ||
const _postcss = /*#__PURE__*/ _interopRequireDefault(require("postcss")); | ||
const _postcssSelectorParser = /*#__PURE__*/ _interopRequireDefault(require("postcss-selector-parser")); | ||
const _parseObjectStyles = /*#__PURE__*/ _interopRequireDefault(require("../util/parseObjectStyles")); | ||
const _isPlainObject = /*#__PURE__*/ _interopRequireDefault(require("../util/isPlainObject")); | ||
const _prefixSelector = /*#__PURE__*/ _interopRequireDefault(require("../util/prefixSelector")); | ||
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss")); | ||
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser")); | ||
const _parseObjectStyles = /*#__PURE__*/ _interop_require_default(require("../util/parseObjectStyles")); | ||
const _isPlainObject = /*#__PURE__*/ _interop_require_default(require("../util/isPlainObject")); | ||
const _prefixSelector = /*#__PURE__*/ _interop_require_default(require("../util/prefixSelector")); | ||
const _pluginUtils = require("../util/pluginUtils"); | ||
const _log = /*#__PURE__*/ _interopRequireDefault(require("../util/log")); | ||
const _sharedState = /*#__PURE__*/ _interopRequireWildcard(require("./sharedState")); | ||
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log")); | ||
const _sharedState = /*#__PURE__*/ _interop_require_wildcard(require("./sharedState")); | ||
const _formatVariantSelector = require("../util/formatVariantSelector"); | ||
@@ -29,6 +35,7 @@ const _nameClass = require("../util/nameClass"); | ||
const _setupContextUtils = require("./setupContextUtils"); | ||
const _isValidArbitraryValue = /*#__PURE__*/ _interopRequireDefault(require("../util/isValidArbitraryValue")); | ||
const _splitAtTopLevelOnlyJs = require("../util/splitAtTopLevelOnly.js"); | ||
const _isSyntacticallyValidPropertyValue = /*#__PURE__*/ _interop_require_default(require("../util/isSyntacticallyValidPropertyValue")); | ||
const _splitAtTopLevelOnly = require("../util/splitAtTopLevelOnly.js"); | ||
const _featureFlags = require("../featureFlags"); | ||
function _interopRequireDefault(obj) { | ||
const _applyImportantSelector = require("../util/applyImportantSelector"); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -46,3 +53,3 @@ default: obj | ||
} | ||
function _interopRequireWildcard(obj, nodeInterop) { | ||
function _interop_require_wildcard(obj, nodeInterop) { | ||
if (!nodeInterop && obj && obj.__esModule) { | ||
@@ -78,3 +85,3 @@ return obj; | ||
} | ||
let classNameParser = (0, _postcssSelectorParser.default)((selectors)=>{ | ||
let classNameParser = (0, _postcssselectorparser.default)((selectors)=>{ | ||
return selectors.first.filter(({ type })=>type === "class").pop().value; | ||
@@ -169,8 +176,8 @@ }); | ||
container.walkRules((r)=>{ | ||
r.selector = (0, _pluginUtils.updateAllClasses)((0, _pluginUtils.filterSelectorsForClass)(r.selector, classCandidate), (className)=>{ | ||
if (className === classCandidate) { | ||
return `!${className}`; | ||
} | ||
return className; | ||
}); | ||
let ast = (0, _postcssselectorparser.default)().astSync(r.selector); | ||
// Remove extraneous selectors that do not include the base candidate | ||
ast.each((sel)=>(0, _formatVariantSelector.eliminateIrrelevantSelectors)(sel, classCandidate)); | ||
// Update all instances of the base candidate to include the important marker | ||
(0, _pluginUtils.updateAllClasses)(ast, (className)=>className === classCandidate ? `!${className}` : className); | ||
r.selector = ast.toString(); | ||
r.walkDecls((d)=>d.important = true); | ||
@@ -206,6 +213,12 @@ }); | ||
{ | ||
let match = /(.*)\/(.*)$/g.exec(variant); | ||
if (match) { | ||
variant = match[1]; | ||
args.modifier = match[2]; | ||
let [baseVariant, ...modifiers] = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(variant, "/"); | ||
// This is a hack to support variants with `/` in them, like `ar-1/10/20:text-red-500` | ||
// In this case 1/10 is a value but /20 is a modifier | ||
if (modifiers.length > 1) { | ||
baseVariant = baseVariant + "/" + modifiers.slice(0, -1).join("/"); | ||
modifiers = modifiers.slice(-1); | ||
} | ||
if (modifiers.length && !context.variantMap.has(variant)) { | ||
variant = baseVariant; | ||
args.modifier = modifiers[0]; | ||
if (!(0, _featureFlags.flagEnabled)(context.tailwindConfig, "generalizedModifiers")) { | ||
@@ -225,10 +238,10 @@ return []; | ||
// group[:hover] (`-` is missing) | ||
let match1 = /(.)(-?)\[(.*)\]/g.exec(variant); | ||
if (match1) { | ||
let [, char, seperator, value] = match1; | ||
let match = /(.)(-?)\[(.*)\]/g.exec(variant); | ||
if (match) { | ||
let [, char, separator, value] = match; | ||
// @-[200px] case | ||
if (char === "@" && seperator === "-") return []; | ||
if (char === "@" && separator === "-") return []; | ||
// group[:hover] case | ||
if (char !== "@" && seperator === "") return []; | ||
variant = variant.replace(`${seperator}[${value}]`, ""); | ||
if (char !== "@" && separator === "") return []; | ||
variant = variant.replace(`${separator}[${value}]`, ""); | ||
args.value = value; | ||
@@ -239,18 +252,30 @@ } | ||
if (isArbitraryValue(variant) && !context.variantMap.has(variant)) { | ||
let sort = context.offsets.recordVariant(variant); | ||
let selector = (0, _dataTypes.normalize)(variant.slice(1, -1)); | ||
if (!(0, _setupContextUtils.isValidVariantFormatString)(selector)) { | ||
let selectors = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(selector, ","); | ||
// We do not support multiple selectors for arbitrary variants | ||
if (selectors.length > 1) { | ||
return []; | ||
} | ||
let fn = (0, _setupContextUtils.parseVariant)(selector); | ||
let sort = context.offsets.recordVariant(variant); | ||
context.variantMap.set(variant, [ | ||
[ | ||
sort, | ||
fn | ||
] | ||
]); | ||
if (!selectors.every(_setupContextUtils.isValidVariantFormatString)) { | ||
return []; | ||
} | ||
let records = selectors.map((sel, idx)=>[ | ||
context.offsets.applyParallelOffset(sort, idx), | ||
(0, _setupContextUtils.parseVariant)(sel.trim()) | ||
]); | ||
context.variantMap.set(variant, records); | ||
} | ||
if (context.variantMap.has(variant)) { | ||
var _context_variantOptions_get; | ||
let isArbitraryVariant = isArbitraryValue(variant); | ||
var _context_variantOptions_get_INTERNAL_FEATURES; | ||
let internalFeatures = (_context_variantOptions_get_INTERNAL_FEATURES = (_context_variantOptions_get = context.variantOptions.get(variant)) === null || _context_variantOptions_get === void 0 ? void 0 : _context_variantOptions_get[_setupContextUtils.INTERNAL_FEATURES]) !== null && _context_variantOptions_get_INTERNAL_FEATURES !== void 0 ? _context_variantOptions_get_INTERNAL_FEATURES : {}; | ||
let variantFunctionTuples = context.variantMap.get(variant).slice(); | ||
let result = []; | ||
let respectPrefix = (()=>{ | ||
if (isArbitraryVariant) return false; | ||
if (internalFeatures.respectPrefix === false) return false; | ||
return true; | ||
})(); | ||
for (let [meta, rule] of matches){ | ||
@@ -310,3 +335,6 @@ // Don't generate variants for user css | ||
format (selectorFormat) { | ||
collectedFormats.push(selectorFormat); | ||
collectedFormats.push({ | ||
format: selectorFormat, | ||
respectPrefix | ||
}); | ||
}, | ||
@@ -318,3 +346,3 @@ args | ||
if (Array.isArray(ruleWithVariant)) { | ||
for (let [idx, variantFunction1] of ruleWithVariant.entries()){ | ||
for (let [idx, variantFunction] of ruleWithVariant.entries()){ | ||
// This is a little bit scary since we are pushing to an array of items that we are | ||
@@ -326,3 +354,3 @@ // currently looping over. However, you can also think of it like a processing queue | ||
context.offsets.applyParallelOffset(variantSort, idx), | ||
variantFunction1, | ||
variantFunction, | ||
// If the clone has been modified we have to pass that back | ||
@@ -336,3 +364,6 @@ // though so each rule can use the modified container | ||
if (typeof ruleWithVariant === "string") { | ||
collectedFormats.push(ruleWithVariant); | ||
collectedFormats.push({ | ||
format: ruleWithVariant, | ||
respectPrefix | ||
}); | ||
} | ||
@@ -357,3 +388,3 @@ if (ruleWithVariant === null) { | ||
// classes, pseudos, ids, ... | ||
let rebuiltBase = (0, _postcssSelectorParser.default)((selectors)=>{ | ||
let rebuiltBase = (0, _postcssselectorparser.default)((selectors)=>{ | ||
selectors.walkClasses((classNode)=>{ | ||
@@ -374,3 +405,6 @@ classNode.value = `${variant}${context.tailwindConfig.separator}${classNode.value}`; | ||
// format: .foo & | ||
collectedFormats.push(modified.replace(rebuiltBase, "&")); | ||
collectedFormats.push({ | ||
format: modified.replace(rebuiltBase, "&"), | ||
respectPrefix | ||
}); | ||
rule.selector = before; | ||
@@ -387,3 +421,3 @@ }); | ||
}; | ||
var _collectedFormats; | ||
var _meta_collectedFormats; | ||
let withOffset = [ | ||
@@ -393,4 +427,3 @@ { | ||
sort: context.offsets.applyVariantOffset(meta.sort, variantSort, Object.assign(args, context.variantOptions.get(variant))), | ||
collectedFormats: ((_collectedFormats = meta.collectedFormats) !== null && _collectedFormats !== void 0 ? _collectedFormats : []).concat(collectedFormats), | ||
isArbitraryVariant: isArbitraryValue(variant) | ||
collectedFormats: ((_meta_collectedFormats = meta.collectedFormats) !== null && _meta_collectedFormats !== void 0 ? _meta_collectedFormats : []).concat(collectedFormats) | ||
}, | ||
@@ -453,3 +486,3 @@ clone.nodes[0] | ||
node.walkDecls((decl)=>{ | ||
if (!isParsableCssValue(decl.name, decl.value)) { | ||
if (!isParsableCssValue(decl.prop, decl.value)) { | ||
isParsable = false; | ||
@@ -476,4 +509,4 @@ return false; | ||
function extractArbitraryProperty(classCandidate, context) { | ||
var ref; | ||
let [, property, value] = (ref = classCandidate.match(/^\[([a-zA-Z0-9-_]+):(\S+)\]$/)) !== null && ref !== void 0 ? ref : []; | ||
var _classCandidate_match; | ||
let [, property, value] = (_classCandidate_match = classCandidate.match(/^\[([a-zA-Z0-9-_]+):(\S+)\]$/)) !== null && _classCandidate_match !== void 0 ? _classCandidate_match : []; | ||
if (value === undefined) { | ||
@@ -485,6 +518,8 @@ return null; | ||
} | ||
if (!(0, _isValidArbitraryValue.default)(value)) { | ||
if (!(0, _isSyntacticallyValidPropertyValue.default)(value)) { | ||
return null; | ||
} | ||
let normalized = (0, _dataTypes.normalize)(value); | ||
let normalized = (0, _dataTypes.normalize)(value, { | ||
property | ||
}); | ||
if (!isParsableCssValue(property, normalized)) { | ||
@@ -553,12 +588,12 @@ return null; | ||
} | ||
return (0, _splitAtTopLevelOnlyJs.splitAtTopLevelOnly)(input, separator); | ||
return (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(input, separator); | ||
} | ||
function* recordCandidates(matches, classCandidate) { | ||
for (const match of matches){ | ||
var ref; | ||
var ref1; | ||
var _match__options; | ||
var _match__options_preserveSource; | ||
match[1].raws.tailwind = { | ||
...match[1].raws.tailwind, | ||
classCandidate, | ||
preserveSource: (ref1 = (ref = match[0].options) === null || ref === void 0 ? void 0 : ref.preserveSource) !== null && ref1 !== void 0 ? ref1 : false | ||
preserveSource: (_match__options_preserveSource = (_match__options = match[0].options) === null || _match__options === void 0 ? void 0 : _match__options.preserveSource) !== null && _match__options_preserveSource !== void 0 ? _match__options_preserveSource : false | ||
}; | ||
@@ -568,3 +603,3 @@ yield match; | ||
} | ||
function* resolveMatches(candidate, context, original = candidate) { | ||
function* resolveMatches(candidate, context) { | ||
let separator = context.tailwindConfig.separator; | ||
@@ -577,10 +612,2 @@ let [classCandidate, ...variants] = splitWithSeparator(candidate, separator).reverse(); | ||
} | ||
if ((0, _featureFlags.flagEnabled)(context.tailwindConfig, "variantGrouping")) { | ||
if (classCandidate.startsWith("(") && classCandidate.endsWith(")")) { | ||
let base = variants.slice().reverse().join(separator); | ||
for (let part of (0, _splitAtTopLevelOnlyJs.splitAtTopLevelOnly)(classCandidate.slice(1, -1), ",")){ | ||
yield* resolveMatches(base + separator + part, context, original); | ||
} | ||
} | ||
} | ||
// TODO: Reintroduce this in ways that doesn't break on false positives | ||
@@ -623,5 +650,5 @@ // function sortAgainst(toSort, against) { | ||
} else if (modifier === "DEFAULT" || modifier === "-DEFAULT") { | ||
let ruleSet1 = plugin; | ||
let [rules1, options1] = parseRules(ruleSet1, context.postCssNodeCache); | ||
for (let rule1 of rules1){ | ||
let ruleSet = plugin; | ||
let [rules, options] = parseRules(ruleSet, context.postCssNodeCache); | ||
for (let rule of rules){ | ||
matchesPerPlugin.push([ | ||
@@ -632,6 +659,6 @@ { | ||
...sort.options, | ||
...options1 | ||
...options | ||
} | ||
}, | ||
rule1 | ||
rule | ||
]); | ||
@@ -641,5 +668,5 @@ } | ||
if (matchesPerPlugin.length > 0) { | ||
var ref; | ||
var ref1, _options; | ||
let matchingTypes = Array.from((0, _pluginUtils.getMatchingTypes)((ref1 = (ref = sort.options) === null || ref === void 0 ? void 0 : ref.types) !== null && ref1 !== void 0 ? ref1 : [], modifier, (_options = sort.options) !== null && _options !== void 0 ? _options : {}, context.tailwindConfig)).map(([_, type])=>type); | ||
var _sort_options; | ||
var _sort_options_types, _sort_options1; | ||
let matchingTypes = Array.from((0, _pluginUtils.getMatchingTypes)((_sort_options_types = (_sort_options = sort.options) === null || _sort_options === void 0 ? void 0 : _sort_options.types) !== null && _sort_options_types !== void 0 ? _sort_options_types : [], modifier, (_sort_options1 = sort.options) !== null && _sort_options1 !== void 0 ? _sort_options1 : {}, context.tailwindConfig)).map(([_, type])=>type); | ||
if (matchingTypes.length > 0) { | ||
@@ -684,6 +711,6 @@ typesByMatches.set(matchesPerPlugin, matchingTypes); | ||
} | ||
var ref2; | ||
var _findFallback; | ||
// Try to find a fallback plugin, because we already know that multiple plugins matched for | ||
// the given arbitrary value. | ||
let fallback = (ref2 = findFallback(withoutAny)) !== null && ref2 !== void 0 ? ref2 : findFallback(withAny); | ||
let fallback = (_findFallback = findFallback(withoutAny)) !== null && _findFallback !== void 0 ? _findFallback : findFallback(withAny); | ||
if (fallback) { | ||
@@ -694,5 +721,5 @@ matches = [ | ||
} else { | ||
var ref3; | ||
var _typesByMatches_get; | ||
let typesPerPlugin = matches.map((match)=>new Set([ | ||
...(ref3 = typesByMatches.get(match)) !== null && ref3 !== void 0 ? ref3 : [] | ||
...(_typesByMatches_get = typesByMatches.get(match)) !== null && _typesByMatches_get !== void 0 ? _typesByMatches_get : [] | ||
])); | ||
@@ -715,7 +742,7 @@ // Remove duplicates, so that we can detect proper unique types for each plugin. | ||
for (let [idx, group] of typesPerPlugin.entries()){ | ||
for (let type1 of group){ | ||
let rules2 = matches[idx].map(([, rule])=>rule).flat().map((rule)=>rule.toString().split("\n").slice(1, -1) // Remove selector and closing '}' | ||
for (let type of group){ | ||
let rules = matches[idx].map(([, rule])=>rule).flat().map((rule)=>rule.toString().split("\n").slice(1, -1) // Remove selector and closing '}' | ||
.map((line)=>line.trim()).map((x)=>` ${x}`) // Re-indent | ||
.join("\n")).join("\n\n"); | ||
messages.push(` Use \`${candidate.replace("[", `[${type1}:`)}\` for \`${rules2.trim()}\``); | ||
messages.push(` Use \`${candidate.replace("[", `[${type}:`)}\` for \`${rules.trim()}\``); | ||
break; | ||
@@ -749,22 +776,11 @@ } | ||
// Apply final format selector | ||
if (match[0].collectedFormats) { | ||
let finalFormat = (0, _formatVariantSelector.formatVariantSelector)("&", ...match[0].collectedFormats); | ||
let container = _postcss.default.root({ | ||
nodes: [ | ||
match[1].clone() | ||
] | ||
}); | ||
container.walkRules((rule)=>{ | ||
var ref; | ||
if (inKeyframes(rule)) return; | ||
var ref1; | ||
rule.selector = (0, _formatVariantSelector.finalizeSelector)(finalFormat, { | ||
selector: rule.selector, | ||
candidate: original, | ||
base: candidate.split(new RegExp(`\\${(ref1 = context === null || context === void 0 ? void 0 : (ref = context.tailwindConfig) === null || ref === void 0 ? void 0 : ref.separator) !== null && ref1 !== void 0 ? ref1 : ":"}(?![^[]*\\])`)).pop(), | ||
isArbitraryVariant: match[0].isArbitraryVariant, | ||
context | ||
}); | ||
}); | ||
match[1] = container.nodes[0]; | ||
match = applyFinalFormat(match, { | ||
context, | ||
candidate | ||
}); | ||
// Skip rules with invalid selectors | ||
// This will cause the candidate to be added to the "not class" | ||
// cache skipping it entirely for future builds | ||
if (match === null) { | ||
continue; | ||
} | ||
@@ -775,2 +791,63 @@ yield match; | ||
} | ||
function applyFinalFormat(match, { context , candidate }) { | ||
if (!match[0].collectedFormats) { | ||
return match; | ||
} | ||
let isValid = true; | ||
let finalFormat; | ||
try { | ||
finalFormat = (0, _formatVariantSelector.formatVariantSelector)(match[0].collectedFormats, { | ||
context, | ||
candidate | ||
}); | ||
} catch { | ||
// The format selector we produced is invalid | ||
// This could be because: | ||
// - A bug exists | ||
// - A plugin introduced an invalid variant selector (ex: `addVariant('foo', '&;foo')`) | ||
// - The user used an invalid arbitrary variant (ex: `[&;foo]:underline`) | ||
// Either way the build will fail because of this | ||
// We would rather that the build pass "silently" given that this could | ||
// happen because of picking up invalid things when scanning content | ||
// So we'll throw out the candidate instead | ||
return null; | ||
} | ||
let container = _postcss.default.root({ | ||
nodes: [ | ||
match[1].clone() | ||
] | ||
}); | ||
container.walkRules((rule)=>{ | ||
if (inKeyframes(rule)) { | ||
return; | ||
} | ||
try { | ||
let selector = (0, _formatVariantSelector.finalizeSelector)(rule.selector, finalFormat, { | ||
candidate, | ||
context | ||
}); | ||
// Finalize Selector determined that this candidate is irrelevant | ||
// TODO: This elimination should happen earlier so this never happens | ||
if (selector === null) { | ||
rule.remove(); | ||
return; | ||
} | ||
rule.selector = selector; | ||
} catch { | ||
// If this selector is invalid we also want to skip it | ||
// But it's likely that being invalid here means there's a bug in a plugin rather than too loosely matching content | ||
isValid = false; | ||
return false; | ||
} | ||
}); | ||
if (!isValid) { | ||
return null; | ||
} | ||
// If all rules have been eliminated we can skip this candidate entirely | ||
if (container.nodes.length === 0) { | ||
return null; | ||
} | ||
match[1] = container.nodes[0]; | ||
return match; | ||
} | ||
function inKeyframes(rule) { | ||
@@ -798,3 +875,3 @@ return rule.parent && rule.parent.type === "atrule" && rule.parent.name === "keyframes"; | ||
rule.selectors = rule.selectors.map((selector)=>{ | ||
return `${important} ${selector}`; | ||
return (0, _applyImportantSelector.applyImportantSelector)(selector, important); | ||
}); | ||
@@ -804,3 +881,3 @@ }; | ||
} | ||
function generateRules(candidates, context) { | ||
function generateRules(candidates, context, isSorting = false) { | ||
let allRules = []; | ||
@@ -822,4 +899,4 @@ let strategy = getImportantStrategy(context.tailwindConfig.important); | ||
context.classCache.set(candidate, matches); | ||
var ref; | ||
let rules = (ref = context.candidateRuleCache.get(candidate)) !== null && ref !== void 0 ? ref : new Set(); | ||
var _context_candidateRuleCache_get; | ||
let rules = (_context_candidateRuleCache_get = context.candidateRuleCache.get(candidate)) !== null && _context_candidateRuleCache_get !== void 0 ? _context_candidateRuleCache_get : new Set(); | ||
context.candidateRuleCache.set(candidate, rules); | ||
@@ -837,5 +914,7 @@ for (const match of matches){ | ||
} | ||
// Note: We have to clone rules during sorting | ||
// so we eliminate some shared mutable state | ||
let newEntry = [ | ||
sort, | ||
rule | ||
isSorting ? rule.clone() : rule | ||
]; | ||
@@ -842,0 +921,0 @@ rules.add(newEntry); |
@@ -7,9 +7,9 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>getModuleDependencies | ||
get: function() { | ||
return getModuleDependencies; | ||
} | ||
}); | ||
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs")); | ||
const _path = /*#__PURE__*/ _interopRequireDefault(require("path")); | ||
const _resolve = /*#__PURE__*/ _interopRequireDefault(require("resolve")); | ||
const _detective = /*#__PURE__*/ _interopRequireDefault(require("detective")); | ||
function _interopRequireDefault(obj) { | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _path = /*#__PURE__*/ _interop_require_default(require("path")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -19,35 +19,83 @@ default: obj | ||
} | ||
function createModule(file) { | ||
const source = _fs.default.readFileSync(file, "utf-8"); | ||
const requires = (0, _detective.default)(source); | ||
return { | ||
file, | ||
requires | ||
}; | ||
let jsExtensions = [ | ||
".js", | ||
".cjs", | ||
".mjs" | ||
]; | ||
// Given the current file `a.ts`, we want to make sure that when importing `b` that we resolve | ||
// `b.ts` before `b.js` | ||
// | ||
// E.g.: | ||
// | ||
// a.ts | ||
// b // .ts | ||
// c // .ts | ||
// a.js | ||
// b // .js or .ts | ||
let jsResolutionOrder = [ | ||
"", | ||
".js", | ||
".cjs", | ||
".mjs", | ||
".ts", | ||
".cts", | ||
".mts", | ||
".jsx", | ||
".tsx" | ||
]; | ||
let tsResolutionOrder = [ | ||
"", | ||
".ts", | ||
".cts", | ||
".mts", | ||
".tsx", | ||
".js", | ||
".cjs", | ||
".mjs", | ||
".jsx" | ||
]; | ||
function resolveWithExtension(file, extensions) { | ||
// Try to find `./a.ts`, `./a.ts`, ... from `./a` | ||
for (let ext of extensions){ | ||
let full = `${file}${ext}`; | ||
if (_fs.default.existsSync(full) && _fs.default.statSync(full).isFile()) { | ||
return full; | ||
} | ||
} | ||
// Try to find `./a/index.js` from `./a` | ||
for (let ext of extensions){ | ||
let full = `${file}/index${ext}`; | ||
if (_fs.default.existsSync(full)) { | ||
return full; | ||
} | ||
} | ||
return null; | ||
} | ||
function getModuleDependencies(entryFile) { | ||
const rootModule = createModule(entryFile); | ||
const modules = [ | ||
rootModule | ||
]; | ||
// Iterate over the modules, even when new | ||
// ones are being added | ||
for (const mdl of modules){ | ||
mdl.requires.filter((dep)=>{ | ||
// Only track local modules, not node_modules | ||
return dep.startsWith("./") || dep.startsWith("../"); | ||
}).forEach((dep)=>{ | ||
try { | ||
const basedir = _path.default.dirname(mdl.file); | ||
const depPath = _resolve.default.sync(dep, { | ||
basedir | ||
}); | ||
const depModule = createModule(depPath); | ||
modules.push(depModule); | ||
} catch (_err) { | ||
// eslint-disable-next-line no-empty | ||
} | ||
}); | ||
function* _getModuleDependencies(filename, base, seen, ext = _path.default.extname(filename)) { | ||
// Try to find the file | ||
let absoluteFile = resolveWithExtension(_path.default.resolve(base, filename), jsExtensions.includes(ext) ? jsResolutionOrder : tsResolutionOrder); | ||
if (absoluteFile === null) return; // File doesn't exist | ||
// Prevent infinite loops when there are circular dependencies | ||
if (seen.has(absoluteFile)) return; // Already seen | ||
seen.add(absoluteFile); | ||
// Mark the file as a dependency | ||
yield absoluteFile; | ||
// Resolve new base for new imports/requires | ||
base = _path.default.dirname(absoluteFile); | ||
ext = _path.default.extname(absoluteFile); | ||
let contents = _fs.default.readFileSync(absoluteFile, "utf-8"); | ||
// Find imports/requires | ||
for (let match of [ | ||
...contents.matchAll(/import[\s\S]*?['"](.{3,}?)['"]/gi), | ||
...contents.matchAll(/import[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi), | ||
...contents.matchAll(/require\(['"`](.+)['"`]\)/gi) | ||
]){ | ||
// Bail out if it's not a relative file | ||
if (!match[1].startsWith(".")) continue; | ||
yield* _getModuleDependencies(match[1], base, seen, ext); | ||
} | ||
return modules; | ||
} | ||
function getModuleDependencies(absoluteFilePath) { | ||
if (absoluteFilePath === null) return new Set(); | ||
return new Set(_getModuleDependencies(absoluteFilePath, _path.default.dirname(absoluteFilePath), new Set())); | ||
} |
@@ -7,6 +7,8 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>normalizeTailwindDirectives | ||
get: function() { | ||
return normalizeTailwindDirectives; | ||
} | ||
}); | ||
const _log = /*#__PURE__*/ _interopRequireDefault(require("../util/log")); | ||
function _interopRequireDefault(obj) { | ||
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -13,0 +15,0 @@ default: obj |
@@ -8,6 +8,9 @@ // @ts-check | ||
enumerable: true, | ||
get: ()=>Offsets | ||
get: function() { | ||
return Offsets; | ||
} | ||
}); | ||
const _bigSign = /*#__PURE__*/ _interopRequireDefault(require("../util/bigSign")); | ||
function _interopRequireDefault(obj) { | ||
const _bigSign = /*#__PURE__*/ _interop_require_default(require("../util/bigSign")); | ||
const _remapbitfield = require("./remap-bitfield.js"); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -100,2 +103,3 @@ default: obj | ||
*/ applyVariantOffset(rule, variant, options) { | ||
options.variant = variant.variants; | ||
return { | ||
@@ -158,3 +162,3 @@ ...rule, | ||
...this.create("variants"), | ||
variants: 1n << this.reservedVariantBits | ||
variants: this.variantOffsets.get(variant) | ||
}; | ||
@@ -171,2 +175,7 @@ } | ||
} | ||
// When sorting the `variants` layer, we need to sort based on the parent layer as well within | ||
// this variants layer. | ||
if (a.parentLayer !== b.parentLayer) { | ||
return this.layerPositions[a.parentLayer] - this.layerPositions[b.parentLayer]; | ||
} | ||
// Sort based on the sorting function | ||
@@ -177,2 +186,15 @@ for (let aOptions of a.options){ | ||
if (!aOptions.sort || !bOptions.sort) continue; | ||
var _max; | ||
let maxFnVariant = (_max = max([ | ||
aOptions.variant, | ||
bOptions.variant | ||
])) !== null && _max !== void 0 ? _max : 0n; | ||
// Create a mask of 0s from bits 1..N where N represents the mask of the Nth bit | ||
let mask = ~(maxFnVariant | maxFnVariant - 1n); | ||
let aVariantsAfterFn = a.variants & mask; | ||
let bVariantsAfterFn = b.variants & mask; | ||
// If the variants the same, we _can_ sort them | ||
if (aVariantsAfterFn !== bVariantsAfterFn) { | ||
continue; | ||
} | ||
let result = aOptions.sort({ | ||
@@ -204,6 +226,53 @@ value: aOptions.value, | ||
/** | ||
* Arbitrary variants are recorded in the order they're encountered. | ||
* This means that the order is not stable between environments and sets of content files. | ||
* | ||
* In order to make the order stable, we need to remap the arbitrary variant offsets to | ||
* be in alphabetical order starting from the offset of the first arbitrary variant. | ||
*/ recalculateVariantOffsets() { | ||
// Sort the variants by their name | ||
let variants = Array.from(this.variantOffsets.entries()).filter(([v])=>v.startsWith("[")).sort(([a], [z])=>fastCompare(a, z)); | ||
// Sort the list of offsets | ||
// This is not necessarily a discrete range of numbers which is why | ||
// we're using sort instead of creating a range from min/max | ||
let newOffsets = variants.map(([, offset])=>offset).sort((a, z)=>(0, _bigSign.default)(a - z)); | ||
// Create a map from the old offsets to the new offsets in the new sort order | ||
/** @type {[bigint, bigint][]} */ let mapping = variants.map(([, oldOffset], i)=>[ | ||
oldOffset, | ||
newOffsets[i] | ||
]); | ||
// Remove any variants that will not move letting us skip | ||
// remapping if everything happens to be in order | ||
return mapping.filter(([a, z])=>a !== z); | ||
} | ||
/** | ||
* @template T | ||
* @param {[RuleOffset, T][]} list | ||
* @returns {[RuleOffset, T][]} | ||
*/ remapArbitraryVariantOffsets(list) { | ||
let mapping = this.recalculateVariantOffsets(); | ||
// No arbitrary variants? Nothing to do. | ||
// Everyhing already in order? Nothing to do. | ||
if (mapping.length === 0) { | ||
return list; | ||
} | ||
// Remap every variant offset in the list | ||
return list.map((item)=>{ | ||
let [offset, rule] = item; | ||
offset = { | ||
...offset, | ||
variants: (0, _remapbitfield.remapBitfield)(offset.variants, mapping) | ||
}; | ||
return [ | ||
offset, | ||
rule | ||
]; | ||
}); | ||
} | ||
/** | ||
* @template T | ||
* @param {[RuleOffset, T][]} list | ||
* @returns {[RuleOffset, T][]} | ||
*/ sort(list) { | ||
list = this.remapArbitraryVariantOffsets(list); | ||
return list.sort(([a], [b])=>(0, _bigSign.default)(this.compare(a, b))); | ||
@@ -224,1 +293,21 @@ } | ||
} | ||
/** | ||
* A fast ASCII order string comparison function. | ||
* | ||
* Using `.sort()` without a custom compare function is faster | ||
* But you can only use that if you're sorting an array of | ||
* only strings. If you're sorting strings inside objects | ||
* or arrays, you need must use a custom compare function. | ||
* | ||
* @param {string} a | ||
* @param {string} b | ||
*/ function fastCompare(a, b) { | ||
let aLen = a.length; | ||
let bLen = b.length; | ||
let minLen = aLen < bLen ? aLen : bLen; | ||
for(let i = 0; i < minLen; i++){ | ||
let cmp = a.charCodeAt(i) - b.charCodeAt(i); | ||
if (cmp !== 0) return cmp; | ||
} | ||
return aLen - bLen; | ||
} |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>expandApplyAtRules | ||
get: function() { | ||
return expandApplyAtRules; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ function partitionRules(root) { |
@@ -12,9 +12,23 @@ "use strict"; | ||
_export(exports, { | ||
pattern: ()=>pattern, | ||
withoutCapturing: ()=>withoutCapturing, | ||
any: ()=>any, | ||
optional: ()=>optional, | ||
zeroOrMore: ()=>zeroOrMore, | ||
nestedBrackets: ()=>nestedBrackets, | ||
escape: ()=>escape | ||
pattern: function() { | ||
return pattern; | ||
}, | ||
withoutCapturing: function() { | ||
return withoutCapturing; | ||
}, | ||
any: function() { | ||
return any; | ||
}, | ||
optional: function() { | ||
return optional; | ||
}, | ||
zeroOrMore: function() { | ||
return zeroOrMore; | ||
}, | ||
nestedBrackets: function() { | ||
return nestedBrackets; | ||
}, | ||
escape: function() { | ||
return escape; | ||
} | ||
}); | ||
@@ -21,0 +35,0 @@ const REGEX_SPECIAL = /[\\^$.*+?()[\]{}|]/g; |
@@ -12,9 +12,13 @@ "use strict"; | ||
_export(exports, { | ||
elementSelectorParser: ()=>elementSelectorParser, | ||
default: ()=>resolveDefaultsAtRules | ||
elementSelectorParser: function() { | ||
return elementSelectorParser; | ||
}, | ||
default: function() { | ||
return resolveDefaultsAtRules; | ||
} | ||
}); | ||
const _postcss = /*#__PURE__*/ _interopRequireDefault(require("postcss")); | ||
const _postcssSelectorParser = /*#__PURE__*/ _interopRequireDefault(require("postcss-selector-parser")); | ||
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss")); | ||
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser")); | ||
const _featureFlags = require("../featureFlags"); | ||
function _interopRequireDefault(obj) { | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -26,3 +30,3 @@ default: obj | ||
id (node) { | ||
return _postcssSelectorParser.default.attribute({ | ||
return _postcssselectorparser.default.attribute({ | ||
attribute: "id", | ||
@@ -65,3 +69,3 @@ operator: "=", | ||
rest.splice(0, combinatorIdx); | ||
rest.unshift(_postcssSelectorParser.default.universal()); | ||
rest.unshift(_postcssselectorparser.default.universal()); | ||
} | ||
@@ -73,3 +77,3 @@ return [ | ||
} | ||
let elementSelectorParser = (0, _postcssSelectorParser.default)((selectors)=>{ | ||
let elementSelectorParser = (0, _postcssselectorparser.default)((selectors)=>{ | ||
return selectors.map((s)=>{ | ||
@@ -106,4 +110,4 @@ let nodes = s.split((n)=>n.type === "combinator" && n.value === " ").pop(); | ||
/** @type {Map<string, Set<string>>} */ let selectorGroups = new Map(); | ||
var ref; | ||
let rules = (ref = variableNodeMap.get(universal.params)) !== null && ref !== void 0 ? ref : []; | ||
var _variableNodeMap_get; | ||
let rules = (_variableNodeMap_get = variableNodeMap.get(universal.params)) !== null && _variableNodeMap_get !== void 0 ? _variableNodeMap_get : []; | ||
for (let rule of rules){ | ||
@@ -116,4 +120,4 @@ for (let selector of extractElementSelector(rule.selector)){ | ||
let selectorGroupName = selector.includes(":-") || selector.includes("::-") ? selector : "__DEFAULT__"; | ||
var ref1; | ||
let selectors = (ref1 = selectorGroups.get(selectorGroupName)) !== null && ref1 !== void 0 ? ref1 : new Set(); | ||
var _selectorGroups_get; | ||
let selectors = (_selectorGroups_get = selectorGroups.get(selectorGroupName)) !== null && _selectorGroups_get !== void 0 ? _selectorGroups_get : new Set(); | ||
selectorGroups.set(selectorGroupName, selectors); | ||
@@ -128,3 +132,3 @@ selectors.add(selector); | ||
} | ||
for (let [, selectors1] of selectorGroups){ | ||
for (let [, selectors] of selectorGroups){ | ||
let universalRule = _postcss.default.rule({ | ||
@@ -134,3 +138,3 @@ source: universal.source | ||
universalRule.selectors = [ | ||
...selectors1 | ||
...selectors | ||
]; | ||
@@ -144,3 +148,3 @@ universalRule.append(universal.nodes.map((node)=>node.clone())); | ||
} else if (universals.size) { | ||
let universalRule1 = _postcss.default.rule({ | ||
let universalRule = _postcss.default.rule({ | ||
selectors: [ | ||
@@ -152,13 +156,13 @@ "*", | ||
}); | ||
for (let universal1 of universals){ | ||
universalRule1.append(universal1.nodes); | ||
if (!universalRule1.parent) { | ||
universal1.before(universalRule1); | ||
for (let universal of universals){ | ||
universalRule.append(universal.nodes); | ||
if (!universalRule.parent) { | ||
universal.before(universalRule); | ||
} | ||
if (!universalRule1.source) { | ||
universalRule1.source = universal1.source; | ||
if (!universalRule.source) { | ||
universalRule.source = universal.source; | ||
} | ||
universal1.remove(); | ||
universal.remove(); | ||
} | ||
let backdropRule = universalRule1.clone({ | ||
let backdropRule = universalRule.clone({ | ||
selectors: [ | ||
@@ -168,5 +172,5 @@ "::backdrop" | ||
}); | ||
universalRule1.after(backdropRule); | ||
universalRule.after(backdropRule); | ||
} | ||
}; | ||
} |
@@ -12,32 +12,45 @@ "use strict"; | ||
_export(exports, { | ||
isValidVariantFormatString: ()=>isValidVariantFormatString, | ||
parseVariant: ()=>parseVariant, | ||
getFileModifiedMap: ()=>getFileModifiedMap, | ||
createContext: ()=>createContext, | ||
getContext: ()=>getContext | ||
INTERNAL_FEATURES: function() { | ||
return INTERNAL_FEATURES; | ||
}, | ||
isValidVariantFormatString: function() { | ||
return isValidVariantFormatString; | ||
}, | ||
parseVariant: function() { | ||
return parseVariant; | ||
}, | ||
getFileModifiedMap: function() { | ||
return getFileModifiedMap; | ||
}, | ||
createContext: function() { | ||
return createContext; | ||
}, | ||
getContext: function() { | ||
return getContext; | ||
} | ||
}); | ||
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs")); | ||
const _url = /*#__PURE__*/ _interopRequireDefault(require("url")); | ||
const _postcss = /*#__PURE__*/ _interopRequireDefault(require("postcss")); | ||
const _dlv = /*#__PURE__*/ _interopRequireDefault(require("dlv")); | ||
const _postcssSelectorParser = /*#__PURE__*/ _interopRequireDefault(require("postcss-selector-parser")); | ||
const _transformThemeValue = /*#__PURE__*/ _interopRequireDefault(require("../util/transformThemeValue")); | ||
const _parseObjectStyles = /*#__PURE__*/ _interopRequireDefault(require("../util/parseObjectStyles")); | ||
const _prefixSelector = /*#__PURE__*/ _interopRequireDefault(require("../util/prefixSelector")); | ||
const _isPlainObject = /*#__PURE__*/ _interopRequireDefault(require("../util/isPlainObject")); | ||
const _escapeClassName = /*#__PURE__*/ _interopRequireDefault(require("../util/escapeClassName")); | ||
const _nameClass = /*#__PURE__*/ _interopRequireWildcard(require("../util/nameClass")); | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _url = /*#__PURE__*/ _interop_require_default(require("url")); | ||
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss")); | ||
const _dlv = /*#__PURE__*/ _interop_require_default(require("dlv")); | ||
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser")); | ||
const _transformThemeValue = /*#__PURE__*/ _interop_require_default(require("../util/transformThemeValue")); | ||
const _parseObjectStyles = /*#__PURE__*/ _interop_require_default(require("../util/parseObjectStyles")); | ||
const _prefixSelector = /*#__PURE__*/ _interop_require_default(require("../util/prefixSelector")); | ||
const _isPlainObject = /*#__PURE__*/ _interop_require_default(require("../util/isPlainObject")); | ||
const _escapeClassName = /*#__PURE__*/ _interop_require_default(require("../util/escapeClassName")); | ||
const _nameClass = /*#__PURE__*/ _interop_require_wildcard(require("../util/nameClass")); | ||
const _pluginUtils = require("../util/pluginUtils"); | ||
const _corePlugins = require("../corePlugins"); | ||
const _sharedState = /*#__PURE__*/ _interopRequireWildcard(require("./sharedState")); | ||
const _sharedState = /*#__PURE__*/ _interop_require_wildcard(require("./sharedState")); | ||
const _toPath = require("../util/toPath"); | ||
const _log = /*#__PURE__*/ _interopRequireDefault(require("../util/log")); | ||
const _negateValue = /*#__PURE__*/ _interopRequireDefault(require("../util/negateValue")); | ||
const _isValidArbitraryValue = /*#__PURE__*/ _interopRequireDefault(require("../util/isValidArbitraryValue")); | ||
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log")); | ||
const _negateValue = /*#__PURE__*/ _interop_require_default(require("../util/negateValue")); | ||
const _isSyntacticallyValidPropertyValue = /*#__PURE__*/ _interop_require_default(require("../util/isSyntacticallyValidPropertyValue")); | ||
const _generateRules = require("./generateRules"); | ||
const _cacheInvalidationJs = require("./cacheInvalidation.js"); | ||
const _offsetsJs = require("./offsets.js"); | ||
const _featureFlagsJs = require("../featureFlags.js"); | ||
const _cacheInvalidation = require("./cacheInvalidation.js"); | ||
const _offsets = require("./offsets.js"); | ||
const _featureFlags = require("../featureFlags.js"); | ||
const _formatVariantSelector = require("../util/formatVariantSelector"); | ||
function _interopRequireDefault(obj) { | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -55,3 +68,3 @@ default: obj | ||
} | ||
function _interopRequireWildcard(obj, nodeInterop) { | ||
function _interop_require_wildcard(obj, nodeInterop) { | ||
if (!nodeInterop && obj && obj.__esModule) { | ||
@@ -87,2 +100,3 @@ return obj; | ||
} | ||
const INTERNAL_FEATURES = Symbol(); | ||
const VARIANT_TYPES = { | ||
@@ -119,23 +133,37 @@ AddVariant: Symbol.for("ADD_VARIANT"), | ||
function parseVariantFormatString(input) { | ||
if (input.includes("{")) { | ||
if (!isBalanced(input)) throw new Error(`Your { and } are unbalanced.`); | ||
return input.split(/{(.*)}/gim).flatMap((line)=>parseVariantFormatString(line)).filter(Boolean); | ||
} | ||
return [ | ||
input.trim() | ||
]; | ||
} | ||
function isBalanced(input) { | ||
let count = 0; | ||
for (let char of input){ | ||
if (char === "{") { | ||
count++; | ||
/** @type {string[]} */ let parts = []; | ||
// When parsing whitespace around special characters are insignificant | ||
// However, _inside_ of a variant they could be | ||
// Because the selector could look like this | ||
// @media { &[data-name="foo bar"] } | ||
// This is why we do not skip whitespace | ||
let current = ""; | ||
let depth = 0; | ||
for(let idx = 0; idx < input.length; idx++){ | ||
let char = input[idx]; | ||
if (char === "\\") { | ||
// Escaped characters are not special | ||
current += "\\" + input[++idx]; | ||
} else if (char === "{") { | ||
// Nested rule: start | ||
++depth; | ||
parts.push(current.trim()); | ||
current = ""; | ||
} else if (char === "}") { | ||
if (--count < 0) { | ||
return false // unbalanced | ||
; | ||
// Nested rule: end | ||
if (--depth < 0) { | ||
throw new Error(`Your { and } are unbalanced.`); | ||
} | ||
parts.push(current.trim()); | ||
current = ""; | ||
} else { | ||
// Normal character | ||
current += char; | ||
} | ||
} | ||
return count === 0; | ||
if (current.length > 0) { | ||
parts.push(current.trim()); | ||
} | ||
parts = parts.filter((part)=>part !== ""); | ||
return parts; | ||
} | ||
@@ -168,3 +196,3 @@ function insertInto(list, value, { before =[] } = {}) { | ||
function getClasses(selector, mutate) { | ||
let parser = (0, _postcssSelectorParser.default)((selectors)=>{ | ||
let parser = (0, _postcssselectorparser.default)((selectors)=>{ | ||
let allClasses = []; | ||
@@ -181,2 +209,16 @@ if (mutate) { | ||
} | ||
/** | ||
* Ignore everything inside a :not(...). This allows you to write code like | ||
* `div:not(.foo)`. If `.foo` is never found in your code, then we used to | ||
* not generated it. But now we will ignore everything inside a `:not`, so | ||
* that it still gets generated. | ||
* | ||
* @param {selectorParser.Root} selectors | ||
*/ function ignoreNot(selectors) { | ||
selectors.walkPseudos((pseudo)=>{ | ||
if (pseudo.value === ":not") { | ||
pseudo.remove(); | ||
} | ||
}); | ||
} | ||
function extractCandidates(node, state = { | ||
@@ -186,31 +228,19 @@ containsNonOnDemandable: false | ||
let classes = []; | ||
// Handle normal rules | ||
let selectors = []; | ||
if (node.type === "rule") { | ||
// Ignore everything inside a :not(...). This allows you to write code like | ||
// `div:not(.foo)`. If `.foo` is never found in your code, then we used to | ||
// not generated it. But now we will ignore everything inside a `:not`, so | ||
// that it still gets generated. | ||
function ignoreNot(selectors) { | ||
selectors.walkPseudos((pseudo)=>{ | ||
if (pseudo.value === ":not") { | ||
pseudo.remove(); | ||
} | ||
}); | ||
// Handle normal rules | ||
selectors.push(...node.selectors); | ||
} else if (node.type === "atrule") { | ||
// Handle at-rules (which contains nested rules) | ||
node.walkRules((rule)=>selectors.push(...rule.selectors)); | ||
} | ||
for (let selector of selectors){ | ||
let classCandidates = getClasses(selector, ignoreNot); | ||
// At least one of the selectors contains non-"on-demandable" candidates. | ||
if (classCandidates.length === 0) { | ||
state.containsNonOnDemandable = true; | ||
} | ||
for (let selector of node.selectors){ | ||
let classCandidates = getClasses(selector, ignoreNot); | ||
// At least one of the selectors contains non-"on-demandable" candidates. | ||
if (classCandidates.length === 0) { | ||
state.containsNonOnDemandable = true; | ||
} | ||
for (let classCandidate of classCandidates){ | ||
classes.push(classCandidate); | ||
} | ||
for (let classCandidate of classCandidates){ | ||
classes.push(classCandidate); | ||
} | ||
} else if (node.type === "atrule") { | ||
node.walkRules((rule)=>{ | ||
for (let classCandidate of rule.selectors.flatMap((selector)=>getClasses(selector))){ | ||
classes.push(classCandidate); | ||
} | ||
}); | ||
} | ||
@@ -256,7 +286,10 @@ if (depth === 0) { | ||
} | ||
let [, name, params] = /@(.*?)( .+|[({].*)/g.exec(str); | ||
return ({ wrap })=>wrap(_postcss.default.atRule({ | ||
let [, name, params] = /@(\S*)( .+|[({].*)?/g.exec(str); | ||
var _params_trim; | ||
return ({ wrap })=>{ | ||
return wrap(_postcss.default.atRule({ | ||
name, | ||
params: params.trim() | ||
params: (_params_trim = params === null || params === void 0 ? void 0 : params.trim()) !== null && _params_trim !== void 0 ? _params_trim : "" | ||
})); | ||
}; | ||
}).reverse(); | ||
@@ -292,15 +325,9 @@ return (api)=>{ | ||
function resolveThemeValue(path, defaultValue, opts = {}) { | ||
const [pathRoot, ...subPaths] = (0, _toPath.toPath)(path); | ||
const value = getConfigValue([ | ||
let parts = (0, _toPath.toPath)(path); | ||
let value = getConfigValue([ | ||
"theme", | ||
pathRoot, | ||
...subPaths | ||
...parts | ||
], defaultValue); | ||
return (0, _transformThemeValue.default)(pathRoot)(value, opts); | ||
return (0, _transformThemeValue.default)(parts[0])(value, opts); | ||
} | ||
const theme = Object.assign((path, defaultValue = undefined)=>resolveThemeValue(path, defaultValue), { | ||
withAlpha: (path, opacityValue)=>resolveThemeValue(path, undefined, { | ||
opacityValue | ||
}) | ||
}); | ||
let variantIdentifier = 0; | ||
@@ -312,3 +339,3 @@ let api = { | ||
config: getConfigValue, | ||
theme, | ||
theme: resolveThemeValue, | ||
corePlugins: (path)=>{ | ||
@@ -443,3 +470,3 @@ if (Array.isArray(tailwindConfig.corePlugins)) { | ||
} | ||
if (!(0, _isValidArbitraryValue.default)(value)) { | ||
if (!(0, _isSyntacticallyValidPropertyValue.default)(value)) { | ||
return []; | ||
@@ -457,3 +484,3 @@ } | ||
}; | ||
let modifiersEnabled = (0, _featureFlagsJs.flagEnabled)(tailwindConfig, "generalizedModifiers"); | ||
let modifiersEnabled = (0, _featureFlags.flagEnabled)(tailwindConfig, "generalizedModifiers"); | ||
let ruleSets = [].concat(modifiersEnabled ? rule(value, extras) : rule(value)).filter(Boolean).map((declaration)=>({ | ||
@@ -511,3 +538,3 @@ [(0, _nameClass.default)(identifier, modifier)]: declaration | ||
} | ||
if (!(0, _isValidArbitraryValue.default)(value)) { | ||
if (!(0, _isSyntacticallyValidPropertyValue.default)(value)) { | ||
return []; | ||
@@ -525,3 +552,3 @@ } | ||
}; | ||
let modifiersEnabled = (0, _featureFlagsJs.flagEnabled)(tailwindConfig, "generalizedModifiers"); | ||
let modifiersEnabled = (0, _featureFlags.flagEnabled)(tailwindConfig, "generalizedModifiers"); | ||
let ruleSets = [].concat(modifiersEnabled ? rule(value, extras) : rule(value)).filter(Boolean).map((declaration)=>({ | ||
@@ -582,10 +609,10 @@ [(0, _nameClass.default)(identifier, modifier)]: declaration | ||
matchVariant (variant, variantFn, options) { | ||
var ref; | ||
var _options_id; | ||
// A unique identifier that "groups" these variants together. | ||
// This is for internal use only which is why it is not present in the types | ||
let id = (ref = options === null || options === void 0 ? void 0 : options.id) !== null && ref !== void 0 ? ref : ++variantIdentifier; | ||
let id = (_options_id = options === null || options === void 0 ? void 0 : options.id) !== null && _options_id !== void 0 ? _options_id : ++variantIdentifier; | ||
let isSpecial = variant === "@"; | ||
let modifiersEnabled = (0, _featureFlagsJs.flagEnabled)(tailwindConfig, "generalizedModifiers"); | ||
var ref1; | ||
for (let [key, value] of Object.entries((ref1 = options === null || options === void 0 ? void 0 : options.values) !== null && ref1 !== void 0 ? ref1 : {})){ | ||
let modifiersEnabled = (0, _featureFlags.flagEnabled)(tailwindConfig, "generalizedModifiers"); | ||
var _options_values; | ||
for (let [key, value] of Object.entries((_options_values = options === null || options === void 0 ? void 0 : options.values) !== null && _options_values !== void 0 ? _options_values : {})){ | ||
if (key === "DEFAULT") continue; | ||
@@ -607,4 +634,4 @@ api.addVariant(isSpecial ? `${variant}${key}` : `${variant}-${key}`, ({ args , container })=>{ | ||
} | ||
var ref2; | ||
let hasDefault = "DEFAULT" in ((ref2 = options === null || options === void 0 ? void 0 : options.values) !== null && ref2 !== void 0 ? ref2 : {}); | ||
var _options_values1; | ||
let hasDefault = "DEFAULT" in ((_options_values1 = options === null || options === void 0 ? void 0 : options.values) !== null && _options_values1 !== void 0 ? _options_values1 : {}); | ||
api.addVariant(variant, ({ args , container })=>{ | ||
@@ -615,4 +642,4 @@ if ((args === null || args === void 0 ? void 0 : args.value) === _sharedState.NONE && !hasDefault) { | ||
var // (JetBrains) plugins. | ||
ref; | ||
return variantFn((args === null || args === void 0 ? void 0 : args.value) === _sharedState.NONE ? options.values.DEFAULT : (ref = args === null || args === void 0 ? void 0 : args.value) !== null && ref !== void 0 ? ref : typeof args === "string" ? args : "", modifiersEnabled ? { | ||
_args_value; | ||
return variantFn((args === null || args === void 0 ? void 0 : args.value) === _sharedState.NONE ? options.values.DEFAULT : (_args_value = args === null || args === void 0 ? void 0 : args.value) !== null && _args_value !== void 0 ? _args_value : typeof args === "string" ? args : "", modifiersEnabled ? { | ||
modifier: args === null || args === void 0 ? void 0 : args.modifier, | ||
@@ -642,4 +669,5 @@ container | ||
let changed = false; | ||
let mtimesToCommit = new Map(); | ||
for (let file of files){ | ||
var ref; | ||
var _fs_statSync; | ||
if (!file) continue; | ||
@@ -649,5 +677,5 @@ let parsed = _url.default.parse(file); | ||
pathname = parsed.search ? pathname.replace(parsed.search, "") : pathname; | ||
let newModified = (ref = _fs.default.statSync(decodeURIComponent(pathname), { | ||
let newModified = (_fs_statSync = _fs.default.statSync(decodeURIComponent(pathname), { | ||
throwIfNoEntry: false | ||
})) === null || ref === void 0 ? void 0 : ref.mtimeMs; | ||
})) === null || _fs_statSync === void 0 ? void 0 : _fs_statSync.mtimeMs; | ||
if (!newModified) { | ||
@@ -659,5 +687,8 @@ continue; | ||
} | ||
fileModifiedMap.set(file, newModified); | ||
mtimesToCommit.set(file, newModified); | ||
} | ||
return changed; | ||
return [ | ||
changed, | ||
mtimesToCommit | ||
]; | ||
} | ||
@@ -700,5 +731,5 @@ function extractVariantAtRules(node) { | ||
} else if (layerRule.params === "components") { | ||
for (let node1 of layerRule.nodes){ | ||
for (let node of layerRule.nodes){ | ||
layerPlugins.push(function({ addComponents }) { | ||
addComponents(node1, { | ||
addComponents(node, { | ||
respectPrefix: false, | ||
@@ -711,5 +742,5 @@ preserveSource: true | ||
} else if (layerRule.params === "utilities") { | ||
for (let node2 of layerRule.nodes){ | ||
for (let node of layerRule.nodes){ | ||
layerPlugins.push(function({ addUtilities }) { | ||
addUtilities(node2, { | ||
addUtilities(node, { | ||
respectPrefix: false, | ||
@@ -772,3 +803,3 @@ preserveSource: true | ||
context.variantMap = variantMap; | ||
let offsets = new _offsetsJs.Offsets(); | ||
let offsets = new _offsets.Offsets(); | ||
context.offsets = offsets; | ||
@@ -800,4 +831,4 @@ let classList = new Set(); | ||
} | ||
var _safelist; | ||
let safelist = ((_safelist = context.tailwindConfig.safelist) !== null && _safelist !== void 0 ? _safelist : []).filter(Boolean); | ||
var _context_tailwindConfig_safelist; | ||
let safelist = ((_context_tailwindConfig_safelist = context.tailwindConfig.safelist) !== null && _context_tailwindConfig_safelist !== void 0 ? _context_tailwindConfig_safelist : []).filter(Boolean); | ||
if (safelist.length > 0) { | ||
@@ -830,4 +861,4 @@ let checks = []; | ||
let [utilName, options] = util; | ||
var ref; | ||
let values = Object.keys((ref = options === null || options === void 0 ? void 0 : options.values) !== null && ref !== void 0 ? ref : {}); | ||
var _options_values; | ||
let values = Object.keys((_options_values = options === null || options === void 0 ? void 0 : options.values) !== null && _options_values !== void 0 ? _options_values : {}); | ||
let classes = values.map((value)=>(0, _nameClass.formatClass)(utilName, value)); | ||
@@ -866,3 +897,3 @@ if (options === null || options === void 0 ? void 0 : options.supportsNegativeValues) { | ||
]; | ||
for (let util1 of utils){ | ||
for (let util of utils){ | ||
for (let { pattern , variants =[] } of checks){ | ||
@@ -875,6 +906,6 @@ // RegExp with the /g flag are stateful, so let's reset the last | ||
} | ||
if (!pattern.test(util1)) continue; | ||
if (!pattern.test(util)) continue; | ||
patternMatchingCount.set(pattern, patternMatchingCount.get(pattern) + 1); | ||
context.changedContent.push({ | ||
content: util1, | ||
content: util, | ||
extension: "html" | ||
@@ -884,3 +915,3 @@ }); | ||
context.changedContent.push({ | ||
content: variant + context.tailwindConfig.separator + util1, | ||
content: variant + context.tailwindConfig.separator + util, | ||
extension: "html" | ||
@@ -902,4 +933,4 @@ }); | ||
} | ||
var _darkMode, ref; | ||
let darkClassName = (ref = [].concat((_darkMode = context.tailwindConfig.darkMode) !== null && _darkMode !== void 0 ? _darkMode : "media")[1]) !== null && ref !== void 0 ? ref : "dark"; | ||
var _context_tailwindConfig_darkMode, _concat_; | ||
let darkClassName = (_concat_ = [].concat((_context_tailwindConfig_darkMode = context.tailwindConfig.darkMode) !== null && _context_tailwindConfig_darkMode !== void 0 ? _context_tailwindConfig_darkMode : "media")[1]) !== null && _concat_ !== void 0 ? _concat_ : "dark"; | ||
// A list of utilities that are used by certain Tailwind CSS utilities but | ||
@@ -915,4 +946,12 @@ // that don't exist on their own. This will result in them "not existing" and | ||
context.getClassOrder = function getClassOrder(classes) { | ||
// Sort classes so they're ordered in a deterministic manner | ||
let sorted = [ | ||
...classes | ||
].sort((a, z)=>{ | ||
if (a === z) return 0; | ||
if (a < z) return -1; | ||
return 1; | ||
}); | ||
// Non-util classes won't be generated, so we default them to null | ||
let sortedClassNames = new Map(classes.map((className)=>[ | ||
let sortedClassNames = new Map(sorted.map((className)=>[ | ||
className, | ||
@@ -923,11 +962,15 @@ null | ||
// Non-tailwind classes won't be generated and will be left as `null` | ||
let rules = (0, _generateRules.generateRules)(new Set(classes), context); | ||
let rules = (0, _generateRules.generateRules)(new Set(sorted), context, true); | ||
rules = context.offsets.sort(rules); | ||
let idx = BigInt(parasiteUtilities.length); | ||
for (const [, rule] of rules){ | ||
sortedClassNames.set(rule.raws.tailwind.candidate, idx++); | ||
let candidate = rule.raws.tailwind.candidate; | ||
var _sortedClassNames_get; | ||
// When multiple rules match a candidate | ||
// always take the position of the first one | ||
sortedClassNames.set(candidate, (_sortedClassNames_get = sortedClassNames.get(candidate)) !== null && _sortedClassNames_get !== void 0 ? _sortedClassNames_get : idx++); | ||
} | ||
return classes.map((className)=>{ | ||
var ref; | ||
let order = (ref = sortedClassNames.get(className)) !== null && ref !== void 0 ? ref : null; | ||
var _sortedClassNames_get; | ||
let order = (_sortedClassNames_get = sortedClassNames.get(className)) !== null && _sortedClassNames_get !== void 0 ? _sortedClassNames_get : null; | ||
let parasiteIndex = parasiteUtilities.indexOf(className); | ||
@@ -948,10 +991,21 @@ if (order === null && parasiteIndex !== -1) { | ||
// ['uppercase', 'lowercase', ...] | ||
context.getClassList = function getClassList() { | ||
context.getClassList = function getClassList(options = {}) { | ||
let output = []; | ||
for (let util of classList){ | ||
if (Array.isArray(util)) { | ||
let [utilName, options] = util; | ||
var _utilOptions_types; | ||
let [utilName, utilOptions] = util; | ||
let negativeClasses = []; | ||
var ref; | ||
for (let [key, value] of Object.entries((ref = options === null || options === void 0 ? void 0 : options.values) !== null && ref !== void 0 ? ref : {})){ | ||
var _utilOptions_modifiers; | ||
let modifiers = Object.keys((_utilOptions_modifiers = utilOptions === null || utilOptions === void 0 ? void 0 : utilOptions.modifiers) !== null && _utilOptions_modifiers !== void 0 ? _utilOptions_modifiers : {}); | ||
if (utilOptions === null || utilOptions === void 0 ? void 0 : (_utilOptions_types = utilOptions.types) === null || _utilOptions_types === void 0 ? void 0 : _utilOptions_types.some(({ type })=>type === "color")) { | ||
var _context_tailwindConfig_theme_opacity; | ||
modifiers.push(...Object.keys((_context_tailwindConfig_theme_opacity = context.tailwindConfig.theme.opacity) !== null && _context_tailwindConfig_theme_opacity !== void 0 ? _context_tailwindConfig_theme_opacity : {})); | ||
} | ||
let metadata = { | ||
modifiers | ||
}; | ||
let includeMetadata = options.includeMetadata && modifiers.length > 0; | ||
var _utilOptions_values; | ||
for (let [key, value] of Object.entries((_utilOptions_values = utilOptions === null || utilOptions === void 0 ? void 0 : utilOptions.values) !== null && _utilOptions_values !== void 0 ? _utilOptions_values : {})){ | ||
// Ignore undefined and null values | ||
@@ -961,5 +1015,13 @@ if (value == null) { | ||
} | ||
output.push((0, _nameClass.formatClass)(utilName, key)); | ||
if ((options === null || options === void 0 ? void 0 : options.supportsNegativeValues) && (0, _negateValue.default)(value)) { | ||
negativeClasses.push((0, _nameClass.formatClass)(utilName, `-${key}`)); | ||
let cls = (0, _nameClass.formatClass)(utilName, key); | ||
output.push(includeMetadata ? [ | ||
cls, | ||
metadata | ||
] : cls); | ||
if ((utilOptions === null || utilOptions === void 0 ? void 0 : utilOptions.supportsNegativeValues) && (0, _negateValue.default)(value)) { | ||
let cls = (0, _nameClass.formatClass)(utilName, `-${key}`); | ||
negativeClasses.push(includeMetadata ? [ | ||
cls, | ||
metadata | ||
] : cls); | ||
} | ||
@@ -979,7 +1041,7 @@ } | ||
if (options.variantInfo === VARIANT_INFO.Base) continue; | ||
var _values; | ||
var _options_values; | ||
result.push({ | ||
name, | ||
isArbitrary: options.type === Symbol.for("MATCH_VARIANT"), | ||
values: Object.keys((_values = options.values) !== null && _values !== void 0 ? _values : {}), | ||
values: Object.keys((_options_values = options.values) !== null && _options_values !== void 0 ? _options_values : {}), | ||
hasDash: name !== "@", | ||
@@ -997,13 +1059,13 @@ selectors ({ modifier , value } = {}) { | ||
let before = container.toString(); | ||
var ref; | ||
let fns = ((ref = context.variantMap.get(name)) !== null && ref !== void 0 ? ref : []).flatMap(([_, fn])=>fn); | ||
var _context_variantMap_get; | ||
let fns = ((_context_variantMap_get = context.variantMap.get(name)) !== null && _context_variantMap_get !== void 0 ? _context_variantMap_get : []).flatMap(([_, fn])=>fn); | ||
let formatStrings = []; | ||
for (let fn of fns){ | ||
var ref1; | ||
var _options_values; | ||
let localFormatStrings = []; | ||
var ref2; | ||
var _options_values_value; | ||
let api = { | ||
args: { | ||
modifier, | ||
value: (ref2 = (ref1 = options.values) === null || ref1 === void 0 ? void 0 : ref1[value]) !== null && ref2 !== void 0 ? ref2 : value | ||
value: (_options_values_value = (_options_values = options.values) === null || _options_values === void 0 ? void 0 : _options_values[value]) !== null && _options_values_value !== void 0 ? _options_values_value : value | ||
}, | ||
@@ -1059,3 +1121,3 @@ separator: context.tailwindConfig.separator, | ||
// classes, pseudos, ids, ... | ||
let rebuiltBase = (0, _postcssSelectorParser.default)((selectors)=>{ | ||
let rebuiltBase = (0, _postcssselectorparser.default)((selectors)=>{ | ||
selectors.walkClasses((classNode)=>{ | ||
@@ -1083,11 +1145,26 @@ classNode.value = `${name}${context.tailwindConfig.separator}${classNode.value}`; | ||
} | ||
var _values; | ||
let result = formatStrings.map((formatString)=>(0, _formatVariantSelector.finalizeSelector)((0, _formatVariantSelector.formatVariantSelector)("&", ...formatString), { | ||
selector: `.${candidate}`, | ||
candidate, | ||
context, | ||
isArbitraryVariant: !(value in ((_values = options.values) !== null && _values !== void 0 ? _values : {})) | ||
}).replace(`.${candidate}`, "&").replace("{ & }", "").trim()); | ||
var _options_values1; | ||
let isArbitraryVariant = !(value in ((_options_values1 = options.values) !== null && _options_values1 !== void 0 ? _options_values1 : {})); | ||
var _options_INTERNAL_FEATURES; | ||
let internalFeatures = (_options_INTERNAL_FEATURES = options[INTERNAL_FEATURES]) !== null && _options_INTERNAL_FEATURES !== void 0 ? _options_INTERNAL_FEATURES : {}; | ||
let respectPrefix = (()=>{ | ||
if (isArbitraryVariant) return false; | ||
if (internalFeatures.respectPrefix === false) return false; | ||
return true; | ||
})(); | ||
formatStrings = formatStrings.map((format)=>format.map((str)=>({ | ||
format: str, | ||
respectPrefix | ||
}))); | ||
manualFormatStrings = manualFormatStrings.map((format)=>({ | ||
format, | ||
respectPrefix | ||
})); | ||
let opts = { | ||
candidate, | ||
context | ||
}; | ||
let result = formatStrings.map((formats)=>(0, _formatVariantSelector.finalizeSelector)(`.${candidate}`, (0, _formatVariantSelector.formatVariantSelector)(formats, opts), opts).replace(`.${candidate}`, "&").replace("{ & }", "").trim()); | ||
if (manualFormatStrings.length > 0) { | ||
result.push((0, _formatVariantSelector.formatVariantSelector)("&", ...manualFormatStrings)); | ||
result.push((0, _formatVariantSelector.formatVariantSelector)(manualFormatStrings, opts).toString().replace(`.${candidate}`, "&")); | ||
} | ||
@@ -1138,3 +1215,3 @@ return result; | ||
function createContext(tailwindConfig, changedContent = [], root = _postcss.default.root()) { | ||
var _blocklist; | ||
var _tailwindConfig_blocklist; | ||
let context = { | ||
@@ -1147,3 +1224,3 @@ disposables: [], | ||
// Seed the not class cache with the blocklist (which is only strings) | ||
notClassCache: new Set((_blocklist = tailwindConfig.blocklist) !== null && _blocklist !== void 0 ? _blocklist : []), | ||
notClassCache: new Set((_tailwindConfig_blocklist = tailwindConfig.blocklist) !== null && _tailwindConfig_blocklist !== void 0 ? _tailwindConfig_blocklist : []), | ||
postCssNodeCache: new Map(), | ||
@@ -1179,7 +1256,7 @@ candidateRuleMap: new Map(), | ||
} | ||
let cssDidChange = (0, _cacheInvalidationJs.hasContentChanged)(sourcePath, root); | ||
let cssDidChange = (0, _cacheInvalidation.hasContentChanged)(sourcePath, root); | ||
// If there's already a context in the cache and we don't need to | ||
// reset the context, return the cached context. | ||
if (existingContext) { | ||
let contextDependenciesChanged = trackModified([ | ||
let [contextDependenciesChanged, mtimesToCommit] = trackModified([ | ||
...contextDependencies | ||
@@ -1190,3 +1267,4 @@ ], getFileModifiedMap(existingContext)); | ||
existingContext, | ||
false | ||
false, | ||
mtimesToCommit | ||
]; | ||
@@ -1206,5 +1284,5 @@ } | ||
contextSourcesMap.delete(oldContext); | ||
for (let [tailwindConfigHash1, context1] of configContextMap){ | ||
if (context1 === oldContext) { | ||
configContextMap.delete(tailwindConfigHash1); | ||
for (let [tailwindConfigHash, context] of configContextMap){ | ||
if (context === oldContext) { | ||
configContextMap.delete(tailwindConfigHash); | ||
} | ||
@@ -1219,21 +1297,22 @@ } | ||
_sharedState.env.DEBUG && console.log("Setting up new context..."); | ||
let context2 = createContext(tailwindConfig, [], root); | ||
Object.assign(context2, { | ||
let context = createContext(tailwindConfig, [], root); | ||
Object.assign(context, { | ||
userConfigPath | ||
}); | ||
trackModified([ | ||
let [, mtimesToCommit] = trackModified([ | ||
...contextDependencies | ||
], getFileModifiedMap(context2)); | ||
], getFileModifiedMap(context)); | ||
// --- | ||
// Update all context tracking state | ||
configContextMap.set(tailwindConfigHash, context2); | ||
contextMap.set(sourcePath, context2); | ||
if (!contextSourcesMap.has(context2)) { | ||
contextSourcesMap.set(context2, new Set()); | ||
configContextMap.set(tailwindConfigHash, context); | ||
contextMap.set(sourcePath, context); | ||
if (!contextSourcesMap.has(context)) { | ||
contextSourcesMap.set(context, new Set()); | ||
} | ||
contextSourcesMap.get(context2).add(sourcePath); | ||
contextSourcesMap.get(context).add(sourcePath); | ||
return [ | ||
context2, | ||
true | ||
context, | ||
true, | ||
mtimesToCommit | ||
]; | ||
} |
@@ -0,1 +1,2 @@ | ||
// @ts-check | ||
"use strict"; | ||
@@ -11,15 +12,18 @@ Object.defineProperty(exports, "__esModule", { | ||
enumerable: true, | ||
get: ()=>setupTrackingContext | ||
get: function() { | ||
return setupTrackingContext; | ||
} | ||
}); | ||
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs")); | ||
const _quickLru = /*#__PURE__*/ _interopRequireDefault(require("quick-lru")); | ||
const _hashConfig = /*#__PURE__*/ _interopRequireDefault(require("../util/hashConfig")); | ||
const _getModuleDependencies = /*#__PURE__*/ _interopRequireDefault(require("../lib/getModuleDependencies")); | ||
const _resolveConfig = /*#__PURE__*/ _interopRequireDefault(require("../public/resolve-config")); | ||
const _resolveConfigPath = /*#__PURE__*/ _interopRequireDefault(require("../util/resolveConfigPath")); | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _quicklru = /*#__PURE__*/ _interop_require_default(require("@alloc/quick-lru")); | ||
const _hashConfig = /*#__PURE__*/ _interop_require_default(require("../util/hashConfig")); | ||
const _resolveconfig = /*#__PURE__*/ _interop_require_default(require("../public/resolve-config")); | ||
const _resolveConfigPath = /*#__PURE__*/ _interop_require_default(require("../util/resolveConfigPath")); | ||
const _setupContextUtils = require("./setupContextUtils"); | ||
const _parseDependency = /*#__PURE__*/ _interopRequireDefault(require("../util/parseDependency")); | ||
const _validateConfigJs = require("../util/validateConfig.js"); | ||
const _contentJs = require("./content.js"); | ||
function _interopRequireDefault(obj) { | ||
const _parseDependency = /*#__PURE__*/ _interop_require_default(require("../util/parseDependency")); | ||
const _validateConfig = require("../util/validateConfig.js"); | ||
const _content = require("./content.js"); | ||
const _loadconfig = require("../lib/load-config"); | ||
const _getModuleDependencies = /*#__PURE__*/ _interop_require_default(require("./getModuleDependencies")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -29,3 +33,3 @@ default: obj | ||
} | ||
let configPathCache = new _quickLru.default({ | ||
let configPathCache = new _quicklru.default({ | ||
maxSize: 100 | ||
@@ -38,3 +42,3 @@ }); | ||
} | ||
let candidateFiles = (0, _contentJs.parseCandidateFiles)(context, tailwindConfig); | ||
let candidateFiles = (0, _content.parseCandidateFiles)(context, tailwindConfig); | ||
return candidateFilesCache.set(context, candidateFiles).get(context); | ||
@@ -47,3 +51,3 @@ } | ||
let [prevConfig, prevConfigHash, prevDeps, prevModified] = configPathCache.get(userConfigPath) || []; | ||
let newDeps = (0, _getModuleDependencies.default)(userConfigPath).map((dep)=>dep.file); | ||
let newDeps = (0, _getModuleDependencies.default)(userConfigPath); | ||
let modified = false; | ||
@@ -68,7 +72,6 @@ let newModified = new Map(); | ||
// It has changed (based on timestamps), or first run | ||
for (let file1 of newDeps){ | ||
delete require.cache[file1]; | ||
for (let file of newDeps){ | ||
delete require.cache[file]; | ||
} | ||
let newConfig = (0, _resolveConfig.default)(require(userConfigPath)); | ||
newConfig = (0, _validateConfigJs.validateConfig)(newConfig); | ||
let newConfig = (0, _validateConfig.validateConfig)((0, _resolveconfig.default)((0, _loadconfig.loadConfig)(userConfigPath))); | ||
let newHash = (0, _hashConfig.default)(newConfig); | ||
@@ -88,9 +91,10 @@ configPathCache.set(userConfigPath, [ | ||
} | ||
var _configOrPath_config, _ref; | ||
// It's a plain object, not a path | ||
let newConfig1 = (0, _resolveConfig.default)(configOrPath.config === undefined ? configOrPath : configOrPath.config); | ||
newConfig1 = (0, _validateConfigJs.validateConfig)(newConfig1); | ||
let newConfig = (0, _resolveconfig.default)((_ref = (_configOrPath_config = configOrPath === null || configOrPath === void 0 ? void 0 : configOrPath.config) !== null && _configOrPath_config !== void 0 ? _configOrPath_config : configOrPath) !== null && _ref !== void 0 ? _ref : {}); | ||
newConfig = (0, _validateConfig.validateConfig)(newConfig); | ||
return [ | ||
newConfig1, | ||
newConfig, | ||
null, | ||
(0, _hashConfig.default)(newConfig1), | ||
(0, _hashConfig.default)(newConfig), | ||
[] | ||
@@ -120,3 +124,4 @@ ]; | ||
} | ||
let [context] = (0, _setupContextUtils.getContext)(root, result, tailwindConfig, userConfigPath, tailwindConfigHash, contextDependencies); | ||
let [context, , mTimesToCommit] = (0, _setupContextUtils.getContext)(root, result, tailwindConfig, userConfigPath, tailwindConfigHash, contextDependencies); | ||
let fileModifiedMap = (0, _setupContextUtils.getFileModifiedMap)(context); | ||
let candidateFiles = getCandidateFiles(context, tailwindConfig); | ||
@@ -129,3 +134,2 @@ // If there are no @tailwind or @apply rules, we don't consider this CSS file or it's | ||
if (tailwindDirectives.size > 0) { | ||
let fileModifiedMap = (0, _setupContextUtils.getFileModifiedMap)(context); | ||
// Add template paths as postcss dependencies. | ||
@@ -137,5 +141,19 @@ for (let contentPath of candidateFiles){ | ||
} | ||
for (let changedContent of (0, _contentJs.resolvedChangedContent)(context, candidateFiles, fileModifiedMap)){ | ||
context.changedContent.push(changedContent); | ||
let [changedContent, contentMTimesToCommit] = (0, _content.resolvedChangedContent)(context, candidateFiles, fileModifiedMap); | ||
for (let content of changedContent){ | ||
context.changedContent.push(content); | ||
} | ||
// Add the mtimes of the content files to the commit list | ||
// We can overwrite the existing values because unconditionally | ||
// This is because: | ||
// 1. Most of the files here won't be in the map yet | ||
// 2. If they are that means it's a context dependency | ||
// and we're reading this after the context. This means | ||
// that the mtime we just read is strictly >= the context | ||
// mtime. Unless the user / os is doing something weird | ||
// in which the mtime would be going backwards. If that | ||
// happens there's already going to be problems. | ||
for (let [path, mtime] of contentMTimesToCommit.entries()){ | ||
mTimesToCommit.set(path, mtime); | ||
} | ||
} | ||
@@ -148,2 +166,8 @@ for (let file of configDependencies){ | ||
} | ||
// "commit" the new modified time for all context deps | ||
// We do this here because we want content tracking to | ||
// read the "old" mtime even when it's a context dependency. | ||
for (let [path, mtime] of mTimesToCommit.entries()){ | ||
fileModifiedMap.set(path, mtime); | ||
} | ||
return context; | ||
@@ -150,0 +174,0 @@ }; |
@@ -12,14 +12,41 @@ "use strict"; | ||
_export(exports, { | ||
env: ()=>env, | ||
contextMap: ()=>contextMap, | ||
configContextMap: ()=>configContextMap, | ||
contextSourcesMap: ()=>contextSourcesMap, | ||
sourceHashMap: ()=>sourceHashMap, | ||
NOT_ON_DEMAND: ()=>NOT_ON_DEMAND, | ||
NONE: ()=>NONE, | ||
resolveDebug: ()=>resolveDebug | ||
env: function() { | ||
return env; | ||
}, | ||
contextMap: function() { | ||
return contextMap; | ||
}, | ||
configContextMap: function() { | ||
return configContextMap; | ||
}, | ||
contextSourcesMap: function() { | ||
return contextSourcesMap; | ||
}, | ||
sourceHashMap: function() { | ||
return sourceHashMap; | ||
}, | ||
NOT_ON_DEMAND: function() { | ||
return NOT_ON_DEMAND; | ||
}, | ||
NONE: function() { | ||
return NONE; | ||
}, | ||
resolveDebug: function() { | ||
return resolveDebug; | ||
} | ||
}); | ||
const env = { | ||
const _packagejson = /*#__PURE__*/ _interop_require_default(require("../../package.json")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
default: obj | ||
}; | ||
} | ||
const env = typeof process !== "undefined" ? { | ||
NODE_ENV: process.env.NODE_ENV, | ||
DEBUG: resolveDebug(process.env.DEBUG) | ||
DEBUG: resolveDebug(process.env.DEBUG), | ||
ENGINE: _packagejson.default.tailwindcss.engine | ||
} : { | ||
NODE_ENV: "production", | ||
DEBUG: false, | ||
ENGINE: _packagejson.default.tailwindcss.engine | ||
}; | ||
@@ -26,0 +53,0 @@ const contextMap = new Map(); |
@@ -7,7 +7,9 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
const _normalizeScreens = require("../util/normalizeScreens"); | ||
const _buildMediaQuery = /*#__PURE__*/ _interopRequireDefault(require("../util/buildMediaQuery")); | ||
function _interopRequireDefault(obj) { | ||
const _buildMediaQuery = /*#__PURE__*/ _interop_require_default(require("../util/buildMediaQuery")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -14,0 +16,0 @@ default: obj |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ const _plugin = require("./plugin"); |
@@ -7,7 +7,9 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>nesting | ||
get: function() { | ||
return nesting; | ||
} | ||
}); | ||
const _postcss = /*#__PURE__*/ _interopRequireDefault(require("postcss")); | ||
const _postcssNested = /*#__PURE__*/ _interopRequireDefault(require("postcss-nested")); | ||
function _interopRequireDefault(obj) { | ||
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss")); | ||
const _postcssnested = /*#__PURE__*/ _interop_require_default(require("postcss-nested")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -17,3 +19,3 @@ default: obj | ||
} | ||
function nesting(opts = _postcssNested.default) { | ||
function nesting(opts = _postcssnested.default) { | ||
return (root, result)=>{ | ||
@@ -33,4 +35,4 @@ root.walkAtRules("screen", (rule)=>{ | ||
let plugin = (()=>{ | ||
var ref; | ||
if (typeof opts === "function" || typeof opts === "object" && (opts === null || opts === void 0 ? void 0 : (ref = opts.hasOwnProperty) === null || ref === void 0 ? void 0 : ref.call(opts, "postcssPlugin"))) { | ||
var _opts_hasOwnProperty; | ||
if (typeof opts === "function" || typeof opts === "object" && (opts === null || opts === void 0 ? void 0 : (_opts_hasOwnProperty = opts.hasOwnProperty) === null || _opts_hasOwnProperty === void 0 ? void 0 : _opts_hasOwnProperty.call(opts, "postcssPlugin"))) { | ||
return opts; | ||
@@ -42,3 +44,3 @@ } | ||
if (Object.keys(opts).length <= 0) { | ||
return _postcssNested.default; | ||
return _postcssnested.default; | ||
} | ||
@@ -45,0 +47,0 @@ throw new Error("tailwindcss/nesting should be loaded with a nesting plugin."); |
@@ -7,17 +7,19 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>processTailwindFeatures | ||
get: function() { | ||
return processTailwindFeatures; | ||
} | ||
}); | ||
const _normalizeTailwindDirectives = /*#__PURE__*/ _interopRequireDefault(require("./lib/normalizeTailwindDirectives")); | ||
const _expandTailwindAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandTailwindAtRules")); | ||
const _expandApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandApplyAtRules")); | ||
const _evaluateTailwindFunctions = /*#__PURE__*/ _interopRequireDefault(require("./lib/evaluateTailwindFunctions")); | ||
const _substituteScreenAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/substituteScreenAtRules")); | ||
const _resolveDefaultsAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/resolveDefaultsAtRules")); | ||
const _collapseAdjacentRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseAdjacentRules")); | ||
const _collapseDuplicateDeclarations = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseDuplicateDeclarations")); | ||
const _partitionApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/partitionApplyAtRules")); | ||
const _detectNesting = /*#__PURE__*/ _interopRequireDefault(require("./lib/detectNesting")); | ||
const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); | ||
const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); | ||
const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); | ||
const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); | ||
const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); | ||
const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); | ||
const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); | ||
const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); | ||
const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); | ||
const _detectNesting = /*#__PURE__*/ _interop_require_default(require("./lib/detectNesting")); | ||
const _setupContextUtils = require("./lib/setupContextUtils"); | ||
const _featureFlags = require("./featureFlags"); | ||
function _interopRequireDefault(obj) { | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -28,3 +30,3 @@ default: obj | ||
function processTailwindFeatures(setupContext) { | ||
return function(root, result) { | ||
return async function(root, result) { | ||
let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); | ||
@@ -53,3 +55,3 @@ (0, _detectNesting.default)()(root, result); | ||
(0, _featureFlags.issueFlagNotices)(context.tailwindConfig); | ||
(0, _expandTailwindAtRules.default)(context)(root, result); | ||
await (0, _expandTailwindAtRules.default)(context)(root, result); | ||
// Partition apply rules that are generated by | ||
@@ -56,0 +58,0 @@ // addComponents, addUtilities and so on. |
@@ -7,6 +7,8 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
const _log = /*#__PURE__*/ _interopRequireDefault(require("../util/log")); | ||
function _interopRequireDefault(obj) { | ||
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -38,3 +40,4 @@ default: obj | ||
800: "#1e293b", | ||
900: "#0f172a" | ||
900: "#0f172a", | ||
950: "#020617" | ||
}, | ||
@@ -51,3 +54,4 @@ gray: { | ||
800: "#1f2937", | ||
900: "#111827" | ||
900: "#111827", | ||
950: "#030712" | ||
}, | ||
@@ -64,3 +68,4 @@ zinc: { | ||
800: "#27272a", | ||
900: "#18181b" | ||
900: "#18181b", | ||
950: "#09090b" | ||
}, | ||
@@ -77,3 +82,4 @@ neutral: { | ||
800: "#262626", | ||
900: "#171717" | ||
900: "#171717", | ||
950: "#0a0a0a" | ||
}, | ||
@@ -90,3 +96,4 @@ stone: { | ||
800: "#292524", | ||
900: "#1c1917" | ||
900: "#1c1917", | ||
950: "#0c0a09" | ||
}, | ||
@@ -103,3 +110,4 @@ red: { | ||
800: "#991b1b", | ||
900: "#7f1d1d" | ||
900: "#7f1d1d", | ||
950: "#450a0a" | ||
}, | ||
@@ -116,3 +124,4 @@ orange: { | ||
800: "#9a3412", | ||
900: "#7c2d12" | ||
900: "#7c2d12", | ||
950: "#431407" | ||
}, | ||
@@ -129,3 +138,4 @@ amber: { | ||
800: "#92400e", | ||
900: "#78350f" | ||
900: "#78350f", | ||
950: "#451a03" | ||
}, | ||
@@ -142,3 +152,4 @@ yellow: { | ||
800: "#854d0e", | ||
900: "#713f12" | ||
900: "#713f12", | ||
950: "#422006" | ||
}, | ||
@@ -155,3 +166,4 @@ lime: { | ||
800: "#3f6212", | ||
900: "#365314" | ||
900: "#365314", | ||
950: "#1a2e05" | ||
}, | ||
@@ -168,3 +180,4 @@ green: { | ||
800: "#166534", | ||
900: "#14532d" | ||
900: "#14532d", | ||
950: "#052e16" | ||
}, | ||
@@ -181,3 +194,4 @@ emerald: { | ||
800: "#065f46", | ||
900: "#064e3b" | ||
900: "#064e3b", | ||
950: "#022c22" | ||
}, | ||
@@ -194,3 +208,4 @@ teal: { | ||
800: "#115e59", | ||
900: "#134e4a" | ||
900: "#134e4a", | ||
950: "#042f2e" | ||
}, | ||
@@ -207,3 +222,4 @@ cyan: { | ||
800: "#155e75", | ||
900: "#164e63" | ||
900: "#164e63", | ||
950: "#083344" | ||
}, | ||
@@ -220,3 +236,4 @@ sky: { | ||
800: "#075985", | ||
900: "#0c4a6e" | ||
900: "#0c4a6e", | ||
950: "#082f49" | ||
}, | ||
@@ -233,3 +250,4 @@ blue: { | ||
800: "#1e40af", | ||
900: "#1e3a8a" | ||
900: "#1e3a8a", | ||
950: "#172554" | ||
}, | ||
@@ -246,3 +264,4 @@ indigo: { | ||
800: "#3730a3", | ||
900: "#312e81" | ||
900: "#312e81", | ||
950: "#1e1b4b" | ||
}, | ||
@@ -259,3 +278,4 @@ violet: { | ||
800: "#5b21b6", | ||
900: "#4c1d95" | ||
900: "#4c1d95", | ||
950: "#2e1065" | ||
}, | ||
@@ -272,3 +292,4 @@ purple: { | ||
800: "#6b21a8", | ||
900: "#581c87" | ||
900: "#581c87", | ||
950: "#3b0764" | ||
}, | ||
@@ -285,3 +306,4 @@ fuchsia: { | ||
800: "#86198f", | ||
900: "#701a75" | ||
900: "#701a75", | ||
950: "#4a044e" | ||
}, | ||
@@ -298,3 +320,4 @@ pink: { | ||
800: "#9d174d", | ||
900: "#831843" | ||
900: "#831843", | ||
950: "#500724" | ||
}, | ||
@@ -311,3 +334,4 @@ rose: { | ||
800: "#9f1239", | ||
900: "#881337" | ||
900: "#881337", | ||
950: "#4c0519" | ||
}, | ||
@@ -314,0 +338,0 @@ get lightBlue () { |
@@ -7,6 +7,8 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
const _createPlugin = /*#__PURE__*/ _interopRequireDefault(require("../util/createPlugin")); | ||
function _interopRequireDefault(obj) { | ||
const _createPlugin = /*#__PURE__*/ _interop_require_default(require("../util/createPlugin")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -13,0 +15,0 @@ default: obj |
@@ -7,7 +7,9 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
const _cloneDeep = require("../util/cloneDeep"); | ||
const _defaultConfigStub = /*#__PURE__*/ _interopRequireDefault(require("../../stubs/defaultConfig.stub")); | ||
function _interopRequireDefault(obj) { | ||
const _configfull = /*#__PURE__*/ _interop_require_default(require("../../stubs/config.full")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -17,2 +19,2 @@ default: obj | ||
} | ||
const _default = (0, _cloneDeep.cloneDeep)(_defaultConfigStub.default); | ||
const _default = (0, _cloneDeep.cloneDeep)(_configfull.default); |
@@ -7,7 +7,9 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
const _cloneDeep = require("../util/cloneDeep"); | ||
const _defaultConfigStub = /*#__PURE__*/ _interopRequireDefault(require("../../stubs/defaultConfig.stub")); | ||
function _interopRequireDefault(obj) { | ||
const _configfull = /*#__PURE__*/ _interop_require_default(require("../../stubs/config.full")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -17,2 +19,2 @@ default: obj | ||
} | ||
const _default = (0, _cloneDeep.cloneDeep)(_defaultConfigStub.default.theme); | ||
const _default = (0, _cloneDeep.cloneDeep)(_configfull.default.theme); |
@@ -7,7 +7,9 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>resolveConfig | ||
get: function() { | ||
return resolveConfig; | ||
} | ||
}); | ||
const _resolveConfig = /*#__PURE__*/ _interopRequireDefault(require("../util/resolveConfig")); | ||
const _getAllConfigs = /*#__PURE__*/ _interopRequireDefault(require("../util/getAllConfigs")); | ||
function _interopRequireDefault(obj) { | ||
const _resolveConfig = /*#__PURE__*/ _interop_require_default(require("../util/resolveConfig")); | ||
const _getAllConfigs = /*#__PURE__*/ _interop_require_default(require("../util/getAllConfigs")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -14,0 +16,0 @@ default: obj |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>bigSign | ||
get: function() { | ||
return bigSign; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ function bigSign(bigIntValue) { |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>buildMediaQuery | ||
get: function() { | ||
return buildMediaQuery; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ function buildMediaQuery(screens) { |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>cloneDeep | ||
get: function() { | ||
return cloneDeep; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ function cloneDeep(value) { |
@@ -1,2 +0,7 @@ | ||
"use strict"; | ||
/** | ||
* @param {import('postcss').Container[]} nodes | ||
* @param {any} source | ||
* @param {any} raws | ||
* @returns {import('postcss').Container[]} | ||
*/ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
@@ -7,19 +12,9 @@ value: true | ||
enumerable: true, | ||
get: ()=>cloneNodes | ||
get: function() { | ||
return cloneNodes; | ||
} | ||
}); | ||
function cloneNodes(nodes, source = undefined, raws = undefined) { | ||
return nodes.map((node)=>{ | ||
var ref; | ||
let cloned = node.clone(); | ||
// We always want override the source map | ||
// except when explicitly told not to | ||
let shouldOverwriteSource = ((ref = node.raws.tailwind) === null || ref === void 0 ? void 0 : ref.preserveSource) !== true || !cloned.source; | ||
if (source !== undefined && shouldOverwriteSource) { | ||
cloned.source = source; | ||
if ("walk" in cloned) { | ||
cloned.walk((child)=>{ | ||
child.source = source; | ||
}); | ||
} | ||
} | ||
if (raws !== undefined) { | ||
@@ -31,4 +26,31 @@ cloned.raws.tailwind = { | ||
} | ||
if (source !== undefined) { | ||
traverse(cloned, (node)=>{ | ||
var _node_raws_tailwind; | ||
// Do not traverse nodes that have opted | ||
// to preserve their original source | ||
let shouldPreserveSource = ((_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.preserveSource) === true && node.source; | ||
if (shouldPreserveSource) { | ||
return false; | ||
} | ||
// Otherwise we can safely replace the source | ||
// And continue traversing | ||
node.source = source; | ||
}); | ||
} | ||
return cloned; | ||
}); | ||
} | ||
/** | ||
* Traverse a tree of nodes and don't traverse children if the callback | ||
* returns false. Ideally we'd use Container#walk instead of this | ||
* function but it stops traversing siblings too. | ||
* | ||
* @param {import('postcss').Container} node | ||
* @param {(node: import('postcss').Container) => boolean} onNode | ||
*/ function traverse(node, onNode) { | ||
if (onNode(node) !== false) { | ||
var _node_each; | ||
(_node_each = node.each) === null || _node_each === void 0 ? void 0 : _node_each.call(node, (child)=>traverse(child, onNode)); | ||
} | ||
} |
@@ -12,7 +12,11 @@ "use strict"; | ||
_export(exports, { | ||
parseColor: ()=>parseColor, | ||
formatColor: ()=>formatColor | ||
parseColor: function() { | ||
return parseColor; | ||
}, | ||
formatColor: function() { | ||
return formatColor; | ||
} | ||
}); | ||
const _colorName = /*#__PURE__*/ _interopRequireDefault(require("color-name")); | ||
function _interopRequireDefault(obj) { | ||
const _colorNames = /*#__PURE__*/ _interop_require_default(require("./colorNames")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -27,7 +31,7 @@ default: obj | ||
let ALPHA_SEP = /\s*[,/]\s*/; | ||
let CUSTOM_PROPERTY = /var\(--(?:[^ )]*?)\)/; | ||
let RGB = new RegExp(`^(rgb)a?\\(\\s*(${VALUE.source}|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$`); | ||
let HSL = new RegExp(`^(hsl)a?\\(\\s*((?:${VALUE.source})(?:deg|rad|grad|turn)?|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$`); | ||
let CUSTOM_PROPERTY = /var\(--(?:[^ )]*?)(?:,(?:[^ )]*?|var\(--[^ )]*?\)))?\)/; | ||
let RGB = new RegExp(`^(rgba?)\\(\\s*(${VALUE.source}|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$`); | ||
let HSL = new RegExp(`^(hsla?)\\(\\s*((?:${VALUE.source})(?:deg|rad|grad|turn)?|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$`); | ||
function parseColor(value, { loose =false } = {}) { | ||
var ref, ref1; | ||
var _match_, _match__toString; | ||
if (typeof value !== "string") { | ||
@@ -48,6 +52,6 @@ return null; | ||
} | ||
if (value in _colorName.default) { | ||
if (value in _colorNames.default) { | ||
return { | ||
mode: "rgb", | ||
color: _colorName.default[value].map((v)=>v.toString()) | ||
color: _colorNames.default[value].map((v)=>v.toString()) | ||
}; | ||
@@ -76,4 +80,4 @@ } | ||
} | ||
var ref2; | ||
let match = (ref2 = value.match(RGB)) !== null && ref2 !== void 0 ? ref2 : value.match(HSL); | ||
var _value_match; | ||
let match = (_value_match = value.match(RGB)) !== null && _value_match !== void 0 ? _value_match : value.match(HSL); | ||
if (match === null) { | ||
@@ -87,2 +91,13 @@ return null; | ||
].filter(Boolean).map((v)=>v.toString()); | ||
// rgba(var(--my-color), 0.1) | ||
// hsla(var(--my-color), 0.1) | ||
if (color.length === 2 && color[0].startsWith("var(")) { | ||
return { | ||
mode: match[1], | ||
color: [ | ||
color[0] | ||
], | ||
alpha: color[1] | ||
}; | ||
} | ||
if (!loose && color.length !== 3) { | ||
@@ -97,3 +112,3 @@ return null; | ||
color, | ||
alpha: (ref = match[5]) === null || ref === void 0 ? void 0 : (ref1 = ref.toString) === null || ref1 === void 0 ? void 0 : ref1.call(ref) | ||
alpha: (_match_ = match[5]) === null || _match_ === void 0 ? void 0 : (_match__toString = _match_.toString) === null || _match__toString === void 0 ? void 0 : _match__toString.call(_match_) | ||
}; | ||
@@ -103,3 +118,6 @@ } | ||
let hasAlpha = alpha !== undefined; | ||
if (mode === "rgba" || mode === "hsla") { | ||
return `${mode}(${color.join(", ")}${hasAlpha ? `, ${alpha}` : ""})`; | ||
} | ||
return `${mode}(${color.join(" ")}${hasAlpha ? ` / ${alpha}` : ""})`; | ||
} |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ function _default(pluginConfig, plugins) { |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ function createPlugin(plugin, config) { |
@@ -7,6 +7,8 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>createUtilityPlugin | ||
get: function() { | ||
return createUtilityPlugin; | ||
} | ||
}); | ||
const _transformThemeValue = /*#__PURE__*/ _interopRequireDefault(require("./transformThemeValue")); | ||
function _interopRequireDefault(obj) { | ||
const _transformThemeValue = /*#__PURE__*/ _interop_require_default(require("./transformThemeValue")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -30,3 +32,3 @@ default: obj | ||
]; | ||
var ref; | ||
var _theme; | ||
matchUtilities(group.reduce((obj, [classPrefix, properties])=>{ | ||
@@ -49,3 +51,3 @@ return Object.assign(obj, { | ||
...options, | ||
values: filterDefault ? Object.fromEntries(Object.entries((ref = theme(themeKey)) !== null && ref !== void 0 ? ref : {}).filter(([modifier])=>modifier !== "DEFAULT")) : theme(themeKey) | ||
values: filterDefault ? Object.fromEntries(Object.entries((_theme = theme(themeKey)) !== null && _theme !== void 0 ? _theme : {}).filter(([modifier])=>modifier !== "DEFAULT")) : theme(themeKey) | ||
}); | ||
@@ -52,0 +54,0 @@ } |
@@ -12,17 +12,47 @@ "use strict"; | ||
_export(exports, { | ||
normalize: ()=>normalize, | ||
url: ()=>url, | ||
number: ()=>number, | ||
percentage: ()=>percentage, | ||
length: ()=>length, | ||
lineWidth: ()=>lineWidth, | ||
shadow: ()=>shadow, | ||
color: ()=>color, | ||
image: ()=>image, | ||
gradient: ()=>gradient, | ||
position: ()=>position, | ||
familyName: ()=>familyName, | ||
genericName: ()=>genericName, | ||
absoluteSize: ()=>absoluteSize, | ||
relativeSize: ()=>relativeSize | ||
normalize: function() { | ||
return normalize; | ||
}, | ||
url: function() { | ||
return url; | ||
}, | ||
number: function() { | ||
return number; | ||
}, | ||
percentage: function() { | ||
return percentage; | ||
}, | ||
length: function() { | ||
return length; | ||
}, | ||
lineWidth: function() { | ||
return lineWidth; | ||
}, | ||
shadow: function() { | ||
return shadow; | ||
}, | ||
color: function() { | ||
return color; | ||
}, | ||
image: function() { | ||
return image; | ||
}, | ||
gradient: function() { | ||
return gradient; | ||
}, | ||
position: function() { | ||
return position; | ||
}, | ||
familyName: function() { | ||
return familyName; | ||
}, | ||
genericName: function() { | ||
return genericName; | ||
}, | ||
absoluteSize: function() { | ||
return absoluteSize; | ||
}, | ||
relativeSize: function() { | ||
return relativeSize; | ||
} | ||
}); | ||
@@ -42,3 +72,28 @@ const _color = require("./color"); | ||
} | ||
function normalize(value, isRoot = true) { | ||
// These properties accept a `<dashed-ident>` as one of the values. This means that you can use them | ||
// as: `timeline-scope: --tl;` | ||
// | ||
// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add | ||
// the `var()` yourself. | ||
// | ||
// More info: | ||
// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope | ||
// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident | ||
// | ||
const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ | ||
// Concrete properties | ||
"scroll-timeline-name", | ||
"timeline-scope", | ||
"view-timeline-name", | ||
"font-palette", | ||
// Shorthand properties | ||
"scroll-timeline", | ||
"animation-timeline", | ||
"view-timeline" | ||
]); | ||
function normalize(value, context = null, isRoot = true) { | ||
let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); | ||
if (value.startsWith("--") && !isVarException) { | ||
return `var(${value})`; | ||
} | ||
// Keep raw strings if it starts with `url(` | ||
@@ -50,3 +105,3 @@ if (value.includes("url(")) { | ||
} | ||
return normalize(part, false); | ||
return normalize(part, context, false); | ||
}).join(""); | ||
@@ -60,9 +115,101 @@ } | ||
} | ||
// Add spaces around operators inside math functions like calc() that do not follow an operator | ||
// or '('. | ||
value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ | ||
return match.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 "); | ||
}); | ||
value = normalizeMathOperatorSpacing(value); | ||
return value; | ||
} | ||
/** | ||
* Add spaces around operators inside math functions | ||
* like calc() that do not follow an operator, '(', or `,`. | ||
* | ||
* @param {string} value | ||
* @returns {string} | ||
*/ function normalizeMathOperatorSpacing(value) { | ||
let preventFormattingInFunctions = [ | ||
"theme" | ||
]; | ||
let preventFormattingKeywords = [ | ||
"min-content", | ||
"max-content", | ||
"fit-content", | ||
// Env | ||
"safe-area-inset-top", | ||
"safe-area-inset-right", | ||
"safe-area-inset-bottom", | ||
"safe-area-inset-left", | ||
"titlebar-area-x", | ||
"titlebar-area-y", | ||
"titlebar-area-width", | ||
"titlebar-area-height", | ||
"keyboard-inset-top", | ||
"keyboard-inset-right", | ||
"keyboard-inset-bottom", | ||
"keyboard-inset-left", | ||
"keyboard-inset-width", | ||
"keyboard-inset-height" | ||
]; | ||
return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ | ||
let result = ""; | ||
function lastChar() { | ||
let char = result.trimEnd(); | ||
return char[char.length - 1]; | ||
} | ||
for(let i = 0; i < match.length; i++){ | ||
function peek(word) { | ||
return word.split("").every((char, j)=>match[i + j] === char); | ||
} | ||
function consumeUntil(chars) { | ||
let minIndex = Infinity; | ||
for (let char of chars){ | ||
let index = match.indexOf(char, i); | ||
if (index !== -1 && index < minIndex) { | ||
minIndex = index; | ||
} | ||
} | ||
let result = match.slice(i, minIndex); | ||
i += result.length - 1; | ||
return result; | ||
} | ||
let char = match[i]; | ||
// Handle `var(--variable)` | ||
if (peek("var")) { | ||
// When we consume until `)`, then we are dealing with this scenario: | ||
// `var(--example)` | ||
// | ||
// When we consume until `,`, then we are dealing with this scenario: | ||
// `var(--example, 1rem)` | ||
// | ||
// In this case we do want to "format", the default value as well | ||
result += consumeUntil([ | ||
")", | ||
"," | ||
]); | ||
} else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { | ||
let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); | ||
result += keyword; | ||
i += keyword.length - 1; | ||
} else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { | ||
result += consumeUntil([ | ||
")" | ||
]); | ||
} else if ([ | ||
"+", | ||
"-", | ||
"*", | ||
"/" | ||
].includes(char) && ![ | ||
"(", | ||
"+", | ||
"-", | ||
"*", | ||
"/", | ||
"," | ||
].includes(lastChar())) { | ||
result += ` ${char} `; | ||
} else { | ||
result += char; | ||
} | ||
} | ||
// Simplify multiple spaces | ||
return result.replace(/\s+/g, " "); | ||
}); | ||
} | ||
function url(value) { | ||
@@ -77,2 +224,5 @@ return value.startsWith("url("); | ||
} | ||
// Please refer to MDN when updating this list: | ||
// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units | ||
// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units | ||
let lengthUnits = [ | ||
@@ -91,6 +241,21 @@ "cm", | ||
"lh", | ||
"rlh", | ||
"vw", | ||
"vh", | ||
"vmin", | ||
"vmax" | ||
"vmax", | ||
"vb", | ||
"vi", | ||
"svw", | ||
"svh", | ||
"lvw", | ||
"lvh", | ||
"dvw", | ||
"dvh", | ||
"cqw", | ||
"cqh", | ||
"cqi", | ||
"cqb", | ||
"cqmin", | ||
"cqmax" | ||
]; | ||
@@ -151,7 +316,8 @@ let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; | ||
let gradientTypes = new Set([ | ||
"conic-gradient", | ||
"linear-gradient", | ||
"radial-gradient", | ||
"repeating-conic-gradient", | ||
"repeating-linear-gradient", | ||
"repeating-radial-gradient", | ||
"conic-gradient" | ||
"repeating-radial-gradient" | ||
]); | ||
@@ -158,0 +324,0 @@ function gradient(value) { |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>defaults | ||
get: function() { | ||
return defaults; | ||
} | ||
}); | ||
@@ -13,11 +15,11 @@ function defaults(target, ...sources) { | ||
for(let k in source){ | ||
var ref; | ||
if (!(target === null || target === void 0 ? void 0 : (ref = target.hasOwnProperty) === null || ref === void 0 ? void 0 : ref.call(target, k))) { | ||
var _target_hasOwnProperty; | ||
if (!(target === null || target === void 0 ? void 0 : (_target_hasOwnProperty = target.hasOwnProperty) === null || _target_hasOwnProperty === void 0 ? void 0 : _target_hasOwnProperty.call(target, k))) { | ||
target[k] = source[k]; | ||
} | ||
} | ||
for (let k1 of Object.getOwnPropertySymbols(source)){ | ||
var ref1; | ||
if (!(target === null || target === void 0 ? void 0 : (ref1 = target.hasOwnProperty) === null || ref1 === void 0 ? void 0 : ref1.call(target, k1))) { | ||
target[k1] = source[k1]; | ||
for (let k of Object.getOwnPropertySymbols(source)){ | ||
var _target_hasOwnProperty1; | ||
if (!(target === null || target === void 0 ? void 0 : (_target_hasOwnProperty1 = target.hasOwnProperty) === null || _target_hasOwnProperty1 === void 0 ? void 0 : _target_hasOwnProperty1.call(target, k))) { | ||
target[k] = source[k]; | ||
} | ||
@@ -24,0 +26,0 @@ } |
@@ -7,7 +7,9 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>escapeClassName | ||
get: function() { | ||
return escapeClassName; | ||
} | ||
}); | ||
const _postcssSelectorParser = /*#__PURE__*/ _interopRequireDefault(require("postcss-selector-parser")); | ||
const _escapeCommas = /*#__PURE__*/ _interopRequireDefault(require("./escapeCommas")); | ||
function _interopRequireDefault(obj) { | ||
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser")); | ||
const _escapeCommas = /*#__PURE__*/ _interop_require_default(require("./escapeCommas")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -18,7 +20,7 @@ default: obj | ||
function escapeClassName(className) { | ||
var ref; | ||
let node = _postcssSelectorParser.default.className(); | ||
var _node_raws; | ||
let node = _postcssselectorparser.default.className(); | ||
node.value = className; | ||
var ref1; | ||
return (0, _escapeCommas.default)((ref1 = node === null || node === void 0 ? void 0 : (ref = node.raws) === null || ref === void 0 ? void 0 : ref.value) !== null && ref1 !== void 0 ? ref1 : node.value); | ||
var _node_raws_value; | ||
return (0, _escapeCommas.default)((_node_raws_value = node === null || node === void 0 ? void 0 : (_node_raws = node.raws) === null || _node_raws === void 0 ? void 0 : _node_raws.value) !== null && _node_raws_value !== void 0 ? _node_raws_value : node.value); | ||
} |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>escapeCommas | ||
get: function() { | ||
return escapeCommas; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ function escapeCommas(className) { |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ const flattenColorPalette = (colors)=>Object.assign({}, ...Object.entries(colors !== null && colors !== void 0 ? colors : {}).flatMap(([color, values])=>typeof values == "object" ? Object.entries(flattenColorPalette(values)).map(([number, hex])=>({ |
@@ -12,11 +12,22 @@ "use strict"; | ||
_export(exports, { | ||
selectorFunctions: ()=>selectorFunctions, | ||
formatVariantSelector: ()=>formatVariantSelector, | ||
finalizeSelector: ()=>finalizeSelector | ||
formatVariantSelector: function() { | ||
return formatVariantSelector; | ||
}, | ||
eliminateIrrelevantSelectors: function() { | ||
return eliminateIrrelevantSelectors; | ||
}, | ||
finalizeSelector: function() { | ||
return finalizeSelector; | ||
}, | ||
handleMergePseudo: function() { | ||
return handleMergePseudo; | ||
} | ||
}); | ||
const _postcssSelectorParser = /*#__PURE__*/ _interopRequireDefault(require("postcss-selector-parser")); | ||
const _unesc = /*#__PURE__*/ _interopRequireDefault(require("postcss-selector-parser/dist/util/unesc")); | ||
const _escapeClassName = /*#__PURE__*/ _interopRequireDefault(require("../util/escapeClassName")); | ||
const _prefixSelector = /*#__PURE__*/ _interopRequireDefault(require("../util/prefixSelector")); | ||
function _interopRequireDefault(obj) { | ||
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser")); | ||
const _unesc = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser/dist/util/unesc")); | ||
const _escapeClassName = /*#__PURE__*/ _interop_require_default(require("../util/escapeClassName")); | ||
const _prefixSelector = /*#__PURE__*/ _interop_require_default(require("../util/prefixSelector")); | ||
const _pseudoElements = require("./pseudoElements"); | ||
const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -26,24 +37,35 @@ default: obj | ||
} | ||
var ref; | ||
let MERGE = ":merge"; | ||
let PARENT = "&"; | ||
let selectorFunctions = new Set([ | ||
MERGE | ||
]); | ||
function formatVariantSelector(current, ...others) { | ||
for (let other of others){ | ||
let incomingValue = resolveFunctionArgument(other, MERGE); | ||
if (incomingValue !== null) { | ||
let existingValue = resolveFunctionArgument(current, MERGE, incomingValue); | ||
if (existingValue !== null) { | ||
let existingTarget = `${MERGE}(${incomingValue})`; | ||
let splitIdx = other.indexOf(existingTarget); | ||
let addition = other.slice(splitIdx + existingTarget.length).split(" ")[0]; | ||
current = current.replace(existingTarget, existingTarget + addition); | ||
continue; | ||
} | ||
} | ||
current = other.replace(PARENT, current); | ||
/** @typedef {import('postcss-selector-parser').Root} Root */ /** @typedef {import('postcss-selector-parser').Selector} Selector */ /** @typedef {import('postcss-selector-parser').Pseudo} Pseudo */ /** @typedef {import('postcss-selector-parser').Node} Node */ /** @typedef {{format: string, respectPrefix: boolean}[]} RawFormats */ /** @typedef {import('postcss-selector-parser').Root} ParsedFormats */ /** @typedef {RawFormats | ParsedFormats} AcceptedFormats */ let MERGE = ":merge"; | ||
function formatVariantSelector(formats, { context , candidate }) { | ||
var _context_tailwindConfig_prefix; | ||
let prefix = (_context_tailwindConfig_prefix = context === null || context === void 0 ? void 0 : context.tailwindConfig.prefix) !== null && _context_tailwindConfig_prefix !== void 0 ? _context_tailwindConfig_prefix : ""; | ||
// Parse the format selector into an AST | ||
let parsedFormats = formats.map((format)=>{ | ||
let ast = (0, _postcssselectorparser.default)().astSync(format.format); | ||
return { | ||
...format, | ||
ast: format.respectPrefix ? (0, _prefixSelector.default)(prefix, ast) : ast | ||
}; | ||
}); | ||
// We start with the candidate selector | ||
let formatAst = _postcssselectorparser.default.root({ | ||
nodes: [ | ||
_postcssselectorparser.default.selector({ | ||
nodes: [ | ||
_postcssselectorparser.default.className({ | ||
value: (0, _escapeClassName.default)(candidate) | ||
}) | ||
] | ||
}) | ||
] | ||
}); | ||
// And iteratively merge each format selector into the candidate selector | ||
for (let { ast } of parsedFormats){ | ||
[formatAst, ast] = handleMergePseudo(formatAst, ast); | ||
// 2. Merge the format selector into the current selector AST | ||
ast.walkNesting((nesting)=>nesting.replaceWith(...formatAst.nodes[0].nodes)); | ||
// 3. Keep going! | ||
formatAst = ast; | ||
} | ||
return current; | ||
return formatAst; | ||
} | ||
@@ -56,6 +78,6 @@ /** | ||
* | ||
* @param {import('postcss-selector-parser').Node} node | ||
* @returns {import('postcss-selector-parser').Node[]} | ||
* @param {Node} node | ||
* @returns {Node[]} | ||
**/ function simpleSelectorForNode(node) { | ||
/** @type {import('postcss-selector-parser').Node[]} */ let nodes = []; | ||
/** @type {Node[]} */ let nodes = []; | ||
// Walk backwards until we hit a combinator node (or the start) | ||
@@ -76,4 +98,4 @@ while(node.prev() && node.prev().type !== "combinator"){ | ||
* | ||
* @param {import('postcss-selector-parser').Selector} sel | ||
* @returns {import('postcss-selector-parser').Selector} | ||
* @param {Selector} sel | ||
* @returns {Selector} | ||
**/ function resortSelector(sel) { | ||
@@ -113,23 +135,16 @@ sel.sort((a, b)=>{ | ||
} | ||
var ref1; | ||
function finalizeSelector(format, { selector , candidate , context , isArbitraryVariant , // Split by the separator, but ignore the separator inside square brackets: | ||
// | ||
// E.g.: dark:lg:hover:[paint-order:markers] | ||
// ┬ ┬ ┬ ┬ | ||
// │ │ │ ╰── We will not split here | ||
// ╰──┴─────┴─────────────── We will split here | ||
// | ||
base =candidate.split(new RegExp(`\\${(ref1 = context === null || context === void 0 ? void 0 : (ref = context.tailwindConfig) === null || ref === void 0 ? void 0 : ref.separator) !== null && ref1 !== void 0 ? ref1 : ":"}(?![^[]*\\])`)).pop() }) { | ||
var ref2; | ||
let ast = (0, _postcssSelectorParser.default)().astSync(selector); | ||
// We explicitly DO NOT prefix classes in arbitrary variants | ||
if ((context === null || context === void 0 ? void 0 : (ref2 = context.tailwindConfig) === null || ref2 === void 0 ? void 0 : ref2.prefix) && !isArbitraryVariant) { | ||
format = (0, _prefixSelector.default)(context.tailwindConfig.prefix, format); | ||
} | ||
format = format.replace(PARENT, `.${(0, _escapeClassName.default)(candidate)}`); | ||
let formatAst = (0, _postcssSelectorParser.default)().astSync(format); | ||
// Remove extraneous selectors that do not include the base class/candidate being matched against | ||
// For example if we have a utility defined `.a, .b { color: red}` | ||
// And the formatted variant is sm:b then we want the final selector to be `.sm\:b` and not `.a, .sm\:b` | ||
ast.each((sel)=>eliminateIrrelevantSelectors(sel, base)); | ||
function finalizeSelector(current, formats, { context , candidate , base }) { | ||
var _context_tailwindConfig; | ||
var _context_tailwindConfig_separator; | ||
let separator = (_context_tailwindConfig_separator = context === null || context === void 0 ? void 0 : (_context_tailwindConfig = context.tailwindConfig) === null || _context_tailwindConfig === void 0 ? void 0 : _context_tailwindConfig.separator) !== null && _context_tailwindConfig_separator !== void 0 ? _context_tailwindConfig_separator : ":"; | ||
// Split by the separator, but ignore the separator inside square brackets: | ||
// | ||
// E.g.: dark:lg:hover:[paint-order:markers] | ||
// ┬ ┬ ┬ ┬ | ||
// │ │ │ ╰── We will not split here | ||
// ╰──┴─────┴─────────────── We will split here | ||
// | ||
base = base !== null && base !== void 0 ? base : (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(candidate, separator).pop(); | ||
// Parse the selector into an AST | ||
let selector = (0, _postcssselectorparser.default)().astSync(current); | ||
// Normalize escaped classes, e.g.: | ||
@@ -146,3 +161,3 @@ // | ||
// | ||
ast.walkClasses((node)=>{ | ||
selector.walkClasses((node)=>{ | ||
if (node.raws && node.value.includes(base)) { | ||
@@ -152,6 +167,23 @@ node.raws.value = (0, _escapeClassName.default)((0, _unesc.default)(node.raws.value)); | ||
}); | ||
let simpleStart = _postcssSelectorParser.default.comment({ | ||
// Remove extraneous selectors that do not include the base candidate | ||
selector.each((sel)=>eliminateIrrelevantSelectors(sel, base)); | ||
// If ffter eliminating irrelevant selectors, we end up with nothing | ||
// Then the whole "rule" this is associated with does not need to exist | ||
// We use `null` as a marker value for that case | ||
if (selector.length === 0) { | ||
return null; | ||
} | ||
// If there are no formats that means there were no variants added to the candidate | ||
// so we can just return the selector as-is | ||
let formatAst = Array.isArray(formats) ? formatVariantSelector(formats, { | ||
context, | ||
candidate | ||
}) : formats; | ||
if (formatAst === null) { | ||
return selector.toString(); | ||
} | ||
let simpleStart = _postcssselectorparser.default.comment({ | ||
value: "/*__simple__*/" | ||
}); | ||
let simpleEnd = _postcssSelectorParser.default.comment({ | ||
let simpleEnd = _postcssselectorparser.default.comment({ | ||
value: "/*__simple__*/" | ||
@@ -161,3 +193,3 @@ }); | ||
// now in a normalized escaped value. | ||
ast.walkClasses((node)=>{ | ||
selector.walkClasses((node)=>{ | ||
if (node.value !== base) { | ||
@@ -177,3 +209,3 @@ return; | ||
for (let child of formatNodes){ | ||
parent.insertBefore(simpleSelector[0], child); | ||
parent.insertBefore(simpleSelector[0], child.clone()); | ||
} | ||
@@ -184,3 +216,3 @@ node.remove(); | ||
let firstNode = parent.index(simpleStart); | ||
parent.nodes.splice(firstNode, simpleSelector.length, ...resortSelector(_postcssSelectorParser.default.selector({ | ||
parent.nodes.splice(firstNode, simpleSelector.length, ...resortSelector(_postcssselectorparser.default.selector({ | ||
nodes: simpleSelector | ||
@@ -191,106 +223,59 @@ })).nodes); | ||
}); | ||
// This will make sure to move pseudo's to the correct spot (the end for | ||
// pseudo elements) because otherwise the selector will never work | ||
// anyway. | ||
// | ||
// E.g.: | ||
// - `before:hover:text-center` would result in `.before\:hover\:text-center:hover::before` | ||
// - `hover:before:text-center` would result in `.hover\:before\:text-center:hover::before` | ||
// | ||
// `::before:hover` doesn't work, which means that we can make it work for you by flipping the order. | ||
function collectPseudoElements(selector) { | ||
let nodes = []; | ||
for (let node of selector.nodes){ | ||
if (isPseudoElement(node)) { | ||
nodes.push(node); | ||
selector.removeChild(node); | ||
} | ||
if (node === null || node === void 0 ? void 0 : node.nodes) { | ||
nodes.push(...collectPseudoElements(node)); | ||
} | ||
} | ||
return nodes; | ||
} | ||
// Remove unnecessary pseudo selectors that we used as placeholders | ||
ast.each((selector)=>{ | ||
selector.walkPseudos((p)=>{ | ||
if (selectorFunctions.has(p.value)) { | ||
p.replaceWith(p.nodes); | ||
} | ||
}); | ||
let pseudoElements = collectPseudoElements(selector); | ||
if (pseudoElements.length > 0) { | ||
selector.nodes.push(pseudoElements.sort(sortSelector)); | ||
selector.walkPseudos((p)=>{ | ||
if (p.value === MERGE) { | ||
p.replaceWith(p.nodes); | ||
} | ||
}); | ||
return ast.toString(); | ||
// Move pseudo elements to the end of the selector (if necessary) | ||
selector.each((sel)=>(0, _pseudoElements.movePseudos)(sel)); | ||
return selector.toString(); | ||
} | ||
// Note: As a rule, double colons (::) should be used instead of a single colon | ||
// (:). This distinguishes pseudo-classes from pseudo-elements. However, since | ||
// this distinction was not present in older versions of the W3C spec, most | ||
// browsers support both syntaxes for the original pseudo-elements. | ||
let pseudoElementsBC = [ | ||
":before", | ||
":after", | ||
":first-line", | ||
":first-letter" | ||
]; | ||
// These pseudo-elements _can_ be combined with other pseudo selectors AND the order does matter. | ||
let pseudoElementExceptions = [ | ||
"::file-selector-button" | ||
]; | ||
// This will make sure to move pseudo's to the correct spot (the end for | ||
// pseudo elements) because otherwise the selector will never work | ||
// anyway. | ||
// | ||
// E.g.: | ||
// - `before:hover:text-center` would result in `.before\:hover\:text-center:hover::before` | ||
// - `hover:before:text-center` would result in `.hover\:before\:text-center:hover::before` | ||
// | ||
// `::before:hover` doesn't work, which means that we can make it work | ||
// for you by flipping the order. | ||
function sortSelector(a, z) { | ||
// Both nodes are non-pseudo's so we can safely ignore them and keep | ||
// them in the same order. | ||
if (a.type !== "pseudo" && z.type !== "pseudo") { | ||
return 0; | ||
} | ||
// If one of them is a combinator, we need to keep it in the same order | ||
// because that means it will start a new "section" in the selector. | ||
if (a.type === "combinator" ^ z.type === "combinator") { | ||
return 0; | ||
} | ||
// One of the items is a pseudo and the other one isn't. Let's move | ||
// the pseudo to the right. | ||
if (a.type === "pseudo" ^ z.type === "pseudo") { | ||
return (a.type === "pseudo") - (z.type === "pseudo"); | ||
} | ||
// Both are pseudo's, move the pseudo elements (except for | ||
// ::file-selector-button) to the right. | ||
return isPseudoElement(a) - isPseudoElement(z); | ||
} | ||
function isPseudoElement(node) { | ||
if (node.type !== "pseudo") return false; | ||
if (pseudoElementExceptions.includes(node.value)) return false; | ||
return node.value.startsWith("::") || pseudoElementsBC.includes(node.value); | ||
} | ||
function resolveFunctionArgument(haystack, needle, arg) { | ||
let startIdx = haystack.indexOf(arg ? `${needle}(${arg})` : needle); | ||
if (startIdx === -1) return null; | ||
// Start inside the `(` | ||
startIdx += needle.length + 1; | ||
let target = ""; | ||
let count = 0; | ||
for (let char of haystack.slice(startIdx)){ | ||
if (char !== "(" && char !== ")") { | ||
target += char; | ||
} else if (char === "(") { | ||
target += char; | ||
count++; | ||
} else if (char === ")") { | ||
if (--count < 0) break; // unbalanced | ||
target += char; | ||
function handleMergePseudo(selector, format) { | ||
/** @type {{pseudo: Pseudo, value: string}[]} */ let merges = []; | ||
// Find all :merge() pseudo-classes in `selector` | ||
selector.walkPseudos((pseudo)=>{ | ||
if (pseudo.value === MERGE) { | ||
merges.push({ | ||
pseudo, | ||
value: pseudo.nodes[0].toString() | ||
}); | ||
} | ||
} | ||
return target; | ||
}); | ||
// Find all :merge() "attachments" in `format` and attach them to the matching selector in `selector` | ||
format.walkPseudos((pseudo)=>{ | ||
if (pseudo.value !== MERGE) { | ||
return; | ||
} | ||
let value = pseudo.nodes[0].toString(); | ||
// Does `selector` contain a :merge() pseudo-class with the same value? | ||
let existing = merges.find((merge)=>merge.value === value); | ||
// Nope so there's nothing to do | ||
if (!existing) { | ||
return; | ||
} | ||
// Everything after `:merge()` up to the next combinator is what is attached to the merged selector | ||
let attachments = []; | ||
let next = pseudo.next(); | ||
while(next && next.type !== "combinator"){ | ||
attachments.push(next); | ||
next = next.next(); | ||
} | ||
let combinator = next; | ||
existing.pseudo.parent.insertAfter(existing.pseudo, _postcssselectorparser.default.selector({ | ||
nodes: attachments.map((node)=>node.clone()) | ||
})); | ||
pseudo.remove(); | ||
attachments.forEach((node)=>node.remove()); | ||
// What about this case: | ||
// :merge(.group):focus > & | ||
// :merge(.group):hover & | ||
if (combinator && combinator.type === "combinator") { | ||
combinator.remove(); | ||
} | ||
}); | ||
return [ | ||
selector, | ||
format | ||
]; | ||
} |
@@ -7,7 +7,9 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>getAllConfigs | ||
get: function() { | ||
return getAllConfigs; | ||
} | ||
}); | ||
const _defaultConfigStubJs = /*#__PURE__*/ _interopRequireDefault(require("../../stubs/defaultConfig.stub.js")); | ||
const _configfull = /*#__PURE__*/ _interop_require_default(require("../../stubs/config.full.js")); | ||
const _featureFlags = require("../featureFlags"); | ||
function _interopRequireDefault(obj) { | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -18,5 +20,5 @@ default: obj | ||
function getAllConfigs(config) { | ||
var ref; | ||
const configs = ((ref = config === null || config === void 0 ? void 0 : config.presets) !== null && ref !== void 0 ? ref : [ | ||
_defaultConfigStubJs.default | ||
var _config_presets; | ||
const configs = ((_config_presets = config === null || config === void 0 ? void 0 : config.presets) !== null && _config_presets !== void 0 ? _config_presets : [ | ||
_configfull.default | ||
]).slice().reverse().flatMap((preset)=>getAllConfigs(preset instanceof Function ? preset() : preset)); | ||
@@ -23,0 +25,0 @@ const features = { |
@@ -7,6 +7,8 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>hashConfig | ||
get: function() { | ||
return hashConfig; | ||
} | ||
}); | ||
const _objectHash = /*#__PURE__*/ _interopRequireDefault(require("object-hash")); | ||
function _interopRequireDefault(obj) { | ||
const _objecthash = /*#__PURE__*/ _interop_require_default(require("object-hash")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -17,5 +19,5 @@ default: obj | ||
function hashConfig(config) { | ||
return (0, _objectHash.default)(config, { | ||
return (0, _objecthash.default)(config, { | ||
ignoreUnknown: true | ||
}); | ||
} |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>isKeyframeRule | ||
get: function() { | ||
return isKeyframeRule; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ function isKeyframeRule(rule) { |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>isPlainObject | ||
get: function() { | ||
return isPlainObject; | ||
} | ||
}); | ||
@@ -15,3 +17,3 @@ function isPlainObject(value) { | ||
const prototype = Object.getPrototypeOf(value); | ||
return prototype === null || prototype === Object.prototype; | ||
return prototype === null || Object.getPrototypeOf(prototype) === null; | ||
} |
@@ -12,7 +12,11 @@ "use strict"; | ||
_export(exports, { | ||
dim: ()=>dim, | ||
default: ()=>_default | ||
dim: function() { | ||
return dim; | ||
}, | ||
default: function() { | ||
return _default; | ||
} | ||
}); | ||
const _picocolors = /*#__PURE__*/ _interopRequireDefault(require("picocolors")); | ||
function _interopRequireDefault(obj) { | ||
const _picocolors = /*#__PURE__*/ _interop_require_default(require("picocolors")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -19,0 +23,0 @@ default: obj |
@@ -12,9 +12,15 @@ "use strict"; | ||
_export(exports, { | ||
asClass: ()=>asClass, | ||
default: ()=>nameClass, | ||
formatClass: ()=>formatClass | ||
asClass: function() { | ||
return asClass; | ||
}, | ||
default: function() { | ||
return nameClass; | ||
}, | ||
formatClass: function() { | ||
return formatClass; | ||
} | ||
}); | ||
const _escapeClassName = /*#__PURE__*/ _interopRequireDefault(require("./escapeClassName")); | ||
const _escapeCommas = /*#__PURE__*/ _interopRequireDefault(require("./escapeCommas")); | ||
function _interopRequireDefault(obj) { | ||
const _escapeClassName = /*#__PURE__*/ _interop_require_default(require("./escapeClassName")); | ||
const _escapeCommas = /*#__PURE__*/ _interop_require_default(require("./escapeCommas")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -21,0 +27,0 @@ default: obj |
@@ -7,5 +7,7 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return negateValue; | ||
} | ||
}); | ||
function _default(value) { | ||
function negateValue(value) { | ||
value = `${value}`; | ||
@@ -12,0 +14,0 @@ if (value === "0") { |
@@ -7,5 +7,8 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>normalizeConfig | ||
get: function() { | ||
return normalizeConfig; | ||
} | ||
}); | ||
const _log = /*#__PURE__*/ _interopRequireWildcard(require("./log")); | ||
const _featureFlags = require("../featureFlags"); | ||
const _log = /*#__PURE__*/ _interop_require_wildcard(require("./log")); | ||
function _getRequireWildcardCache(nodeInterop) { | ||
@@ -19,3 +22,3 @@ if (typeof WeakMap !== "function") return null; | ||
} | ||
function _interopRequireWildcard(obj, nodeInterop) { | ||
function _interop_require_wildcard(obj, nodeInterop) { | ||
if (!nodeInterop && obj && obj.__esModule) { | ||
@@ -133,4 +136,4 @@ return obj; | ||
if (typeof config.content.transform === "object") { | ||
for (let value1 of Object.values(config.content.transform)){ | ||
if (typeof value1 !== "function") { | ||
for (let value of Object.values(config.content.transform)){ | ||
if (typeof value !== "function") { | ||
return false; | ||
@@ -160,3 +163,3 @@ } | ||
config.safelist = (()=>{ | ||
var ref; | ||
var _purge_options; | ||
let { content , purge , safelist } = config; | ||
@@ -166,3 +169,3 @@ if (Array.isArray(safelist)) return safelist; | ||
if (Array.isArray(purge === null || purge === void 0 ? void 0 : purge.safelist)) return purge.safelist; | ||
if (Array.isArray(purge === null || purge === void 0 ? void 0 : (ref = purge.options) === null || ref === void 0 ? void 0 : ref.safelist)) return purge.options.safelist; | ||
if (Array.isArray(purge === null || purge === void 0 ? void 0 : (_purge_options = purge.options) === null || _purge_options === void 0 ? void 0 : _purge_options.safelist)) return purge.options.safelist; | ||
return []; | ||
@@ -193,4 +196,4 @@ })(); | ||
} else { | ||
var _prefix; | ||
config.prefix = (_prefix = config.prefix) !== null && _prefix !== void 0 ? _prefix : ""; | ||
var _config_prefix; | ||
config.prefix = (_config_prefix = config.prefix) !== null && _config_prefix !== void 0 ? _config_prefix : ""; | ||
} | ||
@@ -200,3 +203,2 @@ // Normalize the `content` | ||
relative: (()=>{ | ||
var ref; | ||
let { content } = config; | ||
@@ -206,4 +208,3 @@ if (content === null || content === void 0 ? void 0 : content.relative) { | ||
} | ||
var ref1; | ||
return (ref1 = (ref = config.future) === null || ref === void 0 ? void 0 : ref.relativeContentPathsByDefault) !== null && ref1 !== void 0 ? ref1 : false; | ||
return (0, _featureFlags.flagEnabled)(config, "relativeContentPathsByDefault"); | ||
})(), | ||
@@ -221,9 +222,9 @@ files: (()=>{ | ||
let extract = (()=>{ | ||
var ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9; | ||
if ((ref = config.purge) === null || ref === void 0 ? void 0 : ref.extract) return config.purge.extract; | ||
if ((ref1 = config.content) === null || ref1 === void 0 ? void 0 : ref1.extract) return config.content.extract; | ||
if ((ref2 = config.purge) === null || ref2 === void 0 ? void 0 : (ref3 = ref2.extract) === null || ref3 === void 0 ? void 0 : ref3.DEFAULT) return config.purge.extract.DEFAULT; | ||
if ((ref4 = config.content) === null || ref4 === void 0 ? void 0 : (ref5 = ref4.extract) === null || ref5 === void 0 ? void 0 : ref5.DEFAULT) return config.content.extract.DEFAULT; | ||
if ((ref6 = config.purge) === null || ref6 === void 0 ? void 0 : (ref7 = ref6.options) === null || ref7 === void 0 ? void 0 : ref7.extractors) return config.purge.options.extractors; | ||
if ((ref8 = config.content) === null || ref8 === void 0 ? void 0 : (ref9 = ref8.options) === null || ref9 === void 0 ? void 0 : ref9.extractors) return config.content.options.extractors; | ||
var _config_purge, _config_content, _config_purge1, _config_purge_extract, _config_content1, _config_content_extract, _config_purge2, _config_purge_options, _config_content2, _config_content_options; | ||
if ((_config_purge = config.purge) === null || _config_purge === void 0 ? void 0 : _config_purge.extract) return config.purge.extract; | ||
if ((_config_content = config.content) === null || _config_content === void 0 ? void 0 : _config_content.extract) return config.content.extract; | ||
if ((_config_purge1 = config.purge) === null || _config_purge1 === void 0 ? void 0 : (_config_purge_extract = _config_purge1.extract) === null || _config_purge_extract === void 0 ? void 0 : _config_purge_extract.DEFAULT) return config.purge.extract.DEFAULT; | ||
if ((_config_content1 = config.content) === null || _config_content1 === void 0 ? void 0 : (_config_content_extract = _config_content1.extract) === null || _config_content_extract === void 0 ? void 0 : _config_content_extract.DEFAULT) return config.content.extract.DEFAULT; | ||
if ((_config_purge2 = config.purge) === null || _config_purge2 === void 0 ? void 0 : (_config_purge_options = _config_purge2.options) === null || _config_purge_options === void 0 ? void 0 : _config_purge_options.extractors) return config.purge.options.extractors; | ||
if ((_config_content2 = config.content) === null || _config_content2 === void 0 ? void 0 : (_config_content_options = _config_content2.options) === null || _config_content_options === void 0 ? void 0 : _config_content_options.extractors) return config.content.options.extractors; | ||
return {}; | ||
@@ -233,7 +234,7 @@ })(); | ||
let defaultExtractor = (()=>{ | ||
var ref, ref1, ref2, ref3; | ||
if ((ref = config.purge) === null || ref === void 0 ? void 0 : (ref1 = ref.options) === null || ref1 === void 0 ? void 0 : ref1.defaultExtractor) { | ||
var _config_purge, _config_purge_options, _config_content, _config_content_options; | ||
if ((_config_purge = config.purge) === null || _config_purge === void 0 ? void 0 : (_config_purge_options = _config_purge.options) === null || _config_purge_options === void 0 ? void 0 : _config_purge_options.defaultExtractor) { | ||
return config.purge.options.defaultExtractor; | ||
} | ||
if ((ref2 = config.content) === null || ref2 === void 0 ? void 0 : (ref3 = ref2.options) === null || ref3 === void 0 ? void 0 : ref3.defaultExtractor) { | ||
if ((_config_content = config.content) === null || _config_content === void 0 ? void 0 : (_config_content_options = _config_content.options) === null || _config_content_options === void 0 ? void 0 : _config_content_options.defaultExtractor) { | ||
return config.content.options.defaultExtractor; | ||
@@ -262,7 +263,7 @@ } | ||
let transform = (()=>{ | ||
var ref, ref1, ref2, ref3, ref4, ref5; | ||
if ((ref = config.purge) === null || ref === void 0 ? void 0 : ref.transform) return config.purge.transform; | ||
if ((ref1 = config.content) === null || ref1 === void 0 ? void 0 : ref1.transform) return config.content.transform; | ||
if ((ref2 = config.purge) === null || ref2 === void 0 ? void 0 : (ref3 = ref2.transform) === null || ref3 === void 0 ? void 0 : ref3.DEFAULT) return config.purge.transform.DEFAULT; | ||
if ((ref4 = config.content) === null || ref4 === void 0 ? void 0 : (ref5 = ref4.transform) === null || ref5 === void 0 ? void 0 : ref5.DEFAULT) return config.content.transform.DEFAULT; | ||
var _config_purge, _config_content, _config_purge1, _config_purge_transform, _config_content1, _config_content_transform; | ||
if ((_config_purge = config.purge) === null || _config_purge === void 0 ? void 0 : _config_purge.transform) return config.purge.transform; | ||
if ((_config_content = config.content) === null || _config_content === void 0 ? void 0 : _config_content.transform) return config.content.transform; | ||
if ((_config_purge1 = config.purge) === null || _config_purge1 === void 0 ? void 0 : (_config_purge_transform = _config_purge1.transform) === null || _config_purge_transform === void 0 ? void 0 : _config_purge_transform.DEFAULT) return config.purge.transform.DEFAULT; | ||
if ((_config_content1 = config.content) === null || _config_content1 === void 0 ? void 0 : (_config_content_transform = _config_content1.transform) === null || _config_content_transform === void 0 ? void 0 : _config_content_transform.DEFAULT) return config.content.transform.DEFAULT; | ||
return {}; | ||
@@ -269,0 +270,0 @@ })(); |
@@ -36,6 +36,14 @@ /** | ||
_export(exports, { | ||
normalizeScreens: ()=>normalizeScreens, | ||
isScreenSortable: ()=>isScreenSortable, | ||
compareScreens: ()=>compareScreens, | ||
toScreen: ()=>toScreen | ||
normalizeScreens: function() { | ||
return normalizeScreens; | ||
}, | ||
isScreenSortable: function() { | ||
return isScreenSortable; | ||
}, | ||
compareScreens: function() { | ||
return compareScreens; | ||
}, | ||
toScreen: function() { | ||
return toScreen; | ||
} | ||
}); | ||
@@ -42,0 +50,0 @@ function normalizeScreens(screens, root = true) { |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>parseAnimationValue | ||
get: function() { | ||
return parseAnimationValue; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ const DIRECTIONS = new Set([ |
@@ -12,4 +12,8 @@ "use strict"; | ||
_export(exports, { | ||
parseBoxShadowValue: ()=>parseBoxShadowValue, | ||
formatBoxShadowValue: ()=>formatBoxShadowValue | ||
parseBoxShadowValue: function() { | ||
return parseBoxShadowValue; | ||
}, | ||
formatBoxShadowValue: function() { | ||
return formatBoxShadowValue; | ||
} | ||
}); | ||
@@ -16,0 +20,0 @@ const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); |
@@ -14,3 +14,5 @@ // @ts-check | ||
enumerable: true, | ||
get: ()=>parseDependency | ||
get: function() { | ||
return parseDependency; | ||
} | ||
}); | ||
@@ -17,0 +19,0 @@ function parseDependency(contentPath) { |
@@ -7,6 +7,8 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>parseGlob | ||
get: function() { | ||
return parseGlob; | ||
} | ||
}); | ||
const _globParent = /*#__PURE__*/ _interopRequireDefault(require("glob-parent")); | ||
function _interopRequireDefault(obj) { | ||
const _globparent = /*#__PURE__*/ _interop_require_default(require("glob-parent")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -18,3 +20,3 @@ default: obj | ||
let glob = pattern; | ||
let base = (0, _globParent.default)(pattern); | ||
let base = (0, _globparent.default)(pattern); | ||
if (base !== ".") { | ||
@@ -21,0 +23,0 @@ glob = pattern.substr(base.length); |
@@ -7,8 +7,10 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>parseObjectStyles | ||
get: function() { | ||
return parseObjectStyles; | ||
} | ||
}); | ||
const _postcss = /*#__PURE__*/ _interopRequireDefault(require("postcss")); | ||
const _postcssNested = /*#__PURE__*/ _interopRequireDefault(require("postcss-nested")); | ||
const _postcssJs = /*#__PURE__*/ _interopRequireDefault(require("postcss-js")); | ||
function _interopRequireDefault(obj) { | ||
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss")); | ||
const _postcssnested = /*#__PURE__*/ _interop_require_default(require("postcss-nested")); | ||
const _postcssjs = /*#__PURE__*/ _interop_require_default(require("postcss-js")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -26,3 +28,3 @@ default: obj | ||
return (0, _postcss.default)([ | ||
(0, _postcssNested.default)({ | ||
(0, _postcssnested.default)({ | ||
bubble: [ | ||
@@ -33,5 +35,5 @@ "screen" | ||
]).process(style, { | ||
parser: _postcssJs.default | ||
parser: _postcssjs.default | ||
}).root.nodes; | ||
}); | ||
} |
@@ -12,20 +12,34 @@ "use strict"; | ||
_export(exports, { | ||
updateAllClasses: ()=>updateAllClasses, | ||
filterSelectorsForClass: ()=>filterSelectorsForClass, | ||
asValue: ()=>asValue, | ||
parseColorFormat: ()=>parseColorFormat, | ||
asColor: ()=>asColor, | ||
asLookupValue: ()=>asLookupValue, | ||
typeMap: ()=>typeMap, | ||
coerceValue: ()=>coerceValue, | ||
getMatchingTypes: ()=>getMatchingTypes | ||
updateAllClasses: function() { | ||
return updateAllClasses; | ||
}, | ||
asValue: function() { | ||
return asValue; | ||
}, | ||
parseColorFormat: function() { | ||
return parseColorFormat; | ||
}, | ||
asColor: function() { | ||
return asColor; | ||
}, | ||
asLookupValue: function() { | ||
return asLookupValue; | ||
}, | ||
typeMap: function() { | ||
return typeMap; | ||
}, | ||
coerceValue: function() { | ||
return coerceValue; | ||
}, | ||
getMatchingTypes: function() { | ||
return getMatchingTypes; | ||
} | ||
}); | ||
const _postcssSelectorParser = /*#__PURE__*/ _interopRequireDefault(require("postcss-selector-parser")); | ||
const _escapeCommas = /*#__PURE__*/ _interopRequireDefault(require("./escapeCommas")); | ||
const _escapeCommas = /*#__PURE__*/ _interop_require_default(require("./escapeCommas")); | ||
const _withAlphaVariable = require("./withAlphaVariable"); | ||
const _dataTypes = require("./dataTypes"); | ||
const _negateValue = /*#__PURE__*/ _interopRequireDefault(require("./negateValue")); | ||
const _negateValue = /*#__PURE__*/ _interop_require_default(require("./negateValue")); | ||
const _validateFormalSyntax = require("./validateFormalSyntax"); | ||
const _featureFlagsJs = require("../featureFlags.js"); | ||
function _interopRequireDefault(obj) { | ||
const _featureFlags = require("../featureFlags.js"); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -36,26 +50,9 @@ default: obj | ||
function updateAllClasses(selectors, updateClass) { | ||
let parser = (0, _postcssSelectorParser.default)((selectors)=>{ | ||
selectors.walkClasses((sel)=>{ | ||
let updatedClass = updateClass(sel.value); | ||
sel.value = updatedClass; | ||
if (sel.raws && sel.raws.value) { | ||
sel.raws.value = (0, _escapeCommas.default)(sel.raws.value); | ||
} | ||
}); | ||
selectors.walkClasses((sel)=>{ | ||
sel.value = updateClass(sel.value); | ||
if (sel.raws && sel.raws.value) { | ||
sel.raws.value = (0, _escapeCommas.default)(sel.raws.value); | ||
} | ||
}); | ||
let result = parser.processSync(selectors); | ||
return result; | ||
} | ||
function filterSelectorsForClass(selectors, classCandidate) { | ||
let parser = (0, _postcssSelectorParser.default)((selectors)=>{ | ||
selectors.each((sel)=>{ | ||
const containsClass = sel.nodes.some((node)=>node.type === "class" && node.value === classCandidate); | ||
if (!containsClass) { | ||
sel.remove(); | ||
} | ||
}); | ||
}); | ||
let result = parser.processSync(selectors); | ||
return result; | ||
} | ||
function resolveArbitraryValue(modifier, validate) { | ||
@@ -85,4 +82,4 @@ if (!isArbitraryValue(modifier)) { | ||
function asValue(modifier, options = {}, { validate =()=>true } = {}) { | ||
var ref; | ||
let value = (ref = options.values) === null || ref === void 0 ? void 0 : ref[modifier]; | ||
var _options_values; | ||
let value = (_options_values = options.values) === null || _options_values === void 0 ? void 0 : _options_values[modifier]; | ||
if (value !== undefined) { | ||
@@ -101,2 +98,15 @@ return value; | ||
let slashIdx = modifier.lastIndexOf("/"); | ||
// If the `/` is inside an arbitrary, we want to find the previous one if any | ||
// This logic probably isn't perfect but it should work for most cases | ||
let arbitraryStartIdx = modifier.lastIndexOf("[", slashIdx); | ||
let arbitraryEndIdx = modifier.indexOf("]", slashIdx); | ||
let isNextToArbitrary = modifier[slashIdx - 1] === "]" || modifier[slashIdx + 1] === "["; | ||
// Backtrack to the previous `/` if the one we found was inside an arbitrary | ||
if (!isNextToArbitrary) { | ||
if (arbitraryStartIdx !== -1 && arbitraryEndIdx !== -1) { | ||
if (arbitraryStartIdx < slashIdx && slashIdx < arbitraryEndIdx) { | ||
slashIdx = modifier.lastIndexOf("/", arbitraryStartIdx); | ||
} | ||
} | ||
} | ||
if (slashIdx === -1 || slashIdx === modifier.length - 1) { | ||
@@ -130,15 +140,18 @@ return [ | ||
} | ||
function asColor(_, options = {}, { tailwindConfig ={} , utilityModifier , rawModifier } = {}) { | ||
var ref; | ||
if (((ref = options.values) === null || ref === void 0 ? void 0 : ref[rawModifier]) !== undefined) { | ||
var ref1; | ||
return parseColorFormat((ref1 = options.values) === null || ref1 === void 0 ? void 0 : ref1[rawModifier]); | ||
function unwrapArbitraryModifier(modifier) { | ||
return (0, _dataTypes.normalize)(modifier.slice(1, -1)); | ||
} | ||
function asColor(modifier, options = {}, { tailwindConfig ={} } = {}) { | ||
var _options_values; | ||
if (((_options_values = options.values) === null || _options_values === void 0 ? void 0 : _options_values[modifier]) !== undefined) { | ||
var _options_values1; | ||
return parseColorFormat((_options_values1 = options.values) === null || _options_values1 === void 0 ? void 0 : _options_values1[modifier]); | ||
} | ||
// TODO: Hoist this up to getMatchingTypes or something | ||
// We do this here because we need the alpha value (if any) | ||
let [color, alpha] = splitUtilityModifier(rawModifier); | ||
let [color, alpha] = splitUtilityModifier(modifier); | ||
if (alpha !== undefined) { | ||
var ref2, ref3, ref4; | ||
var ref5; | ||
let normalizedColor = (ref5 = (ref2 = options.values) === null || ref2 === void 0 ? void 0 : ref2[color]) !== null && ref5 !== void 0 ? ref5 : isArbitraryValue(color) ? color.slice(1, -1) : undefined; | ||
var _options_values2, _tailwindConfig_theme, _tailwindConfig_theme_opacity; | ||
var _options_values_color; | ||
let normalizedColor = (_options_values_color = (_options_values2 = options.values) === null || _options_values2 === void 0 ? void 0 : _options_values2[color]) !== null && _options_values_color !== void 0 ? _options_values_color : isArbitraryValue(color) ? color.slice(1, -1) : undefined; | ||
if (normalizedColor === undefined) { | ||
@@ -149,5 +162,5 @@ return undefined; | ||
if (isArbitraryValue(alpha)) { | ||
return (0, _withAlphaVariable.withAlphaValue)(normalizedColor, alpha.slice(1, -1)); | ||
return (0, _withAlphaVariable.withAlphaValue)(normalizedColor, unwrapArbitraryModifier(alpha)); | ||
} | ||
if (((ref3 = tailwindConfig.theme) === null || ref3 === void 0 ? void 0 : (ref4 = ref3.opacity) === null || ref4 === void 0 ? void 0 : ref4[alpha]) === undefined) { | ||
if (((_tailwindConfig_theme = tailwindConfig.theme) === null || _tailwindConfig_theme === void 0 ? void 0 : (_tailwindConfig_theme_opacity = _tailwindConfig_theme.opacity) === null || _tailwindConfig_theme_opacity === void 0 ? void 0 : _tailwindConfig_theme_opacity[alpha]) === undefined) { | ||
return undefined; | ||
@@ -157,5 +170,3 @@ } | ||
} | ||
return asValue(rawModifier, options, { | ||
rawModifier, | ||
utilityModifier, | ||
return asValue(modifier, options, { | ||
validate: _dataTypes.color | ||
@@ -165,9 +176,8 @@ }); | ||
function asLookupValue(modifier, options = {}) { | ||
var ref; | ||
return (ref = options.values) === null || ref === void 0 ? void 0 : ref[modifier]; | ||
var _options_values; | ||
return (_options_values = options.values) === null || _options_values === void 0 ? void 0 : _options_values[modifier]; | ||
} | ||
function guess(validate) { | ||
return (modifier, options, extras)=>{ | ||
return (modifier, options)=>{ | ||
return asValue(modifier, options, { | ||
...extras, | ||
validate | ||
@@ -208,2 +218,17 @@ }); | ||
function coerceValue(types, modifier, options, tailwindConfig) { | ||
if (options.values && modifier in options.values) { | ||
for (let { type } of types !== null && types !== void 0 ? types : []){ | ||
let result = typeMap[type](modifier, options, { | ||
tailwindConfig | ||
}); | ||
if (result === undefined) { | ||
continue; | ||
} | ||
return [ | ||
result, | ||
type, | ||
null | ||
]; | ||
} | ||
} | ||
if (isArbitraryValue(modifier)) { | ||
@@ -236,3 +261,3 @@ let arbitraryValue = modifier.slice(1, -1); | ||
function* getMatchingTypes(types, rawModifier, options, tailwindConfig) { | ||
let modifiersEnabled = (0, _featureFlagsJs.flagEnabled)(tailwindConfig, "generalizedModifiers"); | ||
let modifiersEnabled = (0, _featureFlags.flagEnabled)(tailwindConfig, "generalizedModifiers"); | ||
let [modifier, utilityModifier] = splitUtilityModifier(rawModifier); | ||
@@ -251,35 +276,21 @@ let canUseUtilityModifier = modifiersEnabled && options.modifiers != null && (options.modifiers === "any" || typeof options.modifiers === "object" && (utilityModifier && isArbitraryValue(utilityModifier) || utilityModifier in options.modifiers)); | ||
if (typeof options.modifiers === "object") { | ||
var ref; | ||
var ref1; | ||
let configValue = (ref1 = (ref = options.modifiers) === null || ref === void 0 ? void 0 : ref[utilityModifier]) !== null && ref1 !== void 0 ? ref1 : null; | ||
var _options_modifiers; | ||
var _options_modifiers_utilityModifier; | ||
let configValue = (_options_modifiers_utilityModifier = (_options_modifiers = options.modifiers) === null || _options_modifiers === void 0 ? void 0 : _options_modifiers[utilityModifier]) !== null && _options_modifiers_utilityModifier !== void 0 ? _options_modifiers_utilityModifier : null; | ||
if (configValue !== null) { | ||
utilityModifier = configValue; | ||
} else if (isArbitraryValue(utilityModifier)) { | ||
utilityModifier = utilityModifier.slice(1, -1); | ||
utilityModifier = unwrapArbitraryModifier(utilityModifier); | ||
} | ||
} | ||
let result = asValue(rawModifier, options, { | ||
rawModifier, | ||
utilityModifier, | ||
tailwindConfig | ||
}); | ||
if (result !== undefined) { | ||
yield [ | ||
result, | ||
"any", | ||
null | ||
]; | ||
} | ||
} | ||
for (const { type } of types !== null && types !== void 0 ? types : []){ | ||
let result1 = typeMap[type](modifier, options, { | ||
rawModifier, | ||
utilityModifier, | ||
for (let { type } of types !== null && types !== void 0 ? types : []){ | ||
let result = typeMap[type](modifier, options, { | ||
tailwindConfig | ||
}); | ||
if (result1 === undefined) { | ||
if (result === undefined) { | ||
continue; | ||
} | ||
yield [ | ||
result1, | ||
result, | ||
type, | ||
@@ -286,0 +297,0 @@ utilityModifier !== null && utilityModifier !== void 0 ? utilityModifier : null |
@@ -5,8 +5,21 @@ "use strict"; | ||
}); | ||
Object.defineProperty(exports, "default", { | ||
Object.defineProperty(exports, /** | ||
* @template {string | import('postcss-selector-parser').Root} T | ||
* | ||
* Prefix all classes in the selector with the given prefix | ||
* | ||
* It can take either a string or a selector AST and will return the same type | ||
* | ||
* @param {string} prefix | ||
* @param {T} selector | ||
* @param {boolean} prependNegative | ||
* @returns {T} | ||
*/ "default", { | ||
enumerable: true, | ||
get: ()=>_default | ||
get: function() { | ||
return _default; | ||
} | ||
}); | ||
const _postcssSelectorParser = /*#__PURE__*/ _interopRequireDefault(require("postcss-selector-parser")); | ||
function _interopRequireDefault(obj) { | ||
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -17,9 +30,12 @@ default: obj | ||
function _default(prefix, selector, prependNegative = false) { | ||
return (0, _postcssSelectorParser.default)((selectors)=>{ | ||
selectors.walkClasses((classSelector)=>{ | ||
let baseClass = classSelector.value; | ||
let shouldPlaceNegativeBeforePrefix = prependNegative && baseClass.startsWith("-"); | ||
classSelector.value = shouldPlaceNegativeBeforePrefix ? `-${prefix}${baseClass.slice(1)}` : `${prefix}${baseClass}`; | ||
}); | ||
}).processSync(selector); | ||
if (prefix === "") { | ||
return selector; | ||
} | ||
/** @type {import('postcss-selector-parser').Root} */ let ast = typeof selector === "string" ? (0, _postcssselectorparser.default)().astSync(selector) : selector; | ||
ast.walkClasses((classSelector)=>{ | ||
let baseClass = classSelector.value; | ||
let shouldPlaceNegativeBeforePrefix = prependNegative && baseClass.startsWith("-"); | ||
classSelector.value = shouldPlaceNegativeBeforePrefix ? `-${prefix}${baseClass.slice(1)}` : `${prefix}${baseClass}`; | ||
}); | ||
return typeof selector === "string" ? ast.toString() : ast; | ||
} |
@@ -15,3 +15,5 @@ /** | ||
enumerable: true, | ||
get: ()=>removeAlphaVariables | ||
get: function() { | ||
return removeAlphaVariables; | ||
} | ||
}); | ||
@@ -18,0 +20,0 @@ function removeAlphaVariables(container, toRemove) { |
@@ -7,18 +7,19 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>resolveConfig | ||
get: function() { | ||
return resolveConfig; | ||
} | ||
}); | ||
const _negateValue = /*#__PURE__*/ _interopRequireDefault(require("./negateValue")); | ||
const _corePluginList = /*#__PURE__*/ _interopRequireDefault(require("../corePluginList")); | ||
const _configurePlugins = /*#__PURE__*/ _interopRequireDefault(require("./configurePlugins")); | ||
const _defaultConfigStub = /*#__PURE__*/ _interopRequireDefault(require("../../stubs/defaultConfig.stub")); | ||
const _colors = /*#__PURE__*/ _interopRequireDefault(require("../public/colors")); | ||
const _negateValue = /*#__PURE__*/ _interop_require_default(require("./negateValue")); | ||
const _corePluginList = /*#__PURE__*/ _interop_require_default(require("../corePluginList")); | ||
const _configurePlugins = /*#__PURE__*/ _interop_require_default(require("./configurePlugins")); | ||
const _colors = /*#__PURE__*/ _interop_require_default(require("../public/colors")); | ||
const _defaults = require("./defaults"); | ||
const _toPath = require("./toPath"); | ||
const _normalizeConfig = require("./normalizeConfig"); | ||
const _isPlainObject = /*#__PURE__*/ _interopRequireDefault(require("./isPlainObject")); | ||
const _isPlainObject = /*#__PURE__*/ _interop_require_default(require("./isPlainObject")); | ||
const _cloneDeep = require("./cloneDeep"); | ||
const _pluginUtils = require("./pluginUtils"); | ||
const _withAlphaVariable = require("./withAlphaVariable"); | ||
const _toColorValue = /*#__PURE__*/ _interopRequireDefault(require("./toColorValue")); | ||
function _interopRequireDefault(obj) { | ||
const _toColorValue = /*#__PURE__*/ _interop_require_default(require("./toColorValue")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -193,4 +194,4 @@ default: obj | ||
]; | ||
var ref; | ||
const plugins = (ref = config === null || config === void 0 ? void 0 : config.plugins) !== null && ref !== void 0 ? ref : []; | ||
var _config_plugins; | ||
const plugins = (_config_plugins = config === null || config === void 0 ? void 0 : config.plugins) !== null && _config_plugins !== void 0 ? _config_plugins : []; | ||
if (plugins.length === 0) { | ||
@@ -203,7 +204,7 @@ return; | ||
} | ||
var ref; | ||
var _plugin_config; | ||
allConfigs = [ | ||
...allConfigs, | ||
...extractPluginConfigs([ | ||
(ref = plugin === null || plugin === void 0 ? void 0 : plugin.config) !== null && ref !== void 0 ? ref : {} | ||
(_plugin_config = plugin === null || plugin === void 0 ? void 0 : plugin.config) !== null && _plugin_config !== void 0 ? _plugin_config : {} | ||
]) | ||
@@ -245,16 +246,15 @@ ]; | ||
important: false, | ||
separator: ":", | ||
variantOrder: _defaultConfigStub.default.variantOrder | ||
separator: ":" | ||
} | ||
]; | ||
var ref, ref1; | ||
var _t_theme, _c_plugins; | ||
return (0, _normalizeConfig.normalizeConfig)((0, _defaults.defaults)({ | ||
theme: resolveFunctionKeys(mergeExtensions(mergeThemes(allConfigs.map((t)=>{ | ||
return (ref = t === null || t === void 0 ? void 0 : t.theme) !== null && ref !== void 0 ? ref : {}; | ||
return (_t_theme = t === null || t === void 0 ? void 0 : t.theme) !== null && _t_theme !== void 0 ? _t_theme : {}; | ||
})))), | ||
corePlugins: resolveCorePlugins(allConfigs.map((c)=>c.corePlugins)), | ||
plugins: resolvePluginLists(configs.map((c)=>{ | ||
return (ref1 = c === null || c === void 0 ? void 0 : c.plugins) !== null && ref1 !== void 0 ? ref1 : []; | ||
return (_c_plugins = c === null || c === void 0 ? void 0 : c.plugins) !== null && _c_plugins !== void 0 ? _c_plugins : []; | ||
})) | ||
}, ...allConfigs)); | ||
} |
@@ -5,9 +5,19 @@ "use strict"; | ||
}); | ||
Object.defineProperty(exports, "default", { | ||
enumerable: true, | ||
get: ()=>resolveConfigPath | ||
function _export(target, all) { | ||
for(var name in all)Object.defineProperty(target, name, { | ||
enumerable: true, | ||
get: all[name] | ||
}); | ||
} | ||
_export(exports, { | ||
default: function() { | ||
return resolveConfigPath; | ||
}, | ||
resolveDefaultConfigPath: function() { | ||
return resolveDefaultConfigPath; | ||
} | ||
}); | ||
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs")); | ||
const _path = /*#__PURE__*/ _interopRequireDefault(require("path")); | ||
function _interopRequireDefault(obj) { | ||
const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | ||
const _path = /*#__PURE__*/ _interop_require_default(require("path")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -17,2 +27,8 @@ default: obj | ||
} | ||
const defaultConfigFiles = [ | ||
"./tailwind.config.js", | ||
"./tailwind.config.cjs", | ||
"./tailwind.config.mjs", | ||
"./tailwind.config.ts" | ||
]; | ||
function isObject(value) { | ||
@@ -45,6 +61,6 @@ return typeof value === "object" && value !== null; | ||
// require('tailwindcss') | ||
for (const configFile of [ | ||
"./tailwind.config.js", | ||
"./tailwind.config.cjs" | ||
]){ | ||
return resolveDefaultConfigPath(); | ||
} | ||
function resolveDefaultConfigPath() { | ||
for (const configFile of defaultConfigFiles){ | ||
try { | ||
@@ -51,0 +67,0 @@ const configPath = _path.default.resolve(configFile); |
@@ -7,7 +7,9 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>responsive | ||
get: function() { | ||
return responsive; | ||
} | ||
}); | ||
const _postcss = /*#__PURE__*/ _interopRequireDefault(require("postcss")); | ||
const _cloneNodes = /*#__PURE__*/ _interopRequireDefault(require("./cloneNodes")); | ||
function _interopRequireDefault(obj) { | ||
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss")); | ||
const _cloneNodes = /*#__PURE__*/ _interop_require_default(require("./cloneNodes")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -14,0 +16,0 @@ default: obj |
@@ -21,3 +21,5 @@ /** | ||
enumerable: true, | ||
get: ()=>splitAtTopLevelOnly | ||
get: function() { | ||
return splitAtTopLevelOnly; | ||
} | ||
}); | ||
@@ -28,5 +30,6 @@ function splitAtTopLevelOnly(input, separator) { | ||
let lastPos = 0; | ||
let isEscaped = false; | ||
for(let idx = 0; idx < input.length; idx++){ | ||
let char = input[idx]; | ||
if (stack.length === 0 && char === separator[0]) { | ||
if (stack.length === 0 && char === separator[0] && !isEscaped) { | ||
if (separator.length === 1 || input.slice(idx, idx + separator.length) === separator) { | ||
@@ -37,2 +40,7 @@ parts.push(input.slice(lastPos, idx)); | ||
} | ||
if (isEscaped) { | ||
isEscaped = false; | ||
} else if (char === "\\") { | ||
isEscaped = true; | ||
} | ||
if (char === "(" || char === "[" || char === "{") { | ||
@@ -39,0 +47,0 @@ stack.push(char); |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>tap | ||
get: function() { | ||
return tap; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ function tap(value, mutator) { |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>toColorValue | ||
get: function() { | ||
return toColorValue; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ function toColorValue(maybeFunction) { |
@@ -20,3 +20,5 @@ /** | ||
enumerable: true, | ||
get: ()=>toPath | ||
get: function() { | ||
return toPath; | ||
} | ||
}); | ||
@@ -23,0 +25,0 @@ function toPath(path) { |
@@ -7,7 +7,9 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>transformThemeValue | ||
get: function() { | ||
return transformThemeValue; | ||
} | ||
}); | ||
const _postcss = /*#__PURE__*/ _interopRequireDefault(require("postcss")); | ||
const _isPlainObject = /*#__PURE__*/ _interopRequireDefault(require("./isPlainObject")); | ||
function _interopRequireDefault(obj) { | ||
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss")); | ||
const _isPlainObject = /*#__PURE__*/ _interop_require_default(require("./isPlainObject")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -14,0 +16,0 @@ default: obj |
@@ -7,6 +7,8 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>validateConfig | ||
get: function() { | ||
return validateConfig; | ||
} | ||
}); | ||
const _log = /*#__PURE__*/ _interopRequireDefault(require("./log")); | ||
function _interopRequireDefault(obj) { | ||
const _log = /*#__PURE__*/ _interop_require_default(require("./log")); | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
@@ -24,3 +26,14 @@ default: obj | ||
} | ||
// Warn if the line-clamp plugin is installed | ||
try { | ||
let plugin = require("@tailwindcss/line-clamp"); | ||
if (config.plugins.includes(plugin)) { | ||
_log.default.warn("line-clamp-in-core", [ | ||
"As of Tailwind CSS v3.3, the `@tailwindcss/line-clamp` plugin is now included by default.", | ||
"Remove it from the `plugins` array in your configuration to eliminate this warning." | ||
]); | ||
config.plugins = config.plugins.filter((p)=>p !== plugin); | ||
} | ||
} catch {} | ||
return config; | ||
} |
@@ -7,3 +7,5 @@ "use strict"; | ||
enumerable: true, | ||
get: ()=>backgroundSize | ||
get: function() { | ||
return backgroundSize; | ||
} | ||
}); | ||
@@ -10,0 +12,0 @@ const _dataTypes = require("./dataTypes"); |
@@ -12,4 +12,8 @@ "use strict"; | ||
_export(exports, { | ||
withAlphaValue: ()=>withAlphaValue, | ||
default: ()=>withAlphaVariable | ||
withAlphaValue: function() { | ||
return withAlphaValue; | ||
}, | ||
default: function() { | ||
return withAlphaVariable; | ||
} | ||
}); | ||
@@ -16,0 +20,0 @@ const _color = require("./color"); |
{ | ||
"name": "tailwindcss", | ||
"version": "3.2.4", | ||
"version": "3.3.6", | ||
"description": "A utility-first CSS framework for rapidly building custom user interfaces.", | ||
@@ -15,8 +15,10 @@ "license": "MIT", | ||
}, | ||
"tailwindcss": { | ||
"engine": "stable" | ||
}, | ||
"scripts": { | ||
"preswcify": "npm run generate && rimraf lib", | ||
"swcify": "swc src --out-dir lib --copy-files", | ||
"postswcify": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js", | ||
"rebuild-fixtures": "npm run swcify && node -r @swc/register scripts/rebuildFixtures.js", | ||
"prepublishOnly": "npm install --force && npm run swcify", | ||
"prebuild": "npm run generate && rimraf lib", | ||
"build": "swc src --out-dir lib --copy-files --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"false\"'", | ||
"postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", | ||
"rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", | ||
"style": "eslint .", | ||
@@ -31,3 +33,4 @@ "pretest": "npm run generate", | ||
"release-channel": "node ./scripts/release-channel.js", | ||
"release-notes": "node ./scripts/release-notes.js" | ||
"release-notes": "node ./scripts/release-notes.js", | ||
"prepublishOnly": "npm install --force && npm run build" | ||
}, | ||
@@ -40,3 +43,3 @@ "files": [ | ||
"scripts/*.js", | ||
"stubs/*.stub.js", | ||
"stubs/*", | ||
"nesting/*", | ||
@@ -49,32 +52,33 @@ "types/**/*", | ||
"devDependencies": { | ||
"@swc/cli": "^0.1.57", | ||
"@swc/core": "^1.3.11", | ||
"@swc/jest": "^0.2.23", | ||
"@swc/cli": "^0.1.62", | ||
"@swc/core": "^1.3.55", | ||
"@swc/jest": "^0.2.26", | ||
"@swc/register": "^0.1.10", | ||
"autoprefixer": "^10.4.13", | ||
"cssnano": "^5.1.14", | ||
"esbuild": "^0.15.12", | ||
"eslint": "^8.26.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"autoprefixer": "^10.4.14", | ||
"browserslist": "^4.21.5", | ||
"concurrently": "^8.0.1", | ||
"cssnano": "^6.0.0", | ||
"esbuild": "^0.17.18", | ||
"eslint": "^8.39.0", | ||
"eslint-config-prettier": "^8.8.0", | ||
"eslint-plugin-prettier": "^4.2.1", | ||
"jest": "^28.1.3", | ||
"jest-diff": "^28.1.3", | ||
"prettier": "^2.7.1", | ||
"rimraf": "^3.0.0", | ||
"source-map-js": "^1.0.2" | ||
"jest": "^29.6.0", | ||
"jest-diff": "^29.6.0", | ||
"lightningcss": "1.18.0", | ||
"prettier": "^2.8.8", | ||
"rimraf": "^5.0.0", | ||
"source-map-js": "^1.0.2", | ||
"turbo": "^1.9.3" | ||
}, | ||
"peerDependencies": { | ||
"postcss": "^8.0.9" | ||
}, | ||
"dependencies": { | ||
"@alloc/quick-lru": "^5.2.0", | ||
"arg": "^5.0.2", | ||
"chokidar": "^3.5.3", | ||
"color-name": "^1.1.4", | ||
"detective": "^5.2.1", | ||
"didyoumean": "^1.2.2", | ||
"dlv": "^1.1.3", | ||
"fast-glob": "^3.2.12", | ||
"fast-glob": "^3.3.0", | ||
"glob-parent": "^6.0.2", | ||
"is-glob": "^4.0.3", | ||
"lilconfig": "^2.0.6", | ||
"jiti": "^1.19.1", | ||
"lilconfig": "^2.1.0", | ||
"micromatch": "^4.0.5", | ||
@@ -84,11 +88,10 @@ "normalize-path": "^3.0.0", | ||
"picocolors": "^1.0.0", | ||
"postcss": "^8.4.18", | ||
"postcss-import": "^14.1.0", | ||
"postcss-js": "^4.0.0", | ||
"postcss-load-config": "^3.1.4", | ||
"postcss-nested": "6.0.0", | ||
"postcss-selector-parser": "^6.0.10", | ||
"postcss-value-parser": "^4.2.0", | ||
"quick-lru": "^5.1.1", | ||
"resolve": "^1.22.1" | ||
"postcss": "^8.4.23", | ||
"postcss-import": "^15.1.0", | ||
"postcss-js": "^4.0.1", | ||
"postcss-load-config": "^4.0.1", | ||
"postcss-nested": "^6.0.1", | ||
"postcss-selector-parser": "^6.0.11", | ||
"resolve": "^1.22.2", | ||
"sucrase": "^3.32.0" | ||
}, | ||
@@ -112,9 +115,13 @@ "browserslist": [ | ||
], | ||
"transformIgnorePatterns": [ | ||
"node_modules/(?!lightningcss)" | ||
], | ||
"transform": { | ||
"\\.js$": "@swc/jest" | ||
"\\.js$": "@swc/jest", | ||
"\\.ts$": "@swc/jest" | ||
} | ||
}, | ||
"engines": { | ||
"node": ">=12.13.0" | ||
"node": ">=14.0.0" | ||
} | ||
} |
@@ -17,3 +17,3 @@ <p align="center"> | ||
<p align="center"> | ||
<a href="https://github.com/tailwindlabs/tailwindcss/actions"><img src="https://img.shields.io/github/workflow/status/tailwindlabs/tailwindcss/Node.js%20CI" alt="Build Status"></a> | ||
<a href="https://github.com/tailwindlabs/tailwindcss/actions"><img src="https://img.shields.io/github/actions/workflow/status/tailwindlabs/tailwindcss/ci-stable.yml?branch=master" alt="Build Status"></a> | ||
<a href="https://www.npmjs.com/package/tailwindcss"><img src="https://img.shields.io/npm/dt/tailwindcss.svg" alt="Total Downloads"></a> | ||
@@ -20,0 +20,0 @@ <a href="https://github.com/tailwindcss/tailwindcss/releases"><img src="https://img.shields.io/npm/v/tailwindcss.svg" alt="Latest Release"></a> |
@@ -1,3 +0,31 @@ | ||
import type { Config } from './types/config' | ||
declare function resolveConfig(config: Config): Config | ||
import { Config, ResolvableTo, ThemeConfig } from './types/config' | ||
import { DefaultTheme } from './types/generated/default-theme' | ||
import { DefaultColors } from './types/generated/colors' | ||
type ResolvedConfig<T extends Config> = Omit<T, 'theme'> & { | ||
theme: MergeThemes< | ||
UnwrapResolvables<Omit<T['theme'], 'extend'>>, | ||
T['theme'] extends { extend: infer TExtend } ? UnwrapResolvables<TExtend> : {} | ||
> | ||
} | ||
type UnwrapResolvables<T> = { | ||
[K in keyof T]: T[K] extends ResolvableTo<infer R> ? R : T[K] | ||
} | ||
type ThemeConfigResolved = UnwrapResolvables<ThemeConfig> | ||
type DefaultThemeFull = DefaultTheme & { colors: DefaultColors } | ||
type MergeThemes<Overrides extends object, Extensions extends object> = { | ||
[K in keyof ThemeConfigResolved | keyof Overrides]: (K extends keyof Overrides | ||
? Overrides[K] | ||
: K extends keyof DefaultThemeFull | ||
? DefaultThemeFull[K] | ||
: K extends keyof ThemeConfigResolved | ||
? ThemeConfigResolved[K] | ||
: never) & | ||
(K extends keyof Extensions ? Extensions[K] : {}) | ||
} | ||
declare function resolveConfig<T extends Config>(config: T): ResolvedConfig<T> | ||
export = resolveConfig |
@@ -94,5 +94,4 @@ import prettier from 'prettier' | ||
` | ||
import { Config } from '../../types' | ||
type CSSDeclarationList = Record<string, string> | ||
export type DefaultTheme = Config['theme'] & { ${defaultThemeTypes} } | ||
export type DefaultTheme = { ${defaultThemeTypes} } | ||
`, | ||
@@ -99,0 +98,0 @@ { |
224
src/cli.js
#!/usr/bin/env node | ||
import path from 'path' | ||
import arg from 'arg' | ||
import fs from 'fs' | ||
import { build } from './cli/build' | ||
import { help } from './cli/help' | ||
import { init } from './cli/init' | ||
function isESM() { | ||
const pkgPath = path.resolve('./package.json') | ||
try { | ||
let pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) | ||
return pkg.type && pkg.type === 'module' | ||
} catch (err) { | ||
return false | ||
} | ||
if (__OXIDE__) { | ||
module.exports = require('./oxide/cli') | ||
} else { | ||
module.exports = require('./cli/index') | ||
} | ||
let configs = isESM() | ||
? { | ||
tailwind: 'tailwind.config.cjs', | ||
postcss: 'postcss.config.cjs', | ||
} | ||
: { | ||
tailwind: 'tailwind.config.js', | ||
postcss: 'postcss.config.js', | ||
} | ||
// --- | ||
function oneOf(...options) { | ||
return Object.assign( | ||
(value = true) => { | ||
for (let option of options) { | ||
let parsed = option(value) | ||
if (parsed === value) { | ||
return parsed | ||
} | ||
} | ||
throw new Error('...') | ||
}, | ||
{ manualParsing: true } | ||
) | ||
} | ||
let commands = { | ||
init: { | ||
run: init, | ||
args: { | ||
'--full': { type: Boolean, description: `Initialize a full \`${configs.tailwind}\` file` }, | ||
'--postcss': { type: Boolean, description: `Initialize a \`${configs.postcss}\` file` }, | ||
'-f': '--full', | ||
'-p': '--postcss', | ||
}, | ||
}, | ||
build: { | ||
run: build, | ||
args: { | ||
'--input': { type: String, description: 'Input file' }, | ||
'--output': { type: String, description: 'Output file' }, | ||
'--watch': { type: Boolean, description: 'Watch for changes and rebuild as needed' }, | ||
'--poll': { | ||
type: Boolean, | ||
description: 'Use polling instead of filesystem events when watching', | ||
}, | ||
'--content': { | ||
type: String, | ||
description: 'Content paths to use for removing unused classes', | ||
}, | ||
'--purge': { | ||
type: String, | ||
deprecated: true, | ||
}, | ||
'--postcss': { | ||
type: oneOf(String, Boolean), | ||
description: 'Load custom PostCSS configuration', | ||
}, | ||
'--minify': { type: Boolean, description: 'Minify the output' }, | ||
'--config': { | ||
type: String, | ||
description: 'Path to a custom config file', | ||
}, | ||
'--no-autoprefixer': { | ||
type: Boolean, | ||
description: 'Disable autoprefixer', | ||
}, | ||
'-c': '--config', | ||
'-i': '--input', | ||
'-o': '--output', | ||
'-m': '--minify', | ||
'-w': '--watch', | ||
'-p': '--poll', | ||
}, | ||
}, | ||
} | ||
let sharedFlags = { | ||
'--help': { type: Boolean, description: 'Display usage information' }, | ||
'-h': '--help', | ||
} | ||
if ( | ||
process.stdout.isTTY /* Detect redirecting output to a file */ && | ||
(process.argv[2] === undefined || | ||
process.argv.slice(2).every((flag) => sharedFlags[flag] !== undefined)) | ||
) { | ||
help({ | ||
usage: [ | ||
'tailwindcss [--input input.css] [--output output.css] [--watch] [options...]', | ||
'tailwindcss init [--full] [--postcss] [options...]', | ||
], | ||
commands: Object.keys(commands) | ||
.filter((command) => command !== 'build') | ||
.map((command) => `${command} [options]`), | ||
options: { ...commands.build.args, ...sharedFlags }, | ||
}) | ||
process.exit(0) | ||
} | ||
let command = ((arg = '') => (arg.startsWith('-') ? undefined : arg))(process.argv[2]) || 'build' | ||
if (commands[command] === undefined) { | ||
if (fs.existsSync(path.resolve(command))) { | ||
// TODO: Deprecate this in future versions | ||
// Check if non-existing command, might be a file. | ||
command = 'build' | ||
} else { | ||
help({ | ||
message: `Invalid command: ${command}`, | ||
usage: ['tailwindcss <command> [options]'], | ||
commands: Object.keys(commands) | ||
.filter((command) => command !== 'build') | ||
.map((command) => `${command} [options]`), | ||
options: sharedFlags, | ||
}) | ||
process.exit(1) | ||
} | ||
} | ||
// Execute command | ||
let { args: flags, run } = commands[command] | ||
let args = (() => { | ||
try { | ||
let result = arg( | ||
Object.fromEntries( | ||
Object.entries({ ...flags, ...sharedFlags }) | ||
.filter(([_key, value]) => !value?.type?.manualParsing) | ||
.map(([key, value]) => [key, typeof value === 'object' ? value.type : value]) | ||
), | ||
{ permissive: true } | ||
) | ||
// Manual parsing of flags to allow for special flags like oneOf(Boolean, String) | ||
for (let i = result['_'].length - 1; i >= 0; --i) { | ||
let flag = result['_'][i] | ||
if (!flag.startsWith('-')) continue | ||
let flagName = flag | ||
let handler = flags[flag] | ||
// Resolve flagName & handler | ||
while (typeof handler === 'string') { | ||
flagName = handler | ||
handler = flags[handler] | ||
} | ||
if (!handler) continue | ||
let args = [] | ||
let offset = i + 1 | ||
// Parse args for current flag | ||
while (result['_'][offset] && !result['_'][offset].startsWith('-')) { | ||
args.push(result['_'][offset++]) | ||
} | ||
// Cleanup manually parsed flags + args | ||
result['_'].splice(i, 1 + args.length) | ||
// Set the resolved value in the `result` object | ||
result[flagName] = handler.type( | ||
args.length === 0 ? undefined : args.length === 1 ? args[0] : args, | ||
flagName | ||
) | ||
} | ||
// Ensure that the `command` is always the first argument in the `args`. | ||
// This is important so that we don't have to check if a default command | ||
// (build) was used or not from within each plugin. | ||
// | ||
// E.g.: tailwindcss input.css -> _: ['build', 'input.css'] | ||
// E.g.: tailwindcss build input.css -> _: ['build', 'input.css'] | ||
if (result['_'][0] !== command) { | ||
result['_'].unshift(command) | ||
} | ||
return result | ||
} catch (err) { | ||
if (err.code === 'ARG_UNKNOWN_OPTION') { | ||
help({ | ||
message: err.message, | ||
usage: ['tailwindcss <command> [options]'], | ||
options: sharedFlags, | ||
}) | ||
process.exit(1) | ||
} | ||
throw err | ||
} | ||
})() | ||
if (args['--help']) { | ||
help({ | ||
options: { ...flags, ...sharedFlags }, | ||
usage: [`tailwindcss ${command} [options]`], | ||
}) | ||
process.exit(0) | ||
} | ||
run(args, configs) |
@@ -5,5 +5,6 @@ // @ts-check | ||
import path from 'path' | ||
import { resolveDefaultConfigPath } from '../../util/resolveConfigPath.js' | ||
import { createProcessor } from './plugin.js' | ||
export async function build(args, configs) { | ||
export async function build(args) { | ||
let input = args['--input'] | ||
@@ -29,7 +30,3 @@ let shouldWatch = args['--watch'] | ||
// TODO: Reference the @config path here if exists | ||
let configPath = args['--config'] | ||
? args['--config'] | ||
: ((defaultPath) => (fs.existsSync(defaultPath) ? defaultPath : null))( | ||
path.resolve(`./${configs.tailwind}`) | ||
) | ||
let configPath = args['--config'] ? args['--config'] : resolveDefaultConfigPath() | ||
@@ -39,4 +36,8 @@ let processor = await createProcessor(args, configPath) | ||
if (shouldWatch) { | ||
/* Abort the watcher if stdin is closed to avoid zombie processes */ | ||
process.stdin.on('end', () => process.exit(0)) | ||
// Abort the watcher if stdin is closed to avoid zombie processes | ||
// You can disable this behavior with --watch=always | ||
if (args['--watch'] !== 'always') { | ||
process.stdin.on('end', () => process.exit(0)) | ||
} | ||
process.stdin.resume() | ||
@@ -46,4 +47,7 @@ | ||
} else { | ||
await processor.build() | ||
await processor.build().catch((e) => { | ||
console.error(e) | ||
process.exit(1) | ||
}) | ||
} | ||
} |
@@ -13,5 +13,4 @@ // @ts-check | ||
import { formatNodes, drainStdin, outputFile } from './utils' | ||
import { env } from '../shared' | ||
import { env } from '../../lib/sharedState' | ||
import resolveConfig from '../../../resolveConfig.js' | ||
import getModuleDependencies from '../../lib/getModuleDependencies.js' | ||
import { parseCandidateFiles } from '../../lib/content.js' | ||
@@ -22,2 +21,4 @@ import { createWatcher } from './watching.js' | ||
import log from '../../util/log' | ||
import { loadConfig } from '../../lib/load-config' | ||
import getModuleDependencies from '../../lib/getModuleDependencies' | ||
@@ -122,3 +123,5 @@ /** | ||
configDependencies: new Set(), | ||
/** @type {ReturnType<typeof load> | null} */ | ||
configBag: null, | ||
contextDependencies: new Set(), | ||
@@ -148,33 +151,31 @@ | ||
if (this.watcher && configPath) { | ||
this.refreshConfigDependencies(configPath) | ||
this.refreshConfigDependencies() | ||
} | ||
let config = configPath ? require(configPath) : {} | ||
let config = loadConfig(configPath) | ||
let dependencies = getModuleDependencies(configPath) | ||
this.configBag = { | ||
config, | ||
dependencies, | ||
dispose() { | ||
for (let file of dependencies) { | ||
delete require.cache[require.resolve(file)] | ||
} | ||
}, | ||
} | ||
// @ts-ignore | ||
config = resolveConfig(config, { content: { files: [] } }) | ||
this.configBag.config = resolveConfig(this.configBag.config, { content: { files: [] } }) | ||
// Override content files if `--content` has been passed explicitly | ||
if (content?.length > 0) { | ||
config.content.files = content | ||
this.configBag.config.content.files = content | ||
} | ||
return config | ||
return this.configBag.config | ||
}, | ||
refreshConfigDependencies(configPath) { | ||
refreshConfigDependencies() { | ||
env.DEBUG && console.time('Module dependencies') | ||
for (let file of this.configDependencies) { | ||
delete require.cache[require.resolve(file)] | ||
} | ||
if (configPath) { | ||
let deps = getModuleDependencies(configPath).map(({ file }) => file) | ||
for (let dependency of deps) { | ||
this.configDependencies.add(dependency) | ||
} | ||
} | ||
this.configBag?.dispose() | ||
env.DEBUG && console.timeEnd('Module dependencies') | ||
@@ -191,6 +192,13 @@ }, | ||
for (let file of files) { | ||
content.push({ | ||
content: fs.readFileSync(path.resolve(file), 'utf8'), | ||
extension: path.extname(file).slice(1), | ||
}) | ||
if (__OXIDE__) { | ||
content.push({ | ||
file, | ||
extension: path.extname(file).slice(1), | ||
}) | ||
} else { | ||
content.push({ | ||
content: fs.readFileSync(path.resolve(file), 'utf8'), | ||
extension: path.extname(file).slice(1), | ||
}) | ||
} | ||
} | ||
@@ -211,2 +219,6 @@ | ||
getContext({ createContext, cliConfigPath, root, result, content }) { | ||
env.DEBUG && console.time('Searching for config') | ||
let configPath = findAtConfigPath(root, result) ?? cliConfigPath | ||
env.DEBUG && console.timeEnd('Searching for config') | ||
if (this.context) { | ||
@@ -218,6 +230,2 @@ this.context.changedContent = this.changedContent.splice(0) | ||
env.DEBUG && console.time('Searching for config') | ||
let configPath = findAtConfigPath(root, result) ?? cliConfigPath | ||
env.DEBUG && console.timeEnd('Searching for config') | ||
env.DEBUG && console.time('Loading config') | ||
@@ -244,7 +252,5 @@ let config = this.loadConfig(configPath, content) | ||
env.DEBUG && console.time('Reading content files') | ||
for (let file of this.readContentPaths()) { | ||
this.context.changedContent.push(file) | ||
} | ||
env.DEBUG && console.timeEnd('Reading content files') | ||
@@ -283,5 +289,5 @@ return this.context | ||
postcssPlugin: 'tailwindcss', | ||
Once(root, { result }) { | ||
async Once(root, { result }) { | ||
env.DEBUG && console.time('Compiling CSS') | ||
tailwind(({ createContext }) => { | ||
await tailwind(({ createContext }) => { | ||
console.error() | ||
@@ -367,4 +373,4 @@ console.error('Rebuilding...') | ||
return Promise.all([ | ||
outputFile(output, result.css), | ||
result.map && outputFile(output + '.map', result.map.toString()), | ||
outputFile(result.opts.to, result.css), | ||
result.map && outputFile(result.opts.to + '.map', result.map.toString()), | ||
]) | ||
@@ -391,3 +397,7 @@ }) | ||
console.error(err) | ||
if (state.watcher) { | ||
console.error(err) | ||
} else { | ||
return Promise.reject(err) | ||
} | ||
} | ||
@@ -425,3 +435,3 @@ ) | ||
return ( | ||
state.configDependencies.has(change.file) || | ||
state.configBag?.dependencies.has(change.file) || | ||
state.contextDependencies.has(change.file) | ||
@@ -428,0 +438,0 @@ ) |
@@ -92,3 +92,5 @@ // @ts-check | ||
() => {}, | ||
() => {} | ||
(e) => { | ||
console.error(e.toString()) | ||
} | ||
) | ||
@@ -166,3 +168,3 @@ } | ||
watcher.on('raw', (evt, filePath, meta) => { | ||
if (evt !== 'rename') { | ||
if (evt !== 'rename' || filePath === null) { | ||
return | ||
@@ -225,3 +227,3 @@ } | ||
watcher.add(Array.from(state.contextDependencies)) | ||
watcher.add(Array.from(state.configDependencies)) | ||
watcher.add(Array.from(state.configBag.dependencies)) | ||
watcher.add(state.contentPatterns.all) | ||
@@ -228,0 +230,0 @@ }, |
@@ -1,3 +0,216 @@ | ||
export * from './build' | ||
export * from './config' | ||
export * from './content' | ||
#!/usr/bin/env node | ||
import path from 'path' | ||
import arg from 'arg' | ||
import fs from 'fs' | ||
import { build } from './build' | ||
import { help } from './help' | ||
import { init } from './init' | ||
function oneOf(...options) { | ||
return Object.assign( | ||
(value = true) => { | ||
for (let option of options) { | ||
let parsed = option(value) | ||
if (parsed === value) { | ||
return parsed | ||
} | ||
} | ||
throw new Error('...') | ||
}, | ||
{ manualParsing: true } | ||
) | ||
} | ||
let commands = { | ||
init: { | ||
run: init, | ||
args: { | ||
'--esm': { type: Boolean, description: `Initialize configuration file as ESM` }, | ||
'--ts': { type: Boolean, description: `Initialize configuration file as TypeScript` }, | ||
'--postcss': { type: Boolean, description: `Initialize a \`postcss.config.js\` file` }, | ||
'--full': { | ||
type: Boolean, | ||
description: `Include the default values for all options in the generated configuration file`, | ||
}, | ||
'-f': '--full', | ||
'-p': '--postcss', | ||
}, | ||
}, | ||
build: { | ||
run: build, | ||
args: { | ||
'--input': { type: String, description: 'Input file' }, | ||
'--output': { type: String, description: 'Output file' }, | ||
'--watch': { | ||
type: oneOf(String, Boolean), | ||
description: 'Watch for changes and rebuild as needed', | ||
}, | ||
'--poll': { | ||
type: Boolean, | ||
description: 'Use polling instead of filesystem events when watching', | ||
}, | ||
'--content': { | ||
type: String, | ||
description: 'Content paths to use for removing unused classes', | ||
}, | ||
'--purge': { | ||
type: String, | ||
deprecated: true, | ||
}, | ||
'--postcss': { | ||
type: oneOf(String, Boolean), | ||
description: 'Load custom PostCSS configuration', | ||
}, | ||
'--minify': { type: Boolean, description: 'Minify the output' }, | ||
'--config': { | ||
type: String, | ||
description: 'Path to a custom config file', | ||
}, | ||
'--no-autoprefixer': { | ||
type: Boolean, | ||
description: 'Disable autoprefixer', | ||
}, | ||
'-c': '--config', | ||
'-i': '--input', | ||
'-o': '--output', | ||
'-m': '--minify', | ||
'-w': '--watch', | ||
'-p': '--poll', | ||
}, | ||
}, | ||
} | ||
let sharedFlags = { | ||
'--help': { type: Boolean, description: 'Display usage information' }, | ||
'-h': '--help', | ||
} | ||
if ( | ||
process.stdout.isTTY /* Detect redirecting output to a file */ && | ||
(process.argv[2] === undefined || | ||
process.argv.slice(2).every((flag) => sharedFlags[flag] !== undefined)) | ||
) { | ||
help({ | ||
usage: [ | ||
'tailwindcss [--input input.css] [--output output.css] [--watch] [options...]', | ||
'tailwindcss init [--full] [--postcss] [options...]', | ||
], | ||
commands: Object.keys(commands) | ||
.filter((command) => command !== 'build') | ||
.map((command) => `${command} [options]`), | ||
options: { ...commands.build.args, ...sharedFlags }, | ||
}) | ||
process.exit(0) | ||
} | ||
let command = ((arg = '') => (arg.startsWith('-') ? undefined : arg))(process.argv[2]) || 'build' | ||
if (commands[command] === undefined) { | ||
if (fs.existsSync(path.resolve(command))) { | ||
// TODO: Deprecate this in future versions | ||
// Check if non-existing command, might be a file. | ||
command = 'build' | ||
} else { | ||
help({ | ||
message: `Invalid command: ${command}`, | ||
usage: ['tailwindcss <command> [options]'], | ||
commands: Object.keys(commands) | ||
.filter((command) => command !== 'build') | ||
.map((command) => `${command} [options]`), | ||
options: sharedFlags, | ||
}) | ||
process.exit(1) | ||
} | ||
} | ||
// Execute command | ||
let { args: flags, run } = commands[command] | ||
let args = (() => { | ||
try { | ||
let result = arg( | ||
Object.fromEntries( | ||
Object.entries({ ...flags, ...sharedFlags }) | ||
.filter(([_key, value]) => !value?.type?.manualParsing) | ||
.map(([key, value]) => [key, typeof value === 'object' ? value.type : value]) | ||
), | ||
{ permissive: true } | ||
) | ||
// Manual parsing of flags to allow for special flags like oneOf(Boolean, String) | ||
for (let i = result['_'].length - 1; i >= 0; --i) { | ||
let flag = result['_'][i] | ||
if (!flag.startsWith('-')) continue | ||
let [flagName, flagValue] = flag.split('=') | ||
let handler = flags[flagName] | ||
// Resolve flagName & handler | ||
while (typeof handler === 'string') { | ||
flagName = handler | ||
handler = flags[handler] | ||
} | ||
if (!handler) continue | ||
let args = [] | ||
let offset = i + 1 | ||
// --flag value syntax was used so we need to pull `value` from `args` | ||
if (flagValue === undefined) { | ||
// Parse args for current flag | ||
while (result['_'][offset] && !result['_'][offset].startsWith('-')) { | ||
args.push(result['_'][offset++]) | ||
} | ||
// Cleanup manually parsed flags + args | ||
result['_'].splice(i, 1 + args.length) | ||
// No args were provided, use default value defined in handler | ||
// One arg was provided, use that directly | ||
// Multiple args were provided so pass them all in an array | ||
flagValue = args.length === 0 ? undefined : args.length === 1 ? args[0] : args | ||
} else { | ||
// Remove the whole flag from the args array | ||
result['_'].splice(i, 1) | ||
} | ||
// Set the resolved value in the `result` object | ||
result[flagName] = handler.type(flagValue, flagName) | ||
} | ||
// Ensure that the `command` is always the first argument in the `args`. | ||
// This is important so that we don't have to check if a default command | ||
// (build) was used or not from within each plugin. | ||
// | ||
// E.g.: tailwindcss input.css -> _: ['build', 'input.css'] | ||
// E.g.: tailwindcss build input.css -> _: ['build', 'input.css'] | ||
if (result['_'][0] !== command) { | ||
result['_'].unshift(command) | ||
} | ||
return result | ||
} catch (err) { | ||
if (err.code === 'ARG_UNKNOWN_OPTION') { | ||
help({ | ||
message: err.message, | ||
usage: ['tailwindcss <command> [options]'], | ||
options: sharedFlags, | ||
}) | ||
process.exit(1) | ||
} | ||
throw err | ||
} | ||
})() | ||
if (args['--help']) { | ||
help({ | ||
options: { ...flags, ...sharedFlags }, | ||
usage: [`tailwindcss ${command} [options]`], | ||
}) | ||
process.exit(0) | ||
} | ||
run(args) |
@@ -6,19 +6,46 @@ // @ts-check | ||
export function init(args, configs) { | ||
function isESM() { | ||
const pkgPath = path.resolve('./package.json') | ||
try { | ||
let pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) | ||
return pkg.type && pkg.type === 'module' | ||
} catch (err) { | ||
return false | ||
} | ||
} | ||
export function init(args) { | ||
let messages = [] | ||
let tailwindConfigLocation = path.resolve(args['_'][1] ?? `./${configs.tailwind}`) | ||
let isProjectESM = args['--ts'] || args['--esm'] || isESM() | ||
let syntax = args['--ts'] ? 'ts' : isProjectESM ? 'js' : 'cjs' | ||
let extension = args['--ts'] ? 'ts' : 'js' | ||
let tailwindConfigLocation = path.resolve(args['_'][1] ?? `./tailwind.config.${extension}`) | ||
if (fs.existsSync(tailwindConfigLocation)) { | ||
messages.push(`${path.basename(tailwindConfigLocation)} already exists.`) | ||
} else { | ||
let stubFile = fs.readFileSync( | ||
let stubContentsFile = fs.readFileSync( | ||
args['--full'] | ||
? path.resolve(__dirname, '../../../stubs/defaultConfig.stub.js') | ||
: path.resolve(__dirname, '../../../stubs/simpleConfig.stub.js'), | ||
? path.resolve(__dirname, '../../../stubs/config.full.js') | ||
: path.resolve(__dirname, '../../../stubs/config.simple.js'), | ||
'utf8' | ||
) | ||
let stubFile = fs.readFileSync( | ||
path.resolve(__dirname, `../../../stubs/tailwind.config.${syntax}`), | ||
'utf8' | ||
) | ||
// Change colors import | ||
stubFile = stubFile.replace('../colors', 'tailwindcss/colors') | ||
stubContentsFile = stubContentsFile.replace('../colors', 'tailwindcss/colors') | ||
// Replace contents of {ts,js,cjs} file with the stub {simple,full}. | ||
stubFile = | ||
stubFile | ||
.replace('__CONFIG__', stubContentsFile.replace('module.exports =', '').trim()) | ||
.trim() + '\n\n' | ||
fs.writeFileSync(tailwindConfigLocation, stubFile, 'utf8') | ||
@@ -30,3 +57,3 @@ | ||
if (args['--postcss']) { | ||
let postcssConfigLocation = path.resolve(`./${configs.postcss}`) | ||
let postcssConfigLocation = path.resolve('./postcss.config.js') | ||
if (fs.existsSync(postcssConfigLocation)) { | ||
@@ -36,3 +63,5 @@ messages.push(`${path.basename(postcssConfigLocation)} already exists.`) | ||
let stubFile = fs.readFileSync( | ||
path.resolve(__dirname, '../../../stubs/defaultPostCssConfig.stub.js'), | ||
isProjectESM | ||
? path.resolve(__dirname, '../../../stubs/postcss.config.js') | ||
: path.resolve(__dirname, '../../../stubs/postcss.config.cjs'), | ||
'utf8' | ||
@@ -39,0 +68,0 @@ ) |
@@ -1,1 +0,1 @@ | ||
export default ["preflight","container","accessibility","pointerEvents","visibility","position","inset","isolation","zIndex","order","gridColumn","gridColumnStart","gridColumnEnd","gridRow","gridRowStart","gridRowEnd","float","clear","margin","boxSizing","display","aspectRatio","height","maxHeight","minHeight","width","minWidth","maxWidth","flex","flexShrink","flexGrow","flexBasis","tableLayout","borderCollapse","borderSpacing","transformOrigin","translate","rotate","skew","scale","transform","animation","cursor","touchAction","userSelect","resize","scrollSnapType","scrollSnapAlign","scrollSnapStop","scrollMargin","scrollPadding","listStylePosition","listStyleType","appearance","columns","breakBefore","breakInside","breakAfter","gridAutoColumns","gridAutoFlow","gridAutoRows","gridTemplateColumns","gridTemplateRows","flexDirection","flexWrap","placeContent","placeItems","alignContent","alignItems","justifyContent","justifyItems","gap","space","divideWidth","divideStyle","divideColor","divideOpacity","placeSelf","alignSelf","justifySelf","overflow","overscrollBehavior","scrollBehavior","textOverflow","whitespace","wordBreak","borderRadius","borderWidth","borderStyle","borderColor","borderOpacity","backgroundColor","backgroundOpacity","backgroundImage","gradientColorStops","boxDecorationBreak","backgroundSize","backgroundAttachment","backgroundClip","backgroundPosition","backgroundRepeat","backgroundOrigin","fill","stroke","strokeWidth","objectFit","objectPosition","padding","textAlign","textIndent","verticalAlign","fontFamily","fontSize","fontWeight","textTransform","fontStyle","fontVariantNumeric","lineHeight","letterSpacing","textColor","textOpacity","textDecoration","textDecorationColor","textDecorationStyle","textDecorationThickness","textUnderlineOffset","fontSmoothing","placeholderColor","placeholderOpacity","caretColor","accentColor","opacity","backgroundBlendMode","mixBlendMode","boxShadow","boxShadowColor","outlineStyle","outlineWidth","outlineOffset","outlineColor","ringWidth","ringColor","ringOpacity","ringOffsetWidth","ringOffsetColor","blur","brightness","contrast","dropShadow","grayscale","hueRotate","invert","saturate","sepia","filter","backdropBlur","backdropBrightness","backdropContrast","backdropGrayscale","backdropHueRotate","backdropInvert","backdropOpacity","backdropSaturate","backdropSepia","backdropFilter","transitionProperty","transitionDelay","transitionDuration","transitionTimingFunction","willChange","content"] | ||
export default ["preflight","container","accessibility","pointerEvents","visibility","position","inset","isolation","zIndex","order","gridColumn","gridColumnStart","gridColumnEnd","gridRow","gridRowStart","gridRowEnd","float","clear","margin","boxSizing","lineClamp","display","aspectRatio","height","maxHeight","minHeight","width","minWidth","maxWidth","flex","flexShrink","flexGrow","flexBasis","tableLayout","captionSide","borderCollapse","borderSpacing","transformOrigin","translate","rotate","skew","scale","transform","animation","cursor","touchAction","userSelect","resize","scrollSnapType","scrollSnapAlign","scrollSnapStop","scrollMargin","scrollPadding","listStylePosition","listStyleType","listStyleImage","appearance","columns","breakBefore","breakInside","breakAfter","gridAutoColumns","gridAutoFlow","gridAutoRows","gridTemplateColumns","gridTemplateRows","flexDirection","flexWrap","placeContent","placeItems","alignContent","alignItems","justifyContent","justifyItems","gap","space","divideWidth","divideStyle","divideColor","divideOpacity","placeSelf","alignSelf","justifySelf","overflow","overscrollBehavior","scrollBehavior","textOverflow","hyphens","whitespace","wordBreak","borderRadius","borderWidth","borderStyle","borderColor","borderOpacity","backgroundColor","backgroundOpacity","backgroundImage","gradientColorStops","boxDecorationBreak","backgroundSize","backgroundAttachment","backgroundClip","backgroundPosition","backgroundRepeat","backgroundOrigin","fill","stroke","strokeWidth","objectFit","objectPosition","padding","textAlign","textIndent","verticalAlign","fontFamily","fontSize","fontWeight","textTransform","fontStyle","fontVariantNumeric","lineHeight","letterSpacing","textColor","textOpacity","textDecoration","textDecorationColor","textDecorationStyle","textDecorationThickness","textUnderlineOffset","fontSmoothing","placeholderColor","placeholderOpacity","caretColor","accentColor","opacity","backgroundBlendMode","mixBlendMode","boxShadow","boxShadowColor","outlineStyle","outlineWidth","outlineOffset","outlineColor","ringWidth","ringColor","ringOpacity","ringOffsetWidth","ringOffsetColor","blur","brightness","contrast","dropShadow","grayscale","hueRotate","invert","saturate","sepia","filter","backdropBlur","backdropBrightness","backdropContrast","backdropGrayscale","backdropHueRotate","backdropInvert","backdropOpacity","backdropSaturate","backdropSepia","backdropFilter","transitionProperty","transitionDelay","transitionDuration","transitionTimingFunction","willChange","content"] |
@@ -7,2 +7,8 @@ import colors from 'picocolors' | ||
generalizedModifiers: true, | ||
get disableColorOpacityUtilitiesByDefault() { | ||
return __OXIDE__ | ||
}, | ||
get relativeContentPathsByDefault() { | ||
return __OXIDE__ | ||
}, | ||
} | ||
@@ -17,7 +23,3 @@ | ||
], | ||
experimental: [ | ||
'optimizeUniversalDefaults', | ||
'generalizedModifiers', | ||
// 'variantGrouping', | ||
], | ||
experimental: ['optimizeUniversalDefaults', 'generalizedModifiers'], | ||
} | ||
@@ -24,0 +26,0 @@ |
@@ -1,47 +0,1 @@ | ||
import setupTrackingContext from './lib/setupTrackingContext' | ||
import processTailwindFeatures from './processTailwindFeatures' | ||
import { env } from './lib/sharedState' | ||
import { findAtConfigPath } from './lib/findAtConfigPath' | ||
module.exports = function tailwindcss(configOrPath) { | ||
return { | ||
postcssPlugin: 'tailwindcss', | ||
plugins: [ | ||
env.DEBUG && | ||
function (root) { | ||
console.log('\n') | ||
console.time('JIT TOTAL') | ||
return root | ||
}, | ||
function (root, result) { | ||
// Use the path for the `@config` directive if it exists, otherwise use the | ||
// path for the file being processed | ||
configOrPath = findAtConfigPath(root, result) ?? configOrPath | ||
let context = setupTrackingContext(configOrPath) | ||
if (root.type === 'document') { | ||
let roots = root.nodes.filter((node) => node.type === 'root') | ||
for (const root of roots) { | ||
if (root.type === 'root') { | ||
processTailwindFeatures(context)(root, result) | ||
} | ||
} | ||
return | ||
} | ||
processTailwindFeatures(context)(root, result) | ||
}, | ||
env.DEBUG && | ||
function (root) { | ||
console.timeEnd('JIT TOTAL') | ||
console.log('\n') | ||
return root | ||
}, | ||
].filter(Boolean), | ||
} | ||
} | ||
module.exports.postcss = true | ||
module.exports = require('./plugin') |
@@ -167,3 +167,3 @@ // @ts-check | ||
* @param {Map<string, number>} fileModifiedMap | ||
* @returns {{ content: string, extension: string }[]} | ||
* @returns {[{ content: string, extension: string }[], Map<string, number>]} | ||
*/ | ||
@@ -175,9 +175,10 @@ export function resolvedChangedContent(context, candidateFiles, fileModifiedMap) { | ||
for (let changedFile of resolveChangedFiles(candidateFiles, fileModifiedMap)) { | ||
let content = fs.readFileSync(changedFile, 'utf8') | ||
let [changedFiles, mTimesToCommit] = resolveChangedFiles(candidateFiles, fileModifiedMap) | ||
for (let changedFile of changedFiles) { | ||
let extension = path.extname(changedFile).slice(1) | ||
changedContent.push({ content, extension }) | ||
changedContent.push({ file: changedFile, extension }) | ||
} | ||
return changedContent | ||
return [changedContent, mTimesToCommit] | ||
} | ||
@@ -189,6 +190,7 @@ | ||
* @param {Map<string, number>} fileModifiedMap | ||
* @returns {Set<string>} | ||
* @returns {[Set<string>, Map<string, number>]} | ||
*/ | ||
function resolveChangedFiles(candidateFiles, fileModifiedMap) { | ||
let paths = candidateFiles.map((contentPath) => contentPath.pattern) | ||
let mTimesToCommit = new Map() | ||
@@ -199,19 +201,12 @@ let changedFiles = new Set() | ||
for (let file of files) { | ||
let prevModified = fileModifiedMap.has(file) ? fileModifiedMap.get(file) : -Infinity | ||
let prevModified = fileModifiedMap.get(file) || -Infinity | ||
let modified = fs.statSync(file).mtimeMs | ||
// This check is intentionally >= because we track the last modified time of context dependencies | ||
// earier in the process and we want to make sure we don't miss any changes that happen | ||
// when a context dependency is also a content dependency | ||
// Ideally, we'd do all this tracking at one time but that is a larger refactor | ||
// than we want to commit to right now, so this is a decent compromise. | ||
// This should be sufficient because file modification times will be off by at least | ||
// 1ms (the precision of fstat in Node) in most cases if they exist and were changed. | ||
if (modified >= prevModified) { | ||
if (modified > prevModified) { | ||
changedFiles.add(file) | ||
fileModifiedMap.set(file, modified) | ||
mTimesToCommit.set(file, modified) | ||
} | ||
} | ||
env.DEBUG && console.timeEnd('Finding changed files') | ||
return changedFiles | ||
return [changedFiles, mTimesToCommit] | ||
} |
@@ -1,2 +0,1 @@ | ||
import { flagEnabled } from '../featureFlags' | ||
import * as regex from './regex' | ||
@@ -15,6 +14,8 @@ | ||
for (let pattern of patterns) { | ||
results = [...results, ...(content.match(pattern) ?? [])] | ||
for (let result of content.match(pattern) ?? []) { | ||
results.push(clipAtBalancedParens(result)) | ||
} | ||
} | ||
return results.filter((v) => v !== undefined).map(clipAtBalancedParens) | ||
return results | ||
} | ||
@@ -25,3 +26,2 @@ } | ||
let separator = context.tailwindConfig.separator | ||
let variantGroupingEnabled = flagEnabled(context.tailwindConfig, 'variantGrouping') | ||
let prefix = | ||
@@ -33,5 +33,11 @@ context.tailwindConfig.prefix !== '' | ||
let utility = regex.any([ | ||
// Arbitrary properties | ||
/\[[^\s:'"`]+:[^\s]+\]/, | ||
// Arbitrary properties (without square brackets) | ||
/\[[^\s:'"`]+:[^\s\[\]]+\]/, | ||
// Arbitrary properties with balanced square brackets | ||
// This is a targeted fix to continue to allow theme() | ||
// with square brackets to work in arbitrary properties | ||
// while fixing a problem with the regex matching too much | ||
/\[[^\s:'"`\]]+:[^\s]+?\[[^\s]+\][^\s]+?\]/, | ||
// Utilities | ||
@@ -47,3 +53,8 @@ regex.pattern([ | ||
// Arbitrary values | ||
/-(?:\w+-)*\[[^\s:]+\]/, | ||
regex.any([ | ||
/-(?:\w+-)*\['[^\s]+'\]/, | ||
/-(?:\w+-)*\["[^\s]+"\]/, | ||
/-(?:\w+-)*\[`[^\s]+`\]/, | ||
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s:\[\]]+\]/, | ||
]), | ||
@@ -59,3 +70,8 @@ // Not immediately followed by an `{[(` | ||
// Arbitrary values | ||
/-(?:\w+-)*\[[^\s]+\]/, | ||
regex.any([ | ||
/-(?:\w+-)*\['[^\s]+'\]/, | ||
/-(?:\w+-)*\["[^\s]+"\]/, | ||
/-(?:\w+-)*\[`[^\s]+`\]/, | ||
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s\[\]]+\]/, | ||
]), | ||
@@ -82,2 +98,5 @@ // Not immediately followed by an `{[(` | ||
// With variant modifier (e.g.: group-[..]/modifier) | ||
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]\/\w+/, separator]), | ||
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]/, separator]), | ||
@@ -89,2 +108,5 @@ regex.pattern([/[^\s"'`\[\\]+/, separator]), | ||
regex.any([ | ||
// With variant modifier (e.g.: group-[..]/modifier) | ||
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s`]+\]\/\w+/, separator]), | ||
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s`]+\]/, separator]), | ||
@@ -107,11 +129,3 @@ regex.pattern([/[^\s`\[\\]+/, separator]), | ||
variantGroupingEnabled | ||
? regex.any([ | ||
// Or any of those things but grouped separated by commas | ||
regex.pattern([/\(/, utility, regex.zeroOrMore([/,/, utility]), /\)/]), | ||
// Arbitrary properties, constrained utilities, arbitrary values, etc… | ||
utility, | ||
]) | ||
: utility, | ||
utility, | ||
]) | ||
@@ -195,3 +209,3 @@ } | ||
if (depth < 0) { | ||
return input.substring(0, match.index) | ||
return input.substring(0, match.index - 1) | ||
} | ||
@@ -198,0 +212,0 @@ |
@@ -0,1 +1,9 @@ | ||
function isRoot(node) { | ||
return node.type === 'root' | ||
} | ||
function isAtLayer(node) { | ||
return node.type === 'atrule' && node.name === 'layer' | ||
} | ||
export default function (_context) { | ||
@@ -8,3 +16,3 @@ return (root, result) => { | ||
if (node.parent && node.parent.type !== 'root') { | ||
if (node.parent && !(isRoot(node.parent) || isAtLayer(node.parent))) { | ||
found = true | ||
@@ -11,0 +19,0 @@ node.warn( |
import dlv from 'dlv' | ||
import didYouMean from 'didyoumean' | ||
import transformThemeValue from '../util/transformThemeValue' | ||
import parseValue from 'postcss-value-parser' | ||
import parseValue from '../value-parser/index' | ||
import { normalizeScreens } from '../util/normalizeScreens' | ||
@@ -149,2 +149,5 @@ import buildMediaQuery from '../util/buildMediaQuery' | ||
function resolveFunctions(node, input, functions) { | ||
let hasAnyFn = Object.keys(functions).some((fn) => input.includes(`${fn}(`)) | ||
if (!hasAnyFn) return input | ||
return parseValue(input) | ||
@@ -151,0 +154,0 @@ .walk((vNode) => { |
@@ -6,2 +6,4 @@ import postcss from 'postcss' | ||
import escapeClassName from '../util/escapeClassName' | ||
import { applyImportantSelector } from '../util/applyImportantSelector' | ||
import { movePseudos } from '../util/pseudoElements' | ||
@@ -555,2 +557,9 @@ /** @typedef {Map<string, [any, import('postcss').Rule[]]>} ApplyCache */ | ||
// If the selector becomes empty after replacing the important selector | ||
// This means that it's the same as the parent selector and we don't want to replace it | ||
// Otherwise we'll crash | ||
if (parentSelector === '') { | ||
parentSelector = parent.selector | ||
} | ||
rule.selector = replaceSelector(parentSelector, rule.selector, applyCandidate) | ||
@@ -560,3 +569,3 @@ | ||
if (importantSelector && parentSelector !== parent.selector) { | ||
rule.selector = `${importantSelector} ${rule.selector}` | ||
rule.selector = applyImportantSelector(rule.selector, importantSelector) | ||
} | ||
@@ -567,2 +576,7 @@ | ||
}) | ||
// Move pseudo elements to the end of the selector (if necessary) | ||
let selector = parser().astSync(rule.selector) | ||
selector.each((sel) => movePseudos(sel)) | ||
rule.selector = selector.toString() | ||
}) | ||
@@ -569,0 +583,0 @@ } |
@@ -1,2 +0,3 @@ | ||
import LRU from 'quick-lru' | ||
import fs from 'fs' | ||
import LRU from '@alloc/quick-lru' | ||
import * as sharedState from './sharedState' | ||
@@ -100,3 +101,3 @@ import { generateRules } from './generateRules' | ||
export default function expandTailwindAtRules(context) { | ||
return (root) => { | ||
return async (root) => { | ||
let layerNodes = { | ||
@@ -128,3 +129,3 @@ base: null, | ||
// Find potential rules in changed files | ||
let candidates = new Set([sharedState.NOT_ON_DEMAND]) | ||
let candidates = new Set([...(context.candidates ?? []), sharedState.NOT_ON_DEMAND]) | ||
let seen = new Set() | ||
@@ -134,6 +135,37 @@ | ||
for (let { content, extension } of context.changedContent) { | ||
let transformer = getTransformer(context.tailwindConfig, extension) | ||
let extractor = getExtractor(context, extension) | ||
getClassCandidates(transformer(content), extractor, candidates, seen) | ||
if (__OXIDE__) { | ||
// TODO: Pass through or implement `extractor` | ||
for (let candidate of require('@tailwindcss/oxide').parseCandidateStringsFromFiles( | ||
context.changedContent | ||
// Object.assign({}, builtInTransformers, context.tailwindConfig.content.transform) | ||
)) { | ||
candidates.add(candidate) | ||
} | ||
// for (let { file, content, extension } of context.changedContent) { | ||
// let transformer = getTransformer(context.tailwindConfig, extension) | ||
// let extractor = getExtractor(context, extension) | ||
// getClassCandidatesOxide(file, transformer(content), extractor, candidates, seen) | ||
// } | ||
} else { | ||
/** @type {[item: {file?: string, content?: string}, meta: {transformer: any, extractor: any}][]} */ | ||
let regexParserContent = [] | ||
for (let item of context.changedContent) { | ||
let transformer = getTransformer(context.tailwindConfig, item.extension) | ||
let extractor = getExtractor(context, item.extension) | ||
regexParserContent.push([item, { transformer, extractor }]) | ||
} | ||
const BATCH_SIZE = 500 | ||
for (let i = 0; i < regexParserContent.length; i += BATCH_SIZE) { | ||
let batch = regexParserContent.slice(i, i + BATCH_SIZE) | ||
await Promise.all( | ||
batch.map(async ([{ file, content }, { transformer, extractor }]) => { | ||
content = file ? await fs.promises.readFile(file, 'utf8') : content | ||
getClassCandidates(transformer(content), extractor, candidates, seen) | ||
}) | ||
) | ||
} | ||
} | ||
@@ -149,3 +181,14 @@ | ||
env.DEBUG && console.time('Generate rules') | ||
generateRules(candidates, context) | ||
env.DEBUG && console.time('Sorting candidates') | ||
let sortedCandidates = __OXIDE__ | ||
? candidates | ||
: new Set( | ||
[...candidates].sort((a, z) => { | ||
if (a === z) return 0 | ||
if (a < z) return -1 | ||
return 1 | ||
}) | ||
) | ||
env.DEBUG && console.timeEnd('Sorting candidates') | ||
generateRules(sortedCandidates, context) | ||
env.DEBUG && console.timeEnd('Generate rules') | ||
@@ -229,2 +272,5 @@ | ||
// TODO: Why is the root node having no source location for `end` possible? | ||
root.source.end = root.source.end ?? root.source.start | ||
// If we've got a utility layer and no utilities are generated there's likely something wrong | ||
@@ -231,0 +277,0 @@ const hasUtilityVariants = variantNodes.some( |
@@ -6,12 +6,17 @@ import postcss from 'postcss' | ||
import prefixSelector from '../util/prefixSelector' | ||
import { updateAllClasses, filterSelectorsForClass, getMatchingTypes } from '../util/pluginUtils' | ||
import { updateAllClasses, getMatchingTypes } from '../util/pluginUtils' | ||
import log from '../util/log' | ||
import * as sharedState from './sharedState' | ||
import { formatVariantSelector, finalizeSelector } from '../util/formatVariantSelector' | ||
import { | ||
formatVariantSelector, | ||
finalizeSelector, | ||
eliminateIrrelevantSelectors, | ||
} from '../util/formatVariantSelector' | ||
import { asClass } from '../util/nameClass' | ||
import { normalize } from '../util/dataTypes' | ||
import { isValidVariantFormatString, parseVariant } from './setupContextUtils' | ||
import isValidArbitraryValue from '../util/isValidArbitraryValue' | ||
import { isValidVariantFormatString, parseVariant, INTERNAL_FEATURES } from './setupContextUtils' | ||
import isValidArbitraryValue from '../util/isSyntacticallyValidPropertyValue' | ||
import { splitAtTopLevelOnly } from '../util/splitAtTopLevelOnly.js' | ||
import { flagEnabled } from '../featureFlags' | ||
import { applyImportantSelector } from '../util/applyImportantSelector' | ||
@@ -115,2 +120,3 @@ let classNameParser = selectorParser((selectors) => { | ||
} | ||
let result = [] | ||
@@ -120,14 +126,19 @@ | ||
let container = postcss.root({ nodes: [rule.clone()] }) | ||
container.walkRules((r) => { | ||
r.selector = updateAllClasses( | ||
filterSelectorsForClass(r.selector, classCandidate), | ||
(className) => { | ||
if (className === classCandidate) { | ||
return `!${className}` | ||
} | ||
return className | ||
} | ||
let ast = selectorParser().astSync(r.selector) | ||
// Remove extraneous selectors that do not include the base candidate | ||
ast.each((sel) => eliminateIrrelevantSelectors(sel, classCandidate)) | ||
// Update all instances of the base candidate to include the important marker | ||
updateAllClasses(ast, (className) => | ||
className === classCandidate ? `!${className}` : className | ||
) | ||
r.selector = ast.toString() | ||
r.walkDecls((d) => (d.important = true)) | ||
}) | ||
result.push([{ ...meta, important: true }, container.nodes[0]]) | ||
@@ -158,7 +169,15 @@ } | ||
{ | ||
let match = /(.*)\/(.*)$/g.exec(variant) | ||
if (match) { | ||
variant = match[1] | ||
args.modifier = match[2] | ||
let [baseVariant, ...modifiers] = splitAtTopLevelOnly(variant, '/') | ||
// This is a hack to support variants with `/` in them, like `ar-1/10/20:text-red-500` | ||
// In this case 1/10 is a value but /20 is a modifier | ||
if (modifiers.length > 1) { | ||
baseVariant = baseVariant + '/' + modifiers.slice(0, -1).join('/') | ||
modifiers = modifiers.slice(-1) | ||
} | ||
if (modifiers.length && !context.variantMap.has(variant)) { | ||
variant = baseVariant | ||
args.modifier = modifiers[0] | ||
if (!flagEnabled(context.tailwindConfig, 'generalizedModifiers')) { | ||
@@ -181,9 +200,9 @@ return [] | ||
if (match) { | ||
let [, char, seperator, value] = match | ||
let [, char, separator, value] = match | ||
// @-[200px] case | ||
if (char === '@' && seperator === '-') return [] | ||
if (char === '@' && separator === '-') return [] | ||
// group[:hover] case | ||
if (char !== '@' && seperator === '') return [] | ||
if (char !== '@' && separator === '') return [] | ||
variant = variant.replace(`${seperator}[${value}]`, '') | ||
variant = variant.replace(`${separator}[${value}]`, '') | ||
args.value = value | ||
@@ -195,19 +214,36 @@ } | ||
if (isArbitraryValue(variant) && !context.variantMap.has(variant)) { | ||
let sort = context.offsets.recordVariant(variant) | ||
let selector = normalize(variant.slice(1, -1)) | ||
let selectors = splitAtTopLevelOnly(selector, ',') | ||
if (!isValidVariantFormatString(selector)) { | ||
// We do not support multiple selectors for arbitrary variants | ||
if (selectors.length > 1) { | ||
return [] | ||
} | ||
let fn = parseVariant(selector) | ||
if (!selectors.every(isValidVariantFormatString)) { | ||
return [] | ||
} | ||
let sort = context.offsets.recordVariant(variant) | ||
let records = selectors.map((sel, idx) => [ | ||
context.offsets.applyParallelOffset(sort, idx), | ||
parseVariant(sel.trim()), | ||
]) | ||
context.variantMap.set(variant, [[sort, fn]]) | ||
context.variantMap.set(variant, records) | ||
} | ||
if (context.variantMap.has(variant)) { | ||
let isArbitraryVariant = isArbitraryValue(variant) | ||
let internalFeatures = context.variantOptions.get(variant)?.[INTERNAL_FEATURES] ?? {} | ||
let variantFunctionTuples = context.variantMap.get(variant).slice() | ||
let result = [] | ||
let respectPrefix = (() => { | ||
if (isArbitraryVariant) return false | ||
if (internalFeatures.respectPrefix === false) return false | ||
return true | ||
})() | ||
for (let [meta, rule] of matches) { | ||
@@ -271,3 +307,6 @@ // Don't generate variants for user css | ||
format(selectorFormat) { | ||
collectedFormats.push(selectorFormat) | ||
collectedFormats.push({ | ||
format: selectorFormat, | ||
respectPrefix, | ||
}) | ||
}, | ||
@@ -298,3 +337,6 @@ args, | ||
if (typeof ruleWithVariant === 'string') { | ||
collectedFormats.push(ruleWithVariant) | ||
collectedFormats.push({ | ||
format: ruleWithVariant, | ||
respectPrefix, | ||
}) | ||
} | ||
@@ -340,3 +382,6 @@ | ||
// format: .foo & | ||
collectedFormats.push(modified.replace(rebuiltBase, '&')) | ||
collectedFormats.push({ | ||
format: modified.replace(rebuiltBase, '&'), | ||
respectPrefix, | ||
}) | ||
rule.selector = before | ||
@@ -361,3 +406,2 @@ }) | ||
collectedFormats: (meta.collectedFormats ?? []).concat(collectedFormats), | ||
isArbitraryVariant: isArbitraryValue(variant), | ||
}, | ||
@@ -425,3 +469,3 @@ clone.nodes[0], | ||
node.walkDecls((decl) => { | ||
if (!isParsableCssValue(decl.name, decl.value)) { | ||
if (!isParsableCssValue(decl.prop, decl.value)) { | ||
isParsable = false | ||
@@ -466,3 +510,3 @@ return false | ||
let normalized = normalize(value) | ||
let normalized = normalize(value, { property }) | ||
@@ -544,3 +588,3 @@ if (!isParsableCssValue(property, normalized)) { | ||
function* resolveMatches(candidate, context, original = candidate) { | ||
function* resolveMatches(candidate, context) { | ||
let separator = context.tailwindConfig.separator | ||
@@ -555,11 +599,2 @@ let [classCandidate, ...variants] = splitWithSeparator(candidate, separator).reverse() | ||
if (flagEnabled(context.tailwindConfig, 'variantGrouping')) { | ||
if (classCandidate.startsWith('(') && classCandidate.endsWith(')')) { | ||
let base = variants.slice().reverse().join(separator) | ||
for (let part of splitAtTopLevelOnly(classCandidate.slice(1, -1), ',')) { | ||
yield* resolveMatches(base + separator + part, context, original) | ||
} | ||
} | ||
} | ||
// TODO: Reintroduce this in ways that doesn't break on false positives | ||
@@ -753,20 +788,9 @@ // function sortAgainst(toSort, against) { | ||
// Apply final format selector | ||
if (match[0].collectedFormats) { | ||
let finalFormat = formatVariantSelector('&', ...match[0].collectedFormats) | ||
let container = postcss.root({ nodes: [match[1].clone()] }) | ||
container.walkRules((rule) => { | ||
if (inKeyframes(rule)) return | ||
match = applyFinalFormat(match, { context, candidate }) | ||
rule.selector = finalizeSelector(finalFormat, { | ||
selector: rule.selector, | ||
candidate: original, | ||
base: candidate | ||
.split(new RegExp(`\\${context?.tailwindConfig?.separator ?? ':'}(?![^[]*\\])`)) | ||
.pop(), | ||
isArbitraryVariant: match[0].isArbitraryVariant, | ||
context, | ||
}) | ||
}) | ||
match[1] = container.nodes[0] | ||
// Skip rules with invalid selectors | ||
// This will cause the candidate to be added to the "not class" | ||
// cache skipping it entirely for future builds | ||
if (match === null) { | ||
continue | ||
} | ||
@@ -779,2 +803,72 @@ | ||
function applyFinalFormat(match, { context, candidate }) { | ||
if (!match[0].collectedFormats) { | ||
return match | ||
} | ||
let isValid = true | ||
let finalFormat | ||
try { | ||
finalFormat = formatVariantSelector(match[0].collectedFormats, { | ||
context, | ||
candidate, | ||
}) | ||
} catch { | ||
// The format selector we produced is invalid | ||
// This could be because: | ||
// - A bug exists | ||
// - A plugin introduced an invalid variant selector (ex: `addVariant('foo', '&;foo')`) | ||
// - The user used an invalid arbitrary variant (ex: `[&;foo]:underline`) | ||
// Either way the build will fail because of this | ||
// We would rather that the build pass "silently" given that this could | ||
// happen because of picking up invalid things when scanning content | ||
// So we'll throw out the candidate instead | ||
return null | ||
} | ||
let container = postcss.root({ nodes: [match[1].clone()] }) | ||
container.walkRules((rule) => { | ||
if (inKeyframes(rule)) { | ||
return | ||
} | ||
try { | ||
let selector = finalizeSelector(rule.selector, finalFormat, { | ||
candidate, | ||
context, | ||
}) | ||
// Finalize Selector determined that this candidate is irrelevant | ||
// TODO: This elimination should happen earlier so this never happens | ||
if (selector === null) { | ||
rule.remove() | ||
return | ||
} | ||
rule.selector = selector | ||
} catch { | ||
// If this selector is invalid we also want to skip it | ||
// But it's likely that being invalid here means there's a bug in a plugin rather than too loosely matching content | ||
isValid = false | ||
return false | ||
} | ||
}) | ||
if (!isValid) { | ||
return null | ||
} | ||
// If all rules have been eliminated we can skip this candidate entirely | ||
if (container.nodes.length === 0) { | ||
return null | ||
} | ||
match[1] = container.nodes[0] | ||
return match | ||
} | ||
function inKeyframes(rule) { | ||
@@ -806,3 +900,3 @@ return rule.parent && rule.parent.type === 'atrule' && rule.parent.name === 'keyframes' | ||
rule.selectors = rule.selectors.map((selector) => { | ||
return `${important} ${selector}` | ||
return applyImportantSelector(selector, important) | ||
}) | ||
@@ -813,3 +907,3 @@ } | ||
function generateRules(candidates, context) { | ||
function generateRules(candidates, context, isSorting = false) { | ||
let allRules = [] | ||
@@ -849,3 +943,5 @@ let strategy = getImportantStrategy(context.tailwindConfig.important) | ||
let newEntry = [sort, rule] | ||
// Note: We have to clone rules during sorting | ||
// so we eliminate some shared mutable state | ||
let newEntry = [sort, isSorting ? rule.clone() : rule] | ||
rules.add(newEntry) | ||
@@ -852,0 +948,0 @@ context.ruleCache.add(newEntry) |
import fs from 'fs' | ||
import path from 'path' | ||
import resolve from 'resolve' | ||
import detective from 'detective' | ||
function createModule(file) { | ||
const source = fs.readFileSync(file, 'utf-8') | ||
const requires = detective(source) | ||
let jsExtensions = ['.js', '.cjs', '.mjs'] | ||
return { file, requires } | ||
// Given the current file `a.ts`, we want to make sure that when importing `b` that we resolve | ||
// `b.ts` before `b.js` | ||
// | ||
// E.g.: | ||
// | ||
// a.ts | ||
// b // .ts | ||
// c // .ts | ||
// a.js | ||
// b // .js or .ts | ||
let jsResolutionOrder = ['', '.js', '.cjs', '.mjs', '.ts', '.cts', '.mts', '.jsx', '.tsx'] | ||
let tsResolutionOrder = ['', '.ts', '.cts', '.mts', '.tsx', '.js', '.cjs', '.mjs', '.jsx'] | ||
function resolveWithExtension(file, extensions) { | ||
// Try to find `./a.ts`, `./a.ts`, ... from `./a` | ||
for (let ext of extensions) { | ||
let full = `${file}${ext}` | ||
if (fs.existsSync(full) && fs.statSync(full).isFile()) { | ||
return full | ||
} | ||
} | ||
// Try to find `./a/index.js` from `./a` | ||
for (let ext of extensions) { | ||
let full = `${file}/index${ext}` | ||
if (fs.existsSync(full)) { | ||
return full | ||
} | ||
} | ||
return null | ||
} | ||
export default function getModuleDependencies(entryFile) { | ||
const rootModule = createModule(entryFile) | ||
const modules = [rootModule] | ||
function* _getModuleDependencies(filename, base, seen, ext = path.extname(filename)) { | ||
// Try to find the file | ||
let absoluteFile = resolveWithExtension( | ||
path.resolve(base, filename), | ||
jsExtensions.includes(ext) ? jsResolutionOrder : tsResolutionOrder | ||
) | ||
if (absoluteFile === null) return // File doesn't exist | ||
// Iterate over the modules, even when new | ||
// ones are being added | ||
for (const mdl of modules) { | ||
mdl.requires | ||
.filter((dep) => { | ||
// Only track local modules, not node_modules | ||
return dep.startsWith('./') || dep.startsWith('../') | ||
}) | ||
.forEach((dep) => { | ||
try { | ||
const basedir = path.dirname(mdl.file) | ||
const depPath = resolve.sync(dep, { basedir }) | ||
const depModule = createModule(depPath) | ||
// Prevent infinite loops when there are circular dependencies | ||
if (seen.has(absoluteFile)) return // Already seen | ||
seen.add(absoluteFile) | ||
modules.push(depModule) | ||
} catch (_err) { | ||
// eslint-disable-next-line no-empty | ||
} | ||
}) | ||
// Mark the file as a dependency | ||
yield absoluteFile | ||
// Resolve new base for new imports/requires | ||
base = path.dirname(absoluteFile) | ||
ext = path.extname(absoluteFile) | ||
let contents = fs.readFileSync(absoluteFile, 'utf-8') | ||
// Find imports/requires | ||
for (let match of [ | ||
...contents.matchAll(/import[\s\S]*?['"](.{3,}?)['"]/gi), | ||
...contents.matchAll(/import[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi), | ||
...contents.matchAll(/require\(['"`](.+)['"`]\)/gi), | ||
]) { | ||
// Bail out if it's not a relative file | ||
if (!match[1].startsWith('.')) continue | ||
yield* _getModuleDependencies(match[1], base, seen, ext) | ||
} | ||
} | ||
return modules | ||
export default function getModuleDependencies(absoluteFilePath) { | ||
if (absoluteFilePath === null) return new Set() | ||
return new Set( | ||
_getModuleDependencies(absoluteFilePath, path.dirname(absoluteFilePath), new Set()) | ||
) | ||
} |
// @ts-check | ||
import bigSign from '../util/bigSign' | ||
import { remapBitfield } from './remap-bitfield.js' | ||
@@ -15,2 +16,3 @@ /** | ||
* @property {string|null} modifier The modifier that was used (if any) | ||
* @property {bigint} variant The variant bitmask | ||
*/ | ||
@@ -130,2 +132,4 @@ | ||
applyVariantOffset(rule, variant, options) { | ||
options.variant = variant.variants | ||
return { | ||
@@ -195,3 +199,3 @@ ...rule, | ||
...this.create('variants'), | ||
variants: 1n << this.reservedVariantBits, | ||
variants: this.variantOffsets.get(variant), | ||
} | ||
@@ -211,2 +215,8 @@ } | ||
// When sorting the `variants` layer, we need to sort based on the parent layer as well within | ||
// this variants layer. | ||
if (a.parentLayer !== b.parentLayer) { | ||
return this.layerPositions[a.parentLayer] - this.layerPositions[b.parentLayer] | ||
} | ||
// Sort based on the sorting function | ||
@@ -217,2 +227,15 @@ for (let aOptions of a.options) { | ||
if (!aOptions.sort || !bOptions.sort) continue | ||
let maxFnVariant = max([aOptions.variant, bOptions.variant]) ?? 0n | ||
// Create a mask of 0s from bits 1..N where N represents the mask of the Nth bit | ||
let mask = ~(maxFnVariant | (maxFnVariant - 1n)) | ||
let aVariantsAfterFn = a.variants & mask | ||
let bVariantsAfterFn = b.variants & mask | ||
// If the variants the same, we _can_ sort them | ||
if (aVariantsAfterFn !== bVariantsAfterFn) { | ||
continue | ||
} | ||
let result = aOptions.sort( | ||
@@ -252,2 +275,29 @@ { | ||
/** | ||
* Arbitrary variants are recorded in the order they're encountered. | ||
* This means that the order is not stable between environments and sets of content files. | ||
* | ||
* In order to make the order stable, we need to remap the arbitrary variant offsets to | ||
* be in alphabetical order starting from the offset of the first arbitrary variant. | ||
*/ | ||
recalculateVariantOffsets() { | ||
// Sort the variants by their name | ||
let variants = Array.from(this.variantOffsets.entries()) | ||
.filter(([v]) => v.startsWith('[')) | ||
.sort(([a], [z]) => fastCompare(a, z)) | ||
// Sort the list of offsets | ||
// This is not necessarily a discrete range of numbers which is why | ||
// we're using sort instead of creating a range from min/max | ||
let newOffsets = variants.map(([, offset]) => offset).sort((a, z) => bigSign(a - z)) | ||
// Create a map from the old offsets to the new offsets in the new sort order | ||
/** @type {[bigint, bigint][]} */ | ||
let mapping = variants.map(([, oldOffset], i) => [oldOffset, newOffsets[i]]) | ||
// Remove any variants that will not move letting us skip | ||
// remapping if everything happens to be in order | ||
return mapping.filter(([a, z]) => a !== z) | ||
} | ||
/** | ||
* @template T | ||
@@ -257,3 +307,32 @@ * @param {[RuleOffset, T][]} list | ||
*/ | ||
remapArbitraryVariantOffsets(list) { | ||
let mapping = this.recalculateVariantOffsets() | ||
// No arbitrary variants? Nothing to do. | ||
// Everyhing already in order? Nothing to do. | ||
if (mapping.length === 0) { | ||
return list | ||
} | ||
// Remap every variant offset in the list | ||
return list.map((item) => { | ||
let [offset, rule] = item | ||
offset = { | ||
...offset, | ||
variants: remapBitfield(offset.variants, mapping), | ||
} | ||
return [offset, rule] | ||
}) | ||
} | ||
/** | ||
* @template T | ||
* @param {[RuleOffset, T][]} list | ||
* @returns {[RuleOffset, T][]} | ||
*/ | ||
sort(list) { | ||
list = this.remapArbitraryVariantOffsets(list) | ||
return list.sort(([a], [b]) => bigSign(this.compare(a, b))) | ||
@@ -278,1 +357,25 @@ } | ||
} | ||
/** | ||
* A fast ASCII order string comparison function. | ||
* | ||
* Using `.sort()` without a custom compare function is faster | ||
* But you can only use that if you're sorting an array of | ||
* only strings. If you're sorting strings inside objects | ||
* or arrays, you need must use a custom compare function. | ||
* | ||
* @param {string} a | ||
* @param {string} b | ||
*/ | ||
function fastCompare(a, b) { | ||
let aLen = a.length | ||
let bLen = b.length | ||
let minLen = aLen < bLen ? aLen : bLen | ||
for (let i = 0; i < minLen; i++) { | ||
let cmp = a.charCodeAt(i) - b.charCodeAt(i) | ||
if (cmp !== 0) return cmp | ||
} | ||
return aLen - bLen | ||
} |
@@ -20,3 +20,3 @@ import fs from 'fs' | ||
import negateValue from '../util/negateValue' | ||
import isValidArbitraryValue from '../util/isValidArbitraryValue' | ||
import isSyntacticallyValidPropertyValue from '../util/isSyntacticallyValidPropertyValue' | ||
import { generateRules, getClassNameFromSelector } from './generateRules' | ||
@@ -28,2 +28,4 @@ import { hasContentChanged } from './cacheInvalidation.js' | ||
export const INTERNAL_FEATURES = Symbol() | ||
const VARIANT_TYPES = { | ||
@@ -59,28 +61,46 @@ AddVariant: Symbol.for('ADD_VARIANT'), | ||
function parseVariantFormatString(input) { | ||
if (input.includes('{')) { | ||
if (!isBalanced(input)) throw new Error(`Your { and } are unbalanced.`) | ||
/** @type {string[]} */ | ||
let parts = [] | ||
return input | ||
.split(/{(.*)}/gim) | ||
.flatMap((line) => parseVariantFormatString(line)) | ||
.filter(Boolean) | ||
} | ||
// When parsing whitespace around special characters are insignificant | ||
// However, _inside_ of a variant they could be | ||
// Because the selector could look like this | ||
// @media { &[data-name="foo bar"] } | ||
// This is why we do not skip whitespace | ||
return [input.trim()] | ||
} | ||
let current = '' | ||
let depth = 0 | ||
function isBalanced(input) { | ||
let count = 0 | ||
for (let idx = 0; idx < input.length; idx++) { | ||
let char = input[idx] | ||
for (let char of input) { | ||
if (char === '{') { | ||
count++ | ||
if (char === '\\') { | ||
// Escaped characters are not special | ||
current += '\\' + input[++idx] | ||
} else if (char === '{') { | ||
// Nested rule: start | ||
++depth | ||
parts.push(current.trim()) | ||
current = '' | ||
} else if (char === '}') { | ||
if (--count < 0) { | ||
return false // unbalanced | ||
// Nested rule: end | ||
if (--depth < 0) { | ||
throw new Error(`Your { and } are unbalanced.`) | ||
} | ||
parts.push(current.trim()) | ||
current = '' | ||
} else { | ||
// Normal character | ||
current += char | ||
} | ||
} | ||
return count === 0 | ||
if (current.length > 0) { | ||
parts.push(current.trim()) | ||
} | ||
parts = parts.filter((part) => part !== '') | ||
return parts | ||
} | ||
@@ -134,39 +154,41 @@ | ||
/** | ||
* Ignore everything inside a :not(...). This allows you to write code like | ||
* `div:not(.foo)`. If `.foo` is never found in your code, then we used to | ||
* not generated it. But now we will ignore everything inside a `:not`, so | ||
* that it still gets generated. | ||
* | ||
* @param {selectorParser.Root} selectors | ||
*/ | ||
function ignoreNot(selectors) { | ||
selectors.walkPseudos((pseudo) => { | ||
if (pseudo.value === ':not') { | ||
pseudo.remove() | ||
} | ||
}) | ||
} | ||
function extractCandidates(node, state = { containsNonOnDemandable: false }, depth = 0) { | ||
let classes = [] | ||
let selectors = [] | ||
// Handle normal rules | ||
if (node.type === 'rule') { | ||
// Ignore everything inside a :not(...). This allows you to write code like | ||
// `div:not(.foo)`. If `.foo` is never found in your code, then we used to | ||
// not generated it. But now we will ignore everything inside a `:not`, so | ||
// that it still gets generated. | ||
function ignoreNot(selectors) { | ||
selectors.walkPseudos((pseudo) => { | ||
if (pseudo.value === ':not') { | ||
pseudo.remove() | ||
} | ||
}) | ||
} | ||
// Handle normal rules | ||
selectors.push(...node.selectors) | ||
} else if (node.type === 'atrule') { | ||
// Handle at-rules (which contains nested rules) | ||
node.walkRules((rule) => selectors.push(...rule.selectors)) | ||
} | ||
for (let selector of node.selectors) { | ||
let classCandidates = getClasses(selector, ignoreNot) | ||
// At least one of the selectors contains non-"on-demandable" candidates. | ||
if (classCandidates.length === 0) { | ||
state.containsNonOnDemandable = true | ||
} | ||
for (let selector of selectors) { | ||
let classCandidates = getClasses(selector, ignoreNot) | ||
for (let classCandidate of classCandidates) { | ||
classes.push(classCandidate) | ||
} | ||
// At least one of the selectors contains non-"on-demandable" candidates. | ||
if (classCandidates.length === 0) { | ||
state.containsNonOnDemandable = true | ||
} | ||
} | ||
// Handle at-rules (which contains nested rules) | ||
else if (node.type === 'atrule') { | ||
node.walkRules((rule) => { | ||
for (let classCandidate of rule.selectors.flatMap((selector) => getClasses(selector))) { | ||
classes.push(classCandidate) | ||
} | ||
}) | ||
for (let classCandidate of classCandidates) { | ||
classes.push(classCandidate) | ||
} | ||
} | ||
@@ -219,4 +241,4 @@ | ||
let [, name, params] = /@(.*?)( .+|[({].*)/g.exec(str) | ||
return ({ wrap }) => wrap(postcss.atRule({ name, params: params.trim() })) | ||
let [, name, params] = /@(\S*)( .+|[({].*)?/g.exec(str) | ||
return ({ wrap }) => wrap(postcss.atRule({ name, params: params?.trim() ?? '' })) | ||
}) | ||
@@ -261,14 +283,7 @@ .reverse() | ||
function resolveThemeValue(path, defaultValue, opts = {}) { | ||
const [pathRoot, ...subPaths] = toPath(path) | ||
const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue) | ||
return transformThemeValue(pathRoot)(value, opts) | ||
let parts = toPath(path) | ||
let value = getConfigValue(['theme', ...parts], defaultValue) | ||
return transformThemeValue(parts[0])(value, opts) | ||
} | ||
const theme = Object.assign( | ||
(path, defaultValue = undefined) => resolveThemeValue(path, defaultValue), | ||
{ | ||
withAlpha: (path, opacityValue) => resolveThemeValue(path, undefined, { opacityValue }), | ||
} | ||
) | ||
let variantIdentifier = 0 | ||
@@ -280,3 +295,3 @@ let api = { | ||
config: getConfigValue, | ||
theme, | ||
theme: resolveThemeValue, | ||
corePlugins: (path) => { | ||
@@ -417,3 +432,3 @@ if (Array.isArray(tailwindConfig.corePlugins)) { | ||
if (!isValidArbitraryValue(value)) { | ||
if (!isSyntacticallyValidPropertyValue(value)) { | ||
return [] | ||
@@ -498,3 +513,3 @@ } | ||
if (!isValidArbitraryValue(value)) { | ||
if (!isSyntacticallyValidPropertyValue(value)) { | ||
return [] | ||
@@ -651,2 +666,3 @@ } | ||
let changed = false | ||
let mtimesToCommit = new Map() | ||
@@ -672,6 +688,6 @@ for (let file of files) { | ||
fileModifiedMap.set(file, newModified) | ||
mtimesToCommit.set(file, newModified) | ||
} | ||
return changed | ||
return [changed, mtimesToCommit] | ||
} | ||
@@ -933,8 +949,15 @@ | ||
context.getClassOrder = function getClassOrder(classes) { | ||
// Sort classes so they're ordered in a deterministic manner | ||
let sorted = [...classes].sort((a, z) => { | ||
if (a === z) return 0 | ||
if (a < z) return -1 | ||
return 1 | ||
}) | ||
// Non-util classes won't be generated, so we default them to null | ||
let sortedClassNames = new Map(classes.map((className) => [className, null])) | ||
let sortedClassNames = new Map(sorted.map((className) => [className, null])) | ||
// Sort all classes in order | ||
// Non-tailwind classes won't be generated and will be left as `null` | ||
let rules = generateRules(new Set(classes), context) | ||
let rules = generateRules(new Set(sorted), context, true) | ||
rules = context.offsets.sort(rules) | ||
@@ -945,3 +968,7 @@ | ||
for (const [, rule] of rules) { | ||
sortedClassNames.set(rule.raws.tailwind.candidate, idx++) | ||
let candidate = rule.raws.tailwind.candidate | ||
// When multiple rules match a candidate | ||
// always take the position of the first one | ||
sortedClassNames.set(candidate, sortedClassNames.get(candidate) ?? idx++) | ||
} | ||
@@ -966,3 +993,3 @@ | ||
// ['uppercase', 'lowercase', ...] | ||
context.getClassList = function getClassList() { | ||
context.getClassList = function getClassList(options = {}) { | ||
let output = [] | ||
@@ -972,6 +999,15 @@ | ||
if (Array.isArray(util)) { | ||
let [utilName, options] = util | ||
let [utilName, utilOptions] = util | ||
let negativeClasses = [] | ||
for (let [key, value] of Object.entries(options?.values ?? {})) { | ||
let modifiers = Object.keys(utilOptions?.modifiers ?? {}) | ||
if (utilOptions?.types?.some(({ type }) => type === 'color')) { | ||
modifiers.push(...Object.keys(context.tailwindConfig.theme.opacity ?? {})) | ||
} | ||
let metadata = { modifiers } | ||
let includeMetadata = options.includeMetadata && modifiers.length > 0 | ||
for (let [key, value] of Object.entries(utilOptions?.values ?? {})) { | ||
// Ignore undefined and null values | ||
@@ -982,5 +1018,8 @@ if (value == null) { | ||
output.push(formatClass(utilName, key)) | ||
if (options?.supportsNegativeValues && negateValue(value)) { | ||
negativeClasses.push(formatClass(utilName, `-${key}`)) | ||
let cls = formatClass(utilName, key) | ||
output.push(includeMetadata ? [cls, metadata] : cls) | ||
if (utilOptions?.supportsNegativeValues && negateValue(value)) { | ||
let cls = formatClass(utilName, `-${key}`) | ||
negativeClasses.push(includeMetadata ? [cls, metadata] : cls) | ||
} | ||
@@ -1106,9 +1145,30 @@ } | ||
let result = formatStrings.map((formatString) => | ||
finalizeSelector(formatVariantSelector('&', ...formatString), { | ||
selector: `.${candidate}`, | ||
candidate, | ||
context, | ||
isArbitraryVariant: !(value in (options.values ?? {})), | ||
}) | ||
let isArbitraryVariant = !(value in (options.values ?? {})) | ||
let internalFeatures = options[INTERNAL_FEATURES] ?? {} | ||
let respectPrefix = (() => { | ||
if (isArbitraryVariant) return false | ||
if (internalFeatures.respectPrefix === false) return false | ||
return true | ||
})() | ||
formatStrings = formatStrings.map((format) => | ||
format.map((str) => ({ | ||
format: str, | ||
respectPrefix, | ||
})) | ||
) | ||
manualFormatStrings = manualFormatStrings.map((format) => ({ | ||
format, | ||
respectPrefix, | ||
})) | ||
let opts = { | ||
candidate, | ||
context, | ||
} | ||
let result = formatStrings.map((formats) => | ||
finalizeSelector(`.${candidate}`, formatVariantSelector(formats, opts), opts) | ||
.replace(`.${candidate}`, '&') | ||
@@ -1120,3 +1180,7 @@ .replace('{ & }', '') | ||
if (manualFormatStrings.length > 0) { | ||
result.push(formatVariantSelector('&', ...manualFormatStrings)) | ||
result.push( | ||
formatVariantSelector(manualFormatStrings, opts) | ||
.toString() | ||
.replace(`.${candidate}`, '&') | ||
) | ||
} | ||
@@ -1240,3 +1304,3 @@ | ||
if (existingContext) { | ||
let contextDependenciesChanged = trackModified( | ||
let [contextDependenciesChanged, mtimesToCommit] = trackModified( | ||
[...contextDependencies], | ||
@@ -1246,3 +1310,3 @@ getFileModifiedMap(existingContext) | ||
if (!contextDependenciesChanged && !cssDidChange) { | ||
return [existingContext, false] | ||
return [existingContext, false, mtimesToCommit] | ||
} | ||
@@ -1282,3 +1346,3 @@ } | ||
trackModified([...contextDependencies], getFileModifiedMap(context)) | ||
let [, mtimesToCommit] = trackModified([...contextDependencies], getFileModifiedMap(context)) | ||
@@ -1298,3 +1362,3 @@ // --- | ||
return [context, true] | ||
return [context, true, mtimesToCommit] | ||
} |
@@ -0,6 +1,7 @@ | ||
// @ts-check | ||
import fs from 'fs' | ||
import LRU from 'quick-lru' | ||
import LRU from '@alloc/quick-lru' | ||
import hash from '../util/hashConfig' | ||
import getModuleDependencies from '../lib/getModuleDependencies' | ||
import resolveConfig from '../public/resolve-config' | ||
@@ -12,2 +13,4 @@ import resolveConfigPath from '../util/resolveConfigPath' | ||
import { parseCandidateFiles, resolvedChangedContent } from './content.js' | ||
import { loadConfig } from '../lib/load-config' | ||
import getModuleDependencies from './getModuleDependencies' | ||
@@ -36,3 +39,3 @@ let configPathCache = new LRU({ maxSize: 100 }) | ||
let newDeps = getModuleDependencies(userConfigPath).map((dep) => dep.file) | ||
let newDeps = getModuleDependencies(userConfigPath) | ||
@@ -58,4 +61,3 @@ let modified = false | ||
} | ||
let newConfig = resolveConfig(require(userConfigPath)) | ||
newConfig = validateConfig(newConfig) | ||
let newConfig = validateConfig(resolveConfig(loadConfig(userConfigPath))) | ||
let newHash = hash(newConfig) | ||
@@ -67,5 +69,3 @@ configPathCache.set(userConfigPath, [newConfig, newHash, newDeps, newModified]) | ||
// It's a plain object, not a path | ||
let newConfig = resolveConfig( | ||
configOrPath.config === undefined ? configOrPath : configOrPath.config | ||
) | ||
let newConfig = resolveConfig(configOrPath?.config ?? configOrPath ?? {}) | ||
@@ -108,3 +108,3 @@ newConfig = validateConfig(newConfig) | ||
let [context] = getContext( | ||
let [context, , mTimesToCommit] = getContext( | ||
root, | ||
@@ -118,2 +118,4 @@ result, | ||
let fileModifiedMap = getFileModifiedMap(context) | ||
let candidateFiles = getCandidateFiles(context, tailwindConfig) | ||
@@ -127,4 +129,2 @@ | ||
if (tailwindDirectives.size > 0) { | ||
let fileModifiedMap = getFileModifiedMap(context) | ||
// Add template paths as postcss dependencies. | ||
@@ -137,9 +137,25 @@ for (let contentPath of candidateFiles) { | ||
for (let changedContent of resolvedChangedContent( | ||
let [changedContent, contentMTimesToCommit] = resolvedChangedContent( | ||
context, | ||
candidateFiles, | ||
fileModifiedMap | ||
)) { | ||
context.changedContent.push(changedContent) | ||
) | ||
for (let content of changedContent) { | ||
context.changedContent.push(content) | ||
} | ||
// Add the mtimes of the content files to the commit list | ||
// We can overwrite the existing values because unconditionally | ||
// This is because: | ||
// 1. Most of the files here won't be in the map yet | ||
// 2. If they are that means it's a context dependency | ||
// and we're reading this after the context. This means | ||
// that the mtime we just read is strictly >= the context | ||
// mtime. Unless the user / os is doing something weird | ||
// in which the mtime would be going backwards. If that | ||
// happens there's already going to be problems. | ||
for (let [path, mtime] of contentMTimesToCommit.entries()) { | ||
mTimesToCommit.set(path, mtime) | ||
} | ||
} | ||
@@ -151,2 +167,9 @@ | ||
// "commit" the new modified time for all context deps | ||
// We do this here because we want content tracking to | ||
// read the "old" mtime even when it's a context dependency. | ||
for (let [path, mtime] of mTimesToCommit.entries()) { | ||
fileModifiedMap.set(path, mtime) | ||
} | ||
return context | ||
@@ -153,0 +176,0 @@ } |
@@ -1,5 +0,16 @@ | ||
export const env = { | ||
NODE_ENV: process.env.NODE_ENV, | ||
DEBUG: resolveDebug(process.env.DEBUG), | ||
} | ||
import pkg from '../../package.json' | ||
export const env = | ||
typeof process !== 'undefined' | ||
? { | ||
NODE_ENV: process.env.NODE_ENV, | ||
DEBUG: resolveDebug(process.env.DEBUG), | ||
ENGINE: pkg.tailwindcss.engine, | ||
} | ||
: { | ||
NODE_ENV: 'production', | ||
DEBUG: false, | ||
ENGINE: pkg.tailwindcss.engine, | ||
} | ||
export const contextMap = new Map() | ||
@@ -6,0 +17,0 @@ export const configContextMap = new Map() |
@@ -15,3 +15,3 @@ import normalizeTailwindDirectives from './lib/normalizeTailwindDirectives' | ||
export default function processTailwindFeatures(setupContext) { | ||
return function (root, result) { | ||
return async function (root, result) { | ||
let { tailwindDirectives, applyDirectives } = normalizeTailwindDirectives(root) | ||
@@ -48,3 +48,4 @@ | ||
expandTailwindAtRules(context)(root, result) | ||
await expandTailwindAtRules(context)(root, result) | ||
// Partition apply rules that are generated by | ||
@@ -51,0 +52,0 @@ // addComponents, addUtilities and so on. |
@@ -27,2 +27,3 @@ import log from '../util/log' | ||
900: '#0f172a', | ||
950: '#020617', | ||
}, | ||
@@ -40,2 +41,3 @@ gray: { | ||
900: '#111827', | ||
950: '#030712', | ||
}, | ||
@@ -53,2 +55,3 @@ zinc: { | ||
900: '#18181b', | ||
950: '#09090b', | ||
}, | ||
@@ -66,2 +69,3 @@ neutral: { | ||
900: '#171717', | ||
950: '#0a0a0a', | ||
}, | ||
@@ -79,2 +83,3 @@ stone: { | ||
900: '#1c1917', | ||
950: '#0c0a09', | ||
}, | ||
@@ -92,2 +97,3 @@ red: { | ||
900: '#7f1d1d', | ||
950: '#450a0a', | ||
}, | ||
@@ -105,2 +111,3 @@ orange: { | ||
900: '#7c2d12', | ||
950: '#431407', | ||
}, | ||
@@ -118,2 +125,3 @@ amber: { | ||
900: '#78350f', | ||
950: '#451a03', | ||
}, | ||
@@ -131,2 +139,3 @@ yellow: { | ||
900: '#713f12', | ||
950: '#422006', | ||
}, | ||
@@ -144,2 +153,3 @@ lime: { | ||
900: '#365314', | ||
950: '#1a2e05', | ||
}, | ||
@@ -157,2 +167,3 @@ green: { | ||
900: '#14532d', | ||
950: '#052e16', | ||
}, | ||
@@ -170,2 +181,3 @@ emerald: { | ||
900: '#064e3b', | ||
950: '#022c22', | ||
}, | ||
@@ -183,2 +195,3 @@ teal: { | ||
900: '#134e4a', | ||
950: '#042f2e', | ||
}, | ||
@@ -196,2 +209,3 @@ cyan: { | ||
900: '#164e63', | ||
950: '#083344', | ||
}, | ||
@@ -209,2 +223,3 @@ sky: { | ||
900: '#0c4a6e', | ||
950: '#082f49', | ||
}, | ||
@@ -222,2 +237,3 @@ blue: { | ||
900: '#1e3a8a', | ||
950: '#172554', | ||
}, | ||
@@ -235,2 +251,3 @@ indigo: { | ||
900: '#312e81', | ||
950: '#1e1b4b', | ||
}, | ||
@@ -248,2 +265,3 @@ violet: { | ||
900: '#4c1d95', | ||
950: '#2e1065', | ||
}, | ||
@@ -261,2 +279,3 @@ purple: { | ||
900: '#581c87', | ||
950: '#3b0764', | ||
}, | ||
@@ -274,2 +293,3 @@ fuchsia: { | ||
900: '#701a75', | ||
950: '#4a044e', | ||
}, | ||
@@ -287,2 +307,3 @@ pink: { | ||
900: '#831843', | ||
950: '#500724', | ||
}, | ||
@@ -300,2 +321,3 @@ rose: { | ||
900: '#881337', | ||
950: '#4c0519', | ||
}, | ||
@@ -302,0 +324,0 @@ get lightBlue() { |
import { cloneDeep } from '../util/cloneDeep' | ||
import defaultConfig from '../../stubs/defaultConfig.stub' | ||
import defaultConfig from '../../stubs/config.full' | ||
export default cloneDeep(defaultConfig) |
import { cloneDeep } from '../util/cloneDeep' | ||
import defaultConfig from '../../stubs/defaultConfig.stub' | ||
import defaultFullConfig from '../../stubs/config.full' | ||
export default cloneDeep(defaultConfig.theme) | ||
export default cloneDeep(defaultFullConfig.theme) |
@@ -0,1 +1,7 @@ | ||
/** | ||
* @param {import('postcss').Container[]} nodes | ||
* @param {any} source | ||
* @param {any} raws | ||
* @returns {import('postcss').Container[]} | ||
*/ | ||
export default function cloneNodes(nodes, source = undefined, raws = undefined) { | ||
@@ -5,16 +11,2 @@ return nodes.map((node) => { | ||
// We always want override the source map | ||
// except when explicitly told not to | ||
let shouldOverwriteSource = node.raws.tailwind?.preserveSource !== true || !cloned.source | ||
if (source !== undefined && shouldOverwriteSource) { | ||
cloned.source = source | ||
if ('walk' in cloned) { | ||
cloned.walk((child) => { | ||
child.source = source | ||
}) | ||
} | ||
} | ||
if (raws !== undefined) { | ||
@@ -27,4 +19,33 @@ cloned.raws.tailwind = { | ||
if (source !== undefined) { | ||
traverse(cloned, (node) => { | ||
// Do not traverse nodes that have opted | ||
// to preserve their original source | ||
let shouldPreserveSource = node.raws.tailwind?.preserveSource === true && node.source | ||
if (shouldPreserveSource) { | ||
return false | ||
} | ||
// Otherwise we can safely replace the source | ||
// And continue traversing | ||
node.source = source | ||
}) | ||
} | ||
return cloned | ||
}) | ||
} | ||
/** | ||
* Traverse a tree of nodes and don't traverse children if the callback | ||
* returns false. Ideally we'd use Container#walk instead of this | ||
* function but it stops traversing siblings too. | ||
* | ||
* @param {import('postcss').Container} node | ||
* @param {(node: import('postcss').Container) => boolean} onNode | ||
*/ | ||
function traverse(node, onNode) { | ||
if (onNode(node) !== false) { | ||
node.each?.((child) => traverse(child, onNode)) | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
import namedColors from 'color-name' | ||
import namedColors from './colorNames' | ||
@@ -8,9 +8,9 @@ let HEX = /^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i | ||
let ALPHA_SEP = /\s*[,/]\s*/ | ||
let CUSTOM_PROPERTY = /var\(--(?:[^ )]*?)\)/ | ||
let CUSTOM_PROPERTY = /var\(--(?:[^ )]*?)(?:,(?:[^ )]*?|var\(--[^ )]*?\)))?\)/ | ||
let RGB = new RegExp( | ||
`^(rgb)a?\\(\\s*(${VALUE.source}|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$` | ||
`^(rgba?)\\(\\s*(${VALUE.source}|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$` | ||
) | ||
let HSL = new RegExp( | ||
`^(hsl)a?\\(\\s*((?:${VALUE.source})(?:deg|rad|grad|turn)?|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$` | ||
`^(hsla?)\\(\\s*((?:${VALUE.source})(?:deg|rad|grad|turn)?|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$` | ||
) | ||
@@ -56,2 +56,12 @@ | ||
// rgba(var(--my-color), 0.1) | ||
// hsla(var(--my-color), 0.1) | ||
if (color.length === 2 && color[0].startsWith('var(')) { | ||
return { | ||
mode: match[1], | ||
color: [color[0]], | ||
alpha: color[1], | ||
} | ||
} | ||
if (!loose && color.length !== 3) { | ||
@@ -74,3 +84,8 @@ return null | ||
let hasAlpha = alpha !== undefined | ||
if (mode === 'rgba' || mode === 'hsla') { | ||
return `${mode}(${color.join(', ')}${hasAlpha ? `, ${alpha}` : ''})` | ||
} | ||
return `${mode}(${color.join(' ')}${hasAlpha ? ` / ${alpha}` : ''})` | ||
} |
@@ -13,5 +13,33 @@ import { parseColor } from './color' | ||
// These properties accept a `<dashed-ident>` as one of the values. This means that you can use them | ||
// as: `timeline-scope: --tl;` | ||
// | ||
// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add | ||
// the `var()` yourself. | ||
// | ||
// More info: | ||
// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope | ||
// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident | ||
// | ||
const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ | ||
// Concrete properties | ||
'scroll-timeline-name', | ||
'timeline-scope', | ||
'view-timeline-name', | ||
'font-palette', | ||
// Shorthand properties | ||
'scroll-timeline', | ||
'animation-timeline', | ||
'view-timeline', | ||
]) | ||
// This is not a data type, but rather a function that can normalize the | ||
// correct values. | ||
export function normalize(value, isRoot = true) { | ||
export function normalize(value, context = null, isRoot = true) { | ||
let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property) | ||
if (value.startsWith('--') && !isVarException) { | ||
return `var(${value})` | ||
} | ||
// Keep raw strings if it starts with `url(` | ||
@@ -27,3 +55,3 @@ if (value.includes('url(')) { | ||
return normalize(part, false) | ||
return normalize(part, context, false) | ||
}) | ||
@@ -47,10 +75,3 @@ .join('') | ||
// Add spaces around operators inside math functions like calc() that do not follow an operator | ||
// or '('. | ||
value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match) => { | ||
return match.replace( | ||
/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, | ||
'$1 $2 ' | ||
) | ||
}) | ||
value = normalizeMathOperatorSpacing(value) | ||
@@ -60,2 +81,104 @@ return value | ||
/** | ||
* Add spaces around operators inside math functions | ||
* like calc() that do not follow an operator, '(', or `,`. | ||
* | ||
* @param {string} value | ||
* @returns {string} | ||
*/ | ||
function normalizeMathOperatorSpacing(value) { | ||
let preventFormattingInFunctions = ['theme'] | ||
let preventFormattingKeywords = [ | ||
'min-content', | ||
'max-content', | ||
'fit-content', | ||
// Env | ||
'safe-area-inset-top', | ||
'safe-area-inset-right', | ||
'safe-area-inset-bottom', | ||
'safe-area-inset-left', | ||
'titlebar-area-x', | ||
'titlebar-area-y', | ||
'titlebar-area-width', | ||
'titlebar-area-height', | ||
'keyboard-inset-top', | ||
'keyboard-inset-right', | ||
'keyboard-inset-bottom', | ||
'keyboard-inset-left', | ||
'keyboard-inset-width', | ||
'keyboard-inset-height', | ||
] | ||
return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match) => { | ||
let result = '' | ||
function lastChar() { | ||
let char = result.trimEnd() | ||
return char[char.length - 1] | ||
} | ||
for (let i = 0; i < match.length; i++) { | ||
function peek(word) { | ||
return word.split('').every((char, j) => match[i + j] === char) | ||
} | ||
function consumeUntil(chars) { | ||
let minIndex = Infinity | ||
for (let char of chars) { | ||
let index = match.indexOf(char, i) | ||
if (index !== -1 && index < minIndex) { | ||
minIndex = index | ||
} | ||
} | ||
let result = match.slice(i, minIndex) | ||
i += result.length - 1 | ||
return result | ||
} | ||
let char = match[i] | ||
// Handle `var(--variable)` | ||
if (peek('var')) { | ||
// When we consume until `)`, then we are dealing with this scenario: | ||
// `var(--example)` | ||
// | ||
// When we consume until `,`, then we are dealing with this scenario: | ||
// `var(--example, 1rem)` | ||
// | ||
// In this case we do want to "format", the default value as well | ||
result += consumeUntil([')', ',']) | ||
} | ||
// Skip formatting of known keywords | ||
else if (preventFormattingKeywords.some((keyword) => peek(keyword))) { | ||
let keyword = preventFormattingKeywords.find((keyword) => peek(keyword)) | ||
result += keyword | ||
i += keyword.length - 1 | ||
} | ||
// Skip formatting inside known functions | ||
else if (preventFormattingInFunctions.some((fn) => peek(fn))) { | ||
result += consumeUntil([')']) | ||
} | ||
// Handle operators | ||
else if ( | ||
['+', '-', '*', '/'].includes(char) && | ||
!['(', '+', '-', '*', '/', ','].includes(lastChar()) | ||
) { | ||
result += ` ${char} ` | ||
} else { | ||
result += char | ||
} | ||
} | ||
// Simplify multiple spaces | ||
return result.replace(/\s+/g, ' ') | ||
}) | ||
} | ||
export function url(value) { | ||
@@ -73,2 +196,5 @@ return value.startsWith('url(') | ||
// Please refer to MDN when updating this list: | ||
// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units | ||
// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units | ||
let lengthUnits = [ | ||
@@ -87,2 +213,3 @@ 'cm', | ||
'lh', | ||
'rlh', | ||
'vw', | ||
@@ -92,2 +219,16 @@ 'vh', | ||
'vmax', | ||
'vb', | ||
'vi', | ||
'svw', | ||
'svh', | ||
'lvw', | ||
'lvh', | ||
'dvw', | ||
'dvh', | ||
'cqw', | ||
'cqh', | ||
'cqi', | ||
'cqb', | ||
'cqmin', | ||
'cqmax', | ||
] | ||
@@ -159,7 +300,8 @@ let lengthUnitsPattern = `(?:${lengthUnits.join('|')})` | ||
let gradientTypes = new Set([ | ||
'conic-gradient', | ||
'linear-gradient', | ||
'radial-gradient', | ||
'repeating-conic-gradient', | ||
'repeating-linear-gradient', | ||
'repeating-radial-gradient', | ||
'conic-gradient', | ||
]) | ||
@@ -166,0 +308,0 @@ export function gradient(value) { |
@@ -5,27 +5,56 @@ import selectorParser from 'postcss-selector-parser' | ||
import prefixSelector from '../util/prefixSelector' | ||
import { movePseudos } from './pseudoElements' | ||
import { splitAtTopLevelOnly } from './splitAtTopLevelOnly' | ||
/** @typedef {import('postcss-selector-parser').Root} Root */ | ||
/** @typedef {import('postcss-selector-parser').Selector} Selector */ | ||
/** @typedef {import('postcss-selector-parser').Pseudo} Pseudo */ | ||
/** @typedef {import('postcss-selector-parser').Node} Node */ | ||
/** @typedef {{format: string, respectPrefix: boolean}[]} RawFormats */ | ||
/** @typedef {import('postcss-selector-parser').Root} ParsedFormats */ | ||
/** @typedef {RawFormats | ParsedFormats} AcceptedFormats */ | ||
let MERGE = ':merge' | ||
let PARENT = '&' | ||
export let selectorFunctions = new Set([MERGE]) | ||
/** | ||
* @param {RawFormats} formats | ||
* @param {{context: any, candidate: string, base: string | null}} options | ||
* @returns {ParsedFormats | null} | ||
*/ | ||
export function formatVariantSelector(formats, { context, candidate }) { | ||
let prefix = context?.tailwindConfig.prefix ?? '' | ||
export function formatVariantSelector(current, ...others) { | ||
for (let other of others) { | ||
let incomingValue = resolveFunctionArgument(other, MERGE) | ||
if (incomingValue !== null) { | ||
let existingValue = resolveFunctionArgument(current, MERGE, incomingValue) | ||
if (existingValue !== null) { | ||
let existingTarget = `${MERGE}(${incomingValue})` | ||
let splitIdx = other.indexOf(existingTarget) | ||
let addition = other.slice(splitIdx + existingTarget.length).split(' ')[0] | ||
// Parse the format selector into an AST | ||
let parsedFormats = formats.map((format) => { | ||
let ast = selectorParser().astSync(format.format) | ||
current = current.replace(existingTarget, existingTarget + addition) | ||
continue | ||
} | ||
return { | ||
...format, | ||
ast: format.respectPrefix ? prefixSelector(prefix, ast) : ast, | ||
} | ||
}) | ||
current = other.replace(PARENT, current) | ||
// We start with the candidate selector | ||
let formatAst = selectorParser.root({ | ||
nodes: [ | ||
selectorParser.selector({ | ||
nodes: [selectorParser.className({ value: escapeClassName(candidate) })], | ||
}), | ||
], | ||
}) | ||
// And iteratively merge each format selector into the candidate selector | ||
for (let { ast } of parsedFormats) { | ||
// 1. Handle :merge() special pseudo-class | ||
;[formatAst, ast] = handleMergePseudo(formatAst, ast) | ||
// 2. Merge the format selector into the current selector AST | ||
ast.walkNesting((nesting) => nesting.replaceWith(...formatAst.nodes[0].nodes)) | ||
// 3. Keep going! | ||
formatAst = ast | ||
} | ||
return current | ||
return formatAst | ||
} | ||
@@ -39,7 +68,7 @@ | ||
* | ||
* @param {import('postcss-selector-parser').Node} node | ||
* @returns {import('postcss-selector-parser').Node[]} | ||
* @param {Node} node | ||
* @returns {Node[]} | ||
**/ | ||
function simpleSelectorForNode(node) { | ||
/** @type {import('postcss-selector-parser').Node[]} */ | ||
/** @type {Node[]} */ | ||
let nodes = [] | ||
@@ -65,4 +94,4 @@ | ||
* | ||
* @param {import('postcss-selector-parser').Selector} sel | ||
* @returns {import('postcss-selector-parser').Selector} | ||
* @param {Selector} sel | ||
* @returns {Selector} | ||
**/ | ||
@@ -87,3 +116,15 @@ function resortSelector(sel) { | ||
function eliminateIrrelevantSelectors(sel, base) { | ||
/** | ||
* Remove extraneous selectors that do not include the base class/candidate | ||
* | ||
* Example: | ||
* Given the utility `.a, .b { color: red}` | ||
* Given the candidate `sm:b` | ||
* | ||
* The final selector should be `.sm\:b` and not `.a, .sm\:b` | ||
* | ||
* @param {Selector} ast | ||
* @param {string} base | ||
*/ | ||
export function eliminateIrrelevantSelectors(sel, base) { | ||
let hasClassesMatchingCandidate = false | ||
@@ -111,38 +152,23 @@ | ||
export function finalizeSelector( | ||
format, | ||
{ | ||
selector, | ||
candidate, | ||
context, | ||
isArbitraryVariant, | ||
/** | ||
* @param {string} current | ||
* @param {AcceptedFormats} formats | ||
* @param {{context: any, candidate: string, base: string | null}} options | ||
* @returns {string} | ||
*/ | ||
export function finalizeSelector(current, formats, { context, candidate, base }) { | ||
let separator = context?.tailwindConfig?.separator ?? ':' | ||
// Split by the separator, but ignore the separator inside square brackets: | ||
// | ||
// E.g.: dark:lg:hover:[paint-order:markers] | ||
// ┬ ┬ ┬ ┬ | ||
// │ │ │ ╰── We will not split here | ||
// ╰──┴─────┴─────────────── We will split here | ||
// | ||
base = candidate | ||
.split(new RegExp(`\\${context?.tailwindConfig?.separator ?? ':'}(?![^[]*\\])`)) | ||
.pop(), | ||
} | ||
) { | ||
let ast = selectorParser().astSync(selector) | ||
// Split by the separator, but ignore the separator inside square brackets: | ||
// | ||
// E.g.: dark:lg:hover:[paint-order:markers] | ||
// ┬ ┬ ┬ ┬ | ||
// │ │ │ ╰── We will not split here | ||
// ╰──┴─────┴─────────────── We will split here | ||
// | ||
base = base ?? splitAtTopLevelOnly(candidate, separator).pop() | ||
// We explicitly DO NOT prefix classes in arbitrary variants | ||
if (context?.tailwindConfig?.prefix && !isArbitraryVariant) { | ||
format = prefixSelector(context.tailwindConfig.prefix, format) | ||
} | ||
// Parse the selector into an AST | ||
let selector = selectorParser().astSync(current) | ||
format = format.replace(PARENT, `.${escapeClassName(candidate)}`) | ||
let formatAst = selectorParser().astSync(format) | ||
// Remove extraneous selectors that do not include the base class/candidate being matched against | ||
// For example if we have a utility defined `.a, .b { color: red}` | ||
// And the formatted variant is sm:b then we want the final selector to be `.sm\:b` and not `.a, .sm\:b` | ||
ast.each((sel) => eliminateIrrelevantSelectors(sel, base)) | ||
// Normalize escaped classes, e.g.: | ||
@@ -159,3 +185,3 @@ // | ||
// | ||
ast.walkClasses((node) => { | ||
selector.walkClasses((node) => { | ||
if (node.raws && node.value.includes(base)) { | ||
@@ -166,2 +192,22 @@ node.raws.value = escapeClassName(unescape(node.raws.value)) | ||
// Remove extraneous selectors that do not include the base candidate | ||
selector.each((sel) => eliminateIrrelevantSelectors(sel, base)) | ||
// If ffter eliminating irrelevant selectors, we end up with nothing | ||
// Then the whole "rule" this is associated with does not need to exist | ||
// We use `null` as a marker value for that case | ||
if (selector.length === 0) { | ||
return null | ||
} | ||
// If there are no formats that means there were no variants added to the candidate | ||
// so we can just return the selector as-is | ||
let formatAst = Array.isArray(formats) | ||
? formatVariantSelector(formats, { context, candidate }) | ||
: formats | ||
if (formatAst === null) { | ||
return selector.toString() | ||
} | ||
let simpleStart = selectorParser.comment({ value: '/*__simple__*/' }) | ||
@@ -172,3 +218,3 @@ let simpleEnd = selectorParser.comment({ value: '/*__simple__*/' }) | ||
// now in a normalized escaped value. | ||
ast.walkClasses((node) => { | ||
selector.walkClasses((node) => { | ||
if (node.value !== base) { | ||
@@ -192,3 +238,3 @@ return | ||
for (let child of formatNodes) { | ||
parent.insertBefore(simpleSelector[0], child) | ||
parent.insertBefore(simpleSelector[0], child.clone()) | ||
} | ||
@@ -212,118 +258,77 @@ | ||
// This will make sure to move pseudo's to the correct spot (the end for | ||
// pseudo elements) because otherwise the selector will never work | ||
// anyway. | ||
// | ||
// E.g.: | ||
// - `before:hover:text-center` would result in `.before\:hover\:text-center:hover::before` | ||
// - `hover:before:text-center` would result in `.hover\:before\:text-center:hover::before` | ||
// | ||
// `::before:hover` doesn't work, which means that we can make it work for you by flipping the order. | ||
function collectPseudoElements(selector) { | ||
let nodes = [] | ||
for (let node of selector.nodes) { | ||
if (isPseudoElement(node)) { | ||
nodes.push(node) | ||
selector.removeChild(node) | ||
} | ||
if (node?.nodes) { | ||
nodes.push(...collectPseudoElements(node)) | ||
} | ||
} | ||
return nodes | ||
} | ||
// Remove unnecessary pseudo selectors that we used as placeholders | ||
ast.each((selector) => { | ||
selector.walkPseudos((p) => { | ||
if (selectorFunctions.has(p.value)) { | ||
p.replaceWith(p.nodes) | ||
} | ||
}) | ||
let pseudoElements = collectPseudoElements(selector) | ||
if (pseudoElements.length > 0) { | ||
selector.nodes.push(pseudoElements.sort(sortSelector)) | ||
selector.walkPseudos((p) => { | ||
if (p.value === MERGE) { | ||
p.replaceWith(p.nodes) | ||
} | ||
}) | ||
return ast.toString() | ||
// Move pseudo elements to the end of the selector (if necessary) | ||
selector.each((sel) => movePseudos(sel)) | ||
return selector.toString() | ||
} | ||
// Note: As a rule, double colons (::) should be used instead of a single colon | ||
// (:). This distinguishes pseudo-classes from pseudo-elements. However, since | ||
// this distinction was not present in older versions of the W3C spec, most | ||
// browsers support both syntaxes for the original pseudo-elements. | ||
let pseudoElementsBC = [':before', ':after', ':first-line', ':first-letter'] | ||
/** | ||
* | ||
* @param {Selector} selector | ||
* @param {Selector} format | ||
*/ | ||
export function handleMergePseudo(selector, format) { | ||
/** @type {{pseudo: Pseudo, value: string}[]} */ | ||
let merges = [] | ||
// These pseudo-elements _can_ be combined with other pseudo selectors AND the order does matter. | ||
let pseudoElementExceptions = ['::file-selector-button'] | ||
// Find all :merge() pseudo-classes in `selector` | ||
selector.walkPseudos((pseudo) => { | ||
if (pseudo.value === MERGE) { | ||
merges.push({ | ||
pseudo, | ||
value: pseudo.nodes[0].toString(), | ||
}) | ||
} | ||
}) | ||
// This will make sure to move pseudo's to the correct spot (the end for | ||
// pseudo elements) because otherwise the selector will never work | ||
// anyway. | ||
// | ||
// E.g.: | ||
// - `before:hover:text-center` would result in `.before\:hover\:text-center:hover::before` | ||
// - `hover:before:text-center` would result in `.hover\:before\:text-center:hover::before` | ||
// | ||
// `::before:hover` doesn't work, which means that we can make it work | ||
// for you by flipping the order. | ||
function sortSelector(a, z) { | ||
// Both nodes are non-pseudo's so we can safely ignore them and keep | ||
// them in the same order. | ||
if (a.type !== 'pseudo' && z.type !== 'pseudo') { | ||
return 0 | ||
} | ||
// Find all :merge() "attachments" in `format` and attach them to the matching selector in `selector` | ||
format.walkPseudos((pseudo) => { | ||
if (pseudo.value !== MERGE) { | ||
return | ||
} | ||
// If one of them is a combinator, we need to keep it in the same order | ||
// because that means it will start a new "section" in the selector. | ||
if ((a.type === 'combinator') ^ (z.type === 'combinator')) { | ||
return 0 | ||
} | ||
let value = pseudo.nodes[0].toString() | ||
// One of the items is a pseudo and the other one isn't. Let's move | ||
// the pseudo to the right. | ||
if ((a.type === 'pseudo') ^ (z.type === 'pseudo')) { | ||
return (a.type === 'pseudo') - (z.type === 'pseudo') | ||
} | ||
// Does `selector` contain a :merge() pseudo-class with the same value? | ||
let existing = merges.find((merge) => merge.value === value) | ||
// Both are pseudo's, move the pseudo elements (except for | ||
// ::file-selector-button) to the right. | ||
return isPseudoElement(a) - isPseudoElement(z) | ||
} | ||
// Nope so there's nothing to do | ||
if (!existing) { | ||
return | ||
} | ||
function isPseudoElement(node) { | ||
if (node.type !== 'pseudo') return false | ||
if (pseudoElementExceptions.includes(node.value)) return false | ||
// Everything after `:merge()` up to the next combinator is what is attached to the merged selector | ||
let attachments = [] | ||
let next = pseudo.next() | ||
while (next && next.type !== 'combinator') { | ||
attachments.push(next) | ||
next = next.next() | ||
} | ||
return node.value.startsWith('::') || pseudoElementsBC.includes(node.value) | ||
} | ||
let combinator = next | ||
function resolveFunctionArgument(haystack, needle, arg) { | ||
let startIdx = haystack.indexOf(arg ? `${needle}(${arg})` : needle) | ||
if (startIdx === -1) return null | ||
existing.pseudo.parent.insertAfter( | ||
existing.pseudo, | ||
selectorParser.selector({ nodes: attachments.map((node) => node.clone()) }) | ||
) | ||
// Start inside the `(` | ||
startIdx += needle.length + 1 | ||
pseudo.remove() | ||
attachments.forEach((node) => node.remove()) | ||
let target = '' | ||
let count = 0 | ||
for (let char of haystack.slice(startIdx)) { | ||
if (char !== '(' && char !== ')') { | ||
target += char | ||
} else if (char === '(') { | ||
target += char | ||
count++ | ||
} else if (char === ')') { | ||
if (--count < 0) break // unbalanced | ||
target += char | ||
// What about this case: | ||
// :merge(.group):focus > & | ||
// :merge(.group):hover & | ||
if (combinator && combinator.type === 'combinator') { | ||
combinator.remove() | ||
} | ||
} | ||
}) | ||
return target | ||
return [selector, format] | ||
} |
@@ -1,6 +0,6 @@ | ||
import defaultConfig from '../../stubs/defaultConfig.stub.js' | ||
import defaultFullConfig from '../../stubs/config.full.js' | ||
import { flagEnabled } from '../featureFlags' | ||
export default function getAllConfigs(config) { | ||
const configs = (config?.presets ?? [defaultConfig]) | ||
const configs = (config?.presets ?? [defaultFullConfig]) | ||
.slice() | ||
@@ -7,0 +7,0 @@ .reverse() |
@@ -7,3 +7,3 @@ export default function isPlainObject(value) { | ||
const prototype = Object.getPrototypeOf(value) | ||
return prototype === null || prototype === Object.prototype | ||
return prototype === null || Object.getPrototypeOf(prototype) === null | ||
} |
@@ -1,2 +0,2 @@ | ||
export default function (value) { | ||
export default function negateValue(value) { | ||
value = `${value}` | ||
@@ -3,0 +3,0 @@ |
@@ -0,1 +1,2 @@ | ||
import { flagEnabled } from '../featureFlags' | ||
import log, { dim } from './log' | ||
@@ -192,3 +193,3 @@ | ||
return config.future?.relativeContentPathsByDefault ?? false | ||
return flagEnabled(config, 'relativeContentPathsByDefault') | ||
})(), | ||
@@ -195,0 +196,0 @@ |
@@ -1,2 +0,1 @@ | ||
import selectorParser from 'postcss-selector-parser' | ||
import escapeCommas from './escapeCommas' | ||
@@ -24,33 +23,15 @@ import { withAlphaValue } from './withAlphaVariable' | ||
/** | ||
* @param {import('postcss-selector-parser').Container} selectors | ||
* @param {(className: string) => string} updateClass | ||
* @returns {string} | ||
*/ | ||
export function updateAllClasses(selectors, updateClass) { | ||
let parser = selectorParser((selectors) => { | ||
selectors.walkClasses((sel) => { | ||
let updatedClass = updateClass(sel.value) | ||
sel.value = updatedClass | ||
if (sel.raws && sel.raws.value) { | ||
sel.raws.value = escapeCommas(sel.raws.value) | ||
} | ||
}) | ||
}) | ||
selectors.walkClasses((sel) => { | ||
sel.value = updateClass(sel.value) | ||
let result = parser.processSync(selectors) | ||
return result | ||
} | ||
export function filterSelectorsForClass(selectors, classCandidate) { | ||
let parser = selectorParser((selectors) => { | ||
selectors.each((sel) => { | ||
const containsClass = sel.nodes.some( | ||
(node) => node.type === 'class' && node.value === classCandidate | ||
) | ||
if (!containsClass) { | ||
sel.remove() | ||
} | ||
}) | ||
if (sel.raws && sel.raws.value) { | ||
sel.raws.value = escapeCommas(sel.raws.value) | ||
} | ||
}) | ||
let result = parser.processSync(selectors) | ||
return result | ||
} | ||
@@ -111,2 +92,18 @@ | ||
// If the `/` is inside an arbitrary, we want to find the previous one if any | ||
// This logic probably isn't perfect but it should work for most cases | ||
let arbitraryStartIdx = modifier.lastIndexOf('[', slashIdx) | ||
let arbitraryEndIdx = modifier.indexOf(']', slashIdx) | ||
let isNextToArbitrary = modifier[slashIdx - 1] === ']' || modifier[slashIdx + 1] === '[' | ||
// Backtrack to the previous `/` if the one we found was inside an arbitrary | ||
if (!isNextToArbitrary) { | ||
if (arbitraryStartIdx !== -1 && arbitraryEndIdx !== -1) { | ||
if (arbitraryStartIdx < slashIdx && slashIdx < arbitraryEndIdx) { | ||
slashIdx = modifier.lastIndexOf('/', arbitraryStartIdx) | ||
} | ||
} | ||
} | ||
if (slashIdx === -1 || slashIdx === modifier.length - 1) { | ||
@@ -138,9 +135,9 @@ return [modifier, undefined] | ||
export function asColor( | ||
_, | ||
options = {}, | ||
{ tailwindConfig = {}, utilityModifier, rawModifier } = {} | ||
) { | ||
if (options.values?.[rawModifier] !== undefined) { | ||
return parseColorFormat(options.values?.[rawModifier]) | ||
function unwrapArbitraryModifier(modifier) { | ||
return normalize(modifier.slice(1, -1)) | ||
} | ||
export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) { | ||
if (options.values?.[modifier] !== undefined) { | ||
return parseColorFormat(options.values?.[modifier]) | ||
} | ||
@@ -150,3 +147,3 @@ | ||
// We do this here because we need the alpha value (if any) | ||
let [color, alpha] = splitUtilityModifier(rawModifier) | ||
let [color, alpha] = splitUtilityModifier(modifier) | ||
@@ -164,3 +161,3 @@ if (alpha !== undefined) { | ||
if (isArbitraryValue(alpha)) { | ||
return withAlphaValue(normalizedColor, alpha.slice(1, -1)) | ||
return withAlphaValue(normalizedColor, unwrapArbitraryModifier(alpha)) | ||
} | ||
@@ -175,3 +172,3 @@ | ||
return asValue(rawModifier, options, { rawModifier, utilityModifier, validate: validateColor }) | ||
return asValue(modifier, options, { validate: validateColor }) | ||
} | ||
@@ -184,4 +181,4 @@ | ||
function guess(validate) { | ||
return (modifier, options, extras) => { | ||
return asValue(modifier, options, { ...extras, validate }) | ||
return (modifier, options) => { | ||
return asValue(modifier, options, { validate }) | ||
} | ||
@@ -218,2 +215,16 @@ } | ||
export function coerceValue(types, modifier, options, tailwindConfig) { | ||
if (options.values && modifier in options.values) { | ||
for (let { type } of types ?? []) { | ||
let result = typeMap[type](modifier, options, { | ||
tailwindConfig, | ||
}) | ||
if (result === undefined) { | ||
continue | ||
} | ||
return [result, type, null] | ||
} | ||
} | ||
if (isArbitraryValue(modifier)) { | ||
@@ -288,16 +299,9 @@ let arbitraryValue = modifier.slice(1, -1) | ||
} else if (isArbitraryValue(utilityModifier)) { | ||
utilityModifier = utilityModifier.slice(1, -1) | ||
utilityModifier = unwrapArbitraryModifier(utilityModifier) | ||
} | ||
} | ||
let result = asValue(rawModifier, options, { rawModifier, utilityModifier, tailwindConfig }) | ||
if (result !== undefined) { | ||
yield [result, 'any', null] | ||
} | ||
} | ||
for (const { type } of types ?? []) { | ||
for (let { type } of types ?? []) { | ||
let result = typeMap[type](modifier, options, { | ||
rawModifier, | ||
utilityModifier, | ||
tailwindConfig, | ||
@@ -304,0 +308,0 @@ }) |
import parser from 'postcss-selector-parser' | ||
/** | ||
* @template {string | import('postcss-selector-parser').Root} T | ||
* | ||
* Prefix all classes in the selector with the given prefix | ||
* | ||
* It can take either a string or a selector AST and will return the same type | ||
* | ||
* @param {string} prefix | ||
* @param {T} selector | ||
* @param {boolean} prependNegative | ||
* @returns {T} | ||
*/ | ||
export default function (prefix, selector, prependNegative = false) { | ||
return parser((selectors) => { | ||
selectors.walkClasses((classSelector) => { | ||
let baseClass = classSelector.value | ||
let shouldPlaceNegativeBeforePrefix = prependNegative && baseClass.startsWith('-') | ||
if (prefix === '') { | ||
return selector | ||
} | ||
classSelector.value = shouldPlaceNegativeBeforePrefix | ||
? `-${prefix}${baseClass.slice(1)}` | ||
: `${prefix}${baseClass}` | ||
}) | ||
}).processSync(selector) | ||
/** @type {import('postcss-selector-parser').Root} */ | ||
let ast = typeof selector === 'string' ? parser().astSync(selector) : selector | ||
ast.walkClasses((classSelector) => { | ||
let baseClass = classSelector.value | ||
let shouldPlaceNegativeBeforePrefix = prependNegative && baseClass.startsWith('-') | ||
classSelector.value = shouldPlaceNegativeBeforePrefix | ||
? `-${prefix}${baseClass.slice(1)}` | ||
: `${prefix}${baseClass}` | ||
}) | ||
return typeof selector === 'string' ? ast.toString() : ast | ||
} |
import negateValue from './negateValue' | ||
import corePluginList from '../corePluginList' | ||
import configurePlugins from './configurePlugins' | ||
import defaultConfig from '../../stubs/defaultConfig.stub' | ||
import colors from '../public/colors' | ||
@@ -263,3 +262,2 @@ import { defaults } from './defaults' | ||
separator: ':', | ||
variantOrder: defaultConfig.variantOrder, | ||
}, | ||
@@ -266,0 +264,0 @@ ] |
import fs from 'fs' | ||
import path from 'path' | ||
const defaultConfigFiles = [ | ||
'./tailwind.config.js', | ||
'./tailwind.config.cjs', | ||
'./tailwind.config.mjs', | ||
'./tailwind.config.ts', | ||
] | ||
function isObject(value) { | ||
@@ -46,3 +53,7 @@ return typeof value === 'object' && value !== null | ||
// require('tailwindcss') | ||
for (const configFile of ['./tailwind.config.js', './tailwind.config.cjs']) { | ||
return resolveDefaultConfigPath() | ||
} | ||
export function resolveDefaultConfigPath() { | ||
for (const configFile of defaultConfigFiles) { | ||
try { | ||
@@ -49,0 +60,0 @@ const configPath = path.resolve(configFile) |
@@ -20,2 +20,3 @@ /** | ||
let lastPos = 0 | ||
let isEscaped = false | ||
@@ -25,3 +26,3 @@ for (let idx = 0; idx < input.length; idx++) { | ||
if (stack.length === 0 && char === separator[0]) { | ||
if (stack.length === 0 && char === separator[0] && !isEscaped) { | ||
if (separator.length === 1 || input.slice(idx, idx + separator.length) === separator) { | ||
@@ -33,2 +34,8 @@ parts.push(input.slice(lastPos, idx)) | ||
if (isEscaped) { | ||
isEscaped = false | ||
} else if (char === '\\') { | ||
isEscaped = true | ||
} | ||
if (char === '(' || char === '[' || char === '{') { | ||
@@ -35,0 +42,0 @@ stack.push(char) |
@@ -12,3 +12,16 @@ import log from './log' | ||
// Warn if the line-clamp plugin is installed | ||
try { | ||
let plugin = require('@tailwindcss/line-clamp') | ||
if (config.plugins.includes(plugin)) { | ||
log.warn('line-clamp-in-core', [ | ||
'As of Tailwind CSS v3.3, the `@tailwindcss/line-clamp` plugin is now included by default.', | ||
'Remove it from the `plugins` array in your configuration to eliminate this warning.', | ||
]) | ||
config.plugins = config.plugins.filter((p) => p !== plugin) | ||
} | ||
} catch {} | ||
return config | ||
} |
@@ -14,3 +14,3 @@ import type { CorePluginList } from './generated/corePluginList' | ||
} | ||
type ResolvableTo<T> = T | ((utils: PluginUtils) => T) | ||
export type ResolvableTo<T> = T | ((utils: PluginUtils) => T) | ||
type CSSRuleObject = RecursiveKeyValuePair<string, null | string | string[]> | ||
@@ -50,11 +50,9 @@ | ||
// Safelist related config | ||
type SafelistConfig = | ||
| string[] | ||
| { | ||
pattern: RegExp | ||
variants?: string[] | ||
}[] | ||
type SafelistConfig = string | { pattern: RegExp; variants?: string[] } | ||
// Blocklist related config | ||
type BlocklistConfig = string | ||
// Presets related config | ||
type PresetsConfig = Config[] | ||
type PresetsConfig = Partial<Config> | ||
@@ -86,6 +84,7 @@ // Future related config | ||
// Theme related config | ||
interface ThemeConfig { | ||
export interface ThemeConfig { | ||
// Responsiveness | ||
screens: ResolvableTo<ScreensConfig> | ||
supports: ResolvableTo<Record<string, string>> | ||
data: ResolvableTo<Record<string, string>> | ||
@@ -170,3 +169,9 @@ // Reusable base configs | ||
| string[] | ||
| [fontFamily: string | string[], configuration: Partial<{ fontFeatureSettings: string }>] | ||
| [ | ||
fontFamily: string | string[], | ||
configuration: Partial<{ | ||
fontFeatureSettings: string | ||
fontVariationSettings: string | ||
}> | ||
] | ||
> | ||
@@ -215,3 +220,3 @@ > | ||
contrast: ResolvableTo<KeyValuePair> | ||
dropShadow: ResolvableTo<KeyValuePair> | ||
dropShadow: ResolvableTo<KeyValuePair<string, string | string[]>> | ||
grayscale: ResolvableTo<KeyValuePair> | ||
@@ -237,4 +242,5 @@ hueRotate: ResolvableTo<KeyValuePair> | ||
content: ResolvableTo<KeyValuePair> | ||
} | ||
// Custom | ||
interface CustomThemeConfig extends ThemeConfig { | ||
[key: string]: any | ||
@@ -356,8 +362,9 @@ } | ||
separator: Partial<SeparatorConfig> | ||
safelist: Partial<SafelistConfig> | ||
presets: Partial<PresetsConfig> | ||
safelist: Array<SafelistConfig> | ||
blocklist: Array<BlocklistConfig> | ||
presets: Array<PresetsConfig> | ||
future: Partial<FutureConfig> | ||
experimental: Partial<ExperimentalConfig> | ||
darkMode: Partial<DarkModeConfig> | ||
theme: Partial<ThemeConfig & { extend: Partial<ThemeConfig> }> | ||
theme: Partial<CustomThemeConfig & { extend: Partial<CustomThemeConfig> }> | ||
corePlugins: Partial<CorePluginsConfig> | ||
@@ -364,0 +371,0 @@ plugins: Partial<PluginsConfig> |
@@ -18,2 +18,3 @@ export interface DefaultColors { | ||
'900': '#0f172a' | ||
'950': '#020617' | ||
} | ||
@@ -31,2 +32,3 @@ gray: { | ||
'900': '#111827' | ||
'950': '#030712' | ||
} | ||
@@ -44,2 +46,3 @@ zinc: { | ||
'900': '#18181b' | ||
'950': '#09090b' | ||
} | ||
@@ -57,2 +60,3 @@ neutral: { | ||
'900': '#171717' | ||
'950': '#0a0a0a' | ||
} | ||
@@ -70,2 +74,3 @@ stone: { | ||
'900': '#1c1917' | ||
'950': '#0c0a09' | ||
} | ||
@@ -83,2 +88,3 @@ red: { | ||
'900': '#7f1d1d' | ||
'950': '#450a0a' | ||
} | ||
@@ -96,2 +102,3 @@ orange: { | ||
'900': '#7c2d12' | ||
'950': '#431407' | ||
} | ||
@@ -109,2 +116,3 @@ amber: { | ||
'900': '#78350f' | ||
'950': '#451a03' | ||
} | ||
@@ -122,2 +130,3 @@ yellow: { | ||
'900': '#713f12' | ||
'950': '#422006' | ||
} | ||
@@ -135,2 +144,3 @@ lime: { | ||
'900': '#365314' | ||
'950': '#1a2e05' | ||
} | ||
@@ -148,2 +158,3 @@ green: { | ||
'900': '#14532d' | ||
'950': '#052e16' | ||
} | ||
@@ -161,2 +172,3 @@ emerald: { | ||
'900': '#064e3b' | ||
'950': '#022c22' | ||
} | ||
@@ -174,2 +186,3 @@ teal: { | ||
'900': '#134e4a' | ||
'950': '#042f2e' | ||
} | ||
@@ -187,2 +200,3 @@ cyan: { | ||
'900': '#164e63' | ||
'950': '#083344' | ||
} | ||
@@ -200,2 +214,3 @@ sky: { | ||
'900': '#0c4a6e' | ||
'950': '#082f49' | ||
} | ||
@@ -213,2 +228,3 @@ blue: { | ||
'900': '#1e3a8a' | ||
'950': '#172554' | ||
} | ||
@@ -226,2 +242,3 @@ indigo: { | ||
'900': '#312e81' | ||
'950': '#1e1b4b' | ||
} | ||
@@ -239,2 +256,3 @@ violet: { | ||
'900': '#4c1d95' | ||
'950': '#2e1065' | ||
} | ||
@@ -252,2 +270,3 @@ purple: { | ||
'900': '#581c87' | ||
'950': '#3b0764' | ||
} | ||
@@ -265,2 +284,3 @@ fuchsia: { | ||
'900': '#701a75' | ||
'950': '#4a044e' | ||
} | ||
@@ -278,2 +298,3 @@ pink: { | ||
'900': '#831843' | ||
'950': '#500724' | ||
} | ||
@@ -291,2 +312,3 @@ rose: { | ||
'900': '#881337' | ||
'950': '#4c0519' | ||
} | ||
@@ -293,0 +315,0 @@ /** @deprecated As of Tailwind CSS v2.2, `lightBlue` has been renamed to `sky`. Update your configuration file to silence this warning. */ lightBlue: DefaultColors['sky'] |
@@ -1,1 +0,1 @@ | ||
export type CorePluginList = 'preflight' | 'container' | 'accessibility' | 'pointerEvents' | 'visibility' | 'position' | 'inset' | 'isolation' | 'zIndex' | 'order' | 'gridColumn' | 'gridColumnStart' | 'gridColumnEnd' | 'gridRow' | 'gridRowStart' | 'gridRowEnd' | 'float' | 'clear' | 'margin' | 'boxSizing' | 'display' | 'aspectRatio' | 'height' | 'maxHeight' | 'minHeight' | 'width' | 'minWidth' | 'maxWidth' | 'flex' | 'flexShrink' | 'flexGrow' | 'flexBasis' | 'tableLayout' | 'borderCollapse' | 'borderSpacing' | 'transformOrigin' | 'translate' | 'rotate' | 'skew' | 'scale' | 'transform' | 'animation' | 'cursor' | 'touchAction' | 'userSelect' | 'resize' | 'scrollSnapType' | 'scrollSnapAlign' | 'scrollSnapStop' | 'scrollMargin' | 'scrollPadding' | 'listStylePosition' | 'listStyleType' | 'appearance' | 'columns' | 'breakBefore' | 'breakInside' | 'breakAfter' | 'gridAutoColumns' | 'gridAutoFlow' | 'gridAutoRows' | 'gridTemplateColumns' | 'gridTemplateRows' | 'flexDirection' | 'flexWrap' | 'placeContent' | 'placeItems' | 'alignContent' | 'alignItems' | 'justifyContent' | 'justifyItems' | 'gap' | 'space' | 'divideWidth' | 'divideStyle' | 'divideColor' | 'divideOpacity' | 'placeSelf' | 'alignSelf' | 'justifySelf' | 'overflow' | 'overscrollBehavior' | 'scrollBehavior' | 'textOverflow' | 'whitespace' | 'wordBreak' | 'borderRadius' | 'borderWidth' | 'borderStyle' | 'borderColor' | 'borderOpacity' | 'backgroundColor' | 'backgroundOpacity' | 'backgroundImage' | 'gradientColorStops' | 'boxDecorationBreak' | 'backgroundSize' | 'backgroundAttachment' | 'backgroundClip' | 'backgroundPosition' | 'backgroundRepeat' | 'backgroundOrigin' | 'fill' | 'stroke' | 'strokeWidth' | 'objectFit' | 'objectPosition' | 'padding' | 'textAlign' | 'textIndent' | 'verticalAlign' | 'fontFamily' | 'fontSize' | 'fontWeight' | 'textTransform' | 'fontStyle' | 'fontVariantNumeric' | 'lineHeight' | 'letterSpacing' | 'textColor' | 'textOpacity' | 'textDecoration' | 'textDecorationColor' | 'textDecorationStyle' | 'textDecorationThickness' | 'textUnderlineOffset' | 'fontSmoothing' | 'placeholderColor' | 'placeholderOpacity' | 'caretColor' | 'accentColor' | 'opacity' | 'backgroundBlendMode' | 'mixBlendMode' | 'boxShadow' | 'boxShadowColor' | 'outlineStyle' | 'outlineWidth' | 'outlineOffset' | 'outlineColor' | 'ringWidth' | 'ringColor' | 'ringOpacity' | 'ringOffsetWidth' | 'ringOffsetColor' | 'blur' | 'brightness' | 'contrast' | 'dropShadow' | 'grayscale' | 'hueRotate' | 'invert' | 'saturate' | 'sepia' | 'filter' | 'backdropBlur' | 'backdropBrightness' | 'backdropContrast' | 'backdropGrayscale' | 'backdropHueRotate' | 'backdropInvert' | 'backdropOpacity' | 'backdropSaturate' | 'backdropSepia' | 'backdropFilter' | 'transitionProperty' | 'transitionDelay' | 'transitionDuration' | 'transitionTimingFunction' | 'willChange' | 'content' | ||
export type CorePluginList = 'preflight' | 'container' | 'accessibility' | 'pointerEvents' | 'visibility' | 'position' | 'inset' | 'isolation' | 'zIndex' | 'order' | 'gridColumn' | 'gridColumnStart' | 'gridColumnEnd' | 'gridRow' | 'gridRowStart' | 'gridRowEnd' | 'float' | 'clear' | 'margin' | 'boxSizing' | 'lineClamp' | 'display' | 'aspectRatio' | 'height' | 'maxHeight' | 'minHeight' | 'width' | 'minWidth' | 'maxWidth' | 'flex' | 'flexShrink' | 'flexGrow' | 'flexBasis' | 'tableLayout' | 'captionSide' | 'borderCollapse' | 'borderSpacing' | 'transformOrigin' | 'translate' | 'rotate' | 'skew' | 'scale' | 'transform' | 'animation' | 'cursor' | 'touchAction' | 'userSelect' | 'resize' | 'scrollSnapType' | 'scrollSnapAlign' | 'scrollSnapStop' | 'scrollMargin' | 'scrollPadding' | 'listStylePosition' | 'listStyleType' | 'listStyleImage' | 'appearance' | 'columns' | 'breakBefore' | 'breakInside' | 'breakAfter' | 'gridAutoColumns' | 'gridAutoFlow' | 'gridAutoRows' | 'gridTemplateColumns' | 'gridTemplateRows' | 'flexDirection' | 'flexWrap' | 'placeContent' | 'placeItems' | 'alignContent' | 'alignItems' | 'justifyContent' | 'justifyItems' | 'gap' | 'space' | 'divideWidth' | 'divideStyle' | 'divideColor' | 'divideOpacity' | 'placeSelf' | 'alignSelf' | 'justifySelf' | 'overflow' | 'overscrollBehavior' | 'scrollBehavior' | 'textOverflow' | 'hyphens' | 'whitespace' | 'wordBreak' | 'borderRadius' | 'borderWidth' | 'borderStyle' | 'borderColor' | 'borderOpacity' | 'backgroundColor' | 'backgroundOpacity' | 'backgroundImage' | 'gradientColorStops' | 'boxDecorationBreak' | 'backgroundSize' | 'backgroundAttachment' | 'backgroundClip' | 'backgroundPosition' | 'backgroundRepeat' | 'backgroundOrigin' | 'fill' | 'stroke' | 'strokeWidth' | 'objectFit' | 'objectPosition' | 'padding' | 'textAlign' | 'textIndent' | 'verticalAlign' | 'fontFamily' | 'fontSize' | 'fontWeight' | 'textTransform' | 'fontStyle' | 'fontVariantNumeric' | 'lineHeight' | 'letterSpacing' | 'textColor' | 'textOpacity' | 'textDecoration' | 'textDecorationColor' | 'textDecorationStyle' | 'textDecorationThickness' | 'textUnderlineOffset' | 'fontSmoothing' | 'placeholderColor' | 'placeholderOpacity' | 'caretColor' | 'accentColor' | 'opacity' | 'backgroundBlendMode' | 'mixBlendMode' | 'boxShadow' | 'boxShadowColor' | 'outlineStyle' | 'outlineWidth' | 'outlineOffset' | 'outlineColor' | 'ringWidth' | 'ringColor' | 'ringOpacity' | 'ringOffsetWidth' | 'ringOffsetColor' | 'blur' | 'brightness' | 'contrast' | 'dropShadow' | 'grayscale' | 'hueRotate' | 'invert' | 'saturate' | 'sepia' | 'filter' | 'backdropBlur' | 'backdropBrightness' | 'backdropContrast' | 'backdropGrayscale' | 'backdropHueRotate' | 'backdropInvert' | 'backdropOpacity' | 'backdropSaturate' | 'backdropSepia' | 'backdropFilter' | 'transitionProperty' | 'transitionDelay' | 'transitionDuration' | 'transitionTimingFunction' | 'willChange' | 'content' |
@@ -1,74 +0,6 @@ | ||
import { Config } from '../../types' | ||
type CSSDeclarationList = Record<string, string> | ||
export type DefaultTheme = Config['theme'] & { | ||
screens: Record<'sm' | 'md' | 'lg' | 'xl' | '2xl', string> | ||
columns: Record< | ||
| '1' | ||
| '2' | ||
| '3' | ||
| '4' | ||
| '5' | ||
| '6' | ||
| '7' | ||
| '8' | ||
| '9' | ||
| '10' | ||
| '11' | ||
| '12' | ||
| 'auto' | ||
| '3xs' | ||
| '2xs' | ||
| 'xs' | ||
| 'sm' | ||
| 'md' | ||
| 'lg' | ||
| 'xl' | ||
| '2xl' | ||
| '3xl' | ||
| '4xl' | ||
| '5xl' | ||
| '6xl' | ||
| '7xl', | ||
string | ||
> | ||
spacing: Record< | ||
| '0' | ||
| '1' | ||
| '2' | ||
| '3' | ||
| '4' | ||
| '5' | ||
| '6' | ||
| '7' | ||
| '8' | ||
| '9' | ||
| '10' | ||
| '11' | ||
| '12' | ||
| '14' | ||
| '16' | ||
| '20' | ||
| '24' | ||
| '28' | ||
| '32' | ||
| '36' | ||
| '40' | ||
| '44' | ||
| '48' | ||
| '52' | ||
| '56' | ||
| '60' | ||
| '64' | ||
| '72' | ||
| '80' | ||
| '96' | ||
| 'px' | ||
| '0.5' | ||
| '1.5' | ||
| '2.5' | ||
| '3.5', | ||
string | ||
> | ||
export type DefaultTheme = { | ||
animation: Record<'none' | 'spin' | 'ping' | 'pulse' | 'bounce', string> | ||
aria: Record< | ||
| 'busy' | ||
| 'checked' | ||
@@ -111,2 +43,8 @@ | 'disabled' | ||
blur: Record<'0' | 'none' | 'sm' | 'DEFAULT' | 'md' | 'lg' | 'xl' | '2xl' | '3xl', string> | ||
borderRadius: Record< | ||
'none' | 'sm' | 'DEFAULT' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full', | ||
string | ||
> | ||
borderWidth: Record<'0' | '2' | '4' | '8' | 'DEFAULT', string> | ||
boxShadow: Record<'sm' | 'DEFAULT' | 'md' | 'lg' | 'xl' | '2xl' | 'inner' | 'none', string> | ||
brightness: Record< | ||
@@ -116,10 +54,33 @@ '0' | '50' | '75' | '90' | '95' | '100' | '105' | '110' | '125' | '150' | '200', | ||
> | ||
borderRadius: Record< | ||
'none' | 'sm' | 'DEFAULT' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full', | ||
columns: Record< | ||
| '1' | ||
| '2' | ||
| '3' | ||
| '4' | ||
| '5' | ||
| '6' | ||
| '7' | ||
| '8' | ||
| '9' | ||
| '10' | ||
| '11' | ||
| '12' | ||
| 'auto' | ||
| '3xs' | ||
| '2xs' | ||
| 'xs' | ||
| 'sm' | ||
| 'md' | ||
| 'lg' | ||
| 'xl' | ||
| '2xl' | ||
| '3xl' | ||
| '4xl' | ||
| '5xl' | ||
| '6xl' | ||
| '7xl', | ||
string | ||
> | ||
borderWidth: Record<'0' | '2' | '4' | '8' | 'DEFAULT', string> | ||
boxShadow: Record<'sm' | 'DEFAULT' | 'md' | 'lg' | 'xl' | '2xl' | 'inner' | 'none', string> | ||
content: Record<'none', string> | ||
contrast: Record<'0' | '50' | '75' | '100' | '125' | '150' | '200', string> | ||
content: Record<'none', string> | ||
cursor: Record< | ||
@@ -165,5 +126,2 @@ | 'auto' | ||
dropShadow: Record<'sm' | 'DEFAULT' | 'md' | 'lg' | 'xl' | '2xl' | 'none', string | string[]> | ||
grayscale: Record<'0' | 'DEFAULT', string> | ||
hueRotate: Record<'0' | '15' | '30' | '60' | '90' | '180', string> | ||
invert: Record<'0' | 'DEFAULT', string> | ||
flex: Record<'1' | 'auto' | 'initial' | 'none', string> | ||
@@ -201,2 +159,27 @@ flexGrow: Record<'0' | 'DEFAULT', string> | ||
> | ||
gradientColorStopPositions: Record< | ||
| '0%' | ||
| '5%' | ||
| '10%' | ||
| '15%' | ||
| '20%' | ||
| '25%' | ||
| '30%' | ||
| '35%' | ||
| '40%' | ||
| '45%' | ||
| '50%' | ||
| '55%' | ||
| '60%' | ||
| '65%' | ||
| '70%' | ||
| '75%' | ||
| '80%' | ||
| '85%' | ||
| '90%' | ||
| '95%' | ||
| '100%', | ||
string | ||
> | ||
grayscale: Record<'0' | 'DEFAULT', string> | ||
gridAutoColumns: Record<'auto' | 'min' | 'max' | 'fr', string> | ||
@@ -233,4 +216,4 @@ gridAutoRows: Record<'auto' | 'min' | 'max' | 'fr', string> | ||
> | ||
gridRowEnd: Record<'1' | '2' | '3' | '4' | '5' | '6' | '7' | 'auto', string> | ||
gridRowStart: Record<'1' | '2' | '3' | '4' | '5' | '6' | '7' | 'auto', string> | ||
gridRowEnd: Record<'1' | '2' | '3' | '4' | '5' | '6' | '7' | 'auto', string> | ||
gridTemplateColumns: Record< | ||
@@ -241,2 +224,4 @@ '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'none', | ||
gridTemplateRows: Record<'1' | '2' | '3' | '4' | '5' | '6' | 'none', string> | ||
hueRotate: Record<'0' | '15' | '30' | '60' | '90' | '180', string> | ||
invert: Record<'0' | 'DEFAULT', string> | ||
keyframes: Record<'spin' | 'ping' | 'pulse' | 'bounce', Record<string, CSSDeclarationList>> | ||
@@ -262,2 +247,4 @@ letterSpacing: Record<'tighter' | 'tight' | 'normal' | 'wide' | 'wider' | 'widest', string> | ||
listStyleType: Record<'none' | 'disc' | 'decimal', string> | ||
listStyleImage: Record<'none', string> | ||
lineClamp: Record<'1' | '2' | '3' | '4' | '5' | '6', string> | ||
minHeight: Record<'0' | 'full' | 'screen' | 'min' | 'max' | 'fit', string> | ||
@@ -320,4 +307,43 @@ minWidth: Record<'0' | 'full' | 'min' | 'max' | 'fit', string> | ||
scale: Record<'0' | '50' | '75' | '90' | '95' | '100' | '105' | '110' | '125' | '150', string> | ||
screens: Record<'sm' | 'md' | 'lg' | 'xl' | '2xl', string> | ||
sepia: Record<'0' | 'DEFAULT', string> | ||
skew: Record<'0' | '1' | '2' | '3' | '6' | '12', string> | ||
spacing: Record< | ||
| '0' | ||
| '1' | ||
| '2' | ||
| '3' | ||
| '4' | ||
| '5' | ||
| '6' | ||
| '7' | ||
| '8' | ||
| '9' | ||
| '10' | ||
| '11' | ||
| '12' | ||
| '14' | ||
| '16' | ||
| '20' | ||
| '24' | ||
| '28' | ||
| '32' | ||
| '36' | ||
| '40' | ||
| '44' | ||
| '48' | ||
| '52' | ||
| '56' | ||
| '60' | ||
| '64' | ||
| '72' | ||
| '80' | ||
| '96' | ||
| 'px' | ||
| '0.5' | ||
| '1.5' | ||
| '2.5' | ||
| '3.5', | ||
string | ||
> | ||
strokeWidth: Record<'0' | '1' | '2', string> | ||
@@ -338,5 +364,8 @@ textDecorationThickness: Record<'0' | '1' | '2' | '4' | '8' | 'auto' | 'from-font', string> | ||
> | ||
transitionDelay: Record<'75' | '100' | '150' | '200' | '300' | '500' | '700' | '1000', string> | ||
transitionDelay: Record< | ||
'0' | '75' | '100' | '150' | '200' | '300' | '500' | '700' | '1000', | ||
string | ||
> | ||
transitionDuration: Record< | ||
'75' | '100' | '150' | '200' | '300' | '500' | '700' | '1000' | 'DEFAULT', | ||
'0' | '75' | '100' | '150' | '200' | '300' | '500' | '700' | '1000' | 'DEFAULT', | ||
string | ||
@@ -343,0 +372,0 @@ > |
@@ -1,2 +0,2 @@ | ||
import { PluginCreator } from 'postcss' | ||
import type { PluginCreator } from 'postcss' | ||
import type { Config } from './config.d' | ||
@@ -6,3 +6,7 @@ | ||
export { Config } | ||
export default plugin | ||
declare type _Config = Config | ||
declare namespace plugin { | ||
export type { _Config as Config } | ||
} | ||
export = plugin |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
5574436
22
275
0
19
34347
59
14
254
+ Added@alloc/quick-lru@^5.2.0
+ Addedjiti@^1.19.1
+ Addedsucrase@^3.32.0
+ Added@alloc/quick-lru@5.2.0(transitive)
+ Added@isaacs/cliui@8.0.2(transitive)
+ Added@jridgewell/gen-mapping@0.3.5(transitive)
+ Added@jridgewell/resolve-uri@3.1.2(transitive)
+ Added@jridgewell/set-array@1.2.1(transitive)
+ Added@jridgewell/sourcemap-codec@1.5.0(transitive)
+ Added@jridgewell/trace-mapping@0.3.25(transitive)
+ Added@pkgjs/parseargs@0.11.0(transitive)
+ Addedansi-regex@5.0.16.0.1(transitive)
+ Addedansi-styles@4.3.06.2.1(transitive)
+ Addedany-promise@1.3.0(transitive)
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbrace-expansion@2.0.1(transitive)
+ Addedcolor-convert@2.0.1(transitive)
+ Addedcommander@4.1.1(transitive)
+ Addedcross-spawn@7.0.3(transitive)
+ Addedeastasianwidth@0.2.0(transitive)
+ Addedemoji-regex@8.0.09.2.2(transitive)
+ Addedforeground-child@3.3.0(transitive)
+ Addedglob@10.4.5(transitive)
+ Addedis-fullwidth-code-point@3.0.0(transitive)
+ Addedisexe@2.0.0(transitive)
+ Addedjackspeak@3.4.3(transitive)
+ Addedjiti@1.21.6(transitive)
+ Addedlilconfig@3.1.2(transitive)
+ Addedlines-and-columns@1.2.4(transitive)
+ Addedlru-cache@10.4.3(transitive)
+ Addedminimatch@9.0.5(transitive)
+ Addedminipass@7.1.2(transitive)
+ Addedmz@2.7.0(transitive)
+ Addedobject-assign@4.1.1(transitive)
+ Addedpackage-json-from-dist@1.0.0(transitive)
+ Addedpath-key@3.1.1(transitive)
+ Addedpath-scurry@1.11.1(transitive)
+ Addedpirates@4.0.6(transitive)
+ Addedpostcss-import@15.1.0(transitive)
+ Addedpostcss-load-config@4.0.2(transitive)
+ Addedpostcss-nested@6.2.0(transitive)
+ Addedshebang-command@2.0.0(transitive)
+ Addedshebang-regex@3.0.0(transitive)
+ Addedsignal-exit@4.1.0(transitive)
+ Addedstring-width@4.2.35.1.2(transitive)
+ Addedstrip-ansi@6.0.17.1.0(transitive)
+ Addedsucrase@3.35.0(transitive)
+ Addedthenify@3.3.1(transitive)
+ Addedthenify-all@1.6.0(transitive)
+ Addedts-interface-checker@0.1.13(transitive)
+ Addedwhich@2.0.2(transitive)
+ Addedwrap-ansi@7.0.08.1.0(transitive)
+ Addedyaml@2.5.0(transitive)
- Removedcolor-name@^1.1.4
- Removeddetective@^5.2.1
- Removedpostcss-value-parser@^4.2.0
- Removedquick-lru@^5.1.1
- Removedacorn@7.4.1(transitive)
- Removedacorn-node@1.8.2(transitive)
- Removedacorn-walk@7.2.0(transitive)
- Removeddefined@1.0.1(transitive)
- Removeddetective@5.2.1(transitive)
- Removedminimist@1.2.8(transitive)
- Removedpostcss-import@14.1.0(transitive)
- Removedpostcss-load-config@3.1.4(transitive)
- Removedpostcss-nested@6.0.0(transitive)
- Removedquick-lru@5.1.1(transitive)
- Removedxtend@4.0.2(transitive)
- Removedyaml@1.10.2(transitive)
Updatedfast-glob@^3.3.0
Updatedlilconfig@^2.1.0
Updatedpostcss@^8.4.23
Updatedpostcss-import@^15.1.0
Updatedpostcss-js@^4.0.1
Updatedpostcss-load-config@^4.0.1
Updatedpostcss-nested@^6.0.1
Updatedresolve@^1.22.2